diff --git a/dist/index.d.mts b/dist/index.d.mts index 3954005..5b1d3ca 100644 --- a/dist/index.d.mts +++ b/dist/index.d.mts @@ -1,5 +1,180 @@ import { SqlJsStatic, Database } from 'sql.js'; +/** + * GTFS Realtime TypeScript types + * Based on GTFS Realtime v2.0 specification + */ +declare enum ScheduleRelationship { + SCHEDULED = 0, + ADDED = 1, + UNSCHEDULED = 2, + CANCELED = 3, + SKIPPED = 4, + NO_DATA = 5 +} +declare enum VehicleStopStatus { + INCOMING_AT = 0, + STOPPED_AT = 1, + IN_TRANSIT_TO = 2 +} +declare enum CongestionLevel { + UNKNOWN_CONGESTION_LEVEL = 0, + RUNNING_SMOOTHLY = 1, + STOP_AND_GO = 2, + CONGESTION = 3, + SEVERE_CONGESTION = 4 +} +declare enum OccupancyStatus { + EMPTY = 0, + MANY_SEATS_AVAILABLE = 1, + FEW_SEATS_AVAILABLE = 2, + STANDING_ROOM_ONLY = 3, + CRUSHED_STANDING_ROOM_ONLY = 4, + FULL = 5, + NOT_ACCEPTING_PASSENGERS = 6 +} +declare enum AlertCause { + UNKNOWN_CAUSE = 1, + OTHER_CAUSE = 2, + TECHNICAL_PROBLEM = 3, + STRIKE = 4, + DEMONSTRATION = 5, + ACCIDENT = 6, + HOLIDAY = 7, + WEATHER = 8, + MAINTENANCE = 9, + CONSTRUCTION = 10, + POLICE_ACTIVITY = 11, + MEDICAL_EMERGENCY = 12 +} +declare enum AlertEffect { + NO_SERVICE = 1, + REDUCED_SERVICE = 2, + SIGNIFICANT_DELAYS = 3, + DETOUR = 4, + ADDITIONAL_SERVICE = 5, + MODIFIED_SERVICE = 6, + OTHER_EFFECT = 7, + UNKNOWN_EFFECT = 8, + STOP_MOVED = 9, + NO_EFFECT = 10, + ACCESSIBILITY_ISSUE = 11 +} +interface TranslatedString { + translation: Array<{ + text: string; + language?: string; + }>; +} +interface EntitySelector { + agency_id?: string; + route_id?: string; + route_type?: number; + trip?: { + trip_id?: string; + route_id?: string; + direction_id?: number; + start_time?: string; + start_date?: string; + schedule_relationship?: ScheduleRelationship; + }; + stop_id?: string; +} +interface TimeRange { + start?: number; + end?: number; +} +interface Alert { + id: string; + active_period: TimeRange[]; + informed_entity: EntitySelector[]; + cause?: AlertCause; + effect?: AlertEffect; + url?: TranslatedString; + header_text?: TranslatedString; + description_text?: TranslatedString; + rt_last_updated: number; +} +interface Position { + latitude: number; + longitude: number; + bearing?: number; + odometer?: number; + speed?: number; +} +interface VehicleDescriptor { + id?: string; + label?: string; + license_plate?: string; +} +interface VehiclePosition { + trip_id: string; + route_id?: string; + vehicle?: VehicleDescriptor; + position?: Position; + current_stop_sequence?: number; + stop_id?: string; + current_status?: VehicleStopStatus; + timestamp?: number; + congestion_level?: CongestionLevel; + occupancy_status?: OccupancyStatus; + rt_last_updated: number; +} +interface StopTimeEvent { + delay?: number; + time?: number; + uncertainty?: number; +} +interface StopTimeUpdate { + stop_sequence?: number; + stop_id?: string; + arrival?: StopTimeEvent; + departure?: StopTimeEvent; + schedule_relationship?: ScheduleRelationship; +} +interface TripUpdate { + trip_id: string; + route_id?: string; + vehicle?: VehicleDescriptor; + stop_time_update: StopTimeUpdate[]; + timestamp?: number; + delay?: number; + schedule_relationship?: ScheduleRelationship; + rt_last_updated: number; +} +interface StopTimeRealtime { + arrival_delay?: number; + departure_delay?: number; + schedule_relationship?: ScheduleRelationship; +} +interface TripRealtime { + vehicle_position?: VehiclePosition | null; + trip_update?: { + delay?: number; + schedule_relationship?: ScheduleRelationship; + } | null; +} +interface AlertFilters { + alertId?: string; + activeOnly?: boolean; + routeId?: string; + stopId?: string; + tripId?: string; + cause?: AlertCause; + effect?: AlertEffect; + limit?: number; +} +interface VehiclePositionFilters { + tripId?: string; + routeId?: string; + vehicleId?: string; + limit?: number; +} +interface RealtimeConfig { + feedUrls?: string[]; + stalenessThreshold?: number; +} + /** * GTFS Type Definitions * Based on GTFS Reference: https://gtfs.org/schedule/reference/ @@ -246,181 +421,6 @@ interface RouteFilters { limit?: number; } -/** - * GTFS Realtime TypeScript types - * Based on GTFS Realtime v2.0 specification - */ -declare enum ScheduleRelationship { - SCHEDULED = 0, - ADDED = 1, - UNSCHEDULED = 2, - CANCELED = 3, - SKIPPED = 4, - NO_DATA = 5 -} -declare enum VehicleStopStatus { - INCOMING_AT = 0, - STOPPED_AT = 1, - IN_TRANSIT_TO = 2 -} -declare enum CongestionLevel { - UNKNOWN_CONGESTION_LEVEL = 0, - RUNNING_SMOOTHLY = 1, - STOP_AND_GO = 2, - CONGESTION = 3, - SEVERE_CONGESTION = 4 -} -declare enum OccupancyStatus { - EMPTY = 0, - MANY_SEATS_AVAILABLE = 1, - FEW_SEATS_AVAILABLE = 2, - STANDING_ROOM_ONLY = 3, - CRUSHED_STANDING_ROOM_ONLY = 4, - FULL = 5, - NOT_ACCEPTING_PASSENGERS = 6 -} -declare enum AlertCause { - UNKNOWN_CAUSE = 1, - OTHER_CAUSE = 2, - TECHNICAL_PROBLEM = 3, - STRIKE = 4, - DEMONSTRATION = 5, - ACCIDENT = 6, - HOLIDAY = 7, - WEATHER = 8, - MAINTENANCE = 9, - CONSTRUCTION = 10, - POLICE_ACTIVITY = 11, - MEDICAL_EMERGENCY = 12 -} -declare enum AlertEffect { - NO_SERVICE = 1, - REDUCED_SERVICE = 2, - SIGNIFICANT_DELAYS = 3, - DETOUR = 4, - ADDITIONAL_SERVICE = 5, - MODIFIED_SERVICE = 6, - OTHER_EFFECT = 7, - UNKNOWN_EFFECT = 8, - STOP_MOVED = 9, - NO_EFFECT = 10, - ACCESSIBILITY_ISSUE = 11 -} -interface TranslatedString { - translation: Array<{ - text: string; - language?: string; - }>; -} -interface EntitySelector { - agency_id?: string; - route_id?: string; - route_type?: number; - trip?: { - trip_id?: string; - route_id?: string; - direction_id?: number; - start_time?: string; - start_date?: string; - schedule_relationship?: ScheduleRelationship; - }; - stop_id?: string; -} -interface TimeRange { - start?: number; - end?: number; -} -interface Alert { - id: string; - active_period: TimeRange[]; - informed_entity: EntitySelector[]; - cause?: AlertCause; - effect?: AlertEffect; - url?: TranslatedString; - header_text?: TranslatedString; - description_text?: TranslatedString; - rt_last_updated: number; -} -interface Position { - latitude: number; - longitude: number; - bearing?: number; - odometer?: number; - speed?: number; -} -interface VehicleDescriptor { - id?: string; - label?: string; - license_plate?: string; -} -interface VehiclePosition { - trip_id: string; - route_id?: string; - vehicle?: VehicleDescriptor; - position?: Position; - current_stop_sequence?: number; - stop_id?: string; - current_status?: VehicleStopStatus; - timestamp?: number; - congestion_level?: CongestionLevel; - occupancy_status?: OccupancyStatus; - rt_last_updated: number; -} -interface StopTimeEvent { - delay?: number; - time?: number; - uncertainty?: number; -} -interface StopTimeUpdate { - stop_sequence?: number; - stop_id?: string; - arrival?: StopTimeEvent; - departure?: StopTimeEvent; - schedule_relationship?: ScheduleRelationship; -} -interface TripUpdate { - trip_id: string; - route_id?: string; - vehicle?: VehicleDescriptor; - stop_time_update: StopTimeUpdate[]; - timestamp?: number; - delay?: number; - schedule_relationship?: ScheduleRelationship; - rt_last_updated: number; -} -interface StopTimeRealtime { - arrival_delay?: number; - departure_delay?: number; - schedule_relationship?: ScheduleRelationship; -} -interface TripRealtime { - vehicle_position?: VehiclePosition | null; - trip_update?: { - delay?: number; - schedule_relationship?: ScheduleRelationship; - } | null; -} -interface AlertFilters { - alertId?: string; - activeOnly?: boolean; - routeId?: string; - stopId?: string; - tripId?: string; - cause?: AlertCause; - effect?: AlertEffect; - limit?: number; -} -interface VehiclePositionFilters { - tripId?: string; - routeId?: string; - vehicleId?: string; - limit?: number; -} -interface RealtimeConfig { - feedUrls?: string[]; - stalenessThreshold?: number; -} - /** * Trip Query Methods */ @@ -456,9 +456,26 @@ interface StopTimeWithRealtime extends StopTime { realtime?: StopTimeRealtime; } +interface TripUpdateFilters { + tripId?: string; + routeId?: string; + vehicleId?: string; + limit?: number; +} + +interface StopTimeUpdateFilters { + tripId?: string; + stopId?: string; + stopSequence?: number; + limit?: number; +} /** - * Main GtfsSqlJs Class + * Extended StopTimeUpdate with trip_id and rt_last_updated for debugging */ +interface StopTimeUpdateWithMetadata extends StopTimeUpdate { + trip_id: string; + rt_last_updated: number; +} interface GtfsSqlJsOptions { /** @@ -667,6 +684,39 @@ declare class GtfsSqlJs { * Get vehicle position by trip ID */ getVehiclePositionByTripId(tripId: string): VehiclePosition | null; + /** + * Get trip updates with optional filters + */ + getTripUpdates(filters?: TripUpdateFilters): TripUpdate[]; + /** + * Get trip update by trip ID + */ + getTripUpdateByTripId(tripId: string): TripUpdate | null; + /** + * Get stop time updates with optional filters + */ + getStopTimeUpdates(filters?: StopTimeUpdateFilters): StopTimeUpdate[]; + /** + * Get stop time updates for a specific trip + */ + getStopTimeUpdatesByTripId(tripId: string): StopTimeUpdate[]; + /** + * Export all alerts without staleness filtering (for debugging) + */ + debugExportAllAlerts(): Alert[]; + /** + * Export all vehicle positions without staleness filtering (for debugging) + */ + debugExportAllVehiclePositions(): VehiclePosition[]; + /** + * Export all trip updates without staleness filtering (for debugging) + */ + debugExportAllTripUpdates(): TripUpdate[]; + /** + * Export all stop time updates without staleness filtering (for debugging) + * Returns extended type with trip_id and rt_last_updated for debugging purposes + */ + debugExportAllStopTimeUpdates(): StopTimeUpdateWithMetadata[]; } /** @@ -691,4 +741,4 @@ interface IndexDefinition { } declare const GTFS_SCHEMA: TableSchema[]; -export { type Agency, type AgencyFilters, type Alert, AlertCause, AlertEffect, type AlertFilters, type Attribution, type Calendar, type CalendarDate, type ColumnDefinition, CongestionLevel, type EntitySelector, type FareAttribute, type FareRule, type FeedInfo, type Frequency, GTFS_SCHEMA, GtfsSqlJs, type GtfsSqlJsOptions, type IndexDefinition, type Level, OccupancyStatus, type Pathway, type Position, type RealtimeConfig, type Route, type RouteFilters, ScheduleRelationship, type Shape, type Stop, type StopFilters, type StopTime, type StopTimeEvent, type StopTimeFilters, type StopTimeRealtime, type StopTimeUpdate, type StopTimeWithRealtime, type TableSchema, type TimeRange, type Transfer, type TranslatedString, type Trip, type TripFilters, type TripRealtime, type TripUpdate, type TripWithRealtime, type VehicleDescriptor, type VehiclePosition, type VehiclePositionFilters, VehicleStopStatus }; +export { type Agency, type AgencyFilters, type Alert, AlertCause, AlertEffect, type AlertFilters, type Attribution, type Calendar, type CalendarDate, type ColumnDefinition, CongestionLevel, type EntitySelector, type FareAttribute, type FareRule, type FeedInfo, type Frequency, GTFS_SCHEMA, GtfsSqlJs, type GtfsSqlJsOptions, type IndexDefinition, type Level, OccupancyStatus, type Pathway, type Position, type RealtimeConfig, type Route, type RouteFilters, ScheduleRelationship, type Shape, type Stop, type StopFilters, type StopTime, type StopTimeEvent, type StopTimeFilters, type StopTimeRealtime, type StopTimeUpdate, type StopTimeUpdateFilters, type StopTimeUpdateWithMetadata, type StopTimeWithRealtime, type TableSchema, type TimeRange, type Transfer, type TranslatedString, type Trip, type TripFilters, type TripRealtime, type TripUpdate, type TripUpdateFilters, type TripWithRealtime, type VehicleDescriptor, type VehiclePosition, type VehiclePositionFilters, VehicleStopStatus }; diff --git a/dist/index.d.ts b/dist/index.d.ts index 3954005..5b1d3ca 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,5 +1,180 @@ import { SqlJsStatic, Database } from 'sql.js'; +/** + * GTFS Realtime TypeScript types + * Based on GTFS Realtime v2.0 specification + */ +declare enum ScheduleRelationship { + SCHEDULED = 0, + ADDED = 1, + UNSCHEDULED = 2, + CANCELED = 3, + SKIPPED = 4, + NO_DATA = 5 +} +declare enum VehicleStopStatus { + INCOMING_AT = 0, + STOPPED_AT = 1, + IN_TRANSIT_TO = 2 +} +declare enum CongestionLevel { + UNKNOWN_CONGESTION_LEVEL = 0, + RUNNING_SMOOTHLY = 1, + STOP_AND_GO = 2, + CONGESTION = 3, + SEVERE_CONGESTION = 4 +} +declare enum OccupancyStatus { + EMPTY = 0, + MANY_SEATS_AVAILABLE = 1, + FEW_SEATS_AVAILABLE = 2, + STANDING_ROOM_ONLY = 3, + CRUSHED_STANDING_ROOM_ONLY = 4, + FULL = 5, + NOT_ACCEPTING_PASSENGERS = 6 +} +declare enum AlertCause { + UNKNOWN_CAUSE = 1, + OTHER_CAUSE = 2, + TECHNICAL_PROBLEM = 3, + STRIKE = 4, + DEMONSTRATION = 5, + ACCIDENT = 6, + HOLIDAY = 7, + WEATHER = 8, + MAINTENANCE = 9, + CONSTRUCTION = 10, + POLICE_ACTIVITY = 11, + MEDICAL_EMERGENCY = 12 +} +declare enum AlertEffect { + NO_SERVICE = 1, + REDUCED_SERVICE = 2, + SIGNIFICANT_DELAYS = 3, + DETOUR = 4, + ADDITIONAL_SERVICE = 5, + MODIFIED_SERVICE = 6, + OTHER_EFFECT = 7, + UNKNOWN_EFFECT = 8, + STOP_MOVED = 9, + NO_EFFECT = 10, + ACCESSIBILITY_ISSUE = 11 +} +interface TranslatedString { + translation: Array<{ + text: string; + language?: string; + }>; +} +interface EntitySelector { + agency_id?: string; + route_id?: string; + route_type?: number; + trip?: { + trip_id?: string; + route_id?: string; + direction_id?: number; + start_time?: string; + start_date?: string; + schedule_relationship?: ScheduleRelationship; + }; + stop_id?: string; +} +interface TimeRange { + start?: number; + end?: number; +} +interface Alert { + id: string; + active_period: TimeRange[]; + informed_entity: EntitySelector[]; + cause?: AlertCause; + effect?: AlertEffect; + url?: TranslatedString; + header_text?: TranslatedString; + description_text?: TranslatedString; + rt_last_updated: number; +} +interface Position { + latitude: number; + longitude: number; + bearing?: number; + odometer?: number; + speed?: number; +} +interface VehicleDescriptor { + id?: string; + label?: string; + license_plate?: string; +} +interface VehiclePosition { + trip_id: string; + route_id?: string; + vehicle?: VehicleDescriptor; + position?: Position; + current_stop_sequence?: number; + stop_id?: string; + current_status?: VehicleStopStatus; + timestamp?: number; + congestion_level?: CongestionLevel; + occupancy_status?: OccupancyStatus; + rt_last_updated: number; +} +interface StopTimeEvent { + delay?: number; + time?: number; + uncertainty?: number; +} +interface StopTimeUpdate { + stop_sequence?: number; + stop_id?: string; + arrival?: StopTimeEvent; + departure?: StopTimeEvent; + schedule_relationship?: ScheduleRelationship; +} +interface TripUpdate { + trip_id: string; + route_id?: string; + vehicle?: VehicleDescriptor; + stop_time_update: StopTimeUpdate[]; + timestamp?: number; + delay?: number; + schedule_relationship?: ScheduleRelationship; + rt_last_updated: number; +} +interface StopTimeRealtime { + arrival_delay?: number; + departure_delay?: number; + schedule_relationship?: ScheduleRelationship; +} +interface TripRealtime { + vehicle_position?: VehiclePosition | null; + trip_update?: { + delay?: number; + schedule_relationship?: ScheduleRelationship; + } | null; +} +interface AlertFilters { + alertId?: string; + activeOnly?: boolean; + routeId?: string; + stopId?: string; + tripId?: string; + cause?: AlertCause; + effect?: AlertEffect; + limit?: number; +} +interface VehiclePositionFilters { + tripId?: string; + routeId?: string; + vehicleId?: string; + limit?: number; +} +interface RealtimeConfig { + feedUrls?: string[]; + stalenessThreshold?: number; +} + /** * GTFS Type Definitions * Based on GTFS Reference: https://gtfs.org/schedule/reference/ @@ -246,181 +421,6 @@ interface RouteFilters { limit?: number; } -/** - * GTFS Realtime TypeScript types - * Based on GTFS Realtime v2.0 specification - */ -declare enum ScheduleRelationship { - SCHEDULED = 0, - ADDED = 1, - UNSCHEDULED = 2, - CANCELED = 3, - SKIPPED = 4, - NO_DATA = 5 -} -declare enum VehicleStopStatus { - INCOMING_AT = 0, - STOPPED_AT = 1, - IN_TRANSIT_TO = 2 -} -declare enum CongestionLevel { - UNKNOWN_CONGESTION_LEVEL = 0, - RUNNING_SMOOTHLY = 1, - STOP_AND_GO = 2, - CONGESTION = 3, - SEVERE_CONGESTION = 4 -} -declare enum OccupancyStatus { - EMPTY = 0, - MANY_SEATS_AVAILABLE = 1, - FEW_SEATS_AVAILABLE = 2, - STANDING_ROOM_ONLY = 3, - CRUSHED_STANDING_ROOM_ONLY = 4, - FULL = 5, - NOT_ACCEPTING_PASSENGERS = 6 -} -declare enum AlertCause { - UNKNOWN_CAUSE = 1, - OTHER_CAUSE = 2, - TECHNICAL_PROBLEM = 3, - STRIKE = 4, - DEMONSTRATION = 5, - ACCIDENT = 6, - HOLIDAY = 7, - WEATHER = 8, - MAINTENANCE = 9, - CONSTRUCTION = 10, - POLICE_ACTIVITY = 11, - MEDICAL_EMERGENCY = 12 -} -declare enum AlertEffect { - NO_SERVICE = 1, - REDUCED_SERVICE = 2, - SIGNIFICANT_DELAYS = 3, - DETOUR = 4, - ADDITIONAL_SERVICE = 5, - MODIFIED_SERVICE = 6, - OTHER_EFFECT = 7, - UNKNOWN_EFFECT = 8, - STOP_MOVED = 9, - NO_EFFECT = 10, - ACCESSIBILITY_ISSUE = 11 -} -interface TranslatedString { - translation: Array<{ - text: string; - language?: string; - }>; -} -interface EntitySelector { - agency_id?: string; - route_id?: string; - route_type?: number; - trip?: { - trip_id?: string; - route_id?: string; - direction_id?: number; - start_time?: string; - start_date?: string; - schedule_relationship?: ScheduleRelationship; - }; - stop_id?: string; -} -interface TimeRange { - start?: number; - end?: number; -} -interface Alert { - id: string; - active_period: TimeRange[]; - informed_entity: EntitySelector[]; - cause?: AlertCause; - effect?: AlertEffect; - url?: TranslatedString; - header_text?: TranslatedString; - description_text?: TranslatedString; - rt_last_updated: number; -} -interface Position { - latitude: number; - longitude: number; - bearing?: number; - odometer?: number; - speed?: number; -} -interface VehicleDescriptor { - id?: string; - label?: string; - license_plate?: string; -} -interface VehiclePosition { - trip_id: string; - route_id?: string; - vehicle?: VehicleDescriptor; - position?: Position; - current_stop_sequence?: number; - stop_id?: string; - current_status?: VehicleStopStatus; - timestamp?: number; - congestion_level?: CongestionLevel; - occupancy_status?: OccupancyStatus; - rt_last_updated: number; -} -interface StopTimeEvent { - delay?: number; - time?: number; - uncertainty?: number; -} -interface StopTimeUpdate { - stop_sequence?: number; - stop_id?: string; - arrival?: StopTimeEvent; - departure?: StopTimeEvent; - schedule_relationship?: ScheduleRelationship; -} -interface TripUpdate { - trip_id: string; - route_id?: string; - vehicle?: VehicleDescriptor; - stop_time_update: StopTimeUpdate[]; - timestamp?: number; - delay?: number; - schedule_relationship?: ScheduleRelationship; - rt_last_updated: number; -} -interface StopTimeRealtime { - arrival_delay?: number; - departure_delay?: number; - schedule_relationship?: ScheduleRelationship; -} -interface TripRealtime { - vehicle_position?: VehiclePosition | null; - trip_update?: { - delay?: number; - schedule_relationship?: ScheduleRelationship; - } | null; -} -interface AlertFilters { - alertId?: string; - activeOnly?: boolean; - routeId?: string; - stopId?: string; - tripId?: string; - cause?: AlertCause; - effect?: AlertEffect; - limit?: number; -} -interface VehiclePositionFilters { - tripId?: string; - routeId?: string; - vehicleId?: string; - limit?: number; -} -interface RealtimeConfig { - feedUrls?: string[]; - stalenessThreshold?: number; -} - /** * Trip Query Methods */ @@ -456,9 +456,26 @@ interface StopTimeWithRealtime extends StopTime { realtime?: StopTimeRealtime; } +interface TripUpdateFilters { + tripId?: string; + routeId?: string; + vehicleId?: string; + limit?: number; +} + +interface StopTimeUpdateFilters { + tripId?: string; + stopId?: string; + stopSequence?: number; + limit?: number; +} /** - * Main GtfsSqlJs Class + * Extended StopTimeUpdate with trip_id and rt_last_updated for debugging */ +interface StopTimeUpdateWithMetadata extends StopTimeUpdate { + trip_id: string; + rt_last_updated: number; +} interface GtfsSqlJsOptions { /** @@ -667,6 +684,39 @@ declare class GtfsSqlJs { * Get vehicle position by trip ID */ getVehiclePositionByTripId(tripId: string): VehiclePosition | null; + /** + * Get trip updates with optional filters + */ + getTripUpdates(filters?: TripUpdateFilters): TripUpdate[]; + /** + * Get trip update by trip ID + */ + getTripUpdateByTripId(tripId: string): TripUpdate | null; + /** + * Get stop time updates with optional filters + */ + getStopTimeUpdates(filters?: StopTimeUpdateFilters): StopTimeUpdate[]; + /** + * Get stop time updates for a specific trip + */ + getStopTimeUpdatesByTripId(tripId: string): StopTimeUpdate[]; + /** + * Export all alerts without staleness filtering (for debugging) + */ + debugExportAllAlerts(): Alert[]; + /** + * Export all vehicle positions without staleness filtering (for debugging) + */ + debugExportAllVehiclePositions(): VehiclePosition[]; + /** + * Export all trip updates without staleness filtering (for debugging) + */ + debugExportAllTripUpdates(): TripUpdate[]; + /** + * Export all stop time updates without staleness filtering (for debugging) + * Returns extended type with trip_id and rt_last_updated for debugging purposes + */ + debugExportAllStopTimeUpdates(): StopTimeUpdateWithMetadata[]; } /** @@ -691,4 +741,4 @@ interface IndexDefinition { } declare const GTFS_SCHEMA: TableSchema[]; -export { type Agency, type AgencyFilters, type Alert, AlertCause, AlertEffect, type AlertFilters, type Attribution, type Calendar, type CalendarDate, type ColumnDefinition, CongestionLevel, type EntitySelector, type FareAttribute, type FareRule, type FeedInfo, type Frequency, GTFS_SCHEMA, GtfsSqlJs, type GtfsSqlJsOptions, type IndexDefinition, type Level, OccupancyStatus, type Pathway, type Position, type RealtimeConfig, type Route, type RouteFilters, ScheduleRelationship, type Shape, type Stop, type StopFilters, type StopTime, type StopTimeEvent, type StopTimeFilters, type StopTimeRealtime, type StopTimeUpdate, type StopTimeWithRealtime, type TableSchema, type TimeRange, type Transfer, type TranslatedString, type Trip, type TripFilters, type TripRealtime, type TripUpdate, type TripWithRealtime, type VehicleDescriptor, type VehiclePosition, type VehiclePositionFilters, VehicleStopStatus }; +export { type Agency, type AgencyFilters, type Alert, AlertCause, AlertEffect, type AlertFilters, type Attribution, type Calendar, type CalendarDate, type ColumnDefinition, CongestionLevel, type EntitySelector, type FareAttribute, type FareRule, type FeedInfo, type Frequency, GTFS_SCHEMA, GtfsSqlJs, type GtfsSqlJsOptions, type IndexDefinition, type Level, OccupancyStatus, type Pathway, type Position, type RealtimeConfig, type Route, type RouteFilters, ScheduleRelationship, type Shape, type Stop, type StopFilters, type StopTime, type StopTimeEvent, type StopTimeFilters, type StopTimeRealtime, type StopTimeUpdate, type StopTimeUpdateFilters, type StopTimeUpdateWithMetadata, type StopTimeWithRealtime, type TableSchema, type TimeRange, type Transfer, type TranslatedString, type Trip, type TripFilters, type TripRealtime, type TripUpdate, type TripUpdateFilters, type TripWithRealtime, type VehicleDescriptor, type VehiclePosition, type VehiclePositionFilters, VehicleStopStatus }; diff --git a/dist/index.js b/dist/index.js index 9bfce69..c362e34 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1280,6 +1280,106 @@ function rowToCalendarDate(row) { }; } +// src/queries/rt-vehicle-positions.ts +function parseVehiclePosition(row) { + const vp = { + trip_id: String(row.trip_id), + route_id: row.route_id ? String(row.route_id) : void 0, + rt_last_updated: Number(row.rt_last_updated) + }; + if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) { + vp.vehicle = { + id: row.vehicle_id ? String(row.vehicle_id) : void 0, + label: row.vehicle_label ? String(row.vehicle_label) : void 0, + license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : void 0 + }; + } + if (row.latitude !== null && row.longitude !== null) { + vp.position = { + latitude: Number(row.latitude), + longitude: Number(row.longitude), + bearing: row.bearing !== null ? Number(row.bearing) : void 0, + odometer: row.odometer !== null ? Number(row.odometer) : void 0, + speed: row.speed !== null ? Number(row.speed) : void 0 + }; + } + if (row.current_stop_sequence !== null) { + vp.current_stop_sequence = Number(row.current_stop_sequence); + } + if (row.stop_id) { + vp.stop_id = String(row.stop_id); + } + if (row.current_status !== null) { + vp.current_status = Number(row.current_status); + } + if (row.timestamp !== null) { + vp.timestamp = Number(row.timestamp); + } + if (row.congestion_level !== null) { + vp.congestion_level = Number(row.congestion_level); + } + if (row.occupancy_status !== null) { + vp.occupancy_status = Number(row.occupancy_status); + } + return vp; +} +function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { + const { tripId, routeId, vehicleId, limit } = filters; + const conditions = []; + const params = []; + if (tripId) { + conditions.push("trip_id = ?"); + params.push(tripId); + } + if (routeId) { + conditions.push("route_id = ?"); + params.push(routeId); + } + if (vehicleId) { + conditions.push("vehicle_id = ?"); + params.push(vehicleId); + } + const now = Math.floor(Date.now() / 1e3); + const staleThreshold = now - stalenessThreshold; + conditions.push("rt_last_updated >= ?"); + params.push(staleThreshold); + let sql = "SELECT * FROM rt_vehicle_positions"; + if (conditions.length > 0) { + sql += " WHERE " + conditions.join(" AND "); + } + sql += " ORDER BY rt_last_updated DESC"; + if (limit) { + sql += " LIMIT ?"; + params.push(limit); + } + const stmt = db.prepare(sql); + if (params.length > 0) { + stmt.bind(params); + } + const positions = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + positions.push(parseVehiclePosition(row)); + } + stmt.free(); + return positions; +} +function getVehiclePositionByTripId(db, tripId, stalenessThreshold = 120) { + const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold); + return positions.length > 0 ? positions[0] : null; +} +function getAllVehiclePositions(db) { + const sql = "SELECT * FROM rt_vehicle_positions ORDER BY rt_last_updated DESC"; + const stmt = db.prepare(sql); + const positions = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + positions.push(parseVehiclePosition(row)); + } + stmt.free(); + return positions; +} + // src/queries/trips.ts function mergeRealtimeData(trips, db, stalenessThreshold) { const now = Math.floor(Date.now() / 1e3); @@ -1296,7 +1396,8 @@ function mergeRealtimeData(trips, db, stalenessThreshold) { const vpMap = /* @__PURE__ */ new Map(); while (vpStmt.step()) { const row = vpStmt.getAsObject(); - vpMap.set(String(row.trip_id), row); + const vp = parseVehiclePosition(row); + vpMap.set(vp.trip_id, vp); } vpStmt.free(); const tuStmt = db.prepare(` @@ -1308,56 +1409,26 @@ function mergeRealtimeData(trips, db, stalenessThreshold) { const tuMap = /* @__PURE__ */ new Map(); while (tuStmt.step()) { const row = tuStmt.getAsObject(); - tuMap.set(String(row.trip_id), row); + const tripId = String(row.trip_id); + tuMap.set(tripId, { + delay: row.delay !== null ? Number(row.delay) : void 0, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : void 0 + }); } tuStmt.free(); return trips.map((trip) => { - const vpRow = vpMap.get(trip.trip_id); - const tuRow = tuMap.get(trip.trip_id); - if (!vpRow && !tuRow) { + const vp = vpMap.get(trip.trip_id); + const tu = tuMap.get(trip.trip_id); + if (!vp && !tu) { return { ...trip, realtime: { vehicle_position: null, trip_update: null } }; } - const realtime = { - vehicle_position: null, - trip_update: null - }; - if (vpRow) { - const vp = { - trip_id: String(vpRow.trip_id), - route_id: vpRow.route_id ? String(vpRow.route_id) : void 0, - rt_last_updated: Number(vpRow.rt_last_updated) - }; - if (vpRow.vehicle_id || vpRow.vehicle_label || vpRow.vehicle_license_plate) { - vp.vehicle = { - id: vpRow.vehicle_id ? String(vpRow.vehicle_id) : void 0, - label: vpRow.vehicle_label ? String(vpRow.vehicle_label) : void 0, - license_plate: vpRow.vehicle_license_plate ? String(vpRow.vehicle_license_plate) : void 0 - }; - } - if (vpRow.latitude !== null && vpRow.longitude !== null) { - vp.position = { - latitude: Number(vpRow.latitude), - longitude: Number(vpRow.longitude), - bearing: vpRow.bearing !== null ? Number(vpRow.bearing) : void 0, - odometer: vpRow.odometer !== null ? Number(vpRow.odometer) : void 0, - speed: vpRow.speed !== null ? Number(vpRow.speed) : void 0 - }; + return { + ...trip, + realtime: { + vehicle_position: vp || null, + trip_update: tu || null } - if (vpRow.current_stop_sequence !== null) vp.current_stop_sequence = Number(vpRow.current_stop_sequence); - if (vpRow.stop_id) vp.stop_id = String(vpRow.stop_id); - if (vpRow.current_status !== null) vp.current_status = Number(vpRow.current_status); - if (vpRow.timestamp !== null) vp.timestamp = Number(vpRow.timestamp); - if (vpRow.congestion_level !== null) vp.congestion_level = Number(vpRow.congestion_level); - if (vpRow.occupancy_status !== null) vp.occupancy_status = Number(vpRow.occupancy_status); - realtime.vehicle_position = vp; - } - if (tuRow) { - realtime.trip_update = { - delay: tuRow.delay !== null ? Number(tuRow.delay) : void 0, - schedule_relationship: tuRow.schedule_relationship !== null ? Number(tuRow.schedule_relationship) : void 0 - }; - } - return { ...trip, realtime }; + }; }); } function getTrips(db, filters = {}, stalenessThreshold = 120) { @@ -1667,51 +1738,40 @@ function getAlertById(db, alertId, stalenessThreshold = 120) { const alerts = getAlerts(db, { alertId, limit: 1 }, stalenessThreshold); return alerts.length > 0 ? alerts[0] : null; } +function getAllAlerts(db) { + const sql = "SELECT * FROM rt_alerts ORDER BY rt_last_updated DESC"; + const stmt = db.prepare(sql); + const alerts = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + alerts.push(parseAlert(row)); + } + stmt.free(); + return alerts; +} -// src/queries/rt-vehicle-positions.ts -function parseVehiclePosition(row) { - const vp = { +// src/queries/rt-trip-updates.ts +function parseTripUpdate(row) { + const tu = { trip_id: String(row.trip_id), route_id: row.route_id ? String(row.route_id) : void 0, + stop_time_update: [], + // Will be populated separately + timestamp: row.timestamp !== null ? Number(row.timestamp) : void 0, + delay: row.delay !== null ? Number(row.delay) : void 0, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : void 0, rt_last_updated: Number(row.rt_last_updated) }; if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) { - vp.vehicle = { + tu.vehicle = { id: row.vehicle_id ? String(row.vehicle_id) : void 0, label: row.vehicle_label ? String(row.vehicle_label) : void 0, license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : void 0 }; } - if (row.latitude !== null && row.longitude !== null) { - vp.position = { - latitude: Number(row.latitude), - longitude: Number(row.longitude), - bearing: row.bearing !== null ? Number(row.bearing) : void 0, - odometer: row.odometer !== null ? Number(row.odometer) : void 0, - speed: row.speed !== null ? Number(row.speed) : void 0 - }; - } - if (row.current_stop_sequence !== null) { - vp.current_stop_sequence = Number(row.current_stop_sequence); - } - if (row.stop_id) { - vp.stop_id = String(row.stop_id); - } - if (row.current_status !== null) { - vp.current_status = Number(row.current_status); - } - if (row.timestamp !== null) { - vp.timestamp = Number(row.timestamp); - } - if (row.congestion_level !== null) { - vp.congestion_level = Number(row.congestion_level); - } - if (row.occupancy_status !== null) { - vp.occupancy_status = Number(row.occupancy_status); - } - return vp; + return tu; } -function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { +function getTripUpdates(db, filters = {}, stalenessThreshold = 120) { const { tripId, routeId, vehicleId, limit } = filters; const conditions = []; const params = []; @@ -1731,7 +1791,7 @@ function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { const staleThreshold = now - stalenessThreshold; conditions.push("rt_last_updated >= ?"); params.push(staleThreshold); - let sql = "SELECT * FROM rt_vehicle_positions"; + let sql = "SELECT * FROM rt_trip_updates"; if (conditions.length > 0) { sql += " WHERE " + conditions.join(" AND "); } @@ -1744,17 +1804,113 @@ function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { if (params.length > 0) { stmt.bind(params); } - const positions = []; + const tripUpdates = []; while (stmt.step()) { const row = stmt.getAsObject(); - positions.push(parseVehiclePosition(row)); + tripUpdates.push(parseTripUpdate(row)); } stmt.free(); - return positions; + return tripUpdates; } -function getVehiclePositionByTripId(db, tripId, stalenessThreshold = 120) { - const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold); - return positions.length > 0 ? positions[0] : null; +function getTripUpdateByTripId(db, tripId, stalenessThreshold = 120) { + const updates = getTripUpdates(db, { tripId, limit: 1 }, stalenessThreshold); + return updates.length > 0 ? updates[0] : null; +} +function getAllTripUpdates(db) { + const sql = "SELECT * FROM rt_trip_updates ORDER BY rt_last_updated DESC"; + const stmt = db.prepare(sql); + const tripUpdates = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + tripUpdates.push(parseTripUpdate(row)); + } + stmt.free(); + return tripUpdates; +} + +// src/queries/rt-stop-time-updates.ts +function parseStopTimeUpdate(row) { + const stu = { + stop_sequence: row.stop_sequence !== null ? Number(row.stop_sequence) : void 0, + stop_id: row.stop_id ? String(row.stop_id) : void 0, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : void 0 + }; + if (row.arrival_delay !== null || row.arrival_time !== null || row.arrival_uncertainty !== null) { + stu.arrival = { + delay: row.arrival_delay !== null ? Number(row.arrival_delay) : void 0, + time: row.arrival_time !== null ? Number(row.arrival_time) : void 0, + uncertainty: row.arrival_uncertainty !== null ? Number(row.arrival_uncertainty) : void 0 + }; + } + if (row.departure_delay !== null || row.departure_time !== null || row.departure_uncertainty !== null) { + stu.departure = { + delay: row.departure_delay !== null ? Number(row.departure_delay) : void 0, + time: row.departure_time !== null ? Number(row.departure_time) : void 0, + uncertainty: row.departure_uncertainty !== null ? Number(row.departure_uncertainty) : void 0 + }; + } + return stu; +} +function parseStopTimeUpdateWithMetadata(row) { + const stu = parseStopTimeUpdate(row); + stu.trip_id = String(row.trip_id); + stu.rt_last_updated = Number(row.rt_last_updated); + return stu; +} +function getStopTimeUpdates(db, filters = {}, stalenessThreshold = 120) { + const { tripId, stopId, stopSequence, limit } = filters; + const conditions = []; + const params = []; + if (tripId) { + conditions.push("trip_id = ?"); + params.push(tripId); + } + if (stopId) { + conditions.push("stop_id = ?"); + params.push(stopId); + } + if (stopSequence !== void 0) { + conditions.push("stop_sequence = ?"); + params.push(stopSequence); + } + const now = Math.floor(Date.now() / 1e3); + const staleThreshold = now - stalenessThreshold; + conditions.push("rt_last_updated >= ?"); + params.push(staleThreshold); + let sql = "SELECT * FROM rt_stop_time_updates"; + if (conditions.length > 0) { + sql += " WHERE " + conditions.join(" AND "); + } + sql += " ORDER BY trip_id, stop_sequence"; + if (limit) { + sql += " LIMIT ?"; + params.push(limit); + } + const stmt = db.prepare(sql); + if (params.length > 0) { + stmt.bind(params); + } + const stopTimeUpdates = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + stopTimeUpdates.push(parseStopTimeUpdate(row)); + } + stmt.free(); + return stopTimeUpdates; +} +function getStopTimeUpdatesByTripId(db, tripId, stalenessThreshold = 120) { + return getStopTimeUpdates(db, { tripId }, stalenessThreshold); +} +function getAllStopTimeUpdates(db) { + const sql = "SELECT * FROM rt_stop_time_updates ORDER BY trip_id, stop_sequence"; + const stmt = db.prepare(sql); + const stopTimeUpdates = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + stopTimeUpdates.push(parseStopTimeUpdateWithMetadata(row)); + } + stmt.free(); + return stopTimeUpdates; } // src/gtfs-sqljs.ts @@ -2073,6 +2229,66 @@ var GtfsSqlJs = class _GtfsSqlJs { if (!this.db) throw new Error("Database not initialized"); return getVehiclePositionByTripId(this.db, tripId, this.stalenessThreshold); } + /** + * Get trip updates with optional filters + */ + getTripUpdates(filters) { + if (!this.db) throw new Error("Database not initialized"); + return getTripUpdates(this.db, filters, this.stalenessThreshold); + } + /** + * Get trip update by trip ID + */ + getTripUpdateByTripId(tripId) { + if (!this.db) throw new Error("Database not initialized"); + return getTripUpdateByTripId(this.db, tripId, this.stalenessThreshold); + } + /** + * Get stop time updates with optional filters + */ + getStopTimeUpdates(filters) { + if (!this.db) throw new Error("Database not initialized"); + return getStopTimeUpdates(this.db, filters, this.stalenessThreshold); + } + /** + * Get stop time updates for a specific trip + */ + getStopTimeUpdatesByTripId(tripId) { + if (!this.db) throw new Error("Database not initialized"); + return getStopTimeUpdatesByTripId(this.db, tripId, this.stalenessThreshold); + } + // ==================== Debug Export Methods ==================== + // These methods export all realtime data without staleness filtering + // for debugging purposes + /** + * Export all alerts without staleness filtering (for debugging) + */ + debugExportAllAlerts() { + if (!this.db) throw new Error("Database not initialized"); + return getAllAlerts(this.db); + } + /** + * Export all vehicle positions without staleness filtering (for debugging) + */ + debugExportAllVehiclePositions() { + if (!this.db) throw new Error("Database not initialized"); + return getAllVehiclePositions(this.db); + } + /** + * Export all trip updates without staleness filtering (for debugging) + */ + debugExportAllTripUpdates() { + if (!this.db) throw new Error("Database not initialized"); + return getAllTripUpdates(this.db); + } + /** + * Export all stop time updates without staleness filtering (for debugging) + * Returns extended type with trip_id and rt_last_updated for debugging purposes + */ + debugExportAllStopTimeUpdates() { + if (!this.db) throw new Error("Database not initialized"); + return getAllStopTimeUpdates(this.db); + } }; // src/types/gtfs-rt.ts diff --git a/dist/index.js.map b/dist/index.js.map index ab31171..49b8952 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/index.ts","../src/gtfs-sqljs.ts","../src/schema/schema.ts","../src/loaders/zip-loader.ts","../src/loaders/csv-parser.ts","../src/loaders/data-loader.ts","../src/schema/gtfs-rt-schema.ts","../src/loaders/gtfs-rt-loader.ts","../src/queries/agencies.ts","../src/queries/stops.ts","../src/queries/routes.ts","../src/queries/calendar.ts","../src/queries/trips.ts","../src/queries/stop-times.ts","../src/queries/rt-alerts.ts","../src/queries/rt-vehicle-positions.ts","../src/types/gtfs-rt.ts"],"sourcesContent":["/**\n * gtfs-sqljs - Load GTFS data into sql.js SQLite database\n * @author Théophile Helleboid/SysDevRun\n * @license MIT\n */\n\nexport {\n GtfsSqlJs,\n type GtfsSqlJsOptions,\n type AgencyFilters,\n type StopFilters,\n type RouteFilters,\n type TripFilters,\n type StopTimeFilters,\n type AlertFilters,\n type VehiclePositionFilters,\n type Alert,\n type VehiclePosition,\n type TripWithRealtime,\n type StopTimeWithRealtime\n} from './gtfs-sqljs';\n\n// Export GTFS types\nexport type {\n Agency,\n Stop,\n Route,\n Trip,\n StopTime,\n Calendar,\n CalendarDate,\n FareAttribute,\n FareRule,\n Shape,\n Frequency,\n Transfer,\n Pathway,\n Level,\n FeedInfo,\n Attribution,\n} from './types/gtfs';\n\n// Export GTFS-RT types\nexport type {\n TranslatedString,\n EntitySelector,\n TimeRange,\n Position,\n VehicleDescriptor,\n StopTimeEvent,\n StopTimeUpdate,\n TripUpdate,\n StopTimeRealtime,\n TripRealtime,\n RealtimeConfig\n} from './types/gtfs-rt';\n\n// Export GTFS-RT enums\nexport {\n ScheduleRelationship,\n VehicleStopStatus,\n CongestionLevel,\n OccupancyStatus,\n AlertCause,\n AlertEffect\n} from './types/gtfs-rt';\n\n// Export schema definitions for advanced use\nexport { GTFS_SCHEMA, type TableSchema, type ColumnDefinition, type IndexDefinition } from './schema/schema';\n","/**\n * Main GtfsSqlJs Class\n */\n\nimport initSqlJs, { type Database, type SqlJsStatic } from 'sql.js';\nimport { getAllCreateStatements } from './schema/schema';\nimport { loadGTFSZip } from './loaders/zip-loader';\nimport { loadGTFSData } from './loaders/data-loader';\nimport { createRealtimeTables, clearRealtimeData as clearRTData } from './schema/gtfs-rt-schema';\nimport { loadRealtimeData } from './loaders/gtfs-rt-loader';\n\n// Query methods\nimport { getAgencyById, getAgencies, type AgencyFilters } from './queries/agencies';\nimport { getStopById, getStops, type StopFilters } from './queries/stops';\nimport { getRouteById, getRoutes, type RouteFilters } from './queries/routes';\nimport {\n getActiveServiceIds,\n getCalendarByServiceId,\n getCalendarDates,\n getCalendarDatesForDate,\n} from './queries/calendar';\nimport { getTripById, getTrips, type TripFilters, type TripWithRealtime } from './queries/trips';\nimport { getStopTimesByTrip, getStopTimes, type StopTimeFilters, type StopTimeWithRealtime } from './queries/stop-times';\nimport { getAlerts as getAlertsQuery, getAlertById, type AlertFilters } from './queries/rt-alerts';\nimport { getVehiclePositions as getVehiclePositionsQuery, getVehiclePositionByTripId, type VehiclePositionFilters } from './queries/rt-vehicle-positions';\n\n// Types\nimport type { Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate } from './types/gtfs';\nimport type { Alert, VehiclePosition } from './types/gtfs-rt';\n\n// Export filter types for users\nexport type { AgencyFilters, StopFilters, RouteFilters, TripFilters, StopTimeFilters, AlertFilters, VehiclePositionFilters };\n// Export RT types\nexport type { Alert, VehiclePosition, TripWithRealtime, StopTimeWithRealtime };\n\nexport interface GtfsSqlJsOptions {\n /**\n * Path or URL to GTFS ZIP file\n */\n zipPath?: string;\n\n /**\n * Pre-loaded SQLite database as ArrayBuffer\n */\n database?: ArrayBuffer;\n\n /**\n * Optional: Custom SQL.js instance\n */\n SQL?: SqlJsStatic;\n\n /**\n * Optional: Path to SQL.js WASM file (for custom loading)\n */\n locateFile?: (filename: string) => string;\n\n /**\n * Optional: Array of GTFS filenames to skip importing (e.g., ['shapes.txt'])\n * Tables will be created but no data will be imported for these files\n */\n skipFiles?: string[];\n\n /**\n * Optional: Array of GTFS-RT feed URLs for realtime data\n */\n realtimeFeedUrls?: string[];\n\n /**\n * Optional: Staleness threshold in seconds (default: 120)\n * Realtime data older than this will be excluded from queries\n */\n stalenessThreshold?: number;\n}\n\nexport class GtfsSqlJs {\n private db: Database | null = null;\n private SQL: SqlJsStatic | null = null;\n private realtimeFeedUrls: string[] = [];\n private stalenessThreshold: number = 120;\n\n /**\n * Private constructor - use static factory methods instead\n */\n private constructor() {}\n\n /**\n * Create GtfsSqlJs instance from GTFS ZIP file\n */\n static async fromZip(\n zipPath: string,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromZip(zipPath, options);\n return instance;\n }\n\n /**\n * Create GtfsSqlJs instance from existing SQLite database\n */\n static async fromDatabase(\n database: ArrayBuffer,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromDatabase(database, options);\n return instance;\n }\n\n /**\n * Initialize from ZIP file\n */\n private async initFromZip(zipPath: string, options: Omit): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Create new database\n this.db = new this.SQL.Database();\n\n // Create GTFS schema\n const createStatements = getAllCreateStatements();\n for (const statement of createStatements) {\n this.db.run(statement);\n }\n\n // Create GTFS-RT tables\n createRealtimeTables(this.db);\n\n // Load GTFS data\n const files = await loadGTFSZip(zipPath);\n await loadGTFSData(this.db, files, options.skipFiles);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Initialize from existing database\n */\n private async initFromDatabase(\n database: ArrayBuffer,\n options: Omit\n ): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Load existing database\n this.db = new this.SQL.Database(new Uint8Array(database));\n\n // Ensure RT tables exist (in case loading old database)\n createRealtimeTables(this.db);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Export database to ArrayBuffer\n */\n export(): ArrayBuffer {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n\n const data = this.db.export();\n // Create a new ArrayBuffer and copy the data to ensure proper type\n const buffer = new ArrayBuffer(data.length);\n new Uint8Array(buffer).set(data);\n return buffer;\n }\n\n /**\n * Close the database connection\n */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n /**\n * Get direct access to the database (for advanced queries)\n */\n getDatabase(): Database {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n return this.db;\n }\n\n // ==================== Agency Methods ====================\n\n /**\n * Get an agency by its agency_id\n */\n getAgencyById(agencyId: string): Agency | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencyById(this.db, agencyId);\n }\n\n /**\n * Get agencies with optional filters\n */\n getAgencies(filters?: AgencyFilters): Agency[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencies(this.db, filters);\n }\n\n // ==================== Stop Methods ====================\n\n /**\n * Get a stop by its stop_id\n */\n getStopById(stopId: string): Stop | null {\n if (!this.db) throw new Error('Database not initialized');\n return getStopById(this.db, stopId);\n }\n\n /**\n * Get stops with optional filters\n */\n getStops(filters?: StopFilters): Stop[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStops(this.db, filters);\n }\n\n // ==================== Route Methods ====================\n\n /**\n * Get a route by its route_id\n */\n getRouteById(routeId: string): Route | null {\n if (!this.db) throw new Error('Database not initialized');\n return getRouteById(this.db, routeId);\n }\n\n /**\n * Get routes with optional filters\n */\n getRoutes(filters?: RouteFilters): Route[] {\n if (!this.db) throw new Error('Database not initialized');\n return getRoutes(this.db, filters);\n }\n\n // ==================== Calendar Methods ====================\n\n /**\n * Get active service IDs for a given date (YYYYMMDD format)\n */\n getActiveServiceIds(date: string): string[] {\n if (!this.db) throw new Error('Database not initialized');\n return getActiveServiceIds(this.db, date);\n }\n\n /**\n * Get calendar entry by service_id\n */\n getCalendarByServiceId(serviceId: string): Calendar | null {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarByServiceId(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a service\n */\n getCalendarDates(serviceId: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDates(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a specific date\n */\n getCalendarDatesForDate(date: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDatesForDate(this.db, date);\n }\n\n // ==================== Trip Methods ====================\n\n /**\n * Get a trip by its trip_id\n */\n getTripById(tripId: string): Trip | null {\n if (!this.db) throw new Error('Database not initialized');\n return getTripById(this.db, tripId);\n }\n\n /**\n * Get trips with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get all trips for a route on a specific date\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', date: '20240115' });\n *\n * @example\n * // Get all trips for a route going in one direction\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', directionId: 0 });\n */\n getTrips(filters?: TripFilters & { date?: string }): Trip[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getTrips(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Stop Time Methods ====================\n\n /**\n * Get stop times for a trip (ordered by stop_sequence)\n */\n getStopTimesByTrip(tripId: string): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimesByTrip(this.db, tripId);\n }\n\n /**\n * Get stop times with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.stopId - Filter by stop ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get stop times for a specific trip\n * const stopTimes = gtfs.getStopTimes({ tripId: 'TRIP_123' });\n *\n * @example\n * // Get stop times at a stop for a specific route on a date\n * const stopTimes = gtfs.getStopTimes({\n * stopId: 'STOP_123',\n * routeId: 'ROUTE_1',\n * date: '20240115'\n * });\n */\n getStopTimes(filters?: StopTimeFilters & { date?: string }): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getStopTimes(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Realtime Methods ====================\n\n /**\n * Set GTFS-RT feed URLs\n */\n setRealtimeFeedUrls(urls: string[]): void {\n this.realtimeFeedUrls = urls;\n }\n\n /**\n * Get currently configured GTFS-RT feed URLs\n */\n getRealtimeFeedUrls(): string[] {\n return [...this.realtimeFeedUrls];\n }\n\n /**\n * Set staleness threshold in seconds\n */\n setStalenessThreshold(seconds: number): void {\n this.stalenessThreshold = seconds;\n }\n\n /**\n * Get current staleness threshold\n */\n getStalenessThreshold(): number {\n return this.stalenessThreshold;\n }\n\n /**\n * Fetch and load GTFS Realtime data from configured feed URLs or provided URLs\n * @param urls - Optional array of feed URLs. If not provided, uses configured feed URLs\n */\n async fetchRealtimeData(urls?: string[]): Promise {\n if (!this.db) throw new Error('Database not initialized');\n\n const feedUrls = urls || this.realtimeFeedUrls;\n if (feedUrls.length === 0) {\n throw new Error('No realtime feed URLs configured. Use setRealtimeFeedUrls() or pass urls parameter.');\n }\n\n await loadRealtimeData(this.db, feedUrls);\n }\n\n /**\n * Clear all realtime data from the database\n */\n clearRealtimeData(): void {\n if (!this.db) throw new Error('Database not initialized');\n clearRTData(this.db);\n }\n\n /**\n * Get alerts with optional filters\n */\n getAlerts(filters?: AlertFilters): Alert[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get alert by ID\n */\n getAlertById(alertId: string): Alert | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertById(this.db, alertId, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle positions with optional filters\n */\n getVehiclePositions(filters?: VehiclePositionFilters): VehiclePosition[] {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle position by trip ID\n */\n getVehiclePositionByTripId(tripId: string): VehiclePosition | null {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionByTripId(this.db, tripId, this.stalenessThreshold);\n }\n}\n","/**\n * SQLite Schema Definitions for GTFS Data\n * Matches required/optional fields from GTFS specification\n */\n\nexport interface TableSchema {\n name: string;\n columns: ColumnDefinition[];\n indexes?: IndexDefinition[];\n}\n\nexport interface ColumnDefinition {\n name: string;\n type: 'TEXT' | 'INTEGER' | 'REAL';\n required: boolean;\n primaryKey?: boolean;\n}\n\nexport interface IndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n}\n\nexport const GTFS_SCHEMA: TableSchema[] = [\n {\n name: 'agency',\n columns: [\n { name: 'agency_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'agency_name', type: 'TEXT', required: true },\n { name: 'agency_url', type: 'TEXT', required: true },\n { name: 'agency_timezone', type: 'TEXT', required: true },\n { name: 'agency_lang', type: 'TEXT', required: false },\n { name: 'agency_phone', type: 'TEXT', required: false },\n { name: 'agency_fare_url', type: 'TEXT', required: false },\n { name: 'agency_email', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'stops',\n columns: [\n { name: 'stop_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'stop_name', type: 'TEXT', required: true },\n { name: 'stop_lat', type: 'REAL', required: true },\n { name: 'stop_lon', type: 'REAL', required: true },\n { name: 'stop_code', type: 'TEXT', required: false },\n { name: 'stop_desc', type: 'TEXT', required: false },\n { name: 'zone_id', type: 'TEXT', required: false },\n { name: 'stop_url', type: 'TEXT', required: false },\n { name: 'location_type', type: 'INTEGER', required: false },\n { name: 'parent_station', type: 'TEXT', required: false },\n { name: 'stop_timezone', type: 'TEXT', required: false },\n { name: 'wheelchair_boarding', type: 'INTEGER', required: false },\n { name: 'level_id', type: 'TEXT', required: false },\n { name: 'platform_code', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_stops_stop_code', columns: ['stop_code'] },\n { name: 'idx_stops_stop_name', columns: ['stop_name'] },\n { name: 'idx_stops_parent_station', columns: ['parent_station'] },\n ],\n },\n {\n name: 'routes',\n columns: [\n { name: 'route_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_short_name', type: 'TEXT', required: true },\n { name: 'route_long_name', type: 'TEXT', required: true },\n { name: 'route_type', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_desc', type: 'TEXT', required: false },\n { name: 'route_url', type: 'TEXT', required: false },\n { name: 'route_color', type: 'TEXT', required: false },\n { name: 'route_text_color', type: 'TEXT', required: false },\n { name: 'route_sort_order', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_routes_agency_id', columns: ['agency_id'] },\n ],\n },\n {\n name: 'trips',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_id', type: 'TEXT', required: true },\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'trip_headsign', type: 'TEXT', required: false },\n { name: 'trip_short_name', type: 'TEXT', required: false },\n { name: 'direction_id', type: 'INTEGER', required: false },\n { name: 'block_id', type: 'TEXT', required: false },\n { name: 'shape_id', type: 'TEXT', required: false },\n { name: 'wheelchair_accessible', type: 'INTEGER', required: false },\n { name: 'bikes_allowed', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_trips_route_id', columns: ['route_id'] },\n { name: 'idx_trips_service_id', columns: ['service_id'] },\n { name: 'idx_trips_route_service', columns: ['route_id', 'service_id'] },\n ],\n },\n {\n name: 'stop_times',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'arrival_time', type: 'TEXT', required: true },\n { name: 'departure_time', type: 'TEXT', required: true },\n { name: 'stop_id', type: 'TEXT', required: true },\n { name: 'stop_sequence', type: 'INTEGER', required: true },\n { name: 'stop_headsign', type: 'TEXT', required: false },\n { name: 'pickup_type', type: 'INTEGER', required: false },\n { name: 'drop_off_type', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n { name: 'timepoint', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_stop_times_trip_id', columns: ['trip_id'] },\n { name: 'idx_stop_times_stop_id', columns: ['stop_id'] },\n { name: 'idx_stop_times_trip_sequence', columns: ['trip_id', 'stop_sequence'] },\n ],\n },\n {\n name: 'calendar',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'monday', type: 'INTEGER', required: true },\n { name: 'tuesday', type: 'INTEGER', required: true },\n { name: 'wednesday', type: 'INTEGER', required: true },\n { name: 'thursday', type: 'INTEGER', required: true },\n { name: 'friday', type: 'INTEGER', required: true },\n { name: 'saturday', type: 'INTEGER', required: true },\n { name: 'sunday', type: 'INTEGER', required: true },\n { name: 'start_date', type: 'TEXT', required: true },\n { name: 'end_date', type: 'TEXT', required: true },\n ],\n },\n {\n name: 'calendar_dates',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'date', type: 'TEXT', required: true },\n { name: 'exception_type', type: 'INTEGER', required: true },\n ],\n indexes: [\n { name: 'idx_calendar_dates_service_id', columns: ['service_id'] },\n { name: 'idx_calendar_dates_date', columns: ['date'] },\n { name: 'idx_calendar_dates_service_date', columns: ['service_id', 'date'] },\n ],\n },\n {\n name: 'fare_attributes',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'price', type: 'REAL', required: true },\n { name: 'currency_type', type: 'TEXT', required: true },\n { name: 'payment_method', type: 'INTEGER', required: true },\n { name: 'transfers', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'transfer_duration', type: 'INTEGER', required: false },\n ],\n },\n {\n name: 'fare_rules',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'origin_id', type: 'TEXT', required: false },\n { name: 'destination_id', type: 'TEXT', required: false },\n { name: 'contains_id', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_fare_rules_fare_id', columns: ['fare_id'] },\n { name: 'idx_fare_rules_route_id', columns: ['route_id'] },\n ],\n },\n {\n name: 'shapes',\n columns: [\n { name: 'shape_id', type: 'TEXT', required: true },\n { name: 'shape_pt_lat', type: 'REAL', required: true },\n { name: 'shape_pt_lon', type: 'REAL', required: true },\n { name: 'shape_pt_sequence', type: 'INTEGER', required: true },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n ],\n indexes: [\n { name: 'idx_shapes_shape_id', columns: ['shape_id'] },\n { name: 'idx_shapes_shape_sequence', columns: ['shape_id', 'shape_pt_sequence'] },\n ],\n },\n {\n name: 'frequencies',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'start_time', type: 'TEXT', required: true },\n { name: 'end_time', type: 'TEXT', required: true },\n { name: 'headway_secs', type: 'INTEGER', required: true },\n { name: 'exact_times', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_frequencies_trip_id', columns: ['trip_id'] },\n ],\n },\n {\n name: 'transfers',\n columns: [\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'transfer_type', type: 'INTEGER', required: true },\n { name: 'min_transfer_time', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_transfers_from_stop_id', columns: ['from_stop_id'] },\n { name: 'idx_transfers_to_stop_id', columns: ['to_stop_id'] },\n ],\n },\n {\n name: 'pathways',\n columns: [\n { name: 'pathway_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'pathway_mode', type: 'INTEGER', required: true },\n { name: 'is_bidirectional', type: 'INTEGER', required: true },\n { name: 'length', type: 'REAL', required: false },\n { name: 'traversal_time', type: 'INTEGER', required: false },\n { name: 'stair_count', type: 'INTEGER', required: false },\n { name: 'max_slope', type: 'REAL', required: false },\n { name: 'min_width', type: 'REAL', required: false },\n { name: 'signposted_as', type: 'TEXT', required: false },\n { name: 'reversed_signposted_as', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'levels',\n columns: [\n { name: 'level_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'level_index', type: 'REAL', required: true },\n { name: 'level_name', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'feed_info',\n columns: [\n { name: 'feed_publisher_name', type: 'TEXT', required: true },\n { name: 'feed_publisher_url', type: 'TEXT', required: true },\n { name: 'feed_lang', type: 'TEXT', required: true },\n { name: 'default_lang', type: 'TEXT', required: false },\n { name: 'feed_start_date', type: 'TEXT', required: false },\n { name: 'feed_end_date', type: 'TEXT', required: false },\n { name: 'feed_version', type: 'TEXT', required: false },\n { name: 'feed_contact_email', type: 'TEXT', required: false },\n { name: 'feed_contact_url', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'attributions',\n columns: [\n { name: 'attribution_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'organization_name', type: 'TEXT', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'trip_id', type: 'TEXT', required: false },\n { name: 'is_producer', type: 'INTEGER', required: false },\n { name: 'is_operator', type: 'INTEGER', required: false },\n { name: 'is_authority', type: 'INTEGER', required: false },\n { name: 'attribution_url', type: 'TEXT', required: false },\n { name: 'attribution_email', type: 'TEXT', required: false },\n { name: 'attribution_phone', type: 'TEXT', required: false },\n ],\n },\n];\n\n/**\n * Generate CREATE TABLE SQL statement from schema definition\n */\nexport function generateCreateTableSQL(schema: TableSchema): string {\n const columns = schema.columns.map((col) => {\n const parts = [col.name, col.type];\n if (col.primaryKey) {\n parts.push('PRIMARY KEY');\n }\n if (col.required && !col.primaryKey) {\n parts.push('NOT NULL');\n }\n return parts.join(' ');\n });\n\n return `CREATE TABLE IF NOT EXISTS ${schema.name} (${columns.join(', ')})`;\n}\n\n/**\n * Generate CREATE INDEX SQL statements from schema definition\n */\nexport function generateCreateIndexSQL(schema: TableSchema): string[] {\n if (!schema.indexes) {\n return [];\n }\n\n return schema.indexes.map((idx) => {\n const unique = idx.unique ? 'UNIQUE ' : '';\n const columns = idx.columns.join(', ');\n return `CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${schema.name} (${columns})`;\n });\n}\n\n/**\n * Initialize all GTFS tables in the database\n */\nexport function getAllCreateStatements(): string[] {\n const statements: string[] = [];\n\n for (const schema of GTFS_SCHEMA) {\n statements.push(generateCreateTableSQL(schema));\n statements.push(...generateCreateIndexSQL(schema));\n }\n\n return statements;\n}\n","/**\n * ZIP Loader for GTFS files\n */\n\nimport JSZip from 'jszip';\n\nexport interface GTFSFiles {\n [filename: string]: string;\n}\n\n/**\n * Fetch and extract GTFS ZIP file\n * Works in both browser and Node.js environments\n */\nexport async function loadGTFSZip(source: string | ArrayBuffer | Uint8Array): Promise {\n let zipData: ArrayBuffer | Uint8Array;\n\n // If source is a string, treat it as URL or file path\n if (typeof source === 'string') {\n zipData = await fetchZip(source);\n } else {\n zipData = source;\n }\n\n // Load ZIP file\n const zip = await JSZip.loadAsync(zipData);\n\n // Extract all .txt files (GTFS files)\n const files: GTFSFiles = {};\n const filePromises: Promise[] = [];\n\n zip.forEach((relativePath, file) => {\n // Only process .txt files\n if (!file.dir && relativePath.endsWith('.txt')) {\n const fileName = relativePath.split('/').pop() || relativePath;\n filePromises.push(\n file.async('string').then((content) => {\n files[fileName] = content;\n })\n );\n }\n });\n\n await Promise.all(filePromises);\n\n return files;\n}\n\n/**\n * Fetch ZIP file from URL or file path\n */\nasync function fetchZip(source: string): Promise {\n // Check if source is a URL\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n // For URLs, always use fetch\n if (isUrl) {\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n throw new Error('fetch is not available to load URL');\n }\n\n // For non-URLs, try Node.js fs first, fall back to fetch for browser\n // Check if we're in Node.js environment\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n // In Node.js, treat as file path\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);\n } catch (error) {\n throw new Error(`Failed to read GTFS ZIP file: ${error}`);\n }\n }\n\n // In browser, treat as relative URL and use fetch\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n\n throw new Error('No method available to load ZIP file');\n}\n\n/**\n * Mapping of GTFS file names to database table names\n */\nexport const GTFS_FILE_MAPPING: Record = {\n 'agency.txt': 'agency',\n 'stops.txt': 'stops',\n 'routes.txt': 'routes',\n 'trips.txt': 'trips',\n 'stop_times.txt': 'stop_times',\n 'calendar.txt': 'calendar',\n 'calendar_dates.txt': 'calendar_dates',\n 'fare_attributes.txt': 'fare_attributes',\n 'fare_rules.txt': 'fare_rules',\n 'shapes.txt': 'shapes',\n 'frequencies.txt': 'frequencies',\n 'transfers.txt': 'transfers',\n 'pathways.txt': 'pathways',\n 'levels.txt': 'levels',\n 'feed_info.txt': 'feed_info',\n 'attributions.txt': 'attributions',\n};\n","/**\n * CSV Parser for GTFS files using papaparse\n */\n\nimport Papa from 'papaparse';\n\nexport interface ParsedCSV {\n headers: string[];\n rows: Record[];\n}\n\n/**\n * Parse CSV text into structured data using papaparse\n */\nexport function parseCSV(text: string): ParsedCSV {\n const result = Papa.parse(text, {\n header: true,\n skipEmptyLines: true,\n transformHeader: (header) => header.trim(),\n transform: (value) => value.trim(),\n });\n\n if (result.errors.length > 0) {\n console.warn('CSV parsing warnings:', result.errors);\n }\n\n const headers = result.meta.fields || [];\n const rows = result.data as Record[];\n\n return { headers, rows };\n}\n\n/**\n * Convert parsed row to typed object with proper type conversions\n */\nexport function convertRowTypes(\n row: Record,\n columnTypes: Record\n): Record {\n const result: Record = {};\n\n // Iterate over all expected columns, not just the ones present in the row\n for (const [key, type] of Object.entries(columnTypes)) {\n const value = row[key];\n\n // Handle missing or empty values\n if (value === undefined || value === null || value === '') {\n result[key] = null;\n continue;\n }\n\n if (type === 'INTEGER') {\n const parsed = parseInt(value, 10);\n result[key] = isNaN(parsed) ? null : parsed;\n } else if (type === 'REAL') {\n const parsed = parseFloat(value);\n result[key] = isNaN(parsed) ? null : parsed;\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n","/**\n * Data Loader - Loads GTFS data into SQLite database\n */\n\nimport type { Database } from 'sql.js';\nimport { parseCSV, convertRowTypes } from './csv-parser';\nimport { GTFS_SCHEMA, type TableSchema } from '../schema/schema';\nimport type { GTFSFiles } from './zip-loader';\n\n/**\n * Load GTFS files into SQLite database\n * @param skipFiles - Optional array of filenames to skip importing (tables will be created but remain empty)\n */\nexport async function loadGTFSData(db: Database, files: GTFSFiles, skipFiles?: string[]): Promise {\n // Map of file names to table schemas\n const fileToSchema: Map = new Map();\n for (const schema of GTFS_SCHEMA) {\n // Match file names like agency.txt to table name 'agency'\n fileToSchema.set(`${schema.name}.txt`, schema);\n }\n\n // Normalize skipFiles to a Set for faster lookup\n const skipSet = new Set(skipFiles?.map(f => f.toLowerCase()) || []);\n\n // Process each file\n for (const [fileName, content] of Object.entries(files)) {\n const schema = fileToSchema.get(fileName);\n if (!schema) {\n // Skip unknown files\n continue;\n }\n\n // Skip if in skip list\n if (skipSet.has(fileName.toLowerCase())) {\n console.log(`Skipping import of ${fileName} (table ${schema.name} created but empty)`);\n continue;\n }\n\n await loadTableData(db, schema, content);\n }\n}\n\n/**\n * Load data for a single table\n */\nasync function loadTableData(db: Database, schema: TableSchema, csvContent: string): Promise {\n const { headers, rows } = parseCSV(csvContent);\n\n if (rows.length === 0) {\n return;\n }\n\n // Build column type map\n const columnTypes: Record = {};\n for (const col of schema.columns) {\n columnTypes[col.name] = col.type;\n }\n\n // Prepare INSERT statement\n const columns = headers.filter((h) => schema.columns.some((c) => c.name === h));\n const placeholders = columns.map(() => '?').join(', ');\n const insertSQL = `INSERT INTO ${schema.name} (${columns.join(', ')}) VALUES (${placeholders})`;\n\n const stmt = db.prepare(insertSQL);\n\n // Insert each row\n for (const row of rows) {\n const typedRow = convertRowTypes(row, columnTypes);\n const values = columns.map((col) => {\n const value = typedRow[col];\n // Handle undefined, null, or empty values\n return value === null || value === undefined ? null : value;\n });\n\n try {\n stmt.run(values);\n } catch (error) {\n console.error(`Error inserting row into ${schema.name}:`, error);\n console.error('Row data:', row);\n throw error;\n }\n }\n\n stmt.free();\n}\n","import type { Database } from 'sql.js';\n\n/**\n * Create GTFS Realtime tables in the database\n */\nexport function createRealtimeTables(db: Database): void {\n // Alerts table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_alerts (\n id TEXT PRIMARY KEY,\n active_period TEXT, -- JSON array of TimeRange objects\n informed_entity TEXT, -- JSON array of EntitySelector objects\n cause INTEGER,\n effect INTEGER,\n url TEXT, -- JSON TranslatedString\n header_text TEXT, -- JSON TranslatedString\n description_text TEXT, -- JSON TranslatedString\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n // Create index on rt_last_updated for staleness filtering\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_alerts_updated ON rt_alerts(rt_last_updated)');\n\n // Vehicle Positions table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_vehicle_positions (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n latitude REAL,\n longitude REAL,\n bearing REAL,\n odometer REAL,\n speed REAL,\n current_stop_sequence INTEGER,\n stop_id TEXT,\n current_status INTEGER,\n timestamp INTEGER,\n congestion_level INTEGER,\n occupancy_status INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_updated ON rt_vehicle_positions(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_route ON rt_vehicle_positions(route_id)');\n\n // Trip Updates table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_trip_updates (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n timestamp INTEGER,\n delay INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_updated ON rt_trip_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_route ON rt_trip_updates(route_id)');\n\n // Stop Time Updates table (child of trip updates)\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_stop_time_updates (\n trip_id TEXT NOT NULL,\n stop_sequence INTEGER,\n stop_id TEXT,\n arrival_delay INTEGER,\n arrival_time INTEGER,\n arrival_uncertainty INTEGER,\n departure_delay INTEGER,\n departure_time INTEGER,\n departure_uncertainty INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL,\n PRIMARY KEY (trip_id, stop_sequence),\n FOREIGN KEY (trip_id) REFERENCES rt_trip_updates(trip_id) ON DELETE CASCADE\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_updated ON rt_stop_time_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_stop ON rt_stop_time_updates(stop_id)');\n}\n\n/**\n * Clear all realtime data from the database\n */\nexport function clearRealtimeData(db: Database): void {\n db.run('DELETE FROM rt_alerts');\n db.run('DELETE FROM rt_vehicle_positions');\n db.run('DELETE FROM rt_trip_updates');\n db.run('DELETE FROM rt_stop_time_updates');\n}\n","import type { Database } from 'sql.js';\nimport protobuf from 'protobufjs';\n\n// Types for protobuf decoded objects\ninterface ProtobufTranslation {\n text: string;\n language?: string;\n}\n\ninterface ProtobufTranslatedString {\n translation: ProtobufTranslation[];\n}\n\ninterface ProtobufAlert {\n id: string;\n activePeriod?: unknown[];\n active_period?: unknown[];\n informedEntity?: unknown[];\n informed_entity?: unknown[];\n cause?: number;\n effect?: number;\n url?: ProtobufTranslatedString;\n headerText?: ProtobufTranslatedString;\n header_text?: ProtobufTranslatedString;\n descriptionText?: ProtobufTranslatedString;\n description_text?: ProtobufTranslatedString;\n}\n\ninterface ProtobufTripDescriptor {\n tripId?: string;\n trip_id?: string;\n routeId?: string;\n route_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n}\n\ninterface ProtobufVehicleDescriptor {\n id?: string;\n label?: string;\n licensePlate?: string;\n license_plate?: string;\n}\n\ninterface ProtobufPosition {\n latitude?: number;\n longitude?: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\ninterface ProtobufVehiclePosition {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n position?: ProtobufPosition;\n currentStopSequence?: number;\n current_stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n currentStatus?: number;\n current_status?: number;\n timestamp?: number;\n congestionLevel?: number;\n congestion_level?: number;\n occupancyStatus?: number;\n occupancy_status?: number;\n}\n\ninterface ProtobufStopTimeEvent {\n delay?: number;\n time?: number;\n uncertainty?: number;\n}\n\ninterface ProtobufStopTimeUpdate {\n stopSequence?: number;\n stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n arrival?: ProtobufStopTimeEvent;\n departure?: ProtobufStopTimeEvent;\n}\n\ninterface ProtobufTripUpdate {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n timestamp?: number;\n delay?: number;\n stopTimeUpdate?: ProtobufStopTimeUpdate[];\n stop_time_update?: ProtobufStopTimeUpdate[];\n}\n\n// GTFS Realtime protobuf definition (v2.0)\n// Source: https://github.com/google/transit/blob/master/gtfs-realtime/proto/gtfs-realtime.proto\nconst GTFS_RT_PROTO = `\nsyntax = \"proto2\";\noption java_package = \"com.google.transit.realtime\";\npackage transit_realtime;\n\nmessage FeedMessage {\n required FeedHeader header = 1;\n repeated FeedEntity entity = 2;\n}\n\nmessage FeedHeader {\n required string gtfs_realtime_version = 1;\n enum Incrementality {\n FULL_DATASET = 0;\n DIFFERENTIAL = 1;\n }\n optional Incrementality incrementality = 2 [default = FULL_DATASET];\n optional uint64 timestamp = 3;\n}\n\nmessage FeedEntity {\n required string id = 1;\n optional bool is_deleted = 2 [default = false];\n optional TripUpdate trip_update = 3;\n optional VehiclePosition vehicle = 4;\n optional Alert alert = 5;\n}\n\nmessage TripUpdate {\n required TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 3;\n repeated StopTimeUpdate stop_time_update = 2;\n optional uint64 timestamp = 4;\n optional int32 delay = 5;\n\n message StopTimeEvent {\n optional int32 delay = 1;\n optional int64 time = 2;\n optional int32 uncertainty = 3;\n }\n\n message StopTimeUpdate {\n optional uint32 stop_sequence = 1;\n optional string stop_id = 4;\n optional StopTimeEvent arrival = 2;\n optional StopTimeEvent departure = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n SKIPPED = 1;\n NO_DATA = 2;\n }\n optional ScheduleRelationship schedule_relationship = 5 [default = SCHEDULED];\n }\n}\n\nmessage VehiclePosition {\n optional TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 8;\n optional Position position = 2;\n optional uint32 current_stop_sequence = 3;\n optional string stop_id = 7;\n enum VehicleStopStatus {\n INCOMING_AT = 0;\n STOPPED_AT = 1;\n IN_TRANSIT_TO = 2;\n }\n optional VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];\n optional uint64 timestamp = 5;\n enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0;\n RUNNING_SMOOTHLY = 1;\n STOP_AND_GO = 2;\n CONGESTION = 3;\n SEVERE_CONGESTION = 4;\n }\n optional CongestionLevel congestion_level = 6;\n enum OccupancyStatus {\n EMPTY = 0;\n MANY_SEATS_AVAILABLE = 1;\n FEW_SEATS_AVAILABLE = 2;\n STANDING_ROOM_ONLY = 3;\n CRUSHED_STANDING_ROOM_ONLY = 4;\n FULL = 5;\n NOT_ACCEPTING_PASSENGERS = 6;\n }\n optional OccupancyStatus occupancy_status = 9;\n}\n\nmessage Alert {\n repeated TimeRange active_period = 1;\n repeated EntitySelector informed_entity = 5;\n\n enum Cause {\n UNKNOWN_CAUSE = 1;\n OTHER_CAUSE = 2;\n TECHNICAL_PROBLEM = 3;\n STRIKE = 4;\n DEMONSTRATION = 5;\n ACCIDENT = 6;\n HOLIDAY = 7;\n WEATHER = 8;\n MAINTENANCE = 9;\n CONSTRUCTION = 10;\n POLICE_ACTIVITY = 11;\n MEDICAL_EMERGENCY = 12;\n }\n optional Cause cause = 6 [default = UNKNOWN_CAUSE];\n\n enum Effect {\n NO_SERVICE = 1;\n REDUCED_SERVICE = 2;\n SIGNIFICANT_DELAYS = 3;\n DETOUR = 4;\n ADDITIONAL_SERVICE = 5;\n MODIFIED_SERVICE = 6;\n OTHER_EFFECT = 7;\n UNKNOWN_EFFECT = 8;\n STOP_MOVED = 9;\n NO_EFFECT = 10;\n ACCESSIBILITY_ISSUE = 11;\n }\n optional Effect effect = 7 [default = UNKNOWN_EFFECT];\n optional TranslatedString url = 8;\n optional TranslatedString header_text = 10;\n optional TranslatedString description_text = 11;\n}\n\nmessage TimeRange {\n optional uint64 start = 1;\n optional uint64 end = 2;\n}\n\nmessage Position {\n required float latitude = 1;\n required float longitude = 2;\n optional float bearing = 3;\n optional double odometer = 4;\n optional float speed = 5;\n}\n\nmessage TripDescriptor {\n optional string trip_id = 1;\n optional string route_id = 5;\n optional uint32 direction_id = 6;\n optional string start_time = 2;\n optional string start_date = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n ADDED = 1;\n UNSCHEDULED = 2;\n CANCELED = 3;\n }\n optional ScheduleRelationship schedule_relationship = 4;\n}\n\nmessage VehicleDescriptor {\n optional string id = 1;\n optional string label = 2;\n optional string license_plate = 3;\n}\n\nmessage EntitySelector {\n optional string agency_id = 1;\n optional string route_id = 2;\n optional int32 route_type = 3;\n optional TripDescriptor trip = 4;\n optional string stop_id = 5;\n}\n\nmessage TranslatedString {\n message Translation {\n required string text = 1;\n optional string language = 2;\n }\n repeated Translation translation = 1;\n}\n`;\n\n// Fetch protobuf data from URL or local file\n// Uses fetch API (available in modern browsers and Node.js 18+)\nasync function fetchProtobuf(source: string): Promise {\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n if (isUrl) {\n // Fetch from URL\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n }\n\n // Read from local file (Node.js only)\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return new Uint8Array(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));\n } catch (error) {\n throw new Error(`Failed to read GTFS-RT file from ${source}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // In browser, try fetch for relative paths\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n}\n\n// Load and parse GTFS-RT protobuf schema\nlet gtfsRtRoot: protobuf.Root | null = null;\n\nfunction loadGtfsRtProto(): protobuf.Root {\n if (!gtfsRtRoot) {\n gtfsRtRoot = protobuf.parse(GTFS_RT_PROTO).root;\n }\n return gtfsRtRoot;\n}\n\n// Convert camelCase object keys to snake_case\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction convertKeysToSnakeCase(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(convertKeysToSnakeCase);\n }\n if (typeof obj === 'object') {\n const result: Record = {};\n for (const key in obj as Record) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = convertKeysToSnakeCase((obj as Record)[key]);\n }\n }\n return result;\n }\n return obj;\n}\n\n// Parse TranslatedString to JSON\nfunction parseTranslatedString(ts: ProtobufTranslatedString | undefined): string | null {\n if (!ts || !ts.translation || ts.translation.length === 0) {\n return null;\n }\n return JSON.stringify({\n translation: ts.translation.map((t) => ({\n text: t.text,\n language: t.language || undefined\n }))\n });\n}\n\n// Insert alerts into database\nfunction insertAlerts(db: Database, alerts: ProtobufAlert[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_alerts (\n id, active_period, informed_entity, cause, effect,\n url, header_text, description_text, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const alert of alerts) {\n // Map camelCase protobuf fields to snake_case\n const activePeriod = alert.activePeriod || alert.active_period || [];\n const informedEntity = alert.informedEntity || alert.informed_entity || [];\n const headerText = alert.headerText || alert.header_text;\n const descriptionText = alert.descriptionText || alert.description_text;\n\n // Convert nested objects to snake_case\n const activePeriodSnake = convertKeysToSnakeCase(activePeriod);\n const informedEntitySnake = convertKeysToSnakeCase(informedEntity);\n\n stmt.run([\n alert.id,\n JSON.stringify(activePeriodSnake),\n JSON.stringify(informedEntitySnake),\n alert.cause || null,\n alert.effect || null,\n parseTranslatedString(alert.url),\n parseTranslatedString(headerText),\n parseTranslatedString(descriptionText),\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert vehicle positions into database\nfunction insertVehiclePositions(db: Database, positions: ProtobufVehiclePosition[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_vehicle_positions (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n latitude, longitude, bearing, odometer, speed,\n current_stop_sequence, stop_id, current_status, timestamp,\n congestion_level, occupancy_status, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const vp of positions) {\n const trip = vp.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = vp.vehicle?.id;\n const vehicleLabel = vp.vehicle?.label;\n const vehicleLicensePlate = vp.vehicle?.licensePlate || vp.vehicle?.license_plate;\n const currentStopSequence = vp.currentStopSequence || vp.current_stop_sequence;\n const stopId = vp.stopId || vp.stop_id;\n const currentStatus = vp.currentStatus || vp.current_status;\n const congestionLevel = vp.congestionLevel || vp.congestion_level;\n const occupancyStatus = vp.occupancyStatus || vp.occupancy_status;\n\n stmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n vp.position?.latitude || null,\n vp.position?.longitude || null,\n vp.position?.bearing || null,\n vp.position?.odometer || null,\n vp.position?.speed || null,\n currentStopSequence || null,\n stopId || null,\n currentStatus || null,\n vp.timestamp || null,\n congestionLevel || null,\n occupancyStatus || null,\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert trip updates into database\nfunction insertTripUpdates(db: Database, updates: ProtobufTripUpdate[], timestamp: number): void {\n const tripStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_trip_updates (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n timestamp, delay, schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const stopTimeStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_stop_time_updates (\n trip_id, stop_sequence, stop_id,\n arrival_delay, arrival_time, arrival_uncertainty,\n departure_delay, departure_time, departure_uncertainty,\n schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const tu of updates) {\n const trip = tu.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = tu.vehicle?.id;\n const vehicleLabel = tu.vehicle?.label;\n const vehicleLicensePlate = tu.vehicle?.licensePlate || tu.vehicle?.license_plate;\n const scheduleRelationship = trip.scheduleRelationship || trip.schedule_relationship;\n const stopTimeUpdate = tu.stopTimeUpdate || tu.stop_time_update;\n\n // Insert trip update\n tripStmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n tu.timestamp || null,\n tu.delay || null,\n scheduleRelationship || null,\n timestamp\n ]);\n\n // Insert stop time updates\n if (stopTimeUpdate) {\n for (const stu of stopTimeUpdate) {\n const stopSequence = stu.stopSequence || stu.stop_sequence;\n const stopId = stu.stopId || stu.stop_id;\n const scheduleRel = stu.scheduleRelationship || stu.schedule_relationship;\n\n stopTimeStmt.run([\n tripId,\n stopSequence || null,\n stopId || null,\n stu.arrival?.delay || null,\n stu.arrival?.time || null,\n stu.arrival?.uncertainty || null,\n stu.departure?.delay || null,\n stu.departure?.time || null,\n stu.departure?.uncertainty || null,\n scheduleRel || null,\n timestamp\n ]);\n }\n }\n }\n\n tripStmt.free();\n stopTimeStmt.free();\n}\n\n/**\n * Fetch and load GTFS Realtime data from multiple feed URLs\n * All feeds are fetched in parallel. If any feed fails, an error is thrown.\n */\nexport async function loadRealtimeData(db: Database, feedUrls: string[]): Promise {\n const root = loadGtfsRtProto();\n const FeedMessage = root.lookupType('transit_realtime.FeedMessage');\n\n // Fetch all feeds in parallel\n const fetchPromises = feedUrls.map(async (url) => {\n try {\n const data = await fetchProtobuf(url);\n const message = FeedMessage.decode(data);\n return FeedMessage.toObject(message, {\n longs: Number,\n enums: Number,\n bytes: String,\n defaults: false,\n arrays: true,\n objects: true,\n oneofs: true\n });\n } catch (error) {\n throw new Error(`Failed to fetch or parse GTFS-RT feed from ${url}: ${error instanceof Error ? error.message : String(error)}`);\n }\n });\n\n // Wait for all feeds - if any fails, this will throw\n const feeds = await Promise.all(fetchPromises);\n\n // Current timestamp for staleness tracking\n const now = Math.floor(Date.now() / 1000);\n\n // Collect all entities by type\n const allAlerts: ProtobufAlert[] = [];\n const allVehiclePositions: ProtobufVehiclePosition[] = [];\n const allTripUpdates: ProtobufTripUpdate[] = [];\n\n for (const feed of feeds) {\n if (!feed.entity) continue;\n\n for (const entity of feed.entity) {\n if (entity.alert) {\n allAlerts.push({ id: entity.id, ...entity.alert });\n }\n if (entity.vehicle) {\n allVehiclePositions.push(entity.vehicle);\n }\n if (entity.tripUpdate) {\n allTripUpdates.push(entity.tripUpdate);\n }\n }\n }\n\n // Insert into database\n if (allAlerts.length > 0) {\n insertAlerts(db, allAlerts, now);\n }\n if (allVehiclePositions.length > 0) {\n insertVehiclePositions(db, allVehiclePositions, now);\n }\n if (allTripUpdates.length > 0) {\n insertTripUpdates(db, allTripUpdates, now);\n }\n}\n","/**\n * Agency Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Agency } from '../types/gtfs';\n\nexport interface AgencyFilters {\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get agencies with optional filters\n */\nexport function getAgencies(db: Database, filters: AgencyFilters = {}): Agency[] {\n const { agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM agency';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY agency_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Get an agency by its agency_id\n */\nexport function getAgencyById(db: Database, agencyId: string): Agency | null {\n const stmt = db.prepare('SELECT * FROM agency WHERE agency_id = ?');\n stmt.bind([agencyId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToAgency(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all agencies\n */\nexport function getAllAgencies(db: Database, limit?: number): Agency[] {\n const sql = limit\n ? `SELECT * FROM agency ORDER BY agency_name LIMIT ${limit}`\n : 'SELECT * FROM agency ORDER BY agency_name';\n\n const stmt = db.prepare(sql);\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Convert database row to Agency object\n */\nfunction rowToAgency(row: Record): Agency {\n return {\n agency_id: String(row.agency_id),\n agency_name: String(row.agency_name),\n agency_url: String(row.agency_url),\n agency_timezone: String(row.agency_timezone),\n agency_lang: row.agency_lang ? String(row.agency_lang) : undefined,\n agency_phone: row.agency_phone ? String(row.agency_phone) : undefined,\n agency_fare_url: row.agency_fare_url ? String(row.agency_fare_url) : undefined,\n agency_email: row.agency_email ? String(row.agency_email) : undefined,\n };\n}\n","/**\n * Stop Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Stop } from '../types/gtfs';\n\nexport interface StopFilters {\n stopId?: string;\n stopCode?: string;\n name?: string;\n tripId?: string;\n limit?: number;\n}\n\n/**\n * Get stops with optional filters\n */\nexport function getStops(db: Database, filters: StopFilters = {}): Stop[] {\n const { stopId, stopCode, name, tripId, limit } = filters;\n\n // Handle special case: get stops by trip (requires JOIN)\n if (tripId) {\n return getStopsByTrip(db, tripId);\n }\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (stopId) {\n conditions.push('stop_id = ?');\n params.push(stopId);\n }\n\n if (stopCode) {\n conditions.push('stop_code = ?');\n params.push(stopCode);\n }\n\n if (name) {\n conditions.push('stop_name LIKE ?');\n params.push(`%${name}%`);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM stops';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY stop_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get a stop by its stop_id\n */\nexport function getStopById(db: Database, stopId: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_id = ?');\n stmt.bind([stopId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get a stop by its stop_code\n */\nexport function getStopByCode(db: Database, stopCode: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_code = ?');\n stmt.bind([stopCode]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Search stops by name (case-insensitive, partial match)\n */\nexport function searchStopsByName(db: Database, name: string, limit = 50): Stop[] {\n const stmt = db.prepare(\n 'SELECT * FROM stops WHERE stop_name LIKE ? ORDER BY stop_name LIMIT ?'\n );\n stmt.bind([`%${name}%`, limit]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get all stops\n */\nexport function getAllStops(db: Database, limit?: number): Stop[] {\n const sql = limit\n ? `SELECT * FROM stops ORDER BY stop_name LIMIT ${limit}`\n : 'SELECT * FROM stops ORDER BY stop_name';\n\n const stmt = db.prepare(sql);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get stops for a given trip (ordered by stop_sequence)\n */\nexport function getStopsByTrip(db: Database, tripId: string): Stop[] {\n const stmt = db.prepare(`\n SELECT s.* FROM stops s\n INNER JOIN stop_times st ON s.stop_id = st.stop_id\n WHERE st.trip_id = ?\n ORDER BY st.stop_sequence\n `);\n stmt.bind([tripId]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Convert database row to Stop object\n */\nfunction rowToStop(row: Record): Stop {\n return {\n stop_id: String(row.stop_id),\n stop_name: String(row.stop_name),\n stop_lat: Number(row.stop_lat),\n stop_lon: Number(row.stop_lon),\n stop_code: row.stop_code ? String(row.stop_code) : undefined,\n stop_desc: row.stop_desc ? String(row.stop_desc) : undefined,\n zone_id: row.zone_id ? String(row.zone_id) : undefined,\n stop_url: row.stop_url ? String(row.stop_url) : undefined,\n location_type: row.location_type !== null ? Number(row.location_type) : undefined,\n parent_station: row.parent_station ? String(row.parent_station) : undefined,\n stop_timezone: row.stop_timezone ? String(row.stop_timezone) : undefined,\n wheelchair_boarding: row.wheelchair_boarding !== null ? Number(row.wheelchair_boarding) : undefined,\n level_id: row.level_id ? String(row.level_id) : undefined,\n platform_code: row.platform_code ? String(row.platform_code) : undefined,\n };\n}\n","/**\n * Route Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Route } from '../types/gtfs';\n\nexport interface RouteFilters {\n routeId?: string;\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get routes with optional filters\n */\nexport function getRoutes(db: Database, filters: RouteFilters = {}): Route[] {\n const { routeId, agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM routes';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY route_short_name, route_long_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get a route by its route_id\n */\nexport function getRouteById(db: Database, routeId: string): Route | null {\n const stmt = db.prepare('SELECT * FROM routes WHERE route_id = ?');\n stmt.bind([routeId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToRoute(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all routes\n */\nexport function getAllRoutes(db: Database, limit?: number): Route[] {\n const sql = limit\n ? `SELECT * FROM routes ORDER BY route_short_name, route_long_name LIMIT ${limit}`\n : 'SELECT * FROM routes ORDER BY route_short_name, route_long_name';\n\n const stmt = db.prepare(sql);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get routes by agency\n */\nexport function getRoutesByAgency(db: Database, agencyId: string): Route[] {\n const stmt = db.prepare(\n 'SELECT * FROM routes WHERE agency_id = ? ORDER BY route_short_name, route_long_name'\n );\n stmt.bind([agencyId]);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Convert database row to Route object\n */\nfunction rowToRoute(row: Record): Route {\n return {\n route_id: String(row.route_id),\n route_short_name: String(row.route_short_name),\n route_long_name: String(row.route_long_name),\n route_type: Number(row.route_type),\n agency_id: row.agency_id ? String(row.agency_id) : undefined,\n route_desc: row.route_desc ? String(row.route_desc) : undefined,\n route_url: row.route_url ? String(row.route_url) : undefined,\n route_color: row.route_color ? String(row.route_color) : undefined,\n route_text_color: row.route_text_color ? String(row.route_text_color) : undefined,\n route_sort_order: row.route_sort_order !== null ? Number(row.route_sort_order) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n };\n}\n","/**\n * Calendar Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Calendar, CalendarDate } from '../types/gtfs';\n\n/**\n * Get active service IDs for a given date\n */\nexport function getActiveServiceIds(db: Database, date: string): string[] {\n const serviceIds = new Set();\n\n // Parse date (format: YYYYMMDD)\n const year = parseInt(date.substring(0, 4));\n const month = parseInt(date.substring(4, 6));\n const day = parseInt(date.substring(6, 8));\n const dateObj = new Date(year, month - 1, day);\n const dayOfWeek = dateObj.getDay(); // 0 = Sunday, 1 = Monday, etc.\n\n // Map day of week to GTFS calendar field\n const dayFields = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];\n const dayField = dayFields[dayOfWeek];\n\n // Check calendar.txt for regular service\n const calendarStmt = db.prepare(\n `SELECT service_id FROM calendar\n WHERE ${dayField} = 1\n AND start_date <= ?\n AND end_date >= ?`\n );\n calendarStmt.bind([date, date]);\n\n while (calendarStmt.step()) {\n const row = calendarStmt.getAsObject() as { service_id: string };\n serviceIds.add(row.service_id);\n }\n calendarStmt.free();\n\n // Check calendar_dates.txt for exceptions\n const exceptionsStmt = db.prepare('SELECT service_id, exception_type FROM calendar_dates WHERE date = ?');\n exceptionsStmt.bind([date]);\n\n while (exceptionsStmt.step()) {\n const row = exceptionsStmt.getAsObject() as { service_id: string; exception_type: number };\n if (row.exception_type === 1) {\n // Service added\n serviceIds.add(row.service_id);\n } else if (row.exception_type === 2) {\n // Service removed\n serviceIds.delete(row.service_id);\n }\n }\n exceptionsStmt.free();\n\n return Array.from(serviceIds);\n}\n\n/**\n * Get calendar entry by service_id\n */\nexport function getCalendarByServiceId(db: Database, serviceId: string): Calendar | null {\n const stmt = db.prepare('SELECT * FROM calendar WHERE service_id = ?');\n stmt.bind([serviceId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToCalendar(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get calendar date exceptions for a service\n */\nexport function getCalendarDates(db: Database, serviceId: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE service_id = ? ORDER BY date');\n stmt.bind([serviceId]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Get calendar date exceptions for a specific date\n */\nexport function getCalendarDatesForDate(db: Database, date: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE date = ?');\n stmt.bind([date]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Convert database row to Calendar object\n */\nfunction rowToCalendar(row: Record): Calendar {\n return {\n service_id: String(row.service_id),\n monday: Number(row.monday),\n tuesday: Number(row.tuesday),\n wednesday: Number(row.wednesday),\n thursday: Number(row.thursday),\n friday: Number(row.friday),\n saturday: Number(row.saturday),\n sunday: Number(row.sunday),\n start_date: String(row.start_date),\n end_date: String(row.end_date),\n };\n}\n\n/**\n * Convert database row to CalendarDate object\n */\nfunction rowToCalendarDate(row: Record): CalendarDate {\n return {\n service_id: String(row.service_id),\n date: String(row.date),\n exception_type: Number(row.exception_type),\n };\n}\n","/**\n * Trip Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Trip } from '../types/gtfs';\nimport type { TripRealtime, VehiclePosition } from '../types/gtfs-rt';\n\nexport interface TripFilters {\n tripId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface TripWithRealtime extends Trip {\n realtime?: TripRealtime;\n}\n\n/**\n * Merge realtime data with trips\n */\nfunction mergeRealtimeData(\n trips: Trip[],\n db: Database,\n stalenessThreshold: number\n): TripWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n const tripIds = trips.map(t => t.trip_id);\n if (tripIds.length === 0) return trips;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n\n // Get vehicle positions\n const vpStmt = db.prepare(`\n SELECT * FROM rt_vehicle_positions\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n vpStmt.bind([...tripIds, staleThreshold]);\n\n const vpMap = new Map>();\n while (vpStmt.step()) {\n const row = vpStmt.getAsObject() as Record;\n vpMap.set(String(row.trip_id), row);\n }\n vpStmt.free();\n\n // Get trip updates\n const tuStmt = db.prepare(`\n SELECT * FROM rt_trip_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n tuStmt.bind([...tripIds, staleThreshold]);\n\n const tuMap = new Map>();\n while (tuStmt.step()) {\n const row = tuStmt.getAsObject() as Record;\n tuMap.set(String(row.trip_id), row);\n }\n tuStmt.free();\n\n // Merge realtime data\n return trips.map((trip): TripWithRealtime => {\n const vpRow = vpMap.get(trip.trip_id);\n const tuRow = tuMap.get(trip.trip_id);\n\n if (!vpRow && !tuRow) {\n return { ...trip, realtime: { vehicle_position: null, trip_update: null } };\n }\n\n const realtime: TripRealtime = {\n vehicle_position: null,\n trip_update: null\n };\n\n // Parse vehicle position\n if (vpRow) {\n const vp: VehiclePosition = {\n trip_id: String(vpRow.trip_id),\n route_id: vpRow.route_id ? String(vpRow.route_id) : undefined,\n rt_last_updated: Number(vpRow.rt_last_updated)\n };\n\n if (vpRow.vehicle_id || vpRow.vehicle_label || vpRow.vehicle_license_plate) {\n vp.vehicle = {\n id: vpRow.vehicle_id ? String(vpRow.vehicle_id) : undefined,\n label: vpRow.vehicle_label ? String(vpRow.vehicle_label) : undefined,\n license_plate: vpRow.vehicle_license_plate ? String(vpRow.vehicle_license_plate) : undefined\n };\n }\n\n if (vpRow.latitude !== null && vpRow.longitude !== null) {\n vp.position = {\n latitude: Number(vpRow.latitude),\n longitude: Number(vpRow.longitude),\n bearing: vpRow.bearing !== null ? Number(vpRow.bearing) : undefined,\n odometer: vpRow.odometer !== null ? Number(vpRow.odometer) : undefined,\n speed: vpRow.speed !== null ? Number(vpRow.speed) : undefined\n };\n }\n\n if (vpRow.current_stop_sequence !== null) vp.current_stop_sequence = Number(vpRow.current_stop_sequence);\n if (vpRow.stop_id) vp.stop_id = String(vpRow.stop_id);\n if (vpRow.current_status !== null) vp.current_status = Number(vpRow.current_status);\n if (vpRow.timestamp !== null) vp.timestamp = Number(vpRow.timestamp);\n if (vpRow.congestion_level !== null) vp.congestion_level = Number(vpRow.congestion_level);\n if (vpRow.occupancy_status !== null) vp.occupancy_status = Number(vpRow.occupancy_status);\n\n realtime.vehicle_position = vp;\n }\n\n // Parse trip update\n if (tuRow) {\n realtime.trip_update = {\n delay: tuRow.delay !== null ? Number(tuRow.delay) : undefined,\n schedule_relationship: tuRow.schedule_relationship !== null ? Number(tuRow.schedule_relationship) : undefined\n };\n }\n\n return { ...trip, realtime };\n });\n}\n\n/**\n * Get trips with optional filters\n */\nexport function getTrips(\n db: Database,\n filters: TripFilters = {},\n stalenessThreshold: number = 120\n): Trip[] | TripWithRealtime[] {\n const { tripId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with routes table\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsRoutesJoin ? 't.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (routeId) {\n conditions.push(needsRoutesJoin ? 't.route_id = ?' : 'route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.service_id IN (${placeholders})` : `service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push(needsRoutesJoin ? 't.direction_id = ?' : 'direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = needsRoutesJoin\n ? 'SELECT t.* FROM trips t INNER JOIN routes r ON t.route_id = r.route_id'\n : 'SELECT * FROM trips';\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(trips, db, stalenessThreshold);\n }\n\n return trips;\n}\n\n/**\n * Get a trip by its trip_id\n */\nexport function getTripById(db: Database, tripId: string): Trip | null {\n const stmt = db.prepare('SELECT * FROM trips WHERE trip_id = ?');\n stmt.bind([tripId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToTrip(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get trips for a route\n */\nexport function getTripsByRoute(db: Database, routeId: string): Trip[] {\n const stmt = db.prepare('SELECT * FROM trips WHERE route_id = ?');\n stmt.bind([routeId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route and service (active on a given date)\n */\nexport function getTripsByRouteAndService(\n db: Database,\n routeId: string,\n serviceIds: string[]\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders})`\n );\n stmt.bind([routeId, ...serviceIds]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route, service, and direction\n */\nexport function getTripsByRouteServiceAndDirection(\n db: Database,\n routeId: string,\n serviceIds: string[],\n directionId: number\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders}) AND direction_id = ?`\n );\n stmt.bind([routeId, ...serviceIds, directionId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get all trips for a service (active on a given date)\n */\nexport function getTripsByService(db: Database, serviceIds: string[]): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(`SELECT * FROM trips WHERE service_id IN (${placeholders})`);\n stmt.bind(serviceIds);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Convert database row to Trip object\n */\nfunction rowToTrip(row: Record): Trip {\n return {\n trip_id: String(row.trip_id),\n route_id: String(row.route_id),\n service_id: String(row.service_id),\n trip_headsign: row.trip_headsign ? String(row.trip_headsign) : undefined,\n trip_short_name: row.trip_short_name ? String(row.trip_short_name) : undefined,\n direction_id: row.direction_id !== null ? Number(row.direction_id) : undefined,\n block_id: row.block_id ? String(row.block_id) : undefined,\n shape_id: row.shape_id ? String(row.shape_id) : undefined,\n wheelchair_accessible: row.wheelchair_accessible !== null ? Number(row.wheelchair_accessible) : undefined,\n bikes_allowed: row.bikes_allowed !== null ? Number(row.bikes_allowed) : undefined,\n };\n}\n","/**\n * Stop Time Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { StopTime } from '../types/gtfs';\nimport type { StopTimeRealtime } from '../types/gtfs-rt';\n\nexport interface StopTimeFilters {\n tripId?: string;\n stopId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface StopTimeWithRealtime extends StopTime {\n realtime?: StopTimeRealtime;\n}\n\n/**\n * Merge realtime data with stop times\n */\nfunction mergeRealtimeData(\n stopTimes: StopTime[],\n db: Database,\n stalenessThreshold: number\n): StopTimeWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n // Build map of trip_id -> stop times for this query\n const tripIds = Array.from(new Set(stopTimes.map(st => st.trip_id)));\n if (tripIds.length === 0) return stopTimes;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(`\n SELECT trip_id, stop_sequence, stop_id,\n arrival_delay, departure_delay, schedule_relationship\n FROM rt_stop_time_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n stmt.bind([...tripIds, staleThreshold]);\n\n // Build map of trip_id+stop_sequence -> RT data\n const rtMap = new Map();\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const key = `${row.trip_id}_${row.stop_sequence}`;\n rtMap.set(key, {\n arrival_delay: row.arrival_delay !== null ? Number(row.arrival_delay) : undefined,\n departure_delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n });\n }\n stmt.free();\n\n // Merge RT data with stop times\n return stopTimes.map((st): StopTimeWithRealtime => {\n const key = `${st.trip_id}_${st.stop_sequence}`;\n const rtData = rtMap.get(key);\n\n if (rtData) {\n return { ...st, realtime: rtData };\n }\n return st;\n });\n}\n\n/**\n * Get stop times with optional filters\n */\nexport function getStopTimes(\n db: Database,\n filters: StopTimeFilters = {},\n stalenessThreshold: number = 120\n): StopTime[] | StopTimeWithRealtime[] {\n const { tripId, stopId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with trips and/or routes table\n const needsTripsJoin = routeId || serviceIds || directionId !== undefined || agencyId !== undefined;\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsTripsJoin ? 'st.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (stopId) {\n conditions.push(needsTripsJoin ? 'st.stop_id = ?' : 'stop_id = ?');\n params.push(stopId);\n }\n\n if (routeId) {\n conditions.push('t.route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(`t.service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push('t.direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql: string;\n if (needsRoutesJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id INNER JOIN routes r ON t.route_id = r.route_id';\n } else if (needsTripsJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id';\n } else {\n sql = 'SELECT * FROM stop_times';\n }\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n\n // Order by stop_sequence if filtering by trip, otherwise by arrival_time\n sql += tripId ? ' ORDER BY stop_sequence' : ' ORDER BY arrival_time';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(stopTimes, db, stalenessThreshold);\n }\n\n return stopTimes;\n}\n\n/**\n * Get stop times for a trip\n */\nexport function getStopTimesByTrip(db: Database, tripId: string): StopTime[] {\n const stmt = db.prepare('SELECT * FROM stop_times WHERE trip_id = ? ORDER BY stop_sequence');\n stmt.bind([tripId]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop\n */\nexport function getStopTimesByStop(db: Database, stopId: string, limit = 100): StopTime[] {\n const stmt = db.prepare(\n 'SELECT * FROM stop_times WHERE stop_id = ? ORDER BY arrival_time LIMIT ?'\n );\n stmt.bind([stopId, limit]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop and specific trips (filtered by route/date)\n */\nexport function getStopTimesByStopAndTrips(\n db: Database,\n stopId: string,\n tripIds: string[]\n): StopTime[] {\n if (tripIds.length === 0) {\n return [];\n }\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM stop_times\n WHERE stop_id = ? AND trip_id IN (${placeholders})\n ORDER BY arrival_time`\n );\n stmt.bind([stopId, ...tripIds]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop, route, and direction on a specific date\n */\nexport function getStopTimesForStopRouteDirection(\n db: Database,\n stopId: string,\n routeId: string,\n serviceIds: string[],\n directionId?: number\n): StopTime[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n\n let sql = `\n SELECT st.* FROM stop_times st\n INNER JOIN trips t ON st.trip_id = t.trip_id\n WHERE st.stop_id = ?\n AND t.route_id = ?\n AND t.service_id IN (${placeholders})\n `;\n\n const params: (string | number)[] = [stopId, routeId, ...serviceIds];\n\n if (directionId !== undefined) {\n sql += ' AND t.direction_id = ?';\n params.push(directionId);\n }\n\n sql += ' ORDER BY st.arrival_time';\n\n const stmt = db.prepare(sql);\n stmt.bind(params);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Convert database row to StopTime object\n */\nfunction rowToStopTime(row: Record): StopTime {\n return {\n trip_id: String(row.trip_id),\n arrival_time: String(row.arrival_time),\n departure_time: String(row.departure_time),\n stop_id: String(row.stop_id),\n stop_sequence: Number(row.stop_sequence),\n stop_headsign: row.stop_headsign ? String(row.stop_headsign) : undefined,\n pickup_type: row.pickup_type !== null ? Number(row.pickup_type) : undefined,\n drop_off_type: row.drop_off_type !== null ? Number(row.drop_off_type) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n shape_dist_traveled: row.shape_dist_traveled !== null ? Number(row.shape_dist_traveled) : undefined,\n timepoint: row.timepoint !== null ? Number(row.timepoint) : undefined,\n };\n}\n","import type { Database } from 'sql.js';\nimport type { Alert, EntitySelector, TimeRange, TranslatedString } from '../types/gtfs-rt';\nimport type { AlertFilters } from '../types/gtfs-rt';\n\nexport type { AlertFilters };\n\n/**\n * Parse JSON fields from database\n */\nfunction parseAlert(row: Record): Alert {\n return {\n id: String(row.id),\n active_period: row.active_period ? JSON.parse(String(row.active_period)) as TimeRange[] : [],\n informed_entity: row.informed_entity ? JSON.parse(String(row.informed_entity)) as EntitySelector[] : [],\n cause: row.cause ? Number(row.cause) : undefined,\n effect: row.effect ? Number(row.effect) : undefined,\n url: row.url ? JSON.parse(String(row.url)) as TranslatedString : undefined,\n header_text: row.header_text ? JSON.parse(String(row.header_text)) as TranslatedString : undefined,\n description_text: row.description_text ? JSON.parse(String(row.description_text)) as TranslatedString : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n}\n\n/**\n * Check if an alert is currently active based on its active_period\n */\nfunction isAlertActive(alert: Alert, now: number): boolean {\n // If no active periods defined, assume always active\n if (!alert.active_period || alert.active_period.length === 0) {\n return true;\n }\n\n // Check if current time falls within any active period\n for (const period of alert.active_period) {\n const start = period.start || 0;\n const end = period.end || Number.MAX_SAFE_INTEGER;\n\n if (now >= start && now <= end) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if an alert affects the specified entity\n */\nfunction alertAffectsEntity(alert: Alert, filters: AlertFilters): boolean {\n if (!alert.informed_entity || alert.informed_entity.length === 0) {\n return true; // No specific entities, assume it affects all\n }\n\n for (const entity of alert.informed_entity) {\n // Check route_id\n if (filters.routeId && entity.route_id === filters.routeId) {\n return true;\n }\n\n // Check stop_id\n if (filters.stopId && entity.stop_id === filters.stopId) {\n return true;\n }\n\n // Check trip_id\n if (filters.tripId && entity.trip?.trip_id === filters.tripId) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Get alerts with optional filters\n */\nexport function getAlerts(db: Database, filters: AlertFilters = {}, stalenessThreshold: number = 120): Alert[] {\n const {\n alertId,\n activeOnly,\n routeId,\n stopId,\n tripId,\n cause,\n effect,\n limit\n } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by alert ID\n if (alertId) {\n conditions.push('id = ?');\n params.push(alertId);\n }\n\n // Filter by cause\n if (cause !== undefined) {\n conditions.push('cause = ?');\n params.push(cause);\n }\n\n // Filter by effect\n if (effect !== undefined) {\n conditions.push('effect = ?');\n params.push(effect);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_alerts';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const alerts: Alert[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const alert = parseAlert(row);\n\n // Apply activeOnly filter in application code\n if (activeOnly && !isAlertActive(alert, now)) {\n continue;\n }\n\n // Apply entity filters in application code (since informed_entity is JSON)\n if (routeId || stopId || tripId) {\n if (!alertAffectsEntity(alert, filters)) {\n continue;\n }\n }\n\n alerts.push(alert);\n }\n\n stmt.free();\n return alerts;\n}\n\n/**\n * Get alert by ID\n */\nexport function getAlertById(db: Database, alertId: string, stalenessThreshold: number = 120): Alert | null {\n const alerts = getAlerts(db, { alertId, limit: 1 }, stalenessThreshold);\n return alerts.length > 0 ? alerts[0] : null;\n}\n","import type { Database} from 'sql.js';\nimport type { VehiclePosition } from '../types/gtfs-rt';\nimport type { VehiclePositionFilters } from '../types/gtfs-rt';\n\nexport type { VehiclePositionFilters };\n\n/**\n * Parse vehicle position from database row\n */\nfunction parseVehiclePosition(row: Record): VehiclePosition {\n const vp: VehiclePosition = {\n trip_id: String(row.trip_id),\n route_id: row.route_id ? String(row.route_id) : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n\n // Vehicle descriptor\n if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) {\n vp.vehicle = {\n id: row.vehicle_id ? String(row.vehicle_id) : undefined,\n label: row.vehicle_label ? String(row.vehicle_label) : undefined,\n license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : undefined\n };\n }\n\n // Position\n if (row.latitude !== null && row.longitude !== null) {\n vp.position = {\n latitude: Number(row.latitude),\n longitude: Number(row.longitude),\n bearing: row.bearing !== null ? Number(row.bearing) : undefined,\n odometer: row.odometer !== null ? Number(row.odometer) : undefined,\n speed: row.speed !== null ? Number(row.speed) : undefined\n };\n }\n\n // Other fields\n if (row.current_stop_sequence !== null) {\n vp.current_stop_sequence = Number(row.current_stop_sequence);\n }\n if (row.stop_id) {\n vp.stop_id = String(row.stop_id);\n }\n if (row.current_status !== null) {\n vp.current_status = Number(row.current_status);\n }\n if (row.timestamp !== null) {\n vp.timestamp = Number(row.timestamp);\n }\n if (row.congestion_level !== null) {\n vp.congestion_level = Number(row.congestion_level);\n }\n if (row.occupancy_status !== null) {\n vp.occupancy_status = Number(row.occupancy_status);\n }\n\n return vp;\n}\n\n/**\n * Get vehicle positions with optional filters\n */\nexport function getVehiclePositions(\n db: Database,\n filters: VehiclePositionFilters = {},\n stalenessThreshold: number = 120\n): VehiclePosition[] {\n const { tripId, routeId, vehicleId, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by route_id\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n // Filter by vehicle_id\n if (vehicleId) {\n conditions.push('vehicle_id = ?');\n params.push(vehicleId);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_vehicle_positions';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const positions: VehiclePosition[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n positions.push(parseVehiclePosition(row));\n }\n\n stmt.free();\n return positions;\n}\n\n/**\n * Get vehicle position by trip ID\n */\nexport function getVehiclePositionByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): VehiclePosition | null {\n const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold);\n return positions.length > 0 ? positions[0] : null;\n}\n","/**\n * GTFS Realtime TypeScript types\n * Based on GTFS Realtime v2.0 specification\n */\n\n// Enum types from GTFS-RT specification\n\nexport enum ScheduleRelationship {\n SCHEDULED = 0,\n ADDED = 1,\n UNSCHEDULED = 2,\n CANCELED = 3,\n SKIPPED = 4,\n NO_DATA = 5\n}\n\nexport enum VehicleStopStatus {\n INCOMING_AT = 0,\n STOPPED_AT = 1,\n IN_TRANSIT_TO = 2\n}\n\nexport enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0,\n RUNNING_SMOOTHLY = 1,\n STOP_AND_GO = 2,\n CONGESTION = 3,\n SEVERE_CONGESTION = 4\n}\n\nexport enum OccupancyStatus {\n EMPTY = 0,\n MANY_SEATS_AVAILABLE = 1,\n FEW_SEATS_AVAILABLE = 2,\n STANDING_ROOM_ONLY = 3,\n CRUSHED_STANDING_ROOM_ONLY = 4,\n FULL = 5,\n NOT_ACCEPTING_PASSENGERS = 6\n}\n\nexport enum AlertCause {\n UNKNOWN_CAUSE = 1,\n OTHER_CAUSE = 2,\n TECHNICAL_PROBLEM = 3,\n STRIKE = 4,\n DEMONSTRATION = 5,\n ACCIDENT = 6,\n HOLIDAY = 7,\n WEATHER = 8,\n MAINTENANCE = 9,\n CONSTRUCTION = 10,\n POLICE_ACTIVITY = 11,\n MEDICAL_EMERGENCY = 12\n}\n\nexport enum AlertEffect {\n NO_SERVICE = 1,\n REDUCED_SERVICE = 2,\n SIGNIFICANT_DELAYS = 3,\n DETOUR = 4,\n ADDITIONAL_SERVICE = 5,\n MODIFIED_SERVICE = 6,\n OTHER_EFFECT = 7,\n UNKNOWN_EFFECT = 8,\n STOP_MOVED = 9,\n NO_EFFECT = 10,\n ACCESSIBILITY_ISSUE = 11\n}\n\n// Main GTFS-RT types\n\nexport interface TranslatedString {\n translation: Array<{\n text: string;\n language?: string;\n }>;\n}\n\nexport interface EntitySelector {\n agency_id?: string;\n route_id?: string;\n route_type?: number;\n trip?: {\n trip_id?: string;\n route_id?: string;\n direction_id?: number;\n start_time?: string;\n start_date?: string;\n schedule_relationship?: ScheduleRelationship;\n };\n stop_id?: string;\n}\n\nexport interface TimeRange {\n start?: number; // UNIX timestamp\n end?: number; // UNIX timestamp\n}\n\nexport interface Alert {\n id: string;\n active_period: TimeRange[];\n informed_entity: EntitySelector[];\n cause?: AlertCause;\n effect?: AlertEffect;\n url?: TranslatedString;\n header_text?: TranslatedString;\n description_text?: TranslatedString;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface Position {\n latitude: number;\n longitude: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\nexport interface VehicleDescriptor {\n id?: string;\n label?: string;\n license_plate?: string;\n}\n\nexport interface VehiclePosition {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n position?: Position;\n current_stop_sequence?: number;\n stop_id?: string;\n current_status?: VehicleStopStatus;\n timestamp?: number;\n congestion_level?: CongestionLevel;\n occupancy_status?: OccupancyStatus;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface StopTimeEvent {\n delay?: number; // seconds\n time?: number; // UNIX timestamp (absolute time)\n uncertainty?: number;\n}\n\nexport interface StopTimeUpdate {\n stop_sequence?: number;\n stop_id?: string;\n arrival?: StopTimeEvent;\n departure?: StopTimeEvent;\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripUpdate {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n stop_time_update: StopTimeUpdate[];\n timestamp?: number;\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n rt_last_updated: number; // UNIX timestamp\n}\n\n// Enhanced types for queries with realtime data\n\nexport interface StopTimeRealtime {\n arrival_delay?: number; // seconds\n departure_delay?: number; // seconds\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripRealtime {\n vehicle_position?: VehiclePosition | null;\n trip_update?: {\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n } | null;\n}\n\n// Filter types for realtime queries\n\nexport interface AlertFilters {\n alertId?: string;\n activeOnly?: boolean;\n routeId?: string;\n stopId?: string;\n tripId?: string;\n cause?: AlertCause;\n effect?: AlertEffect;\n limit?: number;\n}\n\nexport interface VehiclePositionFilters {\n tripId?: string;\n routeId?: string;\n vehicleId?: string;\n limit?: number;\n}\n\n// Configuration\n\nexport interface RealtimeConfig {\n feedUrls?: string[];\n stalenessThreshold?: number; // seconds, default 120\n}\n"],"mappings":"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","names":["JSZip","Papa","response","arrayBuffer","protobuf","mergeRealtimeData","initSqlJs","ScheduleRelationship","VehicleStopStatus","CongestionLevel","OccupancyStatus","AlertCause","AlertEffect"]} \ No newline at end of file +{"version":3,"sources":["../src/index.ts","../src/gtfs-sqljs.ts","../src/schema/schema.ts","../src/loaders/zip-loader.ts","../src/loaders/csv-parser.ts","../src/loaders/data-loader.ts","../src/schema/gtfs-rt-schema.ts","../src/loaders/gtfs-rt-loader.ts","../src/queries/agencies.ts","../src/queries/stops.ts","../src/queries/routes.ts","../src/queries/calendar.ts","../src/queries/rt-vehicle-positions.ts","../src/queries/trips.ts","../src/queries/stop-times.ts","../src/queries/rt-alerts.ts","../src/queries/rt-trip-updates.ts","../src/queries/rt-stop-time-updates.ts","../src/types/gtfs-rt.ts"],"sourcesContent":["/**\n * gtfs-sqljs - Load GTFS data into sql.js SQLite database\n * @author Théophile Helleboid/SysDevRun\n * @license MIT\n */\n\nexport {\n GtfsSqlJs,\n type GtfsSqlJsOptions,\n type AgencyFilters,\n type StopFilters,\n type RouteFilters,\n type TripFilters,\n type StopTimeFilters,\n type AlertFilters,\n type VehiclePositionFilters,\n type TripUpdateFilters,\n type StopTimeUpdateFilters,\n type Alert,\n type VehiclePosition,\n type TripUpdate,\n type StopTimeUpdateWithMetadata,\n type TripWithRealtime,\n type StopTimeWithRealtime\n} from './gtfs-sqljs';\n\n// Export GTFS types\nexport type {\n Agency,\n Stop,\n Route,\n Trip,\n StopTime,\n Calendar,\n CalendarDate,\n FareAttribute,\n FareRule,\n Shape,\n Frequency,\n Transfer,\n Pathway,\n Level,\n FeedInfo,\n Attribution,\n} from './types/gtfs';\n\n// Export GTFS-RT types\nexport type {\n TranslatedString,\n EntitySelector,\n TimeRange,\n Position,\n VehicleDescriptor,\n StopTimeEvent,\n StopTimeUpdate,\n StopTimeRealtime,\n TripRealtime,\n RealtimeConfig\n} from './types/gtfs-rt';\n\n// Export GTFS-RT enums\nexport {\n ScheduleRelationship,\n VehicleStopStatus,\n CongestionLevel,\n OccupancyStatus,\n AlertCause,\n AlertEffect\n} from './types/gtfs-rt';\n\n// Export schema definitions for advanced use\nexport { GTFS_SCHEMA, type TableSchema, type ColumnDefinition, type IndexDefinition } from './schema/schema';\n","/**\n * Main GtfsSqlJs Class\n */\n\nimport initSqlJs, { type Database, type SqlJsStatic } from 'sql.js';\nimport { getAllCreateStatements } from './schema/schema';\nimport { loadGTFSZip } from './loaders/zip-loader';\nimport { loadGTFSData } from './loaders/data-loader';\nimport { createRealtimeTables, clearRealtimeData as clearRTData } from './schema/gtfs-rt-schema';\nimport { loadRealtimeData } from './loaders/gtfs-rt-loader';\n\n// Query methods\nimport { getAgencyById, getAgencies, type AgencyFilters } from './queries/agencies';\nimport { getStopById, getStops, type StopFilters } from './queries/stops';\nimport { getRouteById, getRoutes, type RouteFilters } from './queries/routes';\nimport {\n getActiveServiceIds,\n getCalendarByServiceId,\n getCalendarDates,\n getCalendarDatesForDate,\n} from './queries/calendar';\nimport { getTripById, getTrips, type TripFilters, type TripWithRealtime } from './queries/trips';\nimport { getStopTimesByTrip, getStopTimes, type StopTimeFilters, type StopTimeWithRealtime } from './queries/stop-times';\nimport { getAlerts as getAlertsQuery, getAlertById, getAllAlerts, type AlertFilters } from './queries/rt-alerts';\nimport { getVehiclePositions as getVehiclePositionsQuery, getVehiclePositionByTripId, getAllVehiclePositions, type VehiclePositionFilters } from './queries/rt-vehicle-positions';\nimport { getTripUpdates, getTripUpdateByTripId, getAllTripUpdates, type TripUpdateFilters } from './queries/rt-trip-updates';\nimport { getStopTimeUpdates, getStopTimeUpdatesByTripId, getAllStopTimeUpdates, type StopTimeUpdateFilters, type StopTimeUpdateWithMetadata } from './queries/rt-stop-time-updates';\n\n// Types\nimport type { Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate } from './types/gtfs';\nimport type { Alert, VehiclePosition, TripUpdate } from './types/gtfs-rt';\n\n// Export filter types for users\nexport type { AgencyFilters, StopFilters, RouteFilters, TripFilters, StopTimeFilters, AlertFilters, VehiclePositionFilters, TripUpdateFilters, StopTimeUpdateFilters };\n// Export RT types\nexport type { Alert, VehiclePosition, TripUpdate, StopTimeUpdateWithMetadata, TripWithRealtime, StopTimeWithRealtime };\n\nexport interface GtfsSqlJsOptions {\n /**\n * Path or URL to GTFS ZIP file\n */\n zipPath?: string;\n\n /**\n * Pre-loaded SQLite database as ArrayBuffer\n */\n database?: ArrayBuffer;\n\n /**\n * Optional: Custom SQL.js instance\n */\n SQL?: SqlJsStatic;\n\n /**\n * Optional: Path to SQL.js WASM file (for custom loading)\n */\n locateFile?: (filename: string) => string;\n\n /**\n * Optional: Array of GTFS filenames to skip importing (e.g., ['shapes.txt'])\n * Tables will be created but no data will be imported for these files\n */\n skipFiles?: string[];\n\n /**\n * Optional: Array of GTFS-RT feed URLs for realtime data\n */\n realtimeFeedUrls?: string[];\n\n /**\n * Optional: Staleness threshold in seconds (default: 120)\n * Realtime data older than this will be excluded from queries\n */\n stalenessThreshold?: number;\n}\n\nexport class GtfsSqlJs {\n private db: Database | null = null;\n private SQL: SqlJsStatic | null = null;\n private realtimeFeedUrls: string[] = [];\n private stalenessThreshold: number = 120;\n\n /**\n * Private constructor - use static factory methods instead\n */\n private constructor() {}\n\n /**\n * Create GtfsSqlJs instance from GTFS ZIP file\n */\n static async fromZip(\n zipPath: string,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromZip(zipPath, options);\n return instance;\n }\n\n /**\n * Create GtfsSqlJs instance from existing SQLite database\n */\n static async fromDatabase(\n database: ArrayBuffer,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromDatabase(database, options);\n return instance;\n }\n\n /**\n * Initialize from ZIP file\n */\n private async initFromZip(zipPath: string, options: Omit): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Create new database\n this.db = new this.SQL.Database();\n\n // Create GTFS schema\n const createStatements = getAllCreateStatements();\n for (const statement of createStatements) {\n this.db.run(statement);\n }\n\n // Create GTFS-RT tables\n createRealtimeTables(this.db);\n\n // Load GTFS data\n const files = await loadGTFSZip(zipPath);\n await loadGTFSData(this.db, files, options.skipFiles);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Initialize from existing database\n */\n private async initFromDatabase(\n database: ArrayBuffer,\n options: Omit\n ): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Load existing database\n this.db = new this.SQL.Database(new Uint8Array(database));\n\n // Ensure RT tables exist (in case loading old database)\n createRealtimeTables(this.db);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Export database to ArrayBuffer\n */\n export(): ArrayBuffer {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n\n const data = this.db.export();\n // Create a new ArrayBuffer and copy the data to ensure proper type\n const buffer = new ArrayBuffer(data.length);\n new Uint8Array(buffer).set(data);\n return buffer;\n }\n\n /**\n * Close the database connection\n */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n /**\n * Get direct access to the database (for advanced queries)\n */\n getDatabase(): Database {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n return this.db;\n }\n\n // ==================== Agency Methods ====================\n\n /**\n * Get an agency by its agency_id\n */\n getAgencyById(agencyId: string): Agency | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencyById(this.db, agencyId);\n }\n\n /**\n * Get agencies with optional filters\n */\n getAgencies(filters?: AgencyFilters): Agency[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencies(this.db, filters);\n }\n\n // ==================== Stop Methods ====================\n\n /**\n * Get a stop by its stop_id\n */\n getStopById(stopId: string): Stop | null {\n if (!this.db) throw new Error('Database not initialized');\n return getStopById(this.db, stopId);\n }\n\n /**\n * Get stops with optional filters\n */\n getStops(filters?: StopFilters): Stop[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStops(this.db, filters);\n }\n\n // ==================== Route Methods ====================\n\n /**\n * Get a route by its route_id\n */\n getRouteById(routeId: string): Route | null {\n if (!this.db) throw new Error('Database not initialized');\n return getRouteById(this.db, routeId);\n }\n\n /**\n * Get routes with optional filters\n */\n getRoutes(filters?: RouteFilters): Route[] {\n if (!this.db) throw new Error('Database not initialized');\n return getRoutes(this.db, filters);\n }\n\n // ==================== Calendar Methods ====================\n\n /**\n * Get active service IDs for a given date (YYYYMMDD format)\n */\n getActiveServiceIds(date: string): string[] {\n if (!this.db) throw new Error('Database not initialized');\n return getActiveServiceIds(this.db, date);\n }\n\n /**\n * Get calendar entry by service_id\n */\n getCalendarByServiceId(serviceId: string): Calendar | null {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarByServiceId(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a service\n */\n getCalendarDates(serviceId: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDates(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a specific date\n */\n getCalendarDatesForDate(date: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDatesForDate(this.db, date);\n }\n\n // ==================== Trip Methods ====================\n\n /**\n * Get a trip by its trip_id\n */\n getTripById(tripId: string): Trip | null {\n if (!this.db) throw new Error('Database not initialized');\n return getTripById(this.db, tripId);\n }\n\n /**\n * Get trips with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get all trips for a route on a specific date\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', date: '20240115' });\n *\n * @example\n * // Get all trips for a route going in one direction\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', directionId: 0 });\n */\n getTrips(filters?: TripFilters & { date?: string }): Trip[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getTrips(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Stop Time Methods ====================\n\n /**\n * Get stop times for a trip (ordered by stop_sequence)\n */\n getStopTimesByTrip(tripId: string): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimesByTrip(this.db, tripId);\n }\n\n /**\n * Get stop times with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.stopId - Filter by stop ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get stop times for a specific trip\n * const stopTimes = gtfs.getStopTimes({ tripId: 'TRIP_123' });\n *\n * @example\n * // Get stop times at a stop for a specific route on a date\n * const stopTimes = gtfs.getStopTimes({\n * stopId: 'STOP_123',\n * routeId: 'ROUTE_1',\n * date: '20240115'\n * });\n */\n getStopTimes(filters?: StopTimeFilters & { date?: string }): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getStopTimes(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Realtime Methods ====================\n\n /**\n * Set GTFS-RT feed URLs\n */\n setRealtimeFeedUrls(urls: string[]): void {\n this.realtimeFeedUrls = urls;\n }\n\n /**\n * Get currently configured GTFS-RT feed URLs\n */\n getRealtimeFeedUrls(): string[] {\n return [...this.realtimeFeedUrls];\n }\n\n /**\n * Set staleness threshold in seconds\n */\n setStalenessThreshold(seconds: number): void {\n this.stalenessThreshold = seconds;\n }\n\n /**\n * Get current staleness threshold\n */\n getStalenessThreshold(): number {\n return this.stalenessThreshold;\n }\n\n /**\n * Fetch and load GTFS Realtime data from configured feed URLs or provided URLs\n * @param urls - Optional array of feed URLs. If not provided, uses configured feed URLs\n */\n async fetchRealtimeData(urls?: string[]): Promise {\n if (!this.db) throw new Error('Database not initialized');\n\n const feedUrls = urls || this.realtimeFeedUrls;\n if (feedUrls.length === 0) {\n throw new Error('No realtime feed URLs configured. Use setRealtimeFeedUrls() or pass urls parameter.');\n }\n\n await loadRealtimeData(this.db, feedUrls);\n }\n\n /**\n * Clear all realtime data from the database\n */\n clearRealtimeData(): void {\n if (!this.db) throw new Error('Database not initialized');\n clearRTData(this.db);\n }\n\n /**\n * Get alerts with optional filters\n */\n getAlerts(filters?: AlertFilters): Alert[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get alert by ID\n */\n getAlertById(alertId: string): Alert | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertById(this.db, alertId, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle positions with optional filters\n */\n getVehiclePositions(filters?: VehiclePositionFilters): VehiclePosition[] {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle position by trip ID\n */\n getVehiclePositionByTripId(tripId: string): VehiclePosition | null {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionByTripId(this.db, tripId, this.stalenessThreshold);\n }\n\n /**\n * Get trip updates with optional filters\n */\n getTripUpdates(filters?: TripUpdateFilters): TripUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getTripUpdates(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get trip update by trip ID\n */\n getTripUpdateByTripId(tripId: string): TripUpdate | null {\n if (!this.db) throw new Error('Database not initialized');\n return getTripUpdateByTripId(this.db, tripId, this.stalenessThreshold);\n }\n\n /**\n * Get stop time updates with optional filters\n */\n getStopTimeUpdates(filters?: StopTimeUpdateFilters): import('./types/gtfs-rt').StopTimeUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimeUpdates(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get stop time updates for a specific trip\n */\n getStopTimeUpdatesByTripId(tripId: string): import('./types/gtfs-rt').StopTimeUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimeUpdatesByTripId(this.db, tripId, this.stalenessThreshold);\n }\n\n // ==================== Debug Export Methods ====================\n // These methods export all realtime data without staleness filtering\n // for debugging purposes\n\n /**\n * Export all alerts without staleness filtering (for debugging)\n */\n debugExportAllAlerts(): Alert[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllAlerts(this.db);\n }\n\n /**\n * Export all vehicle positions without staleness filtering (for debugging)\n */\n debugExportAllVehiclePositions(): VehiclePosition[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllVehiclePositions(this.db);\n }\n\n /**\n * Export all trip updates without staleness filtering (for debugging)\n */\n debugExportAllTripUpdates(): TripUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllTripUpdates(this.db);\n }\n\n /**\n * Export all stop time updates without staleness filtering (for debugging)\n * Returns extended type with trip_id and rt_last_updated for debugging purposes\n */\n debugExportAllStopTimeUpdates(): StopTimeUpdateWithMetadata[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllStopTimeUpdates(this.db);\n }\n}\n","/**\n * SQLite Schema Definitions for GTFS Data\n * Matches required/optional fields from GTFS specification\n */\n\nexport interface TableSchema {\n name: string;\n columns: ColumnDefinition[];\n indexes?: IndexDefinition[];\n}\n\nexport interface ColumnDefinition {\n name: string;\n type: 'TEXT' | 'INTEGER' | 'REAL';\n required: boolean;\n primaryKey?: boolean;\n}\n\nexport interface IndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n}\n\nexport const GTFS_SCHEMA: TableSchema[] = [\n {\n name: 'agency',\n columns: [\n { name: 'agency_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'agency_name', type: 'TEXT', required: true },\n { name: 'agency_url', type: 'TEXT', required: true },\n { name: 'agency_timezone', type: 'TEXT', required: true },\n { name: 'agency_lang', type: 'TEXT', required: false },\n { name: 'agency_phone', type: 'TEXT', required: false },\n { name: 'agency_fare_url', type: 'TEXT', required: false },\n { name: 'agency_email', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'stops',\n columns: [\n { name: 'stop_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'stop_name', type: 'TEXT', required: true },\n { name: 'stop_lat', type: 'REAL', required: true },\n { name: 'stop_lon', type: 'REAL', required: true },\n { name: 'stop_code', type: 'TEXT', required: false },\n { name: 'stop_desc', type: 'TEXT', required: false },\n { name: 'zone_id', type: 'TEXT', required: false },\n { name: 'stop_url', type: 'TEXT', required: false },\n { name: 'location_type', type: 'INTEGER', required: false },\n { name: 'parent_station', type: 'TEXT', required: false },\n { name: 'stop_timezone', type: 'TEXT', required: false },\n { name: 'wheelchair_boarding', type: 'INTEGER', required: false },\n { name: 'level_id', type: 'TEXT', required: false },\n { name: 'platform_code', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_stops_stop_code', columns: ['stop_code'] },\n { name: 'idx_stops_stop_name', columns: ['stop_name'] },\n { name: 'idx_stops_parent_station', columns: ['parent_station'] },\n ],\n },\n {\n name: 'routes',\n columns: [\n { name: 'route_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_short_name', type: 'TEXT', required: true },\n { name: 'route_long_name', type: 'TEXT', required: true },\n { name: 'route_type', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_desc', type: 'TEXT', required: false },\n { name: 'route_url', type: 'TEXT', required: false },\n { name: 'route_color', type: 'TEXT', required: false },\n { name: 'route_text_color', type: 'TEXT', required: false },\n { name: 'route_sort_order', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_routes_agency_id', columns: ['agency_id'] },\n ],\n },\n {\n name: 'trips',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_id', type: 'TEXT', required: true },\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'trip_headsign', type: 'TEXT', required: false },\n { name: 'trip_short_name', type: 'TEXT', required: false },\n { name: 'direction_id', type: 'INTEGER', required: false },\n { name: 'block_id', type: 'TEXT', required: false },\n { name: 'shape_id', type: 'TEXT', required: false },\n { name: 'wheelchair_accessible', type: 'INTEGER', required: false },\n { name: 'bikes_allowed', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_trips_route_id', columns: ['route_id'] },\n { name: 'idx_trips_service_id', columns: ['service_id'] },\n { name: 'idx_trips_route_service', columns: ['route_id', 'service_id'] },\n ],\n },\n {\n name: 'stop_times',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'arrival_time', type: 'TEXT', required: true },\n { name: 'departure_time', type: 'TEXT', required: true },\n { name: 'stop_id', type: 'TEXT', required: true },\n { name: 'stop_sequence', type: 'INTEGER', required: true },\n { name: 'stop_headsign', type: 'TEXT', required: false },\n { name: 'pickup_type', type: 'INTEGER', required: false },\n { name: 'drop_off_type', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n { name: 'timepoint', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_stop_times_trip_id', columns: ['trip_id'] },\n { name: 'idx_stop_times_stop_id', columns: ['stop_id'] },\n { name: 'idx_stop_times_trip_sequence', columns: ['trip_id', 'stop_sequence'] },\n ],\n },\n {\n name: 'calendar',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'monday', type: 'INTEGER', required: true },\n { name: 'tuesday', type: 'INTEGER', required: true },\n { name: 'wednesday', type: 'INTEGER', required: true },\n { name: 'thursday', type: 'INTEGER', required: true },\n { name: 'friday', type: 'INTEGER', required: true },\n { name: 'saturday', type: 'INTEGER', required: true },\n { name: 'sunday', type: 'INTEGER', required: true },\n { name: 'start_date', type: 'TEXT', required: true },\n { name: 'end_date', type: 'TEXT', required: true },\n ],\n },\n {\n name: 'calendar_dates',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'date', type: 'TEXT', required: true },\n { name: 'exception_type', type: 'INTEGER', required: true },\n ],\n indexes: [\n { name: 'idx_calendar_dates_service_id', columns: ['service_id'] },\n { name: 'idx_calendar_dates_date', columns: ['date'] },\n { name: 'idx_calendar_dates_service_date', columns: ['service_id', 'date'] },\n ],\n },\n {\n name: 'fare_attributes',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'price', type: 'REAL', required: true },\n { name: 'currency_type', type: 'TEXT', required: true },\n { name: 'payment_method', type: 'INTEGER', required: true },\n { name: 'transfers', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'transfer_duration', type: 'INTEGER', required: false },\n ],\n },\n {\n name: 'fare_rules',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'origin_id', type: 'TEXT', required: false },\n { name: 'destination_id', type: 'TEXT', required: false },\n { name: 'contains_id', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_fare_rules_fare_id', columns: ['fare_id'] },\n { name: 'idx_fare_rules_route_id', columns: ['route_id'] },\n ],\n },\n {\n name: 'shapes',\n columns: [\n { name: 'shape_id', type: 'TEXT', required: true },\n { name: 'shape_pt_lat', type: 'REAL', required: true },\n { name: 'shape_pt_lon', type: 'REAL', required: true },\n { name: 'shape_pt_sequence', type: 'INTEGER', required: true },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n ],\n indexes: [\n { name: 'idx_shapes_shape_id', columns: ['shape_id'] },\n { name: 'idx_shapes_shape_sequence', columns: ['shape_id', 'shape_pt_sequence'] },\n ],\n },\n {\n name: 'frequencies',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'start_time', type: 'TEXT', required: true },\n { name: 'end_time', type: 'TEXT', required: true },\n { name: 'headway_secs', type: 'INTEGER', required: true },\n { name: 'exact_times', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_frequencies_trip_id', columns: ['trip_id'] },\n ],\n },\n {\n name: 'transfers',\n columns: [\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'transfer_type', type: 'INTEGER', required: true },\n { name: 'min_transfer_time', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_transfers_from_stop_id', columns: ['from_stop_id'] },\n { name: 'idx_transfers_to_stop_id', columns: ['to_stop_id'] },\n ],\n },\n {\n name: 'pathways',\n columns: [\n { name: 'pathway_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'pathway_mode', type: 'INTEGER', required: true },\n { name: 'is_bidirectional', type: 'INTEGER', required: true },\n { name: 'length', type: 'REAL', required: false },\n { name: 'traversal_time', type: 'INTEGER', required: false },\n { name: 'stair_count', type: 'INTEGER', required: false },\n { name: 'max_slope', type: 'REAL', required: false },\n { name: 'min_width', type: 'REAL', required: false },\n { name: 'signposted_as', type: 'TEXT', required: false },\n { name: 'reversed_signposted_as', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'levels',\n columns: [\n { name: 'level_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'level_index', type: 'REAL', required: true },\n { name: 'level_name', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'feed_info',\n columns: [\n { name: 'feed_publisher_name', type: 'TEXT', required: true },\n { name: 'feed_publisher_url', type: 'TEXT', required: true },\n { name: 'feed_lang', type: 'TEXT', required: true },\n { name: 'default_lang', type: 'TEXT', required: false },\n { name: 'feed_start_date', type: 'TEXT', required: false },\n { name: 'feed_end_date', type: 'TEXT', required: false },\n { name: 'feed_version', type: 'TEXT', required: false },\n { name: 'feed_contact_email', type: 'TEXT', required: false },\n { name: 'feed_contact_url', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'attributions',\n columns: [\n { name: 'attribution_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'organization_name', type: 'TEXT', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'trip_id', type: 'TEXT', required: false },\n { name: 'is_producer', type: 'INTEGER', required: false },\n { name: 'is_operator', type: 'INTEGER', required: false },\n { name: 'is_authority', type: 'INTEGER', required: false },\n { name: 'attribution_url', type: 'TEXT', required: false },\n { name: 'attribution_email', type: 'TEXT', required: false },\n { name: 'attribution_phone', type: 'TEXT', required: false },\n ],\n },\n];\n\n/**\n * Generate CREATE TABLE SQL statement from schema definition\n */\nexport function generateCreateTableSQL(schema: TableSchema): string {\n const columns = schema.columns.map((col) => {\n const parts = [col.name, col.type];\n if (col.primaryKey) {\n parts.push('PRIMARY KEY');\n }\n if (col.required && !col.primaryKey) {\n parts.push('NOT NULL');\n }\n return parts.join(' ');\n });\n\n return `CREATE TABLE IF NOT EXISTS ${schema.name} (${columns.join(', ')})`;\n}\n\n/**\n * Generate CREATE INDEX SQL statements from schema definition\n */\nexport function generateCreateIndexSQL(schema: TableSchema): string[] {\n if (!schema.indexes) {\n return [];\n }\n\n return schema.indexes.map((idx) => {\n const unique = idx.unique ? 'UNIQUE ' : '';\n const columns = idx.columns.join(', ');\n return `CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${schema.name} (${columns})`;\n });\n}\n\n/**\n * Initialize all GTFS tables in the database\n */\nexport function getAllCreateStatements(): string[] {\n const statements: string[] = [];\n\n for (const schema of GTFS_SCHEMA) {\n statements.push(generateCreateTableSQL(schema));\n statements.push(...generateCreateIndexSQL(schema));\n }\n\n return statements;\n}\n","/**\n * ZIP Loader for GTFS files\n */\n\nimport JSZip from 'jszip';\n\nexport interface GTFSFiles {\n [filename: string]: string;\n}\n\n/**\n * Fetch and extract GTFS ZIP file\n * Works in both browser and Node.js environments\n */\nexport async function loadGTFSZip(source: string | ArrayBuffer | Uint8Array): Promise {\n let zipData: ArrayBuffer | Uint8Array;\n\n // If source is a string, treat it as URL or file path\n if (typeof source === 'string') {\n zipData = await fetchZip(source);\n } else {\n zipData = source;\n }\n\n // Load ZIP file\n const zip = await JSZip.loadAsync(zipData);\n\n // Extract all .txt files (GTFS files)\n const files: GTFSFiles = {};\n const filePromises: Promise[] = [];\n\n zip.forEach((relativePath, file) => {\n // Only process .txt files\n if (!file.dir && relativePath.endsWith('.txt')) {\n const fileName = relativePath.split('/').pop() || relativePath;\n filePromises.push(\n file.async('string').then((content) => {\n files[fileName] = content;\n })\n );\n }\n });\n\n await Promise.all(filePromises);\n\n return files;\n}\n\n/**\n * Fetch ZIP file from URL or file path\n */\nasync function fetchZip(source: string): Promise {\n // Check if source is a URL\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n // For URLs, always use fetch\n if (isUrl) {\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n throw new Error('fetch is not available to load URL');\n }\n\n // For non-URLs, try Node.js fs first, fall back to fetch for browser\n // Check if we're in Node.js environment\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n // In Node.js, treat as file path\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);\n } catch (error) {\n throw new Error(`Failed to read GTFS ZIP file: ${error}`);\n }\n }\n\n // In browser, treat as relative URL and use fetch\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n\n throw new Error('No method available to load ZIP file');\n}\n\n/**\n * Mapping of GTFS file names to database table names\n */\nexport const GTFS_FILE_MAPPING: Record = {\n 'agency.txt': 'agency',\n 'stops.txt': 'stops',\n 'routes.txt': 'routes',\n 'trips.txt': 'trips',\n 'stop_times.txt': 'stop_times',\n 'calendar.txt': 'calendar',\n 'calendar_dates.txt': 'calendar_dates',\n 'fare_attributes.txt': 'fare_attributes',\n 'fare_rules.txt': 'fare_rules',\n 'shapes.txt': 'shapes',\n 'frequencies.txt': 'frequencies',\n 'transfers.txt': 'transfers',\n 'pathways.txt': 'pathways',\n 'levels.txt': 'levels',\n 'feed_info.txt': 'feed_info',\n 'attributions.txt': 'attributions',\n};\n","/**\n * CSV Parser for GTFS files using papaparse\n */\n\nimport Papa from 'papaparse';\n\nexport interface ParsedCSV {\n headers: string[];\n rows: Record[];\n}\n\n/**\n * Parse CSV text into structured data using papaparse\n */\nexport function parseCSV(text: string): ParsedCSV {\n const result = Papa.parse(text, {\n header: true,\n skipEmptyLines: true,\n transformHeader: (header) => header.trim(),\n transform: (value) => value.trim(),\n });\n\n if (result.errors.length > 0) {\n console.warn('CSV parsing warnings:', result.errors);\n }\n\n const headers = result.meta.fields || [];\n const rows = result.data as Record[];\n\n return { headers, rows };\n}\n\n/**\n * Convert parsed row to typed object with proper type conversions\n */\nexport function convertRowTypes(\n row: Record,\n columnTypes: Record\n): Record {\n const result: Record = {};\n\n // Iterate over all expected columns, not just the ones present in the row\n for (const [key, type] of Object.entries(columnTypes)) {\n const value = row[key];\n\n // Handle missing or empty values\n if (value === undefined || value === null || value === '') {\n result[key] = null;\n continue;\n }\n\n if (type === 'INTEGER') {\n const parsed = parseInt(value, 10);\n result[key] = isNaN(parsed) ? null : parsed;\n } else if (type === 'REAL') {\n const parsed = parseFloat(value);\n result[key] = isNaN(parsed) ? null : parsed;\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n","/**\n * Data Loader - Loads GTFS data into SQLite database\n */\n\nimport type { Database } from 'sql.js';\nimport { parseCSV, convertRowTypes } from './csv-parser';\nimport { GTFS_SCHEMA, type TableSchema } from '../schema/schema';\nimport type { GTFSFiles } from './zip-loader';\n\n/**\n * Load GTFS files into SQLite database\n * @param skipFiles - Optional array of filenames to skip importing (tables will be created but remain empty)\n */\nexport async function loadGTFSData(db: Database, files: GTFSFiles, skipFiles?: string[]): Promise {\n // Map of file names to table schemas\n const fileToSchema: Map = new Map();\n for (const schema of GTFS_SCHEMA) {\n // Match file names like agency.txt to table name 'agency'\n fileToSchema.set(`${schema.name}.txt`, schema);\n }\n\n // Normalize skipFiles to a Set for faster lookup\n const skipSet = new Set(skipFiles?.map(f => f.toLowerCase()) || []);\n\n // Process each file\n for (const [fileName, content] of Object.entries(files)) {\n const schema = fileToSchema.get(fileName);\n if (!schema) {\n // Skip unknown files\n continue;\n }\n\n // Skip if in skip list\n if (skipSet.has(fileName.toLowerCase())) {\n console.log(`Skipping import of ${fileName} (table ${schema.name} created but empty)`);\n continue;\n }\n\n await loadTableData(db, schema, content);\n }\n}\n\n/**\n * Load data for a single table\n */\nasync function loadTableData(db: Database, schema: TableSchema, csvContent: string): Promise {\n const { headers, rows } = parseCSV(csvContent);\n\n if (rows.length === 0) {\n return;\n }\n\n // Build column type map\n const columnTypes: Record = {};\n for (const col of schema.columns) {\n columnTypes[col.name] = col.type;\n }\n\n // Prepare INSERT statement\n const columns = headers.filter((h) => schema.columns.some((c) => c.name === h));\n const placeholders = columns.map(() => '?').join(', ');\n const insertSQL = `INSERT INTO ${schema.name} (${columns.join(', ')}) VALUES (${placeholders})`;\n\n const stmt = db.prepare(insertSQL);\n\n // Insert each row\n for (const row of rows) {\n const typedRow = convertRowTypes(row, columnTypes);\n const values = columns.map((col) => {\n const value = typedRow[col];\n // Handle undefined, null, or empty values\n return value === null || value === undefined ? null : value;\n });\n\n try {\n stmt.run(values);\n } catch (error) {\n console.error(`Error inserting row into ${schema.name}:`, error);\n console.error('Row data:', row);\n throw error;\n }\n }\n\n stmt.free();\n}\n","import type { Database } from 'sql.js';\n\n/**\n * Create GTFS Realtime tables in the database\n */\nexport function createRealtimeTables(db: Database): void {\n // Alerts table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_alerts (\n id TEXT PRIMARY KEY,\n active_period TEXT, -- JSON array of TimeRange objects\n informed_entity TEXT, -- JSON array of EntitySelector objects\n cause INTEGER,\n effect INTEGER,\n url TEXT, -- JSON TranslatedString\n header_text TEXT, -- JSON TranslatedString\n description_text TEXT, -- JSON TranslatedString\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n // Create index on rt_last_updated for staleness filtering\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_alerts_updated ON rt_alerts(rt_last_updated)');\n\n // Vehicle Positions table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_vehicle_positions (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n latitude REAL,\n longitude REAL,\n bearing REAL,\n odometer REAL,\n speed REAL,\n current_stop_sequence INTEGER,\n stop_id TEXT,\n current_status INTEGER,\n timestamp INTEGER,\n congestion_level INTEGER,\n occupancy_status INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_updated ON rt_vehicle_positions(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_route ON rt_vehicle_positions(route_id)');\n\n // Trip Updates table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_trip_updates (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n timestamp INTEGER,\n delay INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_updated ON rt_trip_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_route ON rt_trip_updates(route_id)');\n\n // Stop Time Updates table (child of trip updates)\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_stop_time_updates (\n trip_id TEXT NOT NULL,\n stop_sequence INTEGER,\n stop_id TEXT,\n arrival_delay INTEGER,\n arrival_time INTEGER,\n arrival_uncertainty INTEGER,\n departure_delay INTEGER,\n departure_time INTEGER,\n departure_uncertainty INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL,\n PRIMARY KEY (trip_id, stop_sequence),\n FOREIGN KEY (trip_id) REFERENCES rt_trip_updates(trip_id) ON DELETE CASCADE\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_updated ON rt_stop_time_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_stop ON rt_stop_time_updates(stop_id)');\n}\n\n/**\n * Clear all realtime data from the database\n */\nexport function clearRealtimeData(db: Database): void {\n db.run('DELETE FROM rt_alerts');\n db.run('DELETE FROM rt_vehicle_positions');\n db.run('DELETE FROM rt_trip_updates');\n db.run('DELETE FROM rt_stop_time_updates');\n}\n","import type { Database } from 'sql.js';\nimport protobuf from 'protobufjs';\n\n// Types for protobuf decoded objects\ninterface ProtobufTranslation {\n text: string;\n language?: string;\n}\n\ninterface ProtobufTranslatedString {\n translation: ProtobufTranslation[];\n}\n\ninterface ProtobufAlert {\n id: string;\n activePeriod?: unknown[];\n active_period?: unknown[];\n informedEntity?: unknown[];\n informed_entity?: unknown[];\n cause?: number;\n effect?: number;\n url?: ProtobufTranslatedString;\n headerText?: ProtobufTranslatedString;\n header_text?: ProtobufTranslatedString;\n descriptionText?: ProtobufTranslatedString;\n description_text?: ProtobufTranslatedString;\n}\n\ninterface ProtobufTripDescriptor {\n tripId?: string;\n trip_id?: string;\n routeId?: string;\n route_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n}\n\ninterface ProtobufVehicleDescriptor {\n id?: string;\n label?: string;\n licensePlate?: string;\n license_plate?: string;\n}\n\ninterface ProtobufPosition {\n latitude?: number;\n longitude?: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\ninterface ProtobufVehiclePosition {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n position?: ProtobufPosition;\n currentStopSequence?: number;\n current_stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n currentStatus?: number;\n current_status?: number;\n timestamp?: number;\n congestionLevel?: number;\n congestion_level?: number;\n occupancyStatus?: number;\n occupancy_status?: number;\n}\n\ninterface ProtobufStopTimeEvent {\n delay?: number;\n time?: number;\n uncertainty?: number;\n}\n\ninterface ProtobufStopTimeUpdate {\n stopSequence?: number;\n stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n arrival?: ProtobufStopTimeEvent;\n departure?: ProtobufStopTimeEvent;\n}\n\ninterface ProtobufTripUpdate {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n timestamp?: number;\n delay?: number;\n stopTimeUpdate?: ProtobufStopTimeUpdate[];\n stop_time_update?: ProtobufStopTimeUpdate[];\n}\n\n// GTFS Realtime protobuf definition (v2.0)\n// Source: https://github.com/google/transit/blob/master/gtfs-realtime/proto/gtfs-realtime.proto\nconst GTFS_RT_PROTO = `\nsyntax = \"proto2\";\noption java_package = \"com.google.transit.realtime\";\npackage transit_realtime;\n\nmessage FeedMessage {\n required FeedHeader header = 1;\n repeated FeedEntity entity = 2;\n}\n\nmessage FeedHeader {\n required string gtfs_realtime_version = 1;\n enum Incrementality {\n FULL_DATASET = 0;\n DIFFERENTIAL = 1;\n }\n optional Incrementality incrementality = 2 [default = FULL_DATASET];\n optional uint64 timestamp = 3;\n}\n\nmessage FeedEntity {\n required string id = 1;\n optional bool is_deleted = 2 [default = false];\n optional TripUpdate trip_update = 3;\n optional VehiclePosition vehicle = 4;\n optional Alert alert = 5;\n}\n\nmessage TripUpdate {\n required TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 3;\n repeated StopTimeUpdate stop_time_update = 2;\n optional uint64 timestamp = 4;\n optional int32 delay = 5;\n\n message StopTimeEvent {\n optional int32 delay = 1;\n optional int64 time = 2;\n optional int32 uncertainty = 3;\n }\n\n message StopTimeUpdate {\n optional uint32 stop_sequence = 1;\n optional string stop_id = 4;\n optional StopTimeEvent arrival = 2;\n optional StopTimeEvent departure = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n SKIPPED = 1;\n NO_DATA = 2;\n }\n optional ScheduleRelationship schedule_relationship = 5 [default = SCHEDULED];\n }\n}\n\nmessage VehiclePosition {\n optional TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 8;\n optional Position position = 2;\n optional uint32 current_stop_sequence = 3;\n optional string stop_id = 7;\n enum VehicleStopStatus {\n INCOMING_AT = 0;\n STOPPED_AT = 1;\n IN_TRANSIT_TO = 2;\n }\n optional VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];\n optional uint64 timestamp = 5;\n enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0;\n RUNNING_SMOOTHLY = 1;\n STOP_AND_GO = 2;\n CONGESTION = 3;\n SEVERE_CONGESTION = 4;\n }\n optional CongestionLevel congestion_level = 6;\n enum OccupancyStatus {\n EMPTY = 0;\n MANY_SEATS_AVAILABLE = 1;\n FEW_SEATS_AVAILABLE = 2;\n STANDING_ROOM_ONLY = 3;\n CRUSHED_STANDING_ROOM_ONLY = 4;\n FULL = 5;\n NOT_ACCEPTING_PASSENGERS = 6;\n }\n optional OccupancyStatus occupancy_status = 9;\n}\n\nmessage Alert {\n repeated TimeRange active_period = 1;\n repeated EntitySelector informed_entity = 5;\n\n enum Cause {\n UNKNOWN_CAUSE = 1;\n OTHER_CAUSE = 2;\n TECHNICAL_PROBLEM = 3;\n STRIKE = 4;\n DEMONSTRATION = 5;\n ACCIDENT = 6;\n HOLIDAY = 7;\n WEATHER = 8;\n MAINTENANCE = 9;\n CONSTRUCTION = 10;\n POLICE_ACTIVITY = 11;\n MEDICAL_EMERGENCY = 12;\n }\n optional Cause cause = 6 [default = UNKNOWN_CAUSE];\n\n enum Effect {\n NO_SERVICE = 1;\n REDUCED_SERVICE = 2;\n SIGNIFICANT_DELAYS = 3;\n DETOUR = 4;\n ADDITIONAL_SERVICE = 5;\n MODIFIED_SERVICE = 6;\n OTHER_EFFECT = 7;\n UNKNOWN_EFFECT = 8;\n STOP_MOVED = 9;\n NO_EFFECT = 10;\n ACCESSIBILITY_ISSUE = 11;\n }\n optional Effect effect = 7 [default = UNKNOWN_EFFECT];\n optional TranslatedString url = 8;\n optional TranslatedString header_text = 10;\n optional TranslatedString description_text = 11;\n}\n\nmessage TimeRange {\n optional uint64 start = 1;\n optional uint64 end = 2;\n}\n\nmessage Position {\n required float latitude = 1;\n required float longitude = 2;\n optional float bearing = 3;\n optional double odometer = 4;\n optional float speed = 5;\n}\n\nmessage TripDescriptor {\n optional string trip_id = 1;\n optional string route_id = 5;\n optional uint32 direction_id = 6;\n optional string start_time = 2;\n optional string start_date = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n ADDED = 1;\n UNSCHEDULED = 2;\n CANCELED = 3;\n }\n optional ScheduleRelationship schedule_relationship = 4;\n}\n\nmessage VehicleDescriptor {\n optional string id = 1;\n optional string label = 2;\n optional string license_plate = 3;\n}\n\nmessage EntitySelector {\n optional string agency_id = 1;\n optional string route_id = 2;\n optional int32 route_type = 3;\n optional TripDescriptor trip = 4;\n optional string stop_id = 5;\n}\n\nmessage TranslatedString {\n message Translation {\n required string text = 1;\n optional string language = 2;\n }\n repeated Translation translation = 1;\n}\n`;\n\n// Fetch protobuf data from URL or local file\n// Uses fetch API (available in modern browsers and Node.js 18+)\nasync function fetchProtobuf(source: string): Promise {\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n if (isUrl) {\n // Fetch from URL\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n }\n\n // Read from local file (Node.js only)\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return new Uint8Array(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));\n } catch (error) {\n throw new Error(`Failed to read GTFS-RT file from ${source}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // In browser, try fetch for relative paths\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n}\n\n// Load and parse GTFS-RT protobuf schema\nlet gtfsRtRoot: protobuf.Root | null = null;\n\nfunction loadGtfsRtProto(): protobuf.Root {\n if (!gtfsRtRoot) {\n gtfsRtRoot = protobuf.parse(GTFS_RT_PROTO).root;\n }\n return gtfsRtRoot;\n}\n\n// Convert camelCase object keys to snake_case\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction convertKeysToSnakeCase(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(convertKeysToSnakeCase);\n }\n if (typeof obj === 'object') {\n const result: Record = {};\n for (const key in obj as Record) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = convertKeysToSnakeCase((obj as Record)[key]);\n }\n }\n return result;\n }\n return obj;\n}\n\n// Parse TranslatedString to JSON\nfunction parseTranslatedString(ts: ProtobufTranslatedString | undefined): string | null {\n if (!ts || !ts.translation || ts.translation.length === 0) {\n return null;\n }\n return JSON.stringify({\n translation: ts.translation.map((t) => ({\n text: t.text,\n language: t.language || undefined\n }))\n });\n}\n\n// Insert alerts into database\nfunction insertAlerts(db: Database, alerts: ProtobufAlert[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_alerts (\n id, active_period, informed_entity, cause, effect,\n url, header_text, description_text, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const alert of alerts) {\n // Map camelCase protobuf fields to snake_case\n const activePeriod = alert.activePeriod || alert.active_period || [];\n const informedEntity = alert.informedEntity || alert.informed_entity || [];\n const headerText = alert.headerText || alert.header_text;\n const descriptionText = alert.descriptionText || alert.description_text;\n\n // Convert nested objects to snake_case\n const activePeriodSnake = convertKeysToSnakeCase(activePeriod);\n const informedEntitySnake = convertKeysToSnakeCase(informedEntity);\n\n stmt.run([\n alert.id,\n JSON.stringify(activePeriodSnake),\n JSON.stringify(informedEntitySnake),\n alert.cause || null,\n alert.effect || null,\n parseTranslatedString(alert.url),\n parseTranslatedString(headerText),\n parseTranslatedString(descriptionText),\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert vehicle positions into database\nfunction insertVehiclePositions(db: Database, positions: ProtobufVehiclePosition[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_vehicle_positions (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n latitude, longitude, bearing, odometer, speed,\n current_stop_sequence, stop_id, current_status, timestamp,\n congestion_level, occupancy_status, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const vp of positions) {\n const trip = vp.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = vp.vehicle?.id;\n const vehicleLabel = vp.vehicle?.label;\n const vehicleLicensePlate = vp.vehicle?.licensePlate || vp.vehicle?.license_plate;\n const currentStopSequence = vp.currentStopSequence || vp.current_stop_sequence;\n const stopId = vp.stopId || vp.stop_id;\n const currentStatus = vp.currentStatus || vp.current_status;\n const congestionLevel = vp.congestionLevel || vp.congestion_level;\n const occupancyStatus = vp.occupancyStatus || vp.occupancy_status;\n\n stmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n vp.position?.latitude || null,\n vp.position?.longitude || null,\n vp.position?.bearing || null,\n vp.position?.odometer || null,\n vp.position?.speed || null,\n currentStopSequence || null,\n stopId || null,\n currentStatus || null,\n vp.timestamp || null,\n congestionLevel || null,\n occupancyStatus || null,\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert trip updates into database\nfunction insertTripUpdates(db: Database, updates: ProtobufTripUpdate[], timestamp: number): void {\n const tripStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_trip_updates (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n timestamp, delay, schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const stopTimeStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_stop_time_updates (\n trip_id, stop_sequence, stop_id,\n arrival_delay, arrival_time, arrival_uncertainty,\n departure_delay, departure_time, departure_uncertainty,\n schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const tu of updates) {\n const trip = tu.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = tu.vehicle?.id;\n const vehicleLabel = tu.vehicle?.label;\n const vehicleLicensePlate = tu.vehicle?.licensePlate || tu.vehicle?.license_plate;\n const scheduleRelationship = trip.scheduleRelationship || trip.schedule_relationship;\n const stopTimeUpdate = tu.stopTimeUpdate || tu.stop_time_update;\n\n // Insert trip update\n tripStmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n tu.timestamp || null,\n tu.delay || null,\n scheduleRelationship || null,\n timestamp\n ]);\n\n // Insert stop time updates\n if (stopTimeUpdate) {\n for (const stu of stopTimeUpdate) {\n const stopSequence = stu.stopSequence || stu.stop_sequence;\n const stopId = stu.stopId || stu.stop_id;\n const scheduleRel = stu.scheduleRelationship || stu.schedule_relationship;\n\n stopTimeStmt.run([\n tripId,\n stopSequence || null,\n stopId || null,\n stu.arrival?.delay || null,\n stu.arrival?.time || null,\n stu.arrival?.uncertainty || null,\n stu.departure?.delay || null,\n stu.departure?.time || null,\n stu.departure?.uncertainty || null,\n scheduleRel || null,\n timestamp\n ]);\n }\n }\n }\n\n tripStmt.free();\n stopTimeStmt.free();\n}\n\n/**\n * Fetch and load GTFS Realtime data from multiple feed URLs\n * All feeds are fetched in parallel. If any feed fails, an error is thrown.\n */\nexport async function loadRealtimeData(db: Database, feedUrls: string[]): Promise {\n const root = loadGtfsRtProto();\n const FeedMessage = root.lookupType('transit_realtime.FeedMessage');\n\n // Fetch all feeds in parallel\n const fetchPromises = feedUrls.map(async (url) => {\n try {\n const data = await fetchProtobuf(url);\n const message = FeedMessage.decode(data);\n return FeedMessage.toObject(message, {\n longs: Number,\n enums: Number,\n bytes: String,\n defaults: false,\n arrays: true,\n objects: true,\n oneofs: true\n });\n } catch (error) {\n throw new Error(`Failed to fetch or parse GTFS-RT feed from ${url}: ${error instanceof Error ? error.message : String(error)}`);\n }\n });\n\n // Wait for all feeds - if any fails, this will throw\n const feeds = await Promise.all(fetchPromises);\n\n // Current timestamp for staleness tracking\n const now = Math.floor(Date.now() / 1000);\n\n // Collect all entities by type\n const allAlerts: ProtobufAlert[] = [];\n const allVehiclePositions: ProtobufVehiclePosition[] = [];\n const allTripUpdates: ProtobufTripUpdate[] = [];\n\n for (const feed of feeds) {\n if (!feed.entity) continue;\n\n for (const entity of feed.entity) {\n if (entity.alert) {\n allAlerts.push({ id: entity.id, ...entity.alert });\n }\n if (entity.vehicle) {\n allVehiclePositions.push(entity.vehicle);\n }\n if (entity.tripUpdate) {\n allTripUpdates.push(entity.tripUpdate);\n }\n }\n }\n\n // Insert into database\n if (allAlerts.length > 0) {\n insertAlerts(db, allAlerts, now);\n }\n if (allVehiclePositions.length > 0) {\n insertVehiclePositions(db, allVehiclePositions, now);\n }\n if (allTripUpdates.length > 0) {\n insertTripUpdates(db, allTripUpdates, now);\n }\n}\n","/**\n * Agency Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Agency } from '../types/gtfs';\n\nexport interface AgencyFilters {\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get agencies with optional filters\n */\nexport function getAgencies(db: Database, filters: AgencyFilters = {}): Agency[] {\n const { agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM agency';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY agency_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Get an agency by its agency_id\n */\nexport function getAgencyById(db: Database, agencyId: string): Agency | null {\n const stmt = db.prepare('SELECT * FROM agency WHERE agency_id = ?');\n stmt.bind([agencyId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToAgency(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all agencies\n */\nexport function getAllAgencies(db: Database, limit?: number): Agency[] {\n const sql = limit\n ? `SELECT * FROM agency ORDER BY agency_name LIMIT ${limit}`\n : 'SELECT * FROM agency ORDER BY agency_name';\n\n const stmt = db.prepare(sql);\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Convert database row to Agency object\n */\nfunction rowToAgency(row: Record): Agency {\n return {\n agency_id: String(row.agency_id),\n agency_name: String(row.agency_name),\n agency_url: String(row.agency_url),\n agency_timezone: String(row.agency_timezone),\n agency_lang: row.agency_lang ? String(row.agency_lang) : undefined,\n agency_phone: row.agency_phone ? String(row.agency_phone) : undefined,\n agency_fare_url: row.agency_fare_url ? String(row.agency_fare_url) : undefined,\n agency_email: row.agency_email ? String(row.agency_email) : undefined,\n };\n}\n","/**\n * Stop Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Stop } from '../types/gtfs';\n\nexport interface StopFilters {\n stopId?: string;\n stopCode?: string;\n name?: string;\n tripId?: string;\n limit?: number;\n}\n\n/**\n * Get stops with optional filters\n */\nexport function getStops(db: Database, filters: StopFilters = {}): Stop[] {\n const { stopId, stopCode, name, tripId, limit } = filters;\n\n // Handle special case: get stops by trip (requires JOIN)\n if (tripId) {\n return getStopsByTrip(db, tripId);\n }\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (stopId) {\n conditions.push('stop_id = ?');\n params.push(stopId);\n }\n\n if (stopCode) {\n conditions.push('stop_code = ?');\n params.push(stopCode);\n }\n\n if (name) {\n conditions.push('stop_name LIKE ?');\n params.push(`%${name}%`);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM stops';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY stop_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get a stop by its stop_id\n */\nexport function getStopById(db: Database, stopId: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_id = ?');\n stmt.bind([stopId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get a stop by its stop_code\n */\nexport function getStopByCode(db: Database, stopCode: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_code = ?');\n stmt.bind([stopCode]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Search stops by name (case-insensitive, partial match)\n */\nexport function searchStopsByName(db: Database, name: string, limit = 50): Stop[] {\n const stmt = db.prepare(\n 'SELECT * FROM stops WHERE stop_name LIKE ? ORDER BY stop_name LIMIT ?'\n );\n stmt.bind([`%${name}%`, limit]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get all stops\n */\nexport function getAllStops(db: Database, limit?: number): Stop[] {\n const sql = limit\n ? `SELECT * FROM stops ORDER BY stop_name LIMIT ${limit}`\n : 'SELECT * FROM stops ORDER BY stop_name';\n\n const stmt = db.prepare(sql);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get stops for a given trip (ordered by stop_sequence)\n */\nexport function getStopsByTrip(db: Database, tripId: string): Stop[] {\n const stmt = db.prepare(`\n SELECT s.* FROM stops s\n INNER JOIN stop_times st ON s.stop_id = st.stop_id\n WHERE st.trip_id = ?\n ORDER BY st.stop_sequence\n `);\n stmt.bind([tripId]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Convert database row to Stop object\n */\nfunction rowToStop(row: Record): Stop {\n return {\n stop_id: String(row.stop_id),\n stop_name: String(row.stop_name),\n stop_lat: Number(row.stop_lat),\n stop_lon: Number(row.stop_lon),\n stop_code: row.stop_code ? String(row.stop_code) : undefined,\n stop_desc: row.stop_desc ? String(row.stop_desc) : undefined,\n zone_id: row.zone_id ? String(row.zone_id) : undefined,\n stop_url: row.stop_url ? String(row.stop_url) : undefined,\n location_type: row.location_type !== null ? Number(row.location_type) : undefined,\n parent_station: row.parent_station ? String(row.parent_station) : undefined,\n stop_timezone: row.stop_timezone ? String(row.stop_timezone) : undefined,\n wheelchair_boarding: row.wheelchair_boarding !== null ? Number(row.wheelchair_boarding) : undefined,\n level_id: row.level_id ? String(row.level_id) : undefined,\n platform_code: row.platform_code ? String(row.platform_code) : undefined,\n };\n}\n","/**\n * Route Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Route } from '../types/gtfs';\n\nexport interface RouteFilters {\n routeId?: string;\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get routes with optional filters\n */\nexport function getRoutes(db: Database, filters: RouteFilters = {}): Route[] {\n const { routeId, agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM routes';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY route_short_name, route_long_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get a route by its route_id\n */\nexport function getRouteById(db: Database, routeId: string): Route | null {\n const stmt = db.prepare('SELECT * FROM routes WHERE route_id = ?');\n stmt.bind([routeId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToRoute(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all routes\n */\nexport function getAllRoutes(db: Database, limit?: number): Route[] {\n const sql = limit\n ? `SELECT * FROM routes ORDER BY route_short_name, route_long_name LIMIT ${limit}`\n : 'SELECT * FROM routes ORDER BY route_short_name, route_long_name';\n\n const stmt = db.prepare(sql);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get routes by agency\n */\nexport function getRoutesByAgency(db: Database, agencyId: string): Route[] {\n const stmt = db.prepare(\n 'SELECT * FROM routes WHERE agency_id = ? ORDER BY route_short_name, route_long_name'\n );\n stmt.bind([agencyId]);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Convert database row to Route object\n */\nfunction rowToRoute(row: Record): Route {\n return {\n route_id: String(row.route_id),\n route_short_name: String(row.route_short_name),\n route_long_name: String(row.route_long_name),\n route_type: Number(row.route_type),\n agency_id: row.agency_id ? String(row.agency_id) : undefined,\n route_desc: row.route_desc ? String(row.route_desc) : undefined,\n route_url: row.route_url ? String(row.route_url) : undefined,\n route_color: row.route_color ? String(row.route_color) : undefined,\n route_text_color: row.route_text_color ? String(row.route_text_color) : undefined,\n route_sort_order: row.route_sort_order !== null ? Number(row.route_sort_order) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n };\n}\n","/**\n * Calendar Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Calendar, CalendarDate } from '../types/gtfs';\n\n/**\n * Get active service IDs for a given date\n */\nexport function getActiveServiceIds(db: Database, date: string): string[] {\n const serviceIds = new Set();\n\n // Parse date (format: YYYYMMDD)\n const year = parseInt(date.substring(0, 4));\n const month = parseInt(date.substring(4, 6));\n const day = parseInt(date.substring(6, 8));\n const dateObj = new Date(year, month - 1, day);\n const dayOfWeek = dateObj.getDay(); // 0 = Sunday, 1 = Monday, etc.\n\n // Map day of week to GTFS calendar field\n const dayFields = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];\n const dayField = dayFields[dayOfWeek];\n\n // Check calendar.txt for regular service\n const calendarStmt = db.prepare(\n `SELECT service_id FROM calendar\n WHERE ${dayField} = 1\n AND start_date <= ?\n AND end_date >= ?`\n );\n calendarStmt.bind([date, date]);\n\n while (calendarStmt.step()) {\n const row = calendarStmt.getAsObject() as { service_id: string };\n serviceIds.add(row.service_id);\n }\n calendarStmt.free();\n\n // Check calendar_dates.txt for exceptions\n const exceptionsStmt = db.prepare('SELECT service_id, exception_type FROM calendar_dates WHERE date = ?');\n exceptionsStmt.bind([date]);\n\n while (exceptionsStmt.step()) {\n const row = exceptionsStmt.getAsObject() as { service_id: string; exception_type: number };\n if (row.exception_type === 1) {\n // Service added\n serviceIds.add(row.service_id);\n } else if (row.exception_type === 2) {\n // Service removed\n serviceIds.delete(row.service_id);\n }\n }\n exceptionsStmt.free();\n\n return Array.from(serviceIds);\n}\n\n/**\n * Get calendar entry by service_id\n */\nexport function getCalendarByServiceId(db: Database, serviceId: string): Calendar | null {\n const stmt = db.prepare('SELECT * FROM calendar WHERE service_id = ?');\n stmt.bind([serviceId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToCalendar(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get calendar date exceptions for a service\n */\nexport function getCalendarDates(db: Database, serviceId: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE service_id = ? ORDER BY date');\n stmt.bind([serviceId]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Get calendar date exceptions for a specific date\n */\nexport function getCalendarDatesForDate(db: Database, date: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE date = ?');\n stmt.bind([date]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Convert database row to Calendar object\n */\nfunction rowToCalendar(row: Record): Calendar {\n return {\n service_id: String(row.service_id),\n monday: Number(row.monday),\n tuesday: Number(row.tuesday),\n wednesday: Number(row.wednesday),\n thursday: Number(row.thursday),\n friday: Number(row.friday),\n saturday: Number(row.saturday),\n sunday: Number(row.sunday),\n start_date: String(row.start_date),\n end_date: String(row.end_date),\n };\n}\n\n/**\n * Convert database row to CalendarDate object\n */\nfunction rowToCalendarDate(row: Record): CalendarDate {\n return {\n service_id: String(row.service_id),\n date: String(row.date),\n exception_type: Number(row.exception_type),\n };\n}\n","import type { Database} from 'sql.js';\nimport type { VehiclePosition } from '../types/gtfs-rt';\nimport type { VehiclePositionFilters } from '../types/gtfs-rt';\n\nexport type { VehiclePositionFilters };\n\n/**\n * Parse vehicle position from database row\n */\nexport function parseVehiclePosition(row: Record): VehiclePosition {\n const vp: VehiclePosition = {\n trip_id: String(row.trip_id),\n route_id: row.route_id ? String(row.route_id) : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n\n // Vehicle descriptor\n if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) {\n vp.vehicle = {\n id: row.vehicle_id ? String(row.vehicle_id) : undefined,\n label: row.vehicle_label ? String(row.vehicle_label) : undefined,\n license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : undefined\n };\n }\n\n // Position\n if (row.latitude !== null && row.longitude !== null) {\n vp.position = {\n latitude: Number(row.latitude),\n longitude: Number(row.longitude),\n bearing: row.bearing !== null ? Number(row.bearing) : undefined,\n odometer: row.odometer !== null ? Number(row.odometer) : undefined,\n speed: row.speed !== null ? Number(row.speed) : undefined\n };\n }\n\n // Other fields\n if (row.current_stop_sequence !== null) {\n vp.current_stop_sequence = Number(row.current_stop_sequence);\n }\n if (row.stop_id) {\n vp.stop_id = String(row.stop_id);\n }\n if (row.current_status !== null) {\n vp.current_status = Number(row.current_status);\n }\n if (row.timestamp !== null) {\n vp.timestamp = Number(row.timestamp);\n }\n if (row.congestion_level !== null) {\n vp.congestion_level = Number(row.congestion_level);\n }\n if (row.occupancy_status !== null) {\n vp.occupancy_status = Number(row.occupancy_status);\n }\n\n return vp;\n}\n\n/**\n * Get vehicle positions with optional filters\n */\nexport function getVehiclePositions(\n db: Database,\n filters: VehiclePositionFilters = {},\n stalenessThreshold: number = 120\n): VehiclePosition[] {\n const { tripId, routeId, vehicleId, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by route_id\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n // Filter by vehicle_id\n if (vehicleId) {\n conditions.push('vehicle_id = ?');\n params.push(vehicleId);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_vehicle_positions';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const positions: VehiclePosition[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n positions.push(parseVehiclePosition(row));\n }\n\n stmt.free();\n return positions;\n}\n\n/**\n * Get vehicle position by trip ID\n */\nexport function getVehiclePositionByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): VehiclePosition | null {\n const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold);\n return positions.length > 0 ? positions[0] : null;\n}\n\n/**\n * Get all vehicle positions without staleness filtering (for debugging)\n */\nexport function getAllVehiclePositions(db: Database): VehiclePosition[] {\n const sql = 'SELECT * FROM rt_vehicle_positions ORDER BY rt_last_updated DESC';\n const stmt = db.prepare(sql);\n\n const positions: VehiclePosition[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n positions.push(parseVehiclePosition(row));\n }\n\n stmt.free();\n return positions;\n}\n","/**\n * Trip Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Trip } from '../types/gtfs';\nimport type { TripRealtime, VehiclePosition } from '../types/gtfs-rt';\nimport { parseVehiclePosition } from './rt-vehicle-positions';\n\nexport interface TripFilters {\n tripId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface TripWithRealtime extends Trip {\n realtime?: TripRealtime;\n}\n\n/**\n * Merge realtime data with trips\n */\nfunction mergeRealtimeData(\n trips: Trip[],\n db: Database,\n stalenessThreshold: number\n): TripWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n const tripIds = trips.map(t => t.trip_id);\n if (tripIds.length === 0) return trips;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n\n // Get vehicle positions\n const vpStmt = db.prepare(`\n SELECT * FROM rt_vehicle_positions\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n vpStmt.bind([...tripIds, staleThreshold]);\n\n const vpMap = new Map();\n while (vpStmt.step()) {\n const row = vpStmt.getAsObject() as Record;\n const vp = parseVehiclePosition(row);\n vpMap.set(vp.trip_id, vp);\n }\n vpStmt.free();\n\n // Get trip updates\n const tuStmt = db.prepare(`\n SELECT * FROM rt_trip_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n tuStmt.bind([...tripIds, staleThreshold]);\n\n const tuMap = new Map();\n while (tuStmt.step()) {\n const row = tuStmt.getAsObject() as Record;\n const tripId = String(row.trip_id);\n tuMap.set(tripId, {\n delay: row.delay !== null ? Number(row.delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n });\n }\n tuStmt.free();\n\n // Merge realtime data\n return trips.map((trip): TripWithRealtime => {\n const vp = vpMap.get(trip.trip_id);\n const tu = tuMap.get(trip.trip_id);\n\n if (!vp && !tu) {\n return { ...trip, realtime: { vehicle_position: null, trip_update: null } };\n }\n\n return {\n ...trip,\n realtime: {\n vehicle_position: vp || null,\n trip_update: tu || null\n }\n };\n });\n}\n\n/**\n * Get trips with optional filters\n */\nexport function getTrips(\n db: Database,\n filters: TripFilters = {},\n stalenessThreshold: number = 120\n): Trip[] | TripWithRealtime[] {\n const { tripId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with routes table\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsRoutesJoin ? 't.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (routeId) {\n conditions.push(needsRoutesJoin ? 't.route_id = ?' : 'route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.service_id IN (${placeholders})` : `service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push(needsRoutesJoin ? 't.direction_id = ?' : 'direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = needsRoutesJoin\n ? 'SELECT t.* FROM trips t INNER JOIN routes r ON t.route_id = r.route_id'\n : 'SELECT * FROM trips';\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(trips, db, stalenessThreshold);\n }\n\n return trips;\n}\n\n/**\n * Get a trip by its trip_id\n */\nexport function getTripById(db: Database, tripId: string): Trip | null {\n const stmt = db.prepare('SELECT * FROM trips WHERE trip_id = ?');\n stmt.bind([tripId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToTrip(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get trips for a route\n */\nexport function getTripsByRoute(db: Database, routeId: string): Trip[] {\n const stmt = db.prepare('SELECT * FROM trips WHERE route_id = ?');\n stmt.bind([routeId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route and service (active on a given date)\n */\nexport function getTripsByRouteAndService(\n db: Database,\n routeId: string,\n serviceIds: string[]\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders})`\n );\n stmt.bind([routeId, ...serviceIds]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route, service, and direction\n */\nexport function getTripsByRouteServiceAndDirection(\n db: Database,\n routeId: string,\n serviceIds: string[],\n directionId: number\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders}) AND direction_id = ?`\n );\n stmt.bind([routeId, ...serviceIds, directionId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get all trips for a service (active on a given date)\n */\nexport function getTripsByService(db: Database, serviceIds: string[]): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(`SELECT * FROM trips WHERE service_id IN (${placeholders})`);\n stmt.bind(serviceIds);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Convert database row to Trip object\n */\nfunction rowToTrip(row: Record): Trip {\n return {\n trip_id: String(row.trip_id),\n route_id: String(row.route_id),\n service_id: String(row.service_id),\n trip_headsign: row.trip_headsign ? String(row.trip_headsign) : undefined,\n trip_short_name: row.trip_short_name ? String(row.trip_short_name) : undefined,\n direction_id: row.direction_id !== null ? Number(row.direction_id) : undefined,\n block_id: row.block_id ? String(row.block_id) : undefined,\n shape_id: row.shape_id ? String(row.shape_id) : undefined,\n wheelchair_accessible: row.wheelchair_accessible !== null ? Number(row.wheelchair_accessible) : undefined,\n bikes_allowed: row.bikes_allowed !== null ? Number(row.bikes_allowed) : undefined,\n };\n}\n","/**\n * Stop Time Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { StopTime } from '../types/gtfs';\nimport type { StopTimeRealtime } from '../types/gtfs-rt';\n\nexport interface StopTimeFilters {\n tripId?: string;\n stopId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface StopTimeWithRealtime extends StopTime {\n realtime?: StopTimeRealtime;\n}\n\n/**\n * Merge realtime data with stop times\n */\nfunction mergeRealtimeData(\n stopTimes: StopTime[],\n db: Database,\n stalenessThreshold: number\n): StopTimeWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n // Build map of trip_id -> stop times for this query\n const tripIds = Array.from(new Set(stopTimes.map(st => st.trip_id)));\n if (tripIds.length === 0) return stopTimes;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(`\n SELECT trip_id, stop_sequence, stop_id,\n arrival_delay, departure_delay, schedule_relationship\n FROM rt_stop_time_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n stmt.bind([...tripIds, staleThreshold]);\n\n // Build map of trip_id+stop_sequence -> RT data\n const rtMap = new Map();\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const key = `${row.trip_id}_${row.stop_sequence}`;\n rtMap.set(key, {\n arrival_delay: row.arrival_delay !== null ? Number(row.arrival_delay) : undefined,\n departure_delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n });\n }\n stmt.free();\n\n // Merge RT data with stop times\n return stopTimes.map((st): StopTimeWithRealtime => {\n const key = `${st.trip_id}_${st.stop_sequence}`;\n const rtData = rtMap.get(key);\n\n if (rtData) {\n return { ...st, realtime: rtData };\n }\n return st;\n });\n}\n\n/**\n * Get stop times with optional filters\n */\nexport function getStopTimes(\n db: Database,\n filters: StopTimeFilters = {},\n stalenessThreshold: number = 120\n): StopTime[] | StopTimeWithRealtime[] {\n const { tripId, stopId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with trips and/or routes table\n const needsTripsJoin = routeId || serviceIds || directionId !== undefined || agencyId !== undefined;\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsTripsJoin ? 'st.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (stopId) {\n conditions.push(needsTripsJoin ? 'st.stop_id = ?' : 'stop_id = ?');\n params.push(stopId);\n }\n\n if (routeId) {\n conditions.push('t.route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(`t.service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push('t.direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql: string;\n if (needsRoutesJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id INNER JOIN routes r ON t.route_id = r.route_id';\n } else if (needsTripsJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id';\n } else {\n sql = 'SELECT * FROM stop_times';\n }\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n\n // Order by stop_sequence if filtering by trip, otherwise by arrival_time\n sql += tripId ? ' ORDER BY stop_sequence' : ' ORDER BY arrival_time';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(stopTimes, db, stalenessThreshold);\n }\n\n return stopTimes;\n}\n\n/**\n * Get stop times for a trip\n */\nexport function getStopTimesByTrip(db: Database, tripId: string): StopTime[] {\n const stmt = db.prepare('SELECT * FROM stop_times WHERE trip_id = ? ORDER BY stop_sequence');\n stmt.bind([tripId]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop\n */\nexport function getStopTimesByStop(db: Database, stopId: string, limit = 100): StopTime[] {\n const stmt = db.prepare(\n 'SELECT * FROM stop_times WHERE stop_id = ? ORDER BY arrival_time LIMIT ?'\n );\n stmt.bind([stopId, limit]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop and specific trips (filtered by route/date)\n */\nexport function getStopTimesByStopAndTrips(\n db: Database,\n stopId: string,\n tripIds: string[]\n): StopTime[] {\n if (tripIds.length === 0) {\n return [];\n }\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM stop_times\n WHERE stop_id = ? AND trip_id IN (${placeholders})\n ORDER BY arrival_time`\n );\n stmt.bind([stopId, ...tripIds]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop, route, and direction on a specific date\n */\nexport function getStopTimesForStopRouteDirection(\n db: Database,\n stopId: string,\n routeId: string,\n serviceIds: string[],\n directionId?: number\n): StopTime[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n\n let sql = `\n SELECT st.* FROM stop_times st\n INNER JOIN trips t ON st.trip_id = t.trip_id\n WHERE st.stop_id = ?\n AND t.route_id = ?\n AND t.service_id IN (${placeholders})\n `;\n\n const params: (string | number)[] = [stopId, routeId, ...serviceIds];\n\n if (directionId !== undefined) {\n sql += ' AND t.direction_id = ?';\n params.push(directionId);\n }\n\n sql += ' ORDER BY st.arrival_time';\n\n const stmt = db.prepare(sql);\n stmt.bind(params);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Convert database row to StopTime object\n */\nfunction rowToStopTime(row: Record): StopTime {\n return {\n trip_id: String(row.trip_id),\n arrival_time: String(row.arrival_time),\n departure_time: String(row.departure_time),\n stop_id: String(row.stop_id),\n stop_sequence: Number(row.stop_sequence),\n stop_headsign: row.stop_headsign ? String(row.stop_headsign) : undefined,\n pickup_type: row.pickup_type !== null ? Number(row.pickup_type) : undefined,\n drop_off_type: row.drop_off_type !== null ? Number(row.drop_off_type) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n shape_dist_traveled: row.shape_dist_traveled !== null ? Number(row.shape_dist_traveled) : undefined,\n timepoint: row.timepoint !== null ? Number(row.timepoint) : undefined,\n };\n}\n","import type { Database } from 'sql.js';\nimport type { Alert, EntitySelector, TimeRange, TranslatedString } from '../types/gtfs-rt';\nimport type { AlertFilters } from '../types/gtfs-rt';\n\nexport type { AlertFilters };\n\n/**\n * Parse JSON fields from database\n */\nfunction parseAlert(row: Record): Alert {\n return {\n id: String(row.id),\n active_period: row.active_period ? JSON.parse(String(row.active_period)) as TimeRange[] : [],\n informed_entity: row.informed_entity ? JSON.parse(String(row.informed_entity)) as EntitySelector[] : [],\n cause: row.cause ? Number(row.cause) : undefined,\n effect: row.effect ? Number(row.effect) : undefined,\n url: row.url ? JSON.parse(String(row.url)) as TranslatedString : undefined,\n header_text: row.header_text ? JSON.parse(String(row.header_text)) as TranslatedString : undefined,\n description_text: row.description_text ? JSON.parse(String(row.description_text)) as TranslatedString : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n}\n\n/**\n * Check if an alert is currently active based on its active_period\n */\nfunction isAlertActive(alert: Alert, now: number): boolean {\n // If no active periods defined, assume always active\n if (!alert.active_period || alert.active_period.length === 0) {\n return true;\n }\n\n // Check if current time falls within any active period\n for (const period of alert.active_period) {\n const start = period.start || 0;\n const end = period.end || Number.MAX_SAFE_INTEGER;\n\n if (now >= start && now <= end) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if an alert affects the specified entity\n */\nfunction alertAffectsEntity(alert: Alert, filters: AlertFilters): boolean {\n if (!alert.informed_entity || alert.informed_entity.length === 0) {\n return true; // No specific entities, assume it affects all\n }\n\n for (const entity of alert.informed_entity) {\n // Check route_id\n if (filters.routeId && entity.route_id === filters.routeId) {\n return true;\n }\n\n // Check stop_id\n if (filters.stopId && entity.stop_id === filters.stopId) {\n return true;\n }\n\n // Check trip_id\n if (filters.tripId && entity.trip?.trip_id === filters.tripId) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Get alerts with optional filters\n */\nexport function getAlerts(db: Database, filters: AlertFilters = {}, stalenessThreshold: number = 120): Alert[] {\n const {\n alertId,\n activeOnly,\n routeId,\n stopId,\n tripId,\n cause,\n effect,\n limit\n } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by alert ID\n if (alertId) {\n conditions.push('id = ?');\n params.push(alertId);\n }\n\n // Filter by cause\n if (cause !== undefined) {\n conditions.push('cause = ?');\n params.push(cause);\n }\n\n // Filter by effect\n if (effect !== undefined) {\n conditions.push('effect = ?');\n params.push(effect);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_alerts';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const alerts: Alert[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const alert = parseAlert(row);\n\n // Apply activeOnly filter in application code\n if (activeOnly && !isAlertActive(alert, now)) {\n continue;\n }\n\n // Apply entity filters in application code (since informed_entity is JSON)\n if (routeId || stopId || tripId) {\n if (!alertAffectsEntity(alert, filters)) {\n continue;\n }\n }\n\n alerts.push(alert);\n }\n\n stmt.free();\n return alerts;\n}\n\n/**\n * Get alert by ID\n */\nexport function getAlertById(db: Database, alertId: string, stalenessThreshold: number = 120): Alert | null {\n const alerts = getAlerts(db, { alertId, limit: 1 }, stalenessThreshold);\n return alerts.length > 0 ? alerts[0] : null;\n}\n\n/**\n * Get all alerts without staleness filtering (for debugging)\n */\nexport function getAllAlerts(db: Database): Alert[] {\n const sql = 'SELECT * FROM rt_alerts ORDER BY rt_last_updated DESC';\n const stmt = db.prepare(sql);\n\n const alerts: Alert[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n alerts.push(parseAlert(row));\n }\n\n stmt.free();\n return alerts;\n}\n","import type { Database } from 'sql.js';\nimport type { TripUpdate } from '../types/gtfs-rt';\n\nexport interface TripUpdateFilters {\n tripId?: string;\n routeId?: string;\n vehicleId?: string;\n limit?: number;\n}\n\n/**\n * Parse trip update from database row\n */\nexport function parseTripUpdate(row: Record): TripUpdate {\n const tu: TripUpdate = {\n trip_id: String(row.trip_id),\n route_id: row.route_id ? String(row.route_id) : undefined,\n stop_time_update: [], // Will be populated separately\n timestamp: row.timestamp !== null ? Number(row.timestamp) : undefined,\n delay: row.delay !== null ? Number(row.delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n\n // Vehicle descriptor\n if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) {\n tu.vehicle = {\n id: row.vehicle_id ? String(row.vehicle_id) : undefined,\n label: row.vehicle_label ? String(row.vehicle_label) : undefined,\n license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : undefined\n };\n }\n\n return tu;\n}\n\n/**\n * Get trip updates with optional filters\n */\nexport function getTripUpdates(\n db: Database,\n filters: TripUpdateFilters = {},\n stalenessThreshold: number = 120\n): TripUpdate[] {\n const { tripId, routeId, vehicleId, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by route_id\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n // Filter by vehicle_id\n if (vehicleId) {\n conditions.push('vehicle_id = ?');\n params.push(vehicleId);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_trip_updates';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const tripUpdates: TripUpdate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n tripUpdates.push(parseTripUpdate(row));\n }\n\n stmt.free();\n return tripUpdates;\n}\n\n/**\n * Get trip update by trip ID\n */\nexport function getTripUpdateByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): TripUpdate | null {\n const updates = getTripUpdates(db, { tripId, limit: 1 }, stalenessThreshold);\n return updates.length > 0 ? updates[0] : null;\n}\n\n/**\n * Get all trip updates without staleness filtering (for debugging)\n */\nexport function getAllTripUpdates(db: Database): TripUpdate[] {\n const sql = 'SELECT * FROM rt_trip_updates ORDER BY rt_last_updated DESC';\n const stmt = db.prepare(sql);\n\n const tripUpdates: TripUpdate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n tripUpdates.push(parseTripUpdate(row));\n }\n\n stmt.free();\n return tripUpdates;\n}\n","import type { Database } from 'sql.js';\nimport type { StopTimeUpdate } from '../types/gtfs-rt';\n\nexport interface StopTimeUpdateFilters {\n tripId?: string;\n stopId?: string;\n stopSequence?: number;\n limit?: number;\n}\n\n/**\n * Parse stop time update from database row\n */\nfunction parseStopTimeUpdate(row: Record): StopTimeUpdate {\n const stu: StopTimeUpdate = {\n stop_sequence: row.stop_sequence !== null ? Number(row.stop_sequence) : undefined,\n stop_id: row.stop_id ? String(row.stop_id) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n };\n\n // Arrival event\n if (row.arrival_delay !== null || row.arrival_time !== null || row.arrival_uncertainty !== null) {\n stu.arrival = {\n delay: row.arrival_delay !== null ? Number(row.arrival_delay) : undefined,\n time: row.arrival_time !== null ? Number(row.arrival_time) : undefined,\n uncertainty: row.arrival_uncertainty !== null ? Number(row.arrival_uncertainty) : undefined\n };\n }\n\n // Departure event\n if (row.departure_delay !== null || row.departure_time !== null || row.departure_uncertainty !== null) {\n stu.departure = {\n delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined,\n time: row.departure_time !== null ? Number(row.departure_time) : undefined,\n uncertainty: row.departure_uncertainty !== null ? Number(row.departure_uncertainty) : undefined\n };\n }\n\n return stu;\n}\n\n/**\n * Extended StopTimeUpdate with trip_id and rt_last_updated for debugging\n */\nexport interface StopTimeUpdateWithMetadata extends StopTimeUpdate {\n trip_id: string;\n rt_last_updated: number;\n}\n\n/**\n * Parse stop time update with metadata from database row\n */\nfunction parseStopTimeUpdateWithMetadata(row: Record): StopTimeUpdateWithMetadata {\n const stu = parseStopTimeUpdate(row) as StopTimeUpdateWithMetadata;\n stu.trip_id = String(row.trip_id);\n stu.rt_last_updated = Number(row.rt_last_updated);\n return stu;\n}\n\n/**\n * Get stop time updates with optional filters\n */\nexport function getStopTimeUpdates(\n db: Database,\n filters: StopTimeUpdateFilters = {},\n stalenessThreshold: number = 120\n): StopTimeUpdate[] {\n const { tripId, stopId, stopSequence, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by stop_id\n if (stopId) {\n conditions.push('stop_id = ?');\n params.push(stopId);\n }\n\n // Filter by stop_sequence\n if (stopSequence !== undefined) {\n conditions.push('stop_sequence = ?');\n params.push(stopSequence);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_stop_time_updates';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY trip_id, stop_sequence';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stopTimeUpdates: StopTimeUpdate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimeUpdates.push(parseStopTimeUpdate(row));\n }\n\n stmt.free();\n return stopTimeUpdates;\n}\n\n/**\n * Get stop time updates for a specific trip\n */\nexport function getStopTimeUpdatesByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): StopTimeUpdate[] {\n return getStopTimeUpdates(db, { tripId }, stalenessThreshold);\n}\n\n/**\n * Get all stop time updates without staleness filtering (for debugging)\n * Returns extended type with trip_id and rt_last_updated for debugging purposes\n */\nexport function getAllStopTimeUpdates(db: Database): StopTimeUpdateWithMetadata[] {\n const sql = 'SELECT * FROM rt_stop_time_updates ORDER BY trip_id, stop_sequence';\n const stmt = db.prepare(sql);\n\n const stopTimeUpdates: StopTimeUpdateWithMetadata[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimeUpdates.push(parseStopTimeUpdateWithMetadata(row));\n }\n\n stmt.free();\n return stopTimeUpdates;\n}\n","/**\n * GTFS Realtime TypeScript types\n * Based on GTFS Realtime v2.0 specification\n */\n\n// Enum types from GTFS-RT specification\n\nexport enum ScheduleRelationship {\n SCHEDULED = 0,\n ADDED = 1,\n UNSCHEDULED = 2,\n CANCELED = 3,\n SKIPPED = 4,\n NO_DATA = 5\n}\n\nexport enum VehicleStopStatus {\n INCOMING_AT = 0,\n STOPPED_AT = 1,\n IN_TRANSIT_TO = 2\n}\n\nexport enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0,\n RUNNING_SMOOTHLY = 1,\n STOP_AND_GO = 2,\n CONGESTION = 3,\n SEVERE_CONGESTION = 4\n}\n\nexport enum OccupancyStatus {\n EMPTY = 0,\n MANY_SEATS_AVAILABLE = 1,\n FEW_SEATS_AVAILABLE = 2,\n STANDING_ROOM_ONLY = 3,\n CRUSHED_STANDING_ROOM_ONLY = 4,\n FULL = 5,\n NOT_ACCEPTING_PASSENGERS = 6\n}\n\nexport enum AlertCause {\n UNKNOWN_CAUSE = 1,\n OTHER_CAUSE = 2,\n TECHNICAL_PROBLEM = 3,\n STRIKE = 4,\n DEMONSTRATION = 5,\n ACCIDENT = 6,\n HOLIDAY = 7,\n WEATHER = 8,\n MAINTENANCE = 9,\n CONSTRUCTION = 10,\n POLICE_ACTIVITY = 11,\n MEDICAL_EMERGENCY = 12\n}\n\nexport enum AlertEffect {\n NO_SERVICE = 1,\n REDUCED_SERVICE = 2,\n SIGNIFICANT_DELAYS = 3,\n DETOUR = 4,\n ADDITIONAL_SERVICE = 5,\n MODIFIED_SERVICE = 6,\n OTHER_EFFECT = 7,\n UNKNOWN_EFFECT = 8,\n STOP_MOVED = 9,\n NO_EFFECT = 10,\n ACCESSIBILITY_ISSUE = 11\n}\n\n// Main GTFS-RT types\n\nexport interface TranslatedString {\n translation: Array<{\n text: string;\n language?: string;\n }>;\n}\n\nexport interface EntitySelector {\n agency_id?: string;\n route_id?: string;\n route_type?: number;\n trip?: {\n trip_id?: string;\n route_id?: string;\n direction_id?: number;\n start_time?: string;\n start_date?: string;\n schedule_relationship?: ScheduleRelationship;\n };\n stop_id?: string;\n}\n\nexport interface TimeRange {\n start?: number; // UNIX timestamp\n end?: number; // UNIX timestamp\n}\n\nexport interface Alert {\n id: string;\n active_period: TimeRange[];\n informed_entity: EntitySelector[];\n cause?: AlertCause;\n effect?: AlertEffect;\n url?: TranslatedString;\n header_text?: TranslatedString;\n description_text?: TranslatedString;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface Position {\n latitude: number;\n longitude: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\nexport interface VehicleDescriptor {\n id?: string;\n label?: string;\n license_plate?: string;\n}\n\nexport interface VehiclePosition {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n position?: Position;\n current_stop_sequence?: number;\n stop_id?: string;\n current_status?: VehicleStopStatus;\n timestamp?: number;\n congestion_level?: CongestionLevel;\n occupancy_status?: OccupancyStatus;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface StopTimeEvent {\n delay?: number; // seconds\n time?: number; // UNIX timestamp (absolute time)\n uncertainty?: number;\n}\n\nexport interface StopTimeUpdate {\n stop_sequence?: number;\n stop_id?: string;\n arrival?: StopTimeEvent;\n departure?: StopTimeEvent;\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripUpdate {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n stop_time_update: StopTimeUpdate[];\n timestamp?: number;\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n rt_last_updated: number; // UNIX timestamp\n}\n\n// Enhanced types for queries with realtime data\n\nexport interface StopTimeRealtime {\n arrival_delay?: number; // seconds\n departure_delay?: number; // seconds\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripRealtime {\n vehicle_position?: VehiclePosition | null;\n trip_update?: {\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n } | null;\n}\n\n// Filter types for realtime queries\n\nexport interface AlertFilters {\n alertId?: string;\n activeOnly?: boolean;\n routeId?: string;\n stopId?: string;\n tripId?: string;\n cause?: AlertCause;\n effect?: AlertEffect;\n limit?: number;\n}\n\nexport interface VehiclePositionFilters {\n tripId?: string;\n routeId?: string;\n vehicleId?: string;\n limit?: number;\n}\n\n// Configuration\n\nexport interface RealtimeConfig {\n feedUrls?: string[];\n stalenessThreshold?: number; // seconds, default 120\n}\n"],"mappings":"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","names":["JSZip","Papa","response","arrayBuffer","protobuf","mergeRealtimeData","initSqlJs","ScheduleRelationship","VehicleStopStatus","CongestionLevel","OccupancyStatus","AlertCause","AlertEffect"]} \ No newline at end of file diff --git a/dist/index.mjs b/dist/index.mjs index f335d7e..ba75994 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -1237,6 +1237,106 @@ function rowToCalendarDate(row) { }; } +// src/queries/rt-vehicle-positions.ts +function parseVehiclePosition(row) { + const vp = { + trip_id: String(row.trip_id), + route_id: row.route_id ? String(row.route_id) : void 0, + rt_last_updated: Number(row.rt_last_updated) + }; + if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) { + vp.vehicle = { + id: row.vehicle_id ? String(row.vehicle_id) : void 0, + label: row.vehicle_label ? String(row.vehicle_label) : void 0, + license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : void 0 + }; + } + if (row.latitude !== null && row.longitude !== null) { + vp.position = { + latitude: Number(row.latitude), + longitude: Number(row.longitude), + bearing: row.bearing !== null ? Number(row.bearing) : void 0, + odometer: row.odometer !== null ? Number(row.odometer) : void 0, + speed: row.speed !== null ? Number(row.speed) : void 0 + }; + } + if (row.current_stop_sequence !== null) { + vp.current_stop_sequence = Number(row.current_stop_sequence); + } + if (row.stop_id) { + vp.stop_id = String(row.stop_id); + } + if (row.current_status !== null) { + vp.current_status = Number(row.current_status); + } + if (row.timestamp !== null) { + vp.timestamp = Number(row.timestamp); + } + if (row.congestion_level !== null) { + vp.congestion_level = Number(row.congestion_level); + } + if (row.occupancy_status !== null) { + vp.occupancy_status = Number(row.occupancy_status); + } + return vp; +} +function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { + const { tripId, routeId, vehicleId, limit } = filters; + const conditions = []; + const params = []; + if (tripId) { + conditions.push("trip_id = ?"); + params.push(tripId); + } + if (routeId) { + conditions.push("route_id = ?"); + params.push(routeId); + } + if (vehicleId) { + conditions.push("vehicle_id = ?"); + params.push(vehicleId); + } + const now = Math.floor(Date.now() / 1e3); + const staleThreshold = now - stalenessThreshold; + conditions.push("rt_last_updated >= ?"); + params.push(staleThreshold); + let sql = "SELECT * FROM rt_vehicle_positions"; + if (conditions.length > 0) { + sql += " WHERE " + conditions.join(" AND "); + } + sql += " ORDER BY rt_last_updated DESC"; + if (limit) { + sql += " LIMIT ?"; + params.push(limit); + } + const stmt = db.prepare(sql); + if (params.length > 0) { + stmt.bind(params); + } + const positions = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + positions.push(parseVehiclePosition(row)); + } + stmt.free(); + return positions; +} +function getVehiclePositionByTripId(db, tripId, stalenessThreshold = 120) { + const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold); + return positions.length > 0 ? positions[0] : null; +} +function getAllVehiclePositions(db) { + const sql = "SELECT * FROM rt_vehicle_positions ORDER BY rt_last_updated DESC"; + const stmt = db.prepare(sql); + const positions = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + positions.push(parseVehiclePosition(row)); + } + stmt.free(); + return positions; +} + // src/queries/trips.ts function mergeRealtimeData(trips, db, stalenessThreshold) { const now = Math.floor(Date.now() / 1e3); @@ -1253,7 +1353,8 @@ function mergeRealtimeData(trips, db, stalenessThreshold) { const vpMap = /* @__PURE__ */ new Map(); while (vpStmt.step()) { const row = vpStmt.getAsObject(); - vpMap.set(String(row.trip_id), row); + const vp = parseVehiclePosition(row); + vpMap.set(vp.trip_id, vp); } vpStmt.free(); const tuStmt = db.prepare(` @@ -1265,56 +1366,26 @@ function mergeRealtimeData(trips, db, stalenessThreshold) { const tuMap = /* @__PURE__ */ new Map(); while (tuStmt.step()) { const row = tuStmt.getAsObject(); - tuMap.set(String(row.trip_id), row); + const tripId = String(row.trip_id); + tuMap.set(tripId, { + delay: row.delay !== null ? Number(row.delay) : void 0, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : void 0 + }); } tuStmt.free(); return trips.map((trip) => { - const vpRow = vpMap.get(trip.trip_id); - const tuRow = tuMap.get(trip.trip_id); - if (!vpRow && !tuRow) { + const vp = vpMap.get(trip.trip_id); + const tu = tuMap.get(trip.trip_id); + if (!vp && !tu) { return { ...trip, realtime: { vehicle_position: null, trip_update: null } }; } - const realtime = { - vehicle_position: null, - trip_update: null - }; - if (vpRow) { - const vp = { - trip_id: String(vpRow.trip_id), - route_id: vpRow.route_id ? String(vpRow.route_id) : void 0, - rt_last_updated: Number(vpRow.rt_last_updated) - }; - if (vpRow.vehicle_id || vpRow.vehicle_label || vpRow.vehicle_license_plate) { - vp.vehicle = { - id: vpRow.vehicle_id ? String(vpRow.vehicle_id) : void 0, - label: vpRow.vehicle_label ? String(vpRow.vehicle_label) : void 0, - license_plate: vpRow.vehicle_license_plate ? String(vpRow.vehicle_license_plate) : void 0 - }; - } - if (vpRow.latitude !== null && vpRow.longitude !== null) { - vp.position = { - latitude: Number(vpRow.latitude), - longitude: Number(vpRow.longitude), - bearing: vpRow.bearing !== null ? Number(vpRow.bearing) : void 0, - odometer: vpRow.odometer !== null ? Number(vpRow.odometer) : void 0, - speed: vpRow.speed !== null ? Number(vpRow.speed) : void 0 - }; + return { + ...trip, + realtime: { + vehicle_position: vp || null, + trip_update: tu || null } - if (vpRow.current_stop_sequence !== null) vp.current_stop_sequence = Number(vpRow.current_stop_sequence); - if (vpRow.stop_id) vp.stop_id = String(vpRow.stop_id); - if (vpRow.current_status !== null) vp.current_status = Number(vpRow.current_status); - if (vpRow.timestamp !== null) vp.timestamp = Number(vpRow.timestamp); - if (vpRow.congestion_level !== null) vp.congestion_level = Number(vpRow.congestion_level); - if (vpRow.occupancy_status !== null) vp.occupancy_status = Number(vpRow.occupancy_status); - realtime.vehicle_position = vp; - } - if (tuRow) { - realtime.trip_update = { - delay: tuRow.delay !== null ? Number(tuRow.delay) : void 0, - schedule_relationship: tuRow.schedule_relationship !== null ? Number(tuRow.schedule_relationship) : void 0 - }; - } - return { ...trip, realtime }; + }; }); } function getTrips(db, filters = {}, stalenessThreshold = 120) { @@ -1624,51 +1695,40 @@ function getAlertById(db, alertId, stalenessThreshold = 120) { const alerts = getAlerts(db, { alertId, limit: 1 }, stalenessThreshold); return alerts.length > 0 ? alerts[0] : null; } +function getAllAlerts(db) { + const sql = "SELECT * FROM rt_alerts ORDER BY rt_last_updated DESC"; + const stmt = db.prepare(sql); + const alerts = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + alerts.push(parseAlert(row)); + } + stmt.free(); + return alerts; +} -// src/queries/rt-vehicle-positions.ts -function parseVehiclePosition(row) { - const vp = { +// src/queries/rt-trip-updates.ts +function parseTripUpdate(row) { + const tu = { trip_id: String(row.trip_id), route_id: row.route_id ? String(row.route_id) : void 0, + stop_time_update: [], + // Will be populated separately + timestamp: row.timestamp !== null ? Number(row.timestamp) : void 0, + delay: row.delay !== null ? Number(row.delay) : void 0, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : void 0, rt_last_updated: Number(row.rt_last_updated) }; if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) { - vp.vehicle = { + tu.vehicle = { id: row.vehicle_id ? String(row.vehicle_id) : void 0, label: row.vehicle_label ? String(row.vehicle_label) : void 0, license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : void 0 }; } - if (row.latitude !== null && row.longitude !== null) { - vp.position = { - latitude: Number(row.latitude), - longitude: Number(row.longitude), - bearing: row.bearing !== null ? Number(row.bearing) : void 0, - odometer: row.odometer !== null ? Number(row.odometer) : void 0, - speed: row.speed !== null ? Number(row.speed) : void 0 - }; - } - if (row.current_stop_sequence !== null) { - vp.current_stop_sequence = Number(row.current_stop_sequence); - } - if (row.stop_id) { - vp.stop_id = String(row.stop_id); - } - if (row.current_status !== null) { - vp.current_status = Number(row.current_status); - } - if (row.timestamp !== null) { - vp.timestamp = Number(row.timestamp); - } - if (row.congestion_level !== null) { - vp.congestion_level = Number(row.congestion_level); - } - if (row.occupancy_status !== null) { - vp.occupancy_status = Number(row.occupancy_status); - } - return vp; + return tu; } -function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { +function getTripUpdates(db, filters = {}, stalenessThreshold = 120) { const { tripId, routeId, vehicleId, limit } = filters; const conditions = []; const params = []; @@ -1688,7 +1748,7 @@ function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { const staleThreshold = now - stalenessThreshold; conditions.push("rt_last_updated >= ?"); params.push(staleThreshold); - let sql = "SELECT * FROM rt_vehicle_positions"; + let sql = "SELECT * FROM rt_trip_updates"; if (conditions.length > 0) { sql += " WHERE " + conditions.join(" AND "); } @@ -1701,17 +1761,113 @@ function getVehiclePositions(db, filters = {}, stalenessThreshold = 120) { if (params.length > 0) { stmt.bind(params); } - const positions = []; + const tripUpdates = []; while (stmt.step()) { const row = stmt.getAsObject(); - positions.push(parseVehiclePosition(row)); + tripUpdates.push(parseTripUpdate(row)); } stmt.free(); - return positions; + return tripUpdates; } -function getVehiclePositionByTripId(db, tripId, stalenessThreshold = 120) { - const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold); - return positions.length > 0 ? positions[0] : null; +function getTripUpdateByTripId(db, tripId, stalenessThreshold = 120) { + const updates = getTripUpdates(db, { tripId, limit: 1 }, stalenessThreshold); + return updates.length > 0 ? updates[0] : null; +} +function getAllTripUpdates(db) { + const sql = "SELECT * FROM rt_trip_updates ORDER BY rt_last_updated DESC"; + const stmt = db.prepare(sql); + const tripUpdates = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + tripUpdates.push(parseTripUpdate(row)); + } + stmt.free(); + return tripUpdates; +} + +// src/queries/rt-stop-time-updates.ts +function parseStopTimeUpdate(row) { + const stu = { + stop_sequence: row.stop_sequence !== null ? Number(row.stop_sequence) : void 0, + stop_id: row.stop_id ? String(row.stop_id) : void 0, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : void 0 + }; + if (row.arrival_delay !== null || row.arrival_time !== null || row.arrival_uncertainty !== null) { + stu.arrival = { + delay: row.arrival_delay !== null ? Number(row.arrival_delay) : void 0, + time: row.arrival_time !== null ? Number(row.arrival_time) : void 0, + uncertainty: row.arrival_uncertainty !== null ? Number(row.arrival_uncertainty) : void 0 + }; + } + if (row.departure_delay !== null || row.departure_time !== null || row.departure_uncertainty !== null) { + stu.departure = { + delay: row.departure_delay !== null ? Number(row.departure_delay) : void 0, + time: row.departure_time !== null ? Number(row.departure_time) : void 0, + uncertainty: row.departure_uncertainty !== null ? Number(row.departure_uncertainty) : void 0 + }; + } + return stu; +} +function parseStopTimeUpdateWithMetadata(row) { + const stu = parseStopTimeUpdate(row); + stu.trip_id = String(row.trip_id); + stu.rt_last_updated = Number(row.rt_last_updated); + return stu; +} +function getStopTimeUpdates(db, filters = {}, stalenessThreshold = 120) { + const { tripId, stopId, stopSequence, limit } = filters; + const conditions = []; + const params = []; + if (tripId) { + conditions.push("trip_id = ?"); + params.push(tripId); + } + if (stopId) { + conditions.push("stop_id = ?"); + params.push(stopId); + } + if (stopSequence !== void 0) { + conditions.push("stop_sequence = ?"); + params.push(stopSequence); + } + const now = Math.floor(Date.now() / 1e3); + const staleThreshold = now - stalenessThreshold; + conditions.push("rt_last_updated >= ?"); + params.push(staleThreshold); + let sql = "SELECT * FROM rt_stop_time_updates"; + if (conditions.length > 0) { + sql += " WHERE " + conditions.join(" AND "); + } + sql += " ORDER BY trip_id, stop_sequence"; + if (limit) { + sql += " LIMIT ?"; + params.push(limit); + } + const stmt = db.prepare(sql); + if (params.length > 0) { + stmt.bind(params); + } + const stopTimeUpdates = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + stopTimeUpdates.push(parseStopTimeUpdate(row)); + } + stmt.free(); + return stopTimeUpdates; +} +function getStopTimeUpdatesByTripId(db, tripId, stalenessThreshold = 120) { + return getStopTimeUpdates(db, { tripId }, stalenessThreshold); +} +function getAllStopTimeUpdates(db) { + const sql = "SELECT * FROM rt_stop_time_updates ORDER BY trip_id, stop_sequence"; + const stmt = db.prepare(sql); + const stopTimeUpdates = []; + while (stmt.step()) { + const row = stmt.getAsObject(); + stopTimeUpdates.push(parseStopTimeUpdateWithMetadata(row)); + } + stmt.free(); + return stopTimeUpdates; } // src/gtfs-sqljs.ts @@ -2030,6 +2186,66 @@ var GtfsSqlJs = class _GtfsSqlJs { if (!this.db) throw new Error("Database not initialized"); return getVehiclePositionByTripId(this.db, tripId, this.stalenessThreshold); } + /** + * Get trip updates with optional filters + */ + getTripUpdates(filters) { + if (!this.db) throw new Error("Database not initialized"); + return getTripUpdates(this.db, filters, this.stalenessThreshold); + } + /** + * Get trip update by trip ID + */ + getTripUpdateByTripId(tripId) { + if (!this.db) throw new Error("Database not initialized"); + return getTripUpdateByTripId(this.db, tripId, this.stalenessThreshold); + } + /** + * Get stop time updates with optional filters + */ + getStopTimeUpdates(filters) { + if (!this.db) throw new Error("Database not initialized"); + return getStopTimeUpdates(this.db, filters, this.stalenessThreshold); + } + /** + * Get stop time updates for a specific trip + */ + getStopTimeUpdatesByTripId(tripId) { + if (!this.db) throw new Error("Database not initialized"); + return getStopTimeUpdatesByTripId(this.db, tripId, this.stalenessThreshold); + } + // ==================== Debug Export Methods ==================== + // These methods export all realtime data without staleness filtering + // for debugging purposes + /** + * Export all alerts without staleness filtering (for debugging) + */ + debugExportAllAlerts() { + if (!this.db) throw new Error("Database not initialized"); + return getAllAlerts(this.db); + } + /** + * Export all vehicle positions without staleness filtering (for debugging) + */ + debugExportAllVehiclePositions() { + if (!this.db) throw new Error("Database not initialized"); + return getAllVehiclePositions(this.db); + } + /** + * Export all trip updates without staleness filtering (for debugging) + */ + debugExportAllTripUpdates() { + if (!this.db) throw new Error("Database not initialized"); + return getAllTripUpdates(this.db); + } + /** + * Export all stop time updates without staleness filtering (for debugging) + * Returns extended type with trip_id and rt_last_updated for debugging purposes + */ + debugExportAllStopTimeUpdates() { + if (!this.db) throw new Error("Database not initialized"); + return getAllStopTimeUpdates(this.db); + } }; // src/types/gtfs-rt.ts diff --git a/dist/index.mjs.map b/dist/index.mjs.map index e3c9d15..495a9f5 100644 --- a/dist/index.mjs.map +++ b/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"sources":["../src/gtfs-sqljs.ts","../src/schema/schema.ts","../src/loaders/zip-loader.ts","../src/loaders/csv-parser.ts","../src/loaders/data-loader.ts","../src/schema/gtfs-rt-schema.ts","../src/loaders/gtfs-rt-loader.ts","../src/queries/agencies.ts","../src/queries/stops.ts","../src/queries/routes.ts","../src/queries/calendar.ts","../src/queries/trips.ts","../src/queries/stop-times.ts","../src/queries/rt-alerts.ts","../src/queries/rt-vehicle-positions.ts","../src/types/gtfs-rt.ts"],"sourcesContent":["/**\n * Main GtfsSqlJs Class\n */\n\nimport initSqlJs, { type Database, type SqlJsStatic } from 'sql.js';\nimport { getAllCreateStatements } from './schema/schema';\nimport { loadGTFSZip } from './loaders/zip-loader';\nimport { loadGTFSData } from './loaders/data-loader';\nimport { createRealtimeTables, clearRealtimeData as clearRTData } from './schema/gtfs-rt-schema';\nimport { loadRealtimeData } from './loaders/gtfs-rt-loader';\n\n// Query methods\nimport { getAgencyById, getAgencies, type AgencyFilters } from './queries/agencies';\nimport { getStopById, getStops, type StopFilters } from './queries/stops';\nimport { getRouteById, getRoutes, type RouteFilters } from './queries/routes';\nimport {\n getActiveServiceIds,\n getCalendarByServiceId,\n getCalendarDates,\n getCalendarDatesForDate,\n} from './queries/calendar';\nimport { getTripById, getTrips, type TripFilters, type TripWithRealtime } from './queries/trips';\nimport { getStopTimesByTrip, getStopTimes, type StopTimeFilters, type StopTimeWithRealtime } from './queries/stop-times';\nimport { getAlerts as getAlertsQuery, getAlertById, type AlertFilters } from './queries/rt-alerts';\nimport { getVehiclePositions as getVehiclePositionsQuery, getVehiclePositionByTripId, type VehiclePositionFilters } from './queries/rt-vehicle-positions';\n\n// Types\nimport type { Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate } from './types/gtfs';\nimport type { Alert, VehiclePosition } from './types/gtfs-rt';\n\n// Export filter types for users\nexport type { AgencyFilters, StopFilters, RouteFilters, TripFilters, StopTimeFilters, AlertFilters, VehiclePositionFilters };\n// Export RT types\nexport type { Alert, VehiclePosition, TripWithRealtime, StopTimeWithRealtime };\n\nexport interface GtfsSqlJsOptions {\n /**\n * Path or URL to GTFS ZIP file\n */\n zipPath?: string;\n\n /**\n * Pre-loaded SQLite database as ArrayBuffer\n */\n database?: ArrayBuffer;\n\n /**\n * Optional: Custom SQL.js instance\n */\n SQL?: SqlJsStatic;\n\n /**\n * Optional: Path to SQL.js WASM file (for custom loading)\n */\n locateFile?: (filename: string) => string;\n\n /**\n * Optional: Array of GTFS filenames to skip importing (e.g., ['shapes.txt'])\n * Tables will be created but no data will be imported for these files\n */\n skipFiles?: string[];\n\n /**\n * Optional: Array of GTFS-RT feed URLs for realtime data\n */\n realtimeFeedUrls?: string[];\n\n /**\n * Optional: Staleness threshold in seconds (default: 120)\n * Realtime data older than this will be excluded from queries\n */\n stalenessThreshold?: number;\n}\n\nexport class GtfsSqlJs {\n private db: Database | null = null;\n private SQL: SqlJsStatic | null = null;\n private realtimeFeedUrls: string[] = [];\n private stalenessThreshold: number = 120;\n\n /**\n * Private constructor - use static factory methods instead\n */\n private constructor() {}\n\n /**\n * Create GtfsSqlJs instance from GTFS ZIP file\n */\n static async fromZip(\n zipPath: string,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromZip(zipPath, options);\n return instance;\n }\n\n /**\n * Create GtfsSqlJs instance from existing SQLite database\n */\n static async fromDatabase(\n database: ArrayBuffer,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromDatabase(database, options);\n return instance;\n }\n\n /**\n * Initialize from ZIP file\n */\n private async initFromZip(zipPath: string, options: Omit): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Create new database\n this.db = new this.SQL.Database();\n\n // Create GTFS schema\n const createStatements = getAllCreateStatements();\n for (const statement of createStatements) {\n this.db.run(statement);\n }\n\n // Create GTFS-RT tables\n createRealtimeTables(this.db);\n\n // Load GTFS data\n const files = await loadGTFSZip(zipPath);\n await loadGTFSData(this.db, files, options.skipFiles);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Initialize from existing database\n */\n private async initFromDatabase(\n database: ArrayBuffer,\n options: Omit\n ): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Load existing database\n this.db = new this.SQL.Database(new Uint8Array(database));\n\n // Ensure RT tables exist (in case loading old database)\n createRealtimeTables(this.db);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Export database to ArrayBuffer\n */\n export(): ArrayBuffer {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n\n const data = this.db.export();\n // Create a new ArrayBuffer and copy the data to ensure proper type\n const buffer = new ArrayBuffer(data.length);\n new Uint8Array(buffer).set(data);\n return buffer;\n }\n\n /**\n * Close the database connection\n */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n /**\n * Get direct access to the database (for advanced queries)\n */\n getDatabase(): Database {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n return this.db;\n }\n\n // ==================== Agency Methods ====================\n\n /**\n * Get an agency by its agency_id\n */\n getAgencyById(agencyId: string): Agency | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencyById(this.db, agencyId);\n }\n\n /**\n * Get agencies with optional filters\n */\n getAgencies(filters?: AgencyFilters): Agency[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencies(this.db, filters);\n }\n\n // ==================== Stop Methods ====================\n\n /**\n * Get a stop by its stop_id\n */\n getStopById(stopId: string): Stop | null {\n if (!this.db) throw new Error('Database not initialized');\n return getStopById(this.db, stopId);\n }\n\n /**\n * Get stops with optional filters\n */\n getStops(filters?: StopFilters): Stop[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStops(this.db, filters);\n }\n\n // ==================== Route Methods ====================\n\n /**\n * Get a route by its route_id\n */\n getRouteById(routeId: string): Route | null {\n if (!this.db) throw new Error('Database not initialized');\n return getRouteById(this.db, routeId);\n }\n\n /**\n * Get routes with optional filters\n */\n getRoutes(filters?: RouteFilters): Route[] {\n if (!this.db) throw new Error('Database not initialized');\n return getRoutes(this.db, filters);\n }\n\n // ==================== Calendar Methods ====================\n\n /**\n * Get active service IDs for a given date (YYYYMMDD format)\n */\n getActiveServiceIds(date: string): string[] {\n if (!this.db) throw new Error('Database not initialized');\n return getActiveServiceIds(this.db, date);\n }\n\n /**\n * Get calendar entry by service_id\n */\n getCalendarByServiceId(serviceId: string): Calendar | null {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarByServiceId(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a service\n */\n getCalendarDates(serviceId: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDates(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a specific date\n */\n getCalendarDatesForDate(date: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDatesForDate(this.db, date);\n }\n\n // ==================== Trip Methods ====================\n\n /**\n * Get a trip by its trip_id\n */\n getTripById(tripId: string): Trip | null {\n if (!this.db) throw new Error('Database not initialized');\n return getTripById(this.db, tripId);\n }\n\n /**\n * Get trips with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get all trips for a route on a specific date\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', date: '20240115' });\n *\n * @example\n * // Get all trips for a route going in one direction\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', directionId: 0 });\n */\n getTrips(filters?: TripFilters & { date?: string }): Trip[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getTrips(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Stop Time Methods ====================\n\n /**\n * Get stop times for a trip (ordered by stop_sequence)\n */\n getStopTimesByTrip(tripId: string): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimesByTrip(this.db, tripId);\n }\n\n /**\n * Get stop times with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.stopId - Filter by stop ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get stop times for a specific trip\n * const stopTimes = gtfs.getStopTimes({ tripId: 'TRIP_123' });\n *\n * @example\n * // Get stop times at a stop for a specific route on a date\n * const stopTimes = gtfs.getStopTimes({\n * stopId: 'STOP_123',\n * routeId: 'ROUTE_1',\n * date: '20240115'\n * });\n */\n getStopTimes(filters?: StopTimeFilters & { date?: string }): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getStopTimes(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Realtime Methods ====================\n\n /**\n * Set GTFS-RT feed URLs\n */\n setRealtimeFeedUrls(urls: string[]): void {\n this.realtimeFeedUrls = urls;\n }\n\n /**\n * Get currently configured GTFS-RT feed URLs\n */\n getRealtimeFeedUrls(): string[] {\n return [...this.realtimeFeedUrls];\n }\n\n /**\n * Set staleness threshold in seconds\n */\n setStalenessThreshold(seconds: number): void {\n this.stalenessThreshold = seconds;\n }\n\n /**\n * Get current staleness threshold\n */\n getStalenessThreshold(): number {\n return this.stalenessThreshold;\n }\n\n /**\n * Fetch and load GTFS Realtime data from configured feed URLs or provided URLs\n * @param urls - Optional array of feed URLs. If not provided, uses configured feed URLs\n */\n async fetchRealtimeData(urls?: string[]): Promise {\n if (!this.db) throw new Error('Database not initialized');\n\n const feedUrls = urls || this.realtimeFeedUrls;\n if (feedUrls.length === 0) {\n throw new Error('No realtime feed URLs configured. Use setRealtimeFeedUrls() or pass urls parameter.');\n }\n\n await loadRealtimeData(this.db, feedUrls);\n }\n\n /**\n * Clear all realtime data from the database\n */\n clearRealtimeData(): void {\n if (!this.db) throw new Error('Database not initialized');\n clearRTData(this.db);\n }\n\n /**\n * Get alerts with optional filters\n */\n getAlerts(filters?: AlertFilters): Alert[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get alert by ID\n */\n getAlertById(alertId: string): Alert | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertById(this.db, alertId, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle positions with optional filters\n */\n getVehiclePositions(filters?: VehiclePositionFilters): VehiclePosition[] {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle position by trip ID\n */\n getVehiclePositionByTripId(tripId: string): VehiclePosition | null {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionByTripId(this.db, tripId, this.stalenessThreshold);\n }\n}\n","/**\n * SQLite Schema Definitions for GTFS Data\n * Matches required/optional fields from GTFS specification\n */\n\nexport interface TableSchema {\n name: string;\n columns: ColumnDefinition[];\n indexes?: IndexDefinition[];\n}\n\nexport interface ColumnDefinition {\n name: string;\n type: 'TEXT' | 'INTEGER' | 'REAL';\n required: boolean;\n primaryKey?: boolean;\n}\n\nexport interface IndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n}\n\nexport const GTFS_SCHEMA: TableSchema[] = [\n {\n name: 'agency',\n columns: [\n { name: 'agency_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'agency_name', type: 'TEXT', required: true },\n { name: 'agency_url', type: 'TEXT', required: true },\n { name: 'agency_timezone', type: 'TEXT', required: true },\n { name: 'agency_lang', type: 'TEXT', required: false },\n { name: 'agency_phone', type: 'TEXT', required: false },\n { name: 'agency_fare_url', type: 'TEXT', required: false },\n { name: 'agency_email', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'stops',\n columns: [\n { name: 'stop_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'stop_name', type: 'TEXT', required: true },\n { name: 'stop_lat', type: 'REAL', required: true },\n { name: 'stop_lon', type: 'REAL', required: true },\n { name: 'stop_code', type: 'TEXT', required: false },\n { name: 'stop_desc', type: 'TEXT', required: false },\n { name: 'zone_id', type: 'TEXT', required: false },\n { name: 'stop_url', type: 'TEXT', required: false },\n { name: 'location_type', type: 'INTEGER', required: false },\n { name: 'parent_station', type: 'TEXT', required: false },\n { name: 'stop_timezone', type: 'TEXT', required: false },\n { name: 'wheelchair_boarding', type: 'INTEGER', required: false },\n { name: 'level_id', type: 'TEXT', required: false },\n { name: 'platform_code', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_stops_stop_code', columns: ['stop_code'] },\n { name: 'idx_stops_stop_name', columns: ['stop_name'] },\n { name: 'idx_stops_parent_station', columns: ['parent_station'] },\n ],\n },\n {\n name: 'routes',\n columns: [\n { name: 'route_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_short_name', type: 'TEXT', required: true },\n { name: 'route_long_name', type: 'TEXT', required: true },\n { name: 'route_type', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_desc', type: 'TEXT', required: false },\n { name: 'route_url', type: 'TEXT', required: false },\n { name: 'route_color', type: 'TEXT', required: false },\n { name: 'route_text_color', type: 'TEXT', required: false },\n { name: 'route_sort_order', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_routes_agency_id', columns: ['agency_id'] },\n ],\n },\n {\n name: 'trips',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_id', type: 'TEXT', required: true },\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'trip_headsign', type: 'TEXT', required: false },\n { name: 'trip_short_name', type: 'TEXT', required: false },\n { name: 'direction_id', type: 'INTEGER', required: false },\n { name: 'block_id', type: 'TEXT', required: false },\n { name: 'shape_id', type: 'TEXT', required: false },\n { name: 'wheelchair_accessible', type: 'INTEGER', required: false },\n { name: 'bikes_allowed', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_trips_route_id', columns: ['route_id'] },\n { name: 'idx_trips_service_id', columns: ['service_id'] },\n { name: 'idx_trips_route_service', columns: ['route_id', 'service_id'] },\n ],\n },\n {\n name: 'stop_times',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'arrival_time', type: 'TEXT', required: true },\n { name: 'departure_time', type: 'TEXT', required: true },\n { name: 'stop_id', type: 'TEXT', required: true },\n { name: 'stop_sequence', type: 'INTEGER', required: true },\n { name: 'stop_headsign', type: 'TEXT', required: false },\n { name: 'pickup_type', type: 'INTEGER', required: false },\n { name: 'drop_off_type', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n { name: 'timepoint', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_stop_times_trip_id', columns: ['trip_id'] },\n { name: 'idx_stop_times_stop_id', columns: ['stop_id'] },\n { name: 'idx_stop_times_trip_sequence', columns: ['trip_id', 'stop_sequence'] },\n ],\n },\n {\n name: 'calendar',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'monday', type: 'INTEGER', required: true },\n { name: 'tuesday', type: 'INTEGER', required: true },\n { name: 'wednesday', type: 'INTEGER', required: true },\n { name: 'thursday', type: 'INTEGER', required: true },\n { name: 'friday', type: 'INTEGER', required: true },\n { name: 'saturday', type: 'INTEGER', required: true },\n { name: 'sunday', type: 'INTEGER', required: true },\n { name: 'start_date', type: 'TEXT', required: true },\n { name: 'end_date', type: 'TEXT', required: true },\n ],\n },\n {\n name: 'calendar_dates',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'date', type: 'TEXT', required: true },\n { name: 'exception_type', type: 'INTEGER', required: true },\n ],\n indexes: [\n { name: 'idx_calendar_dates_service_id', columns: ['service_id'] },\n { name: 'idx_calendar_dates_date', columns: ['date'] },\n { name: 'idx_calendar_dates_service_date', columns: ['service_id', 'date'] },\n ],\n },\n {\n name: 'fare_attributes',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'price', type: 'REAL', required: true },\n { name: 'currency_type', type: 'TEXT', required: true },\n { name: 'payment_method', type: 'INTEGER', required: true },\n { name: 'transfers', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'transfer_duration', type: 'INTEGER', required: false },\n ],\n },\n {\n name: 'fare_rules',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'origin_id', type: 'TEXT', required: false },\n { name: 'destination_id', type: 'TEXT', required: false },\n { name: 'contains_id', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_fare_rules_fare_id', columns: ['fare_id'] },\n { name: 'idx_fare_rules_route_id', columns: ['route_id'] },\n ],\n },\n {\n name: 'shapes',\n columns: [\n { name: 'shape_id', type: 'TEXT', required: true },\n { name: 'shape_pt_lat', type: 'REAL', required: true },\n { name: 'shape_pt_lon', type: 'REAL', required: true },\n { name: 'shape_pt_sequence', type: 'INTEGER', required: true },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n ],\n indexes: [\n { name: 'idx_shapes_shape_id', columns: ['shape_id'] },\n { name: 'idx_shapes_shape_sequence', columns: ['shape_id', 'shape_pt_sequence'] },\n ],\n },\n {\n name: 'frequencies',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'start_time', type: 'TEXT', required: true },\n { name: 'end_time', type: 'TEXT', required: true },\n { name: 'headway_secs', type: 'INTEGER', required: true },\n { name: 'exact_times', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_frequencies_trip_id', columns: ['trip_id'] },\n ],\n },\n {\n name: 'transfers',\n columns: [\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'transfer_type', type: 'INTEGER', required: true },\n { name: 'min_transfer_time', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_transfers_from_stop_id', columns: ['from_stop_id'] },\n { name: 'idx_transfers_to_stop_id', columns: ['to_stop_id'] },\n ],\n },\n {\n name: 'pathways',\n columns: [\n { name: 'pathway_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'pathway_mode', type: 'INTEGER', required: true },\n { name: 'is_bidirectional', type: 'INTEGER', required: true },\n { name: 'length', type: 'REAL', required: false },\n { name: 'traversal_time', type: 'INTEGER', required: false },\n { name: 'stair_count', type: 'INTEGER', required: false },\n { name: 'max_slope', type: 'REAL', required: false },\n { name: 'min_width', type: 'REAL', required: false },\n { name: 'signposted_as', type: 'TEXT', required: false },\n { name: 'reversed_signposted_as', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'levels',\n columns: [\n { name: 'level_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'level_index', type: 'REAL', required: true },\n { name: 'level_name', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'feed_info',\n columns: [\n { name: 'feed_publisher_name', type: 'TEXT', required: true },\n { name: 'feed_publisher_url', type: 'TEXT', required: true },\n { name: 'feed_lang', type: 'TEXT', required: true },\n { name: 'default_lang', type: 'TEXT', required: false },\n { name: 'feed_start_date', type: 'TEXT', required: false },\n { name: 'feed_end_date', type: 'TEXT', required: false },\n { name: 'feed_version', type: 'TEXT', required: false },\n { name: 'feed_contact_email', type: 'TEXT', required: false },\n { name: 'feed_contact_url', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'attributions',\n columns: [\n { name: 'attribution_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'organization_name', type: 'TEXT', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'trip_id', type: 'TEXT', required: false },\n { name: 'is_producer', type: 'INTEGER', required: false },\n { name: 'is_operator', type: 'INTEGER', required: false },\n { name: 'is_authority', type: 'INTEGER', required: false },\n { name: 'attribution_url', type: 'TEXT', required: false },\n { name: 'attribution_email', type: 'TEXT', required: false },\n { name: 'attribution_phone', type: 'TEXT', required: false },\n ],\n },\n];\n\n/**\n * Generate CREATE TABLE SQL statement from schema definition\n */\nexport function generateCreateTableSQL(schema: TableSchema): string {\n const columns = schema.columns.map((col) => {\n const parts = [col.name, col.type];\n if (col.primaryKey) {\n parts.push('PRIMARY KEY');\n }\n if (col.required && !col.primaryKey) {\n parts.push('NOT NULL');\n }\n return parts.join(' ');\n });\n\n return `CREATE TABLE IF NOT EXISTS ${schema.name} (${columns.join(', ')})`;\n}\n\n/**\n * Generate CREATE INDEX SQL statements from schema definition\n */\nexport function generateCreateIndexSQL(schema: TableSchema): string[] {\n if (!schema.indexes) {\n return [];\n }\n\n return schema.indexes.map((idx) => {\n const unique = idx.unique ? 'UNIQUE ' : '';\n const columns = idx.columns.join(', ');\n return `CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${schema.name} (${columns})`;\n });\n}\n\n/**\n * Initialize all GTFS tables in the database\n */\nexport function getAllCreateStatements(): string[] {\n const statements: string[] = [];\n\n for (const schema of GTFS_SCHEMA) {\n statements.push(generateCreateTableSQL(schema));\n statements.push(...generateCreateIndexSQL(schema));\n }\n\n return statements;\n}\n","/**\n * ZIP Loader for GTFS files\n */\n\nimport JSZip from 'jszip';\n\nexport interface GTFSFiles {\n [filename: string]: string;\n}\n\n/**\n * Fetch and extract GTFS ZIP file\n * Works in both browser and Node.js environments\n */\nexport async function loadGTFSZip(source: string | ArrayBuffer | Uint8Array): Promise {\n let zipData: ArrayBuffer | Uint8Array;\n\n // If source is a string, treat it as URL or file path\n if (typeof source === 'string') {\n zipData = await fetchZip(source);\n } else {\n zipData = source;\n }\n\n // Load ZIP file\n const zip = await JSZip.loadAsync(zipData);\n\n // Extract all .txt files (GTFS files)\n const files: GTFSFiles = {};\n const filePromises: Promise[] = [];\n\n zip.forEach((relativePath, file) => {\n // Only process .txt files\n if (!file.dir && relativePath.endsWith('.txt')) {\n const fileName = relativePath.split('/').pop() || relativePath;\n filePromises.push(\n file.async('string').then((content) => {\n files[fileName] = content;\n })\n );\n }\n });\n\n await Promise.all(filePromises);\n\n return files;\n}\n\n/**\n * Fetch ZIP file from URL or file path\n */\nasync function fetchZip(source: string): Promise {\n // Check if source is a URL\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n // For URLs, always use fetch\n if (isUrl) {\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n throw new Error('fetch is not available to load URL');\n }\n\n // For non-URLs, try Node.js fs first, fall back to fetch for browser\n // Check if we're in Node.js environment\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n // In Node.js, treat as file path\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);\n } catch (error) {\n throw new Error(`Failed to read GTFS ZIP file: ${error}`);\n }\n }\n\n // In browser, treat as relative URL and use fetch\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n\n throw new Error('No method available to load ZIP file');\n}\n\n/**\n * Mapping of GTFS file names to database table names\n */\nexport const GTFS_FILE_MAPPING: Record = {\n 'agency.txt': 'agency',\n 'stops.txt': 'stops',\n 'routes.txt': 'routes',\n 'trips.txt': 'trips',\n 'stop_times.txt': 'stop_times',\n 'calendar.txt': 'calendar',\n 'calendar_dates.txt': 'calendar_dates',\n 'fare_attributes.txt': 'fare_attributes',\n 'fare_rules.txt': 'fare_rules',\n 'shapes.txt': 'shapes',\n 'frequencies.txt': 'frequencies',\n 'transfers.txt': 'transfers',\n 'pathways.txt': 'pathways',\n 'levels.txt': 'levels',\n 'feed_info.txt': 'feed_info',\n 'attributions.txt': 'attributions',\n};\n","/**\n * CSV Parser for GTFS files using papaparse\n */\n\nimport Papa from 'papaparse';\n\nexport interface ParsedCSV {\n headers: string[];\n rows: Record[];\n}\n\n/**\n * Parse CSV text into structured data using papaparse\n */\nexport function parseCSV(text: string): ParsedCSV {\n const result = Papa.parse(text, {\n header: true,\n skipEmptyLines: true,\n transformHeader: (header) => header.trim(),\n transform: (value) => value.trim(),\n });\n\n if (result.errors.length > 0) {\n console.warn('CSV parsing warnings:', result.errors);\n }\n\n const headers = result.meta.fields || [];\n const rows = result.data as Record[];\n\n return { headers, rows };\n}\n\n/**\n * Convert parsed row to typed object with proper type conversions\n */\nexport function convertRowTypes(\n row: Record,\n columnTypes: Record\n): Record {\n const result: Record = {};\n\n // Iterate over all expected columns, not just the ones present in the row\n for (const [key, type] of Object.entries(columnTypes)) {\n const value = row[key];\n\n // Handle missing or empty values\n if (value === undefined || value === null || value === '') {\n result[key] = null;\n continue;\n }\n\n if (type === 'INTEGER') {\n const parsed = parseInt(value, 10);\n result[key] = isNaN(parsed) ? null : parsed;\n } else if (type === 'REAL') {\n const parsed = parseFloat(value);\n result[key] = isNaN(parsed) ? null : parsed;\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n","/**\n * Data Loader - Loads GTFS data into SQLite database\n */\n\nimport type { Database } from 'sql.js';\nimport { parseCSV, convertRowTypes } from './csv-parser';\nimport { GTFS_SCHEMA, type TableSchema } from '../schema/schema';\nimport type { GTFSFiles } from './zip-loader';\n\n/**\n * Load GTFS files into SQLite database\n * @param skipFiles - Optional array of filenames to skip importing (tables will be created but remain empty)\n */\nexport async function loadGTFSData(db: Database, files: GTFSFiles, skipFiles?: string[]): Promise {\n // Map of file names to table schemas\n const fileToSchema: Map = new Map();\n for (const schema of GTFS_SCHEMA) {\n // Match file names like agency.txt to table name 'agency'\n fileToSchema.set(`${schema.name}.txt`, schema);\n }\n\n // Normalize skipFiles to a Set for faster lookup\n const skipSet = new Set(skipFiles?.map(f => f.toLowerCase()) || []);\n\n // Process each file\n for (const [fileName, content] of Object.entries(files)) {\n const schema = fileToSchema.get(fileName);\n if (!schema) {\n // Skip unknown files\n continue;\n }\n\n // Skip if in skip list\n if (skipSet.has(fileName.toLowerCase())) {\n console.log(`Skipping import of ${fileName} (table ${schema.name} created but empty)`);\n continue;\n }\n\n await loadTableData(db, schema, content);\n }\n}\n\n/**\n * Load data for a single table\n */\nasync function loadTableData(db: Database, schema: TableSchema, csvContent: string): Promise {\n const { headers, rows } = parseCSV(csvContent);\n\n if (rows.length === 0) {\n return;\n }\n\n // Build column type map\n const columnTypes: Record = {};\n for (const col of schema.columns) {\n columnTypes[col.name] = col.type;\n }\n\n // Prepare INSERT statement\n const columns = headers.filter((h) => schema.columns.some((c) => c.name === h));\n const placeholders = columns.map(() => '?').join(', ');\n const insertSQL = `INSERT INTO ${schema.name} (${columns.join(', ')}) VALUES (${placeholders})`;\n\n const stmt = db.prepare(insertSQL);\n\n // Insert each row\n for (const row of rows) {\n const typedRow = convertRowTypes(row, columnTypes);\n const values = columns.map((col) => {\n const value = typedRow[col];\n // Handle undefined, null, or empty values\n return value === null || value === undefined ? null : value;\n });\n\n try {\n stmt.run(values);\n } catch (error) {\n console.error(`Error inserting row into ${schema.name}:`, error);\n console.error('Row data:', row);\n throw error;\n }\n }\n\n stmt.free();\n}\n","import type { Database } from 'sql.js';\n\n/**\n * Create GTFS Realtime tables in the database\n */\nexport function createRealtimeTables(db: Database): void {\n // Alerts table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_alerts (\n id TEXT PRIMARY KEY,\n active_period TEXT, -- JSON array of TimeRange objects\n informed_entity TEXT, -- JSON array of EntitySelector objects\n cause INTEGER,\n effect INTEGER,\n url TEXT, -- JSON TranslatedString\n header_text TEXT, -- JSON TranslatedString\n description_text TEXT, -- JSON TranslatedString\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n // Create index on rt_last_updated for staleness filtering\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_alerts_updated ON rt_alerts(rt_last_updated)');\n\n // Vehicle Positions table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_vehicle_positions (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n latitude REAL,\n longitude REAL,\n bearing REAL,\n odometer REAL,\n speed REAL,\n current_stop_sequence INTEGER,\n stop_id TEXT,\n current_status INTEGER,\n timestamp INTEGER,\n congestion_level INTEGER,\n occupancy_status INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_updated ON rt_vehicle_positions(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_route ON rt_vehicle_positions(route_id)');\n\n // Trip Updates table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_trip_updates (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n timestamp INTEGER,\n delay INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_updated ON rt_trip_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_route ON rt_trip_updates(route_id)');\n\n // Stop Time Updates table (child of trip updates)\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_stop_time_updates (\n trip_id TEXT NOT NULL,\n stop_sequence INTEGER,\n stop_id TEXT,\n arrival_delay INTEGER,\n arrival_time INTEGER,\n arrival_uncertainty INTEGER,\n departure_delay INTEGER,\n departure_time INTEGER,\n departure_uncertainty INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL,\n PRIMARY KEY (trip_id, stop_sequence),\n FOREIGN KEY (trip_id) REFERENCES rt_trip_updates(trip_id) ON DELETE CASCADE\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_updated ON rt_stop_time_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_stop ON rt_stop_time_updates(stop_id)');\n}\n\n/**\n * Clear all realtime data from the database\n */\nexport function clearRealtimeData(db: Database): void {\n db.run('DELETE FROM rt_alerts');\n db.run('DELETE FROM rt_vehicle_positions');\n db.run('DELETE FROM rt_trip_updates');\n db.run('DELETE FROM rt_stop_time_updates');\n}\n","import type { Database } from 'sql.js';\nimport protobuf from 'protobufjs';\n\n// Types for protobuf decoded objects\ninterface ProtobufTranslation {\n text: string;\n language?: string;\n}\n\ninterface ProtobufTranslatedString {\n translation: ProtobufTranslation[];\n}\n\ninterface ProtobufAlert {\n id: string;\n activePeriod?: unknown[];\n active_period?: unknown[];\n informedEntity?: unknown[];\n informed_entity?: unknown[];\n cause?: number;\n effect?: number;\n url?: ProtobufTranslatedString;\n headerText?: ProtobufTranslatedString;\n header_text?: ProtobufTranslatedString;\n descriptionText?: ProtobufTranslatedString;\n description_text?: ProtobufTranslatedString;\n}\n\ninterface ProtobufTripDescriptor {\n tripId?: string;\n trip_id?: string;\n routeId?: string;\n route_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n}\n\ninterface ProtobufVehicleDescriptor {\n id?: string;\n label?: string;\n licensePlate?: string;\n license_plate?: string;\n}\n\ninterface ProtobufPosition {\n latitude?: number;\n longitude?: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\ninterface ProtobufVehiclePosition {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n position?: ProtobufPosition;\n currentStopSequence?: number;\n current_stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n currentStatus?: number;\n current_status?: number;\n timestamp?: number;\n congestionLevel?: number;\n congestion_level?: number;\n occupancyStatus?: number;\n occupancy_status?: number;\n}\n\ninterface ProtobufStopTimeEvent {\n delay?: number;\n time?: number;\n uncertainty?: number;\n}\n\ninterface ProtobufStopTimeUpdate {\n stopSequence?: number;\n stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n arrival?: ProtobufStopTimeEvent;\n departure?: ProtobufStopTimeEvent;\n}\n\ninterface ProtobufTripUpdate {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n timestamp?: number;\n delay?: number;\n stopTimeUpdate?: ProtobufStopTimeUpdate[];\n stop_time_update?: ProtobufStopTimeUpdate[];\n}\n\n// GTFS Realtime protobuf definition (v2.0)\n// Source: https://github.com/google/transit/blob/master/gtfs-realtime/proto/gtfs-realtime.proto\nconst GTFS_RT_PROTO = `\nsyntax = \"proto2\";\noption java_package = \"com.google.transit.realtime\";\npackage transit_realtime;\n\nmessage FeedMessage {\n required FeedHeader header = 1;\n repeated FeedEntity entity = 2;\n}\n\nmessage FeedHeader {\n required string gtfs_realtime_version = 1;\n enum Incrementality {\n FULL_DATASET = 0;\n DIFFERENTIAL = 1;\n }\n optional Incrementality incrementality = 2 [default = FULL_DATASET];\n optional uint64 timestamp = 3;\n}\n\nmessage FeedEntity {\n required string id = 1;\n optional bool is_deleted = 2 [default = false];\n optional TripUpdate trip_update = 3;\n optional VehiclePosition vehicle = 4;\n optional Alert alert = 5;\n}\n\nmessage TripUpdate {\n required TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 3;\n repeated StopTimeUpdate stop_time_update = 2;\n optional uint64 timestamp = 4;\n optional int32 delay = 5;\n\n message StopTimeEvent {\n optional int32 delay = 1;\n optional int64 time = 2;\n optional int32 uncertainty = 3;\n }\n\n message StopTimeUpdate {\n optional uint32 stop_sequence = 1;\n optional string stop_id = 4;\n optional StopTimeEvent arrival = 2;\n optional StopTimeEvent departure = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n SKIPPED = 1;\n NO_DATA = 2;\n }\n optional ScheduleRelationship schedule_relationship = 5 [default = SCHEDULED];\n }\n}\n\nmessage VehiclePosition {\n optional TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 8;\n optional Position position = 2;\n optional uint32 current_stop_sequence = 3;\n optional string stop_id = 7;\n enum VehicleStopStatus {\n INCOMING_AT = 0;\n STOPPED_AT = 1;\n IN_TRANSIT_TO = 2;\n }\n optional VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];\n optional uint64 timestamp = 5;\n enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0;\n RUNNING_SMOOTHLY = 1;\n STOP_AND_GO = 2;\n CONGESTION = 3;\n SEVERE_CONGESTION = 4;\n }\n optional CongestionLevel congestion_level = 6;\n enum OccupancyStatus {\n EMPTY = 0;\n MANY_SEATS_AVAILABLE = 1;\n FEW_SEATS_AVAILABLE = 2;\n STANDING_ROOM_ONLY = 3;\n CRUSHED_STANDING_ROOM_ONLY = 4;\n FULL = 5;\n NOT_ACCEPTING_PASSENGERS = 6;\n }\n optional OccupancyStatus occupancy_status = 9;\n}\n\nmessage Alert {\n repeated TimeRange active_period = 1;\n repeated EntitySelector informed_entity = 5;\n\n enum Cause {\n UNKNOWN_CAUSE = 1;\n OTHER_CAUSE = 2;\n TECHNICAL_PROBLEM = 3;\n STRIKE = 4;\n DEMONSTRATION = 5;\n ACCIDENT = 6;\n HOLIDAY = 7;\n WEATHER = 8;\n MAINTENANCE = 9;\n CONSTRUCTION = 10;\n POLICE_ACTIVITY = 11;\n MEDICAL_EMERGENCY = 12;\n }\n optional Cause cause = 6 [default = UNKNOWN_CAUSE];\n\n enum Effect {\n NO_SERVICE = 1;\n REDUCED_SERVICE = 2;\n SIGNIFICANT_DELAYS = 3;\n DETOUR = 4;\n ADDITIONAL_SERVICE = 5;\n MODIFIED_SERVICE = 6;\n OTHER_EFFECT = 7;\n UNKNOWN_EFFECT = 8;\n STOP_MOVED = 9;\n NO_EFFECT = 10;\n ACCESSIBILITY_ISSUE = 11;\n }\n optional Effect effect = 7 [default = UNKNOWN_EFFECT];\n optional TranslatedString url = 8;\n optional TranslatedString header_text = 10;\n optional TranslatedString description_text = 11;\n}\n\nmessage TimeRange {\n optional uint64 start = 1;\n optional uint64 end = 2;\n}\n\nmessage Position {\n required float latitude = 1;\n required float longitude = 2;\n optional float bearing = 3;\n optional double odometer = 4;\n optional float speed = 5;\n}\n\nmessage TripDescriptor {\n optional string trip_id = 1;\n optional string route_id = 5;\n optional uint32 direction_id = 6;\n optional string start_time = 2;\n optional string start_date = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n ADDED = 1;\n UNSCHEDULED = 2;\n CANCELED = 3;\n }\n optional ScheduleRelationship schedule_relationship = 4;\n}\n\nmessage VehicleDescriptor {\n optional string id = 1;\n optional string label = 2;\n optional string license_plate = 3;\n}\n\nmessage EntitySelector {\n optional string agency_id = 1;\n optional string route_id = 2;\n optional int32 route_type = 3;\n optional TripDescriptor trip = 4;\n optional string stop_id = 5;\n}\n\nmessage TranslatedString {\n message Translation {\n required string text = 1;\n optional string language = 2;\n }\n repeated Translation translation = 1;\n}\n`;\n\n// Fetch protobuf data from URL or local file\n// Uses fetch API (available in modern browsers and Node.js 18+)\nasync function fetchProtobuf(source: string): Promise {\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n if (isUrl) {\n // Fetch from URL\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n }\n\n // Read from local file (Node.js only)\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return new Uint8Array(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));\n } catch (error) {\n throw new Error(`Failed to read GTFS-RT file from ${source}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // In browser, try fetch for relative paths\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n}\n\n// Load and parse GTFS-RT protobuf schema\nlet gtfsRtRoot: protobuf.Root | null = null;\n\nfunction loadGtfsRtProto(): protobuf.Root {\n if (!gtfsRtRoot) {\n gtfsRtRoot = protobuf.parse(GTFS_RT_PROTO).root;\n }\n return gtfsRtRoot;\n}\n\n// Convert camelCase object keys to snake_case\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction convertKeysToSnakeCase(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(convertKeysToSnakeCase);\n }\n if (typeof obj === 'object') {\n const result: Record = {};\n for (const key in obj as Record) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = convertKeysToSnakeCase((obj as Record)[key]);\n }\n }\n return result;\n }\n return obj;\n}\n\n// Parse TranslatedString to JSON\nfunction parseTranslatedString(ts: ProtobufTranslatedString | undefined): string | null {\n if (!ts || !ts.translation || ts.translation.length === 0) {\n return null;\n }\n return JSON.stringify({\n translation: ts.translation.map((t) => ({\n text: t.text,\n language: t.language || undefined\n }))\n });\n}\n\n// Insert alerts into database\nfunction insertAlerts(db: Database, alerts: ProtobufAlert[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_alerts (\n id, active_period, informed_entity, cause, effect,\n url, header_text, description_text, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const alert of alerts) {\n // Map camelCase protobuf fields to snake_case\n const activePeriod = alert.activePeriod || alert.active_period || [];\n const informedEntity = alert.informedEntity || alert.informed_entity || [];\n const headerText = alert.headerText || alert.header_text;\n const descriptionText = alert.descriptionText || alert.description_text;\n\n // Convert nested objects to snake_case\n const activePeriodSnake = convertKeysToSnakeCase(activePeriod);\n const informedEntitySnake = convertKeysToSnakeCase(informedEntity);\n\n stmt.run([\n alert.id,\n JSON.stringify(activePeriodSnake),\n JSON.stringify(informedEntitySnake),\n alert.cause || null,\n alert.effect || null,\n parseTranslatedString(alert.url),\n parseTranslatedString(headerText),\n parseTranslatedString(descriptionText),\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert vehicle positions into database\nfunction insertVehiclePositions(db: Database, positions: ProtobufVehiclePosition[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_vehicle_positions (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n latitude, longitude, bearing, odometer, speed,\n current_stop_sequence, stop_id, current_status, timestamp,\n congestion_level, occupancy_status, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const vp of positions) {\n const trip = vp.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = vp.vehicle?.id;\n const vehicleLabel = vp.vehicle?.label;\n const vehicleLicensePlate = vp.vehicle?.licensePlate || vp.vehicle?.license_plate;\n const currentStopSequence = vp.currentStopSequence || vp.current_stop_sequence;\n const stopId = vp.stopId || vp.stop_id;\n const currentStatus = vp.currentStatus || vp.current_status;\n const congestionLevel = vp.congestionLevel || vp.congestion_level;\n const occupancyStatus = vp.occupancyStatus || vp.occupancy_status;\n\n stmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n vp.position?.latitude || null,\n vp.position?.longitude || null,\n vp.position?.bearing || null,\n vp.position?.odometer || null,\n vp.position?.speed || null,\n currentStopSequence || null,\n stopId || null,\n currentStatus || null,\n vp.timestamp || null,\n congestionLevel || null,\n occupancyStatus || null,\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert trip updates into database\nfunction insertTripUpdates(db: Database, updates: ProtobufTripUpdate[], timestamp: number): void {\n const tripStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_trip_updates (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n timestamp, delay, schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const stopTimeStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_stop_time_updates (\n trip_id, stop_sequence, stop_id,\n arrival_delay, arrival_time, arrival_uncertainty,\n departure_delay, departure_time, departure_uncertainty,\n schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const tu of updates) {\n const trip = tu.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = tu.vehicle?.id;\n const vehicleLabel = tu.vehicle?.label;\n const vehicleLicensePlate = tu.vehicle?.licensePlate || tu.vehicle?.license_plate;\n const scheduleRelationship = trip.scheduleRelationship || trip.schedule_relationship;\n const stopTimeUpdate = tu.stopTimeUpdate || tu.stop_time_update;\n\n // Insert trip update\n tripStmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n tu.timestamp || null,\n tu.delay || null,\n scheduleRelationship || null,\n timestamp\n ]);\n\n // Insert stop time updates\n if (stopTimeUpdate) {\n for (const stu of stopTimeUpdate) {\n const stopSequence = stu.stopSequence || stu.stop_sequence;\n const stopId = stu.stopId || stu.stop_id;\n const scheduleRel = stu.scheduleRelationship || stu.schedule_relationship;\n\n stopTimeStmt.run([\n tripId,\n stopSequence || null,\n stopId || null,\n stu.arrival?.delay || null,\n stu.arrival?.time || null,\n stu.arrival?.uncertainty || null,\n stu.departure?.delay || null,\n stu.departure?.time || null,\n stu.departure?.uncertainty || null,\n scheduleRel || null,\n timestamp\n ]);\n }\n }\n }\n\n tripStmt.free();\n stopTimeStmt.free();\n}\n\n/**\n * Fetch and load GTFS Realtime data from multiple feed URLs\n * All feeds are fetched in parallel. If any feed fails, an error is thrown.\n */\nexport async function loadRealtimeData(db: Database, feedUrls: string[]): Promise {\n const root = loadGtfsRtProto();\n const FeedMessage = root.lookupType('transit_realtime.FeedMessage');\n\n // Fetch all feeds in parallel\n const fetchPromises = feedUrls.map(async (url) => {\n try {\n const data = await fetchProtobuf(url);\n const message = FeedMessage.decode(data);\n return FeedMessage.toObject(message, {\n longs: Number,\n enums: Number,\n bytes: String,\n defaults: false,\n arrays: true,\n objects: true,\n oneofs: true\n });\n } catch (error) {\n throw new Error(`Failed to fetch or parse GTFS-RT feed from ${url}: ${error instanceof Error ? error.message : String(error)}`);\n }\n });\n\n // Wait for all feeds - if any fails, this will throw\n const feeds = await Promise.all(fetchPromises);\n\n // Current timestamp for staleness tracking\n const now = Math.floor(Date.now() / 1000);\n\n // Collect all entities by type\n const allAlerts: ProtobufAlert[] = [];\n const allVehiclePositions: ProtobufVehiclePosition[] = [];\n const allTripUpdates: ProtobufTripUpdate[] = [];\n\n for (const feed of feeds) {\n if (!feed.entity) continue;\n\n for (const entity of feed.entity) {\n if (entity.alert) {\n allAlerts.push({ id: entity.id, ...entity.alert });\n }\n if (entity.vehicle) {\n allVehiclePositions.push(entity.vehicle);\n }\n if (entity.tripUpdate) {\n allTripUpdates.push(entity.tripUpdate);\n }\n }\n }\n\n // Insert into database\n if (allAlerts.length > 0) {\n insertAlerts(db, allAlerts, now);\n }\n if (allVehiclePositions.length > 0) {\n insertVehiclePositions(db, allVehiclePositions, now);\n }\n if (allTripUpdates.length > 0) {\n insertTripUpdates(db, allTripUpdates, now);\n }\n}\n","/**\n * Agency Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Agency } from '../types/gtfs';\n\nexport interface AgencyFilters {\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get agencies with optional filters\n */\nexport function getAgencies(db: Database, filters: AgencyFilters = {}): Agency[] {\n const { agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM agency';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY agency_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Get an agency by its agency_id\n */\nexport function getAgencyById(db: Database, agencyId: string): Agency | null {\n const stmt = db.prepare('SELECT * FROM agency WHERE agency_id = ?');\n stmt.bind([agencyId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToAgency(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all agencies\n */\nexport function getAllAgencies(db: Database, limit?: number): Agency[] {\n const sql = limit\n ? `SELECT * FROM agency ORDER BY agency_name LIMIT ${limit}`\n : 'SELECT * FROM agency ORDER BY agency_name';\n\n const stmt = db.prepare(sql);\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Convert database row to Agency object\n */\nfunction rowToAgency(row: Record): Agency {\n return {\n agency_id: String(row.agency_id),\n agency_name: String(row.agency_name),\n agency_url: String(row.agency_url),\n agency_timezone: String(row.agency_timezone),\n agency_lang: row.agency_lang ? String(row.agency_lang) : undefined,\n agency_phone: row.agency_phone ? String(row.agency_phone) : undefined,\n agency_fare_url: row.agency_fare_url ? String(row.agency_fare_url) : undefined,\n agency_email: row.agency_email ? String(row.agency_email) : undefined,\n };\n}\n","/**\n * Stop Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Stop } from '../types/gtfs';\n\nexport interface StopFilters {\n stopId?: string;\n stopCode?: string;\n name?: string;\n tripId?: string;\n limit?: number;\n}\n\n/**\n * Get stops with optional filters\n */\nexport function getStops(db: Database, filters: StopFilters = {}): Stop[] {\n const { stopId, stopCode, name, tripId, limit } = filters;\n\n // Handle special case: get stops by trip (requires JOIN)\n if (tripId) {\n return getStopsByTrip(db, tripId);\n }\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (stopId) {\n conditions.push('stop_id = ?');\n params.push(stopId);\n }\n\n if (stopCode) {\n conditions.push('stop_code = ?');\n params.push(stopCode);\n }\n\n if (name) {\n conditions.push('stop_name LIKE ?');\n params.push(`%${name}%`);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM stops';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY stop_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get a stop by its stop_id\n */\nexport function getStopById(db: Database, stopId: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_id = ?');\n stmt.bind([stopId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get a stop by its stop_code\n */\nexport function getStopByCode(db: Database, stopCode: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_code = ?');\n stmt.bind([stopCode]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Search stops by name (case-insensitive, partial match)\n */\nexport function searchStopsByName(db: Database, name: string, limit = 50): Stop[] {\n const stmt = db.prepare(\n 'SELECT * FROM stops WHERE stop_name LIKE ? ORDER BY stop_name LIMIT ?'\n );\n stmt.bind([`%${name}%`, limit]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get all stops\n */\nexport function getAllStops(db: Database, limit?: number): Stop[] {\n const sql = limit\n ? `SELECT * FROM stops ORDER BY stop_name LIMIT ${limit}`\n : 'SELECT * FROM stops ORDER BY stop_name';\n\n const stmt = db.prepare(sql);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get stops for a given trip (ordered by stop_sequence)\n */\nexport function getStopsByTrip(db: Database, tripId: string): Stop[] {\n const stmt = db.prepare(`\n SELECT s.* FROM stops s\n INNER JOIN stop_times st ON s.stop_id = st.stop_id\n WHERE st.trip_id = ?\n ORDER BY st.stop_sequence\n `);\n stmt.bind([tripId]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Convert database row to Stop object\n */\nfunction rowToStop(row: Record): Stop {\n return {\n stop_id: String(row.stop_id),\n stop_name: String(row.stop_name),\n stop_lat: Number(row.stop_lat),\n stop_lon: Number(row.stop_lon),\n stop_code: row.stop_code ? String(row.stop_code) : undefined,\n stop_desc: row.stop_desc ? String(row.stop_desc) : undefined,\n zone_id: row.zone_id ? String(row.zone_id) : undefined,\n stop_url: row.stop_url ? String(row.stop_url) : undefined,\n location_type: row.location_type !== null ? Number(row.location_type) : undefined,\n parent_station: row.parent_station ? String(row.parent_station) : undefined,\n stop_timezone: row.stop_timezone ? String(row.stop_timezone) : undefined,\n wheelchair_boarding: row.wheelchair_boarding !== null ? Number(row.wheelchair_boarding) : undefined,\n level_id: row.level_id ? String(row.level_id) : undefined,\n platform_code: row.platform_code ? String(row.platform_code) : undefined,\n };\n}\n","/**\n * Route Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Route } from '../types/gtfs';\n\nexport interface RouteFilters {\n routeId?: string;\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get routes with optional filters\n */\nexport function getRoutes(db: Database, filters: RouteFilters = {}): Route[] {\n const { routeId, agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM routes';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY route_short_name, route_long_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get a route by its route_id\n */\nexport function getRouteById(db: Database, routeId: string): Route | null {\n const stmt = db.prepare('SELECT * FROM routes WHERE route_id = ?');\n stmt.bind([routeId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToRoute(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all routes\n */\nexport function getAllRoutes(db: Database, limit?: number): Route[] {\n const sql = limit\n ? `SELECT * FROM routes ORDER BY route_short_name, route_long_name LIMIT ${limit}`\n : 'SELECT * FROM routes ORDER BY route_short_name, route_long_name';\n\n const stmt = db.prepare(sql);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get routes by agency\n */\nexport function getRoutesByAgency(db: Database, agencyId: string): Route[] {\n const stmt = db.prepare(\n 'SELECT * FROM routes WHERE agency_id = ? ORDER BY route_short_name, route_long_name'\n );\n stmt.bind([agencyId]);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Convert database row to Route object\n */\nfunction rowToRoute(row: Record): Route {\n return {\n route_id: String(row.route_id),\n route_short_name: String(row.route_short_name),\n route_long_name: String(row.route_long_name),\n route_type: Number(row.route_type),\n agency_id: row.agency_id ? String(row.agency_id) : undefined,\n route_desc: row.route_desc ? String(row.route_desc) : undefined,\n route_url: row.route_url ? String(row.route_url) : undefined,\n route_color: row.route_color ? String(row.route_color) : undefined,\n route_text_color: row.route_text_color ? String(row.route_text_color) : undefined,\n route_sort_order: row.route_sort_order !== null ? Number(row.route_sort_order) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n };\n}\n","/**\n * Calendar Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Calendar, CalendarDate } from '../types/gtfs';\n\n/**\n * Get active service IDs for a given date\n */\nexport function getActiveServiceIds(db: Database, date: string): string[] {\n const serviceIds = new Set();\n\n // Parse date (format: YYYYMMDD)\n const year = parseInt(date.substring(0, 4));\n const month = parseInt(date.substring(4, 6));\n const day = parseInt(date.substring(6, 8));\n const dateObj = new Date(year, month - 1, day);\n const dayOfWeek = dateObj.getDay(); // 0 = Sunday, 1 = Monday, etc.\n\n // Map day of week to GTFS calendar field\n const dayFields = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];\n const dayField = dayFields[dayOfWeek];\n\n // Check calendar.txt for regular service\n const calendarStmt = db.prepare(\n `SELECT service_id FROM calendar\n WHERE ${dayField} = 1\n AND start_date <= ?\n AND end_date >= ?`\n );\n calendarStmt.bind([date, date]);\n\n while (calendarStmt.step()) {\n const row = calendarStmt.getAsObject() as { service_id: string };\n serviceIds.add(row.service_id);\n }\n calendarStmt.free();\n\n // Check calendar_dates.txt for exceptions\n const exceptionsStmt = db.prepare('SELECT service_id, exception_type FROM calendar_dates WHERE date = ?');\n exceptionsStmt.bind([date]);\n\n while (exceptionsStmt.step()) {\n const row = exceptionsStmt.getAsObject() as { service_id: string; exception_type: number };\n if (row.exception_type === 1) {\n // Service added\n serviceIds.add(row.service_id);\n } else if (row.exception_type === 2) {\n // Service removed\n serviceIds.delete(row.service_id);\n }\n }\n exceptionsStmt.free();\n\n return Array.from(serviceIds);\n}\n\n/**\n * Get calendar entry by service_id\n */\nexport function getCalendarByServiceId(db: Database, serviceId: string): Calendar | null {\n const stmt = db.prepare('SELECT * FROM calendar WHERE service_id = ?');\n stmt.bind([serviceId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToCalendar(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get calendar date exceptions for a service\n */\nexport function getCalendarDates(db: Database, serviceId: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE service_id = ? ORDER BY date');\n stmt.bind([serviceId]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Get calendar date exceptions for a specific date\n */\nexport function getCalendarDatesForDate(db: Database, date: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE date = ?');\n stmt.bind([date]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Convert database row to Calendar object\n */\nfunction rowToCalendar(row: Record): Calendar {\n return {\n service_id: String(row.service_id),\n monday: Number(row.monday),\n tuesday: Number(row.tuesday),\n wednesday: Number(row.wednesday),\n thursday: Number(row.thursday),\n friday: Number(row.friday),\n saturday: Number(row.saturday),\n sunday: Number(row.sunday),\n start_date: String(row.start_date),\n end_date: String(row.end_date),\n };\n}\n\n/**\n * Convert database row to CalendarDate object\n */\nfunction rowToCalendarDate(row: Record): CalendarDate {\n return {\n service_id: String(row.service_id),\n date: String(row.date),\n exception_type: Number(row.exception_type),\n };\n}\n","/**\n * Trip Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Trip } from '../types/gtfs';\nimport type { TripRealtime, VehiclePosition } from '../types/gtfs-rt';\n\nexport interface TripFilters {\n tripId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface TripWithRealtime extends Trip {\n realtime?: TripRealtime;\n}\n\n/**\n * Merge realtime data with trips\n */\nfunction mergeRealtimeData(\n trips: Trip[],\n db: Database,\n stalenessThreshold: number\n): TripWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n const tripIds = trips.map(t => t.trip_id);\n if (tripIds.length === 0) return trips;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n\n // Get vehicle positions\n const vpStmt = db.prepare(`\n SELECT * FROM rt_vehicle_positions\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n vpStmt.bind([...tripIds, staleThreshold]);\n\n const vpMap = new Map>();\n while (vpStmt.step()) {\n const row = vpStmt.getAsObject() as Record;\n vpMap.set(String(row.trip_id), row);\n }\n vpStmt.free();\n\n // Get trip updates\n const tuStmt = db.prepare(`\n SELECT * FROM rt_trip_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n tuStmt.bind([...tripIds, staleThreshold]);\n\n const tuMap = new Map>();\n while (tuStmt.step()) {\n const row = tuStmt.getAsObject() as Record;\n tuMap.set(String(row.trip_id), row);\n }\n tuStmt.free();\n\n // Merge realtime data\n return trips.map((trip): TripWithRealtime => {\n const vpRow = vpMap.get(trip.trip_id);\n const tuRow = tuMap.get(trip.trip_id);\n\n if (!vpRow && !tuRow) {\n return { ...trip, realtime: { vehicle_position: null, trip_update: null } };\n }\n\n const realtime: TripRealtime = {\n vehicle_position: null,\n trip_update: null\n };\n\n // Parse vehicle position\n if (vpRow) {\n const vp: VehiclePosition = {\n trip_id: String(vpRow.trip_id),\n route_id: vpRow.route_id ? String(vpRow.route_id) : undefined,\n rt_last_updated: Number(vpRow.rt_last_updated)\n };\n\n if (vpRow.vehicle_id || vpRow.vehicle_label || vpRow.vehicle_license_plate) {\n vp.vehicle = {\n id: vpRow.vehicle_id ? String(vpRow.vehicle_id) : undefined,\n label: vpRow.vehicle_label ? String(vpRow.vehicle_label) : undefined,\n license_plate: vpRow.vehicle_license_plate ? String(vpRow.vehicle_license_plate) : undefined\n };\n }\n\n if (vpRow.latitude !== null && vpRow.longitude !== null) {\n vp.position = {\n latitude: Number(vpRow.latitude),\n longitude: Number(vpRow.longitude),\n bearing: vpRow.bearing !== null ? Number(vpRow.bearing) : undefined,\n odometer: vpRow.odometer !== null ? Number(vpRow.odometer) : undefined,\n speed: vpRow.speed !== null ? Number(vpRow.speed) : undefined\n };\n }\n\n if (vpRow.current_stop_sequence !== null) vp.current_stop_sequence = Number(vpRow.current_stop_sequence);\n if (vpRow.stop_id) vp.stop_id = String(vpRow.stop_id);\n if (vpRow.current_status !== null) vp.current_status = Number(vpRow.current_status);\n if (vpRow.timestamp !== null) vp.timestamp = Number(vpRow.timestamp);\n if (vpRow.congestion_level !== null) vp.congestion_level = Number(vpRow.congestion_level);\n if (vpRow.occupancy_status !== null) vp.occupancy_status = Number(vpRow.occupancy_status);\n\n realtime.vehicle_position = vp;\n }\n\n // Parse trip update\n if (tuRow) {\n realtime.trip_update = {\n delay: tuRow.delay !== null ? Number(tuRow.delay) : undefined,\n schedule_relationship: tuRow.schedule_relationship !== null ? Number(tuRow.schedule_relationship) : undefined\n };\n }\n\n return { ...trip, realtime };\n });\n}\n\n/**\n * Get trips with optional filters\n */\nexport function getTrips(\n db: Database,\n filters: TripFilters = {},\n stalenessThreshold: number = 120\n): Trip[] | TripWithRealtime[] {\n const { tripId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with routes table\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsRoutesJoin ? 't.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (routeId) {\n conditions.push(needsRoutesJoin ? 't.route_id = ?' : 'route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.service_id IN (${placeholders})` : `service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push(needsRoutesJoin ? 't.direction_id = ?' : 'direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = needsRoutesJoin\n ? 'SELECT t.* FROM trips t INNER JOIN routes r ON t.route_id = r.route_id'\n : 'SELECT * FROM trips';\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(trips, db, stalenessThreshold);\n }\n\n return trips;\n}\n\n/**\n * Get a trip by its trip_id\n */\nexport function getTripById(db: Database, tripId: string): Trip | null {\n const stmt = db.prepare('SELECT * FROM trips WHERE trip_id = ?');\n stmt.bind([tripId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToTrip(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get trips for a route\n */\nexport function getTripsByRoute(db: Database, routeId: string): Trip[] {\n const stmt = db.prepare('SELECT * FROM trips WHERE route_id = ?');\n stmt.bind([routeId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route and service (active on a given date)\n */\nexport function getTripsByRouteAndService(\n db: Database,\n routeId: string,\n serviceIds: string[]\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders})`\n );\n stmt.bind([routeId, ...serviceIds]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route, service, and direction\n */\nexport function getTripsByRouteServiceAndDirection(\n db: Database,\n routeId: string,\n serviceIds: string[],\n directionId: number\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders}) AND direction_id = ?`\n );\n stmt.bind([routeId, ...serviceIds, directionId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get all trips for a service (active on a given date)\n */\nexport function getTripsByService(db: Database, serviceIds: string[]): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(`SELECT * FROM trips WHERE service_id IN (${placeholders})`);\n stmt.bind(serviceIds);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Convert database row to Trip object\n */\nfunction rowToTrip(row: Record): Trip {\n return {\n trip_id: String(row.trip_id),\n route_id: String(row.route_id),\n service_id: String(row.service_id),\n trip_headsign: row.trip_headsign ? String(row.trip_headsign) : undefined,\n trip_short_name: row.trip_short_name ? String(row.trip_short_name) : undefined,\n direction_id: row.direction_id !== null ? Number(row.direction_id) : undefined,\n block_id: row.block_id ? String(row.block_id) : undefined,\n shape_id: row.shape_id ? String(row.shape_id) : undefined,\n wheelchair_accessible: row.wheelchair_accessible !== null ? Number(row.wheelchair_accessible) : undefined,\n bikes_allowed: row.bikes_allowed !== null ? Number(row.bikes_allowed) : undefined,\n };\n}\n","/**\n * Stop Time Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { StopTime } from '../types/gtfs';\nimport type { StopTimeRealtime } from '../types/gtfs-rt';\n\nexport interface StopTimeFilters {\n tripId?: string;\n stopId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface StopTimeWithRealtime extends StopTime {\n realtime?: StopTimeRealtime;\n}\n\n/**\n * Merge realtime data with stop times\n */\nfunction mergeRealtimeData(\n stopTimes: StopTime[],\n db: Database,\n stalenessThreshold: number\n): StopTimeWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n // Build map of trip_id -> stop times for this query\n const tripIds = Array.from(new Set(stopTimes.map(st => st.trip_id)));\n if (tripIds.length === 0) return stopTimes;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(`\n SELECT trip_id, stop_sequence, stop_id,\n arrival_delay, departure_delay, schedule_relationship\n FROM rt_stop_time_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n stmt.bind([...tripIds, staleThreshold]);\n\n // Build map of trip_id+stop_sequence -> RT data\n const rtMap = new Map();\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const key = `${row.trip_id}_${row.stop_sequence}`;\n rtMap.set(key, {\n arrival_delay: row.arrival_delay !== null ? Number(row.arrival_delay) : undefined,\n departure_delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n });\n }\n stmt.free();\n\n // Merge RT data with stop times\n return stopTimes.map((st): StopTimeWithRealtime => {\n const key = `${st.trip_id}_${st.stop_sequence}`;\n const rtData = rtMap.get(key);\n\n if (rtData) {\n return { ...st, realtime: rtData };\n }\n return st;\n });\n}\n\n/**\n * Get stop times with optional filters\n */\nexport function getStopTimes(\n db: Database,\n filters: StopTimeFilters = {},\n stalenessThreshold: number = 120\n): StopTime[] | StopTimeWithRealtime[] {\n const { tripId, stopId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with trips and/or routes table\n const needsTripsJoin = routeId || serviceIds || directionId !== undefined || agencyId !== undefined;\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsTripsJoin ? 'st.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (stopId) {\n conditions.push(needsTripsJoin ? 'st.stop_id = ?' : 'stop_id = ?');\n params.push(stopId);\n }\n\n if (routeId) {\n conditions.push('t.route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(`t.service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push('t.direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql: string;\n if (needsRoutesJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id INNER JOIN routes r ON t.route_id = r.route_id';\n } else if (needsTripsJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id';\n } else {\n sql = 'SELECT * FROM stop_times';\n }\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n\n // Order by stop_sequence if filtering by trip, otherwise by arrival_time\n sql += tripId ? ' ORDER BY stop_sequence' : ' ORDER BY arrival_time';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(stopTimes, db, stalenessThreshold);\n }\n\n return stopTimes;\n}\n\n/**\n * Get stop times for a trip\n */\nexport function getStopTimesByTrip(db: Database, tripId: string): StopTime[] {\n const stmt = db.prepare('SELECT * FROM stop_times WHERE trip_id = ? ORDER BY stop_sequence');\n stmt.bind([tripId]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop\n */\nexport function getStopTimesByStop(db: Database, stopId: string, limit = 100): StopTime[] {\n const stmt = db.prepare(\n 'SELECT * FROM stop_times WHERE stop_id = ? ORDER BY arrival_time LIMIT ?'\n );\n stmt.bind([stopId, limit]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop and specific trips (filtered by route/date)\n */\nexport function getStopTimesByStopAndTrips(\n db: Database,\n stopId: string,\n tripIds: string[]\n): StopTime[] {\n if (tripIds.length === 0) {\n return [];\n }\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM stop_times\n WHERE stop_id = ? AND trip_id IN (${placeholders})\n ORDER BY arrival_time`\n );\n stmt.bind([stopId, ...tripIds]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop, route, and direction on a specific date\n */\nexport function getStopTimesForStopRouteDirection(\n db: Database,\n stopId: string,\n routeId: string,\n serviceIds: string[],\n directionId?: number\n): StopTime[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n\n let sql = `\n SELECT st.* FROM stop_times st\n INNER JOIN trips t ON st.trip_id = t.trip_id\n WHERE st.stop_id = ?\n AND t.route_id = ?\n AND t.service_id IN (${placeholders})\n `;\n\n const params: (string | number)[] = [stopId, routeId, ...serviceIds];\n\n if (directionId !== undefined) {\n sql += ' AND t.direction_id = ?';\n params.push(directionId);\n }\n\n sql += ' ORDER BY st.arrival_time';\n\n const stmt = db.prepare(sql);\n stmt.bind(params);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Convert database row to StopTime object\n */\nfunction rowToStopTime(row: Record): StopTime {\n return {\n trip_id: String(row.trip_id),\n arrival_time: String(row.arrival_time),\n departure_time: String(row.departure_time),\n stop_id: String(row.stop_id),\n stop_sequence: Number(row.stop_sequence),\n stop_headsign: row.stop_headsign ? String(row.stop_headsign) : undefined,\n pickup_type: row.pickup_type !== null ? Number(row.pickup_type) : undefined,\n drop_off_type: row.drop_off_type !== null ? Number(row.drop_off_type) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n shape_dist_traveled: row.shape_dist_traveled !== null ? Number(row.shape_dist_traveled) : undefined,\n timepoint: row.timepoint !== null ? Number(row.timepoint) : undefined,\n };\n}\n","import type { Database } from 'sql.js';\nimport type { Alert, EntitySelector, TimeRange, TranslatedString } from '../types/gtfs-rt';\nimport type { AlertFilters } from '../types/gtfs-rt';\n\nexport type { AlertFilters };\n\n/**\n * Parse JSON fields from database\n */\nfunction parseAlert(row: Record): Alert {\n return {\n id: String(row.id),\n active_period: row.active_period ? JSON.parse(String(row.active_period)) as TimeRange[] : [],\n informed_entity: row.informed_entity ? JSON.parse(String(row.informed_entity)) as EntitySelector[] : [],\n cause: row.cause ? Number(row.cause) : undefined,\n effect: row.effect ? Number(row.effect) : undefined,\n url: row.url ? JSON.parse(String(row.url)) as TranslatedString : undefined,\n header_text: row.header_text ? JSON.parse(String(row.header_text)) as TranslatedString : undefined,\n description_text: row.description_text ? JSON.parse(String(row.description_text)) as TranslatedString : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n}\n\n/**\n * Check if an alert is currently active based on its active_period\n */\nfunction isAlertActive(alert: Alert, now: number): boolean {\n // If no active periods defined, assume always active\n if (!alert.active_period || alert.active_period.length === 0) {\n return true;\n }\n\n // Check if current time falls within any active period\n for (const period of alert.active_period) {\n const start = period.start || 0;\n const end = period.end || Number.MAX_SAFE_INTEGER;\n\n if (now >= start && now <= end) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if an alert affects the specified entity\n */\nfunction alertAffectsEntity(alert: Alert, filters: AlertFilters): boolean {\n if (!alert.informed_entity || alert.informed_entity.length === 0) {\n return true; // No specific entities, assume it affects all\n }\n\n for (const entity of alert.informed_entity) {\n // Check route_id\n if (filters.routeId && entity.route_id === filters.routeId) {\n return true;\n }\n\n // Check stop_id\n if (filters.stopId && entity.stop_id === filters.stopId) {\n return true;\n }\n\n // Check trip_id\n if (filters.tripId && entity.trip?.trip_id === filters.tripId) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Get alerts with optional filters\n */\nexport function getAlerts(db: Database, filters: AlertFilters = {}, stalenessThreshold: number = 120): Alert[] {\n const {\n alertId,\n activeOnly,\n routeId,\n stopId,\n tripId,\n cause,\n effect,\n limit\n } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by alert ID\n if (alertId) {\n conditions.push('id = ?');\n params.push(alertId);\n }\n\n // Filter by cause\n if (cause !== undefined) {\n conditions.push('cause = ?');\n params.push(cause);\n }\n\n // Filter by effect\n if (effect !== undefined) {\n conditions.push('effect = ?');\n params.push(effect);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_alerts';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const alerts: Alert[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const alert = parseAlert(row);\n\n // Apply activeOnly filter in application code\n if (activeOnly && !isAlertActive(alert, now)) {\n continue;\n }\n\n // Apply entity filters in application code (since informed_entity is JSON)\n if (routeId || stopId || tripId) {\n if (!alertAffectsEntity(alert, filters)) {\n continue;\n }\n }\n\n alerts.push(alert);\n }\n\n stmt.free();\n return alerts;\n}\n\n/**\n * Get alert by ID\n */\nexport function getAlertById(db: Database, alertId: string, stalenessThreshold: number = 120): Alert | null {\n const alerts = getAlerts(db, { alertId, limit: 1 }, stalenessThreshold);\n return alerts.length > 0 ? alerts[0] : null;\n}\n","import type { Database} from 'sql.js';\nimport type { VehiclePosition } from '../types/gtfs-rt';\nimport type { VehiclePositionFilters } from '../types/gtfs-rt';\n\nexport type { VehiclePositionFilters };\n\n/**\n * Parse vehicle position from database row\n */\nfunction parseVehiclePosition(row: Record): VehiclePosition {\n const vp: VehiclePosition = {\n trip_id: String(row.trip_id),\n route_id: row.route_id ? String(row.route_id) : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n\n // Vehicle descriptor\n if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) {\n vp.vehicle = {\n id: row.vehicle_id ? String(row.vehicle_id) : undefined,\n label: row.vehicle_label ? String(row.vehicle_label) : undefined,\n license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : undefined\n };\n }\n\n // Position\n if (row.latitude !== null && row.longitude !== null) {\n vp.position = {\n latitude: Number(row.latitude),\n longitude: Number(row.longitude),\n bearing: row.bearing !== null ? Number(row.bearing) : undefined,\n odometer: row.odometer !== null ? Number(row.odometer) : undefined,\n speed: row.speed !== null ? Number(row.speed) : undefined\n };\n }\n\n // Other fields\n if (row.current_stop_sequence !== null) {\n vp.current_stop_sequence = Number(row.current_stop_sequence);\n }\n if (row.stop_id) {\n vp.stop_id = String(row.stop_id);\n }\n if (row.current_status !== null) {\n vp.current_status = Number(row.current_status);\n }\n if (row.timestamp !== null) {\n vp.timestamp = Number(row.timestamp);\n }\n if (row.congestion_level !== null) {\n vp.congestion_level = Number(row.congestion_level);\n }\n if (row.occupancy_status !== null) {\n vp.occupancy_status = Number(row.occupancy_status);\n }\n\n return vp;\n}\n\n/**\n * Get vehicle positions with optional filters\n */\nexport function getVehiclePositions(\n db: Database,\n filters: VehiclePositionFilters = {},\n stalenessThreshold: number = 120\n): VehiclePosition[] {\n const { tripId, routeId, vehicleId, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by route_id\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n // Filter by vehicle_id\n if (vehicleId) {\n conditions.push('vehicle_id = ?');\n params.push(vehicleId);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_vehicle_positions';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const positions: VehiclePosition[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n positions.push(parseVehiclePosition(row));\n }\n\n stmt.free();\n return positions;\n}\n\n/**\n * Get vehicle position by trip ID\n */\nexport function getVehiclePositionByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): VehiclePosition | null {\n const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold);\n return positions.length > 0 ? positions[0] : null;\n}\n","/**\n * GTFS Realtime TypeScript types\n * Based on GTFS Realtime v2.0 specification\n */\n\n// Enum types from GTFS-RT specification\n\nexport enum ScheduleRelationship {\n SCHEDULED = 0,\n ADDED = 1,\n UNSCHEDULED = 2,\n CANCELED = 3,\n SKIPPED = 4,\n NO_DATA = 5\n}\n\nexport enum VehicleStopStatus {\n INCOMING_AT = 0,\n STOPPED_AT = 1,\n IN_TRANSIT_TO = 2\n}\n\nexport enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0,\n RUNNING_SMOOTHLY = 1,\n STOP_AND_GO = 2,\n CONGESTION = 3,\n SEVERE_CONGESTION = 4\n}\n\nexport enum OccupancyStatus {\n EMPTY = 0,\n MANY_SEATS_AVAILABLE = 1,\n FEW_SEATS_AVAILABLE = 2,\n STANDING_ROOM_ONLY = 3,\n CRUSHED_STANDING_ROOM_ONLY = 4,\n FULL = 5,\n NOT_ACCEPTING_PASSENGERS = 6\n}\n\nexport enum AlertCause {\n UNKNOWN_CAUSE = 1,\n OTHER_CAUSE = 2,\n TECHNICAL_PROBLEM = 3,\n STRIKE = 4,\n DEMONSTRATION = 5,\n ACCIDENT = 6,\n HOLIDAY = 7,\n WEATHER = 8,\n MAINTENANCE = 9,\n CONSTRUCTION = 10,\n POLICE_ACTIVITY = 11,\n MEDICAL_EMERGENCY = 12\n}\n\nexport enum AlertEffect {\n NO_SERVICE = 1,\n REDUCED_SERVICE = 2,\n SIGNIFICANT_DELAYS = 3,\n DETOUR = 4,\n ADDITIONAL_SERVICE = 5,\n MODIFIED_SERVICE = 6,\n OTHER_EFFECT = 7,\n UNKNOWN_EFFECT = 8,\n STOP_MOVED = 9,\n NO_EFFECT = 10,\n ACCESSIBILITY_ISSUE = 11\n}\n\n// Main GTFS-RT types\n\nexport interface TranslatedString {\n translation: Array<{\n text: string;\n language?: string;\n }>;\n}\n\nexport interface EntitySelector {\n agency_id?: string;\n route_id?: string;\n route_type?: number;\n trip?: {\n trip_id?: string;\n route_id?: string;\n direction_id?: number;\n start_time?: string;\n start_date?: string;\n schedule_relationship?: ScheduleRelationship;\n };\n stop_id?: string;\n}\n\nexport interface TimeRange {\n start?: number; // UNIX timestamp\n end?: number; // UNIX timestamp\n}\n\nexport interface Alert {\n id: string;\n active_period: TimeRange[];\n informed_entity: EntitySelector[];\n cause?: AlertCause;\n effect?: AlertEffect;\n url?: TranslatedString;\n header_text?: TranslatedString;\n description_text?: TranslatedString;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface Position {\n latitude: number;\n longitude: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\nexport interface VehicleDescriptor {\n id?: string;\n label?: string;\n license_plate?: string;\n}\n\nexport interface VehiclePosition {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n position?: Position;\n current_stop_sequence?: number;\n stop_id?: string;\n current_status?: VehicleStopStatus;\n timestamp?: number;\n congestion_level?: CongestionLevel;\n occupancy_status?: OccupancyStatus;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface StopTimeEvent {\n delay?: number; // seconds\n time?: number; // UNIX timestamp (absolute time)\n uncertainty?: number;\n}\n\nexport interface StopTimeUpdate {\n stop_sequence?: number;\n stop_id?: string;\n arrival?: StopTimeEvent;\n departure?: StopTimeEvent;\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripUpdate {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n stop_time_update: StopTimeUpdate[];\n timestamp?: number;\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n rt_last_updated: number; // UNIX timestamp\n}\n\n// Enhanced types for queries with realtime data\n\nexport interface StopTimeRealtime {\n arrival_delay?: number; // seconds\n departure_delay?: number; // seconds\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripRealtime {\n vehicle_position?: VehiclePosition | null;\n trip_update?: {\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n } | null;\n}\n\n// Filter types for realtime queries\n\nexport interface AlertFilters {\n alertId?: string;\n activeOnly?: boolean;\n routeId?: string;\n stopId?: string;\n tripId?: string;\n cause?: AlertCause;\n effect?: AlertEffect;\n limit?: number;\n}\n\nexport interface VehiclePositionFilters {\n tripId?: string;\n routeId?: string;\n vehicleId?: string;\n limit?: number;\n}\n\n// Configuration\n\nexport interface RealtimeConfig {\n feedUrls?: string[];\n stalenessThreshold?: number; // seconds, default 120\n}\n"],"mappings":"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","names":["response","arrayBuffer","mergeRealtimeData","ScheduleRelationship","VehicleStopStatus","CongestionLevel","OccupancyStatus","AlertCause","AlertEffect"]} \ No newline at end of file +{"version":3,"sources":["../src/gtfs-sqljs.ts","../src/schema/schema.ts","../src/loaders/zip-loader.ts","../src/loaders/csv-parser.ts","../src/loaders/data-loader.ts","../src/schema/gtfs-rt-schema.ts","../src/loaders/gtfs-rt-loader.ts","../src/queries/agencies.ts","../src/queries/stops.ts","../src/queries/routes.ts","../src/queries/calendar.ts","../src/queries/rt-vehicle-positions.ts","../src/queries/trips.ts","../src/queries/stop-times.ts","../src/queries/rt-alerts.ts","../src/queries/rt-trip-updates.ts","../src/queries/rt-stop-time-updates.ts","../src/types/gtfs-rt.ts"],"sourcesContent":["/**\n * Main GtfsSqlJs Class\n */\n\nimport initSqlJs, { type Database, type SqlJsStatic } from 'sql.js';\nimport { getAllCreateStatements } from './schema/schema';\nimport { loadGTFSZip } from './loaders/zip-loader';\nimport { loadGTFSData } from './loaders/data-loader';\nimport { createRealtimeTables, clearRealtimeData as clearRTData } from './schema/gtfs-rt-schema';\nimport { loadRealtimeData } from './loaders/gtfs-rt-loader';\n\n// Query methods\nimport { getAgencyById, getAgencies, type AgencyFilters } from './queries/agencies';\nimport { getStopById, getStops, type StopFilters } from './queries/stops';\nimport { getRouteById, getRoutes, type RouteFilters } from './queries/routes';\nimport {\n getActiveServiceIds,\n getCalendarByServiceId,\n getCalendarDates,\n getCalendarDatesForDate,\n} from './queries/calendar';\nimport { getTripById, getTrips, type TripFilters, type TripWithRealtime } from './queries/trips';\nimport { getStopTimesByTrip, getStopTimes, type StopTimeFilters, type StopTimeWithRealtime } from './queries/stop-times';\nimport { getAlerts as getAlertsQuery, getAlertById, getAllAlerts, type AlertFilters } from './queries/rt-alerts';\nimport { getVehiclePositions as getVehiclePositionsQuery, getVehiclePositionByTripId, getAllVehiclePositions, type VehiclePositionFilters } from './queries/rt-vehicle-positions';\nimport { getTripUpdates, getTripUpdateByTripId, getAllTripUpdates, type TripUpdateFilters } from './queries/rt-trip-updates';\nimport { getStopTimeUpdates, getStopTimeUpdatesByTripId, getAllStopTimeUpdates, type StopTimeUpdateFilters, type StopTimeUpdateWithMetadata } from './queries/rt-stop-time-updates';\n\n// Types\nimport type { Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate } from './types/gtfs';\nimport type { Alert, VehiclePosition, TripUpdate } from './types/gtfs-rt';\n\n// Export filter types for users\nexport type { AgencyFilters, StopFilters, RouteFilters, TripFilters, StopTimeFilters, AlertFilters, VehiclePositionFilters, TripUpdateFilters, StopTimeUpdateFilters };\n// Export RT types\nexport type { Alert, VehiclePosition, TripUpdate, StopTimeUpdateWithMetadata, TripWithRealtime, StopTimeWithRealtime };\n\nexport interface GtfsSqlJsOptions {\n /**\n * Path or URL to GTFS ZIP file\n */\n zipPath?: string;\n\n /**\n * Pre-loaded SQLite database as ArrayBuffer\n */\n database?: ArrayBuffer;\n\n /**\n * Optional: Custom SQL.js instance\n */\n SQL?: SqlJsStatic;\n\n /**\n * Optional: Path to SQL.js WASM file (for custom loading)\n */\n locateFile?: (filename: string) => string;\n\n /**\n * Optional: Array of GTFS filenames to skip importing (e.g., ['shapes.txt'])\n * Tables will be created but no data will be imported for these files\n */\n skipFiles?: string[];\n\n /**\n * Optional: Array of GTFS-RT feed URLs for realtime data\n */\n realtimeFeedUrls?: string[];\n\n /**\n * Optional: Staleness threshold in seconds (default: 120)\n * Realtime data older than this will be excluded from queries\n */\n stalenessThreshold?: number;\n}\n\nexport class GtfsSqlJs {\n private db: Database | null = null;\n private SQL: SqlJsStatic | null = null;\n private realtimeFeedUrls: string[] = [];\n private stalenessThreshold: number = 120;\n\n /**\n * Private constructor - use static factory methods instead\n */\n private constructor() {}\n\n /**\n * Create GtfsSqlJs instance from GTFS ZIP file\n */\n static async fromZip(\n zipPath: string,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromZip(zipPath, options);\n return instance;\n }\n\n /**\n * Create GtfsSqlJs instance from existing SQLite database\n */\n static async fromDatabase(\n database: ArrayBuffer,\n options: Omit = {}\n ): Promise {\n const instance = new GtfsSqlJs();\n await instance.initFromDatabase(database, options);\n return instance;\n }\n\n /**\n * Initialize from ZIP file\n */\n private async initFromZip(zipPath: string, options: Omit): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Create new database\n this.db = new this.SQL.Database();\n\n // Create GTFS schema\n const createStatements = getAllCreateStatements();\n for (const statement of createStatements) {\n this.db.run(statement);\n }\n\n // Create GTFS-RT tables\n createRealtimeTables(this.db);\n\n // Load GTFS data\n const files = await loadGTFSZip(zipPath);\n await loadGTFSData(this.db, files, options.skipFiles);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Initialize from existing database\n */\n private async initFromDatabase(\n database: ArrayBuffer,\n options: Omit\n ): Promise {\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Load existing database\n this.db = new this.SQL.Database(new Uint8Array(database));\n\n // Ensure RT tables exist (in case loading old database)\n createRealtimeTables(this.db);\n\n // Set RT configuration\n if (options.realtimeFeedUrls) {\n this.realtimeFeedUrls = options.realtimeFeedUrls;\n }\n if (options.stalenessThreshold !== undefined) {\n this.stalenessThreshold = options.stalenessThreshold;\n }\n }\n\n /**\n * Export database to ArrayBuffer\n */\n export(): ArrayBuffer {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n\n const data = this.db.export();\n // Create a new ArrayBuffer and copy the data to ensure proper type\n const buffer = new ArrayBuffer(data.length);\n new Uint8Array(buffer).set(data);\n return buffer;\n }\n\n /**\n * Close the database connection\n */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n /**\n * Get direct access to the database (for advanced queries)\n */\n getDatabase(): Database {\n if (!this.db) {\n throw new Error('Database not initialized');\n }\n return this.db;\n }\n\n // ==================== Agency Methods ====================\n\n /**\n * Get an agency by its agency_id\n */\n getAgencyById(agencyId: string): Agency | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencyById(this.db, agencyId);\n }\n\n /**\n * Get agencies with optional filters\n */\n getAgencies(filters?: AgencyFilters): Agency[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAgencies(this.db, filters);\n }\n\n // ==================== Stop Methods ====================\n\n /**\n * Get a stop by its stop_id\n */\n getStopById(stopId: string): Stop | null {\n if (!this.db) throw new Error('Database not initialized');\n return getStopById(this.db, stopId);\n }\n\n /**\n * Get stops with optional filters\n */\n getStops(filters?: StopFilters): Stop[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStops(this.db, filters);\n }\n\n // ==================== Route Methods ====================\n\n /**\n * Get a route by its route_id\n */\n getRouteById(routeId: string): Route | null {\n if (!this.db) throw new Error('Database not initialized');\n return getRouteById(this.db, routeId);\n }\n\n /**\n * Get routes with optional filters\n */\n getRoutes(filters?: RouteFilters): Route[] {\n if (!this.db) throw new Error('Database not initialized');\n return getRoutes(this.db, filters);\n }\n\n // ==================== Calendar Methods ====================\n\n /**\n * Get active service IDs for a given date (YYYYMMDD format)\n */\n getActiveServiceIds(date: string): string[] {\n if (!this.db) throw new Error('Database not initialized');\n return getActiveServiceIds(this.db, date);\n }\n\n /**\n * Get calendar entry by service_id\n */\n getCalendarByServiceId(serviceId: string): Calendar | null {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarByServiceId(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a service\n */\n getCalendarDates(serviceId: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDates(this.db, serviceId);\n }\n\n /**\n * Get calendar date exceptions for a specific date\n */\n getCalendarDatesForDate(date: string): CalendarDate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getCalendarDatesForDate(this.db, date);\n }\n\n // ==================== Trip Methods ====================\n\n /**\n * Get a trip by its trip_id\n */\n getTripById(tripId: string): Trip | null {\n if (!this.db) throw new Error('Database not initialized');\n return getTripById(this.db, tripId);\n }\n\n /**\n * Get trips with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get all trips for a route on a specific date\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', date: '20240115' });\n *\n * @example\n * // Get all trips for a route going in one direction\n * const trips = gtfs.getTrips({ routeId: 'ROUTE_1', directionId: 0 });\n */\n getTrips(filters?: TripFilters & { date?: string }): Trip[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getTrips(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Stop Time Methods ====================\n\n /**\n * Get stop times for a trip (ordered by stop_sequence)\n */\n getStopTimesByTrip(tripId: string): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimesByTrip(this.db, tripId);\n }\n\n /**\n * Get stop times with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID\n * @param filters.stopId - Filter by stop ID\n * @param filters.routeId - Filter by route ID\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID\n * @param filters.agencyId - Filter by agency ID\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get stop times for a specific trip\n * const stopTimes = gtfs.getStopTimes({ tripId: 'TRIP_123' });\n *\n * @example\n * // Get stop times at a stop for a specific route on a date\n * const stopTimes = gtfs.getStopTimes({\n * stopId: 'STOP_123',\n * routeId: 'ROUTE_1',\n * date: '20240115'\n * });\n */\n getStopTimes(filters?: StopTimeFilters & { date?: string }): StopTime[] {\n if (!this.db) throw new Error('Database not initialized');\n\n // Handle date parameter by converting it to serviceIds\n const { date, ...restFilters } = filters || {};\n const finalFilters = { ...restFilters };\n\n if (date) {\n const serviceIds = getActiveServiceIds(this.db, date);\n finalFilters.serviceIds = serviceIds;\n }\n\n return getStopTimes(this.db, finalFilters, this.stalenessThreshold);\n }\n\n // ==================== Realtime Methods ====================\n\n /**\n * Set GTFS-RT feed URLs\n */\n setRealtimeFeedUrls(urls: string[]): void {\n this.realtimeFeedUrls = urls;\n }\n\n /**\n * Get currently configured GTFS-RT feed URLs\n */\n getRealtimeFeedUrls(): string[] {\n return [...this.realtimeFeedUrls];\n }\n\n /**\n * Set staleness threshold in seconds\n */\n setStalenessThreshold(seconds: number): void {\n this.stalenessThreshold = seconds;\n }\n\n /**\n * Get current staleness threshold\n */\n getStalenessThreshold(): number {\n return this.stalenessThreshold;\n }\n\n /**\n * Fetch and load GTFS Realtime data from configured feed URLs or provided URLs\n * @param urls - Optional array of feed URLs. If not provided, uses configured feed URLs\n */\n async fetchRealtimeData(urls?: string[]): Promise {\n if (!this.db) throw new Error('Database not initialized');\n\n const feedUrls = urls || this.realtimeFeedUrls;\n if (feedUrls.length === 0) {\n throw new Error('No realtime feed URLs configured. Use setRealtimeFeedUrls() or pass urls parameter.');\n }\n\n await loadRealtimeData(this.db, feedUrls);\n }\n\n /**\n * Clear all realtime data from the database\n */\n clearRealtimeData(): void {\n if (!this.db) throw new Error('Database not initialized');\n clearRTData(this.db);\n }\n\n /**\n * Get alerts with optional filters\n */\n getAlerts(filters?: AlertFilters): Alert[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get alert by ID\n */\n getAlertById(alertId: string): Alert | null {\n if (!this.db) throw new Error('Database not initialized');\n return getAlertById(this.db, alertId, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle positions with optional filters\n */\n getVehiclePositions(filters?: VehiclePositionFilters): VehiclePosition[] {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionsQuery(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get vehicle position by trip ID\n */\n getVehiclePositionByTripId(tripId: string): VehiclePosition | null {\n if (!this.db) throw new Error('Database not initialized');\n return getVehiclePositionByTripId(this.db, tripId, this.stalenessThreshold);\n }\n\n /**\n * Get trip updates with optional filters\n */\n getTripUpdates(filters?: TripUpdateFilters): TripUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getTripUpdates(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get trip update by trip ID\n */\n getTripUpdateByTripId(tripId: string): TripUpdate | null {\n if (!this.db) throw new Error('Database not initialized');\n return getTripUpdateByTripId(this.db, tripId, this.stalenessThreshold);\n }\n\n /**\n * Get stop time updates with optional filters\n */\n getStopTimeUpdates(filters?: StopTimeUpdateFilters): import('./types/gtfs-rt').StopTimeUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimeUpdates(this.db, filters, this.stalenessThreshold);\n }\n\n /**\n * Get stop time updates for a specific trip\n */\n getStopTimeUpdatesByTripId(tripId: string): import('./types/gtfs-rt').StopTimeUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getStopTimeUpdatesByTripId(this.db, tripId, this.stalenessThreshold);\n }\n\n // ==================== Debug Export Methods ====================\n // These methods export all realtime data without staleness filtering\n // for debugging purposes\n\n /**\n * Export all alerts without staleness filtering (for debugging)\n */\n debugExportAllAlerts(): Alert[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllAlerts(this.db);\n }\n\n /**\n * Export all vehicle positions without staleness filtering (for debugging)\n */\n debugExportAllVehiclePositions(): VehiclePosition[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllVehiclePositions(this.db);\n }\n\n /**\n * Export all trip updates without staleness filtering (for debugging)\n */\n debugExportAllTripUpdates(): TripUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllTripUpdates(this.db);\n }\n\n /**\n * Export all stop time updates without staleness filtering (for debugging)\n * Returns extended type with trip_id and rt_last_updated for debugging purposes\n */\n debugExportAllStopTimeUpdates(): StopTimeUpdateWithMetadata[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllStopTimeUpdates(this.db);\n }\n}\n","/**\n * SQLite Schema Definitions for GTFS Data\n * Matches required/optional fields from GTFS specification\n */\n\nexport interface TableSchema {\n name: string;\n columns: ColumnDefinition[];\n indexes?: IndexDefinition[];\n}\n\nexport interface ColumnDefinition {\n name: string;\n type: 'TEXT' | 'INTEGER' | 'REAL';\n required: boolean;\n primaryKey?: boolean;\n}\n\nexport interface IndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n}\n\nexport const GTFS_SCHEMA: TableSchema[] = [\n {\n name: 'agency',\n columns: [\n { name: 'agency_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'agency_name', type: 'TEXT', required: true },\n { name: 'agency_url', type: 'TEXT', required: true },\n { name: 'agency_timezone', type: 'TEXT', required: true },\n { name: 'agency_lang', type: 'TEXT', required: false },\n { name: 'agency_phone', type: 'TEXT', required: false },\n { name: 'agency_fare_url', type: 'TEXT', required: false },\n { name: 'agency_email', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'stops',\n columns: [\n { name: 'stop_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'stop_name', type: 'TEXT', required: true },\n { name: 'stop_lat', type: 'REAL', required: true },\n { name: 'stop_lon', type: 'REAL', required: true },\n { name: 'stop_code', type: 'TEXT', required: false },\n { name: 'stop_desc', type: 'TEXT', required: false },\n { name: 'zone_id', type: 'TEXT', required: false },\n { name: 'stop_url', type: 'TEXT', required: false },\n { name: 'location_type', type: 'INTEGER', required: false },\n { name: 'parent_station', type: 'TEXT', required: false },\n { name: 'stop_timezone', type: 'TEXT', required: false },\n { name: 'wheelchair_boarding', type: 'INTEGER', required: false },\n { name: 'level_id', type: 'TEXT', required: false },\n { name: 'platform_code', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_stops_stop_code', columns: ['stop_code'] },\n { name: 'idx_stops_stop_name', columns: ['stop_name'] },\n { name: 'idx_stops_parent_station', columns: ['parent_station'] },\n ],\n },\n {\n name: 'routes',\n columns: [\n { name: 'route_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_short_name', type: 'TEXT', required: true },\n { name: 'route_long_name', type: 'TEXT', required: true },\n { name: 'route_type', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_desc', type: 'TEXT', required: false },\n { name: 'route_url', type: 'TEXT', required: false },\n { name: 'route_color', type: 'TEXT', required: false },\n { name: 'route_text_color', type: 'TEXT', required: false },\n { name: 'route_sort_order', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_routes_agency_id', columns: ['agency_id'] },\n ],\n },\n {\n name: 'trips',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'route_id', type: 'TEXT', required: true },\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'trip_headsign', type: 'TEXT', required: false },\n { name: 'trip_short_name', type: 'TEXT', required: false },\n { name: 'direction_id', type: 'INTEGER', required: false },\n { name: 'block_id', type: 'TEXT', required: false },\n { name: 'shape_id', type: 'TEXT', required: false },\n { name: 'wheelchair_accessible', type: 'INTEGER', required: false },\n { name: 'bikes_allowed', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_trips_route_id', columns: ['route_id'] },\n { name: 'idx_trips_service_id', columns: ['service_id'] },\n { name: 'idx_trips_route_service', columns: ['route_id', 'service_id'] },\n ],\n },\n {\n name: 'stop_times',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'arrival_time', type: 'TEXT', required: true },\n { name: 'departure_time', type: 'TEXT', required: true },\n { name: 'stop_id', type: 'TEXT', required: true },\n { name: 'stop_sequence', type: 'INTEGER', required: true },\n { name: 'stop_headsign', type: 'TEXT', required: false },\n { name: 'pickup_type', type: 'INTEGER', required: false },\n { name: 'drop_off_type', type: 'INTEGER', required: false },\n { name: 'continuous_pickup', type: 'INTEGER', required: false },\n { name: 'continuous_drop_off', type: 'INTEGER', required: false },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n { name: 'timepoint', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_stop_times_trip_id', columns: ['trip_id'] },\n { name: 'idx_stop_times_stop_id', columns: ['stop_id'] },\n { name: 'idx_stop_times_trip_sequence', columns: ['trip_id', 'stop_sequence'] },\n ],\n },\n {\n name: 'calendar',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'monday', type: 'INTEGER', required: true },\n { name: 'tuesday', type: 'INTEGER', required: true },\n { name: 'wednesday', type: 'INTEGER', required: true },\n { name: 'thursday', type: 'INTEGER', required: true },\n { name: 'friday', type: 'INTEGER', required: true },\n { name: 'saturday', type: 'INTEGER', required: true },\n { name: 'sunday', type: 'INTEGER', required: true },\n { name: 'start_date', type: 'TEXT', required: true },\n { name: 'end_date', type: 'TEXT', required: true },\n ],\n },\n {\n name: 'calendar_dates',\n columns: [\n { name: 'service_id', type: 'TEXT', required: true },\n { name: 'date', type: 'TEXT', required: true },\n { name: 'exception_type', type: 'INTEGER', required: true },\n ],\n indexes: [\n { name: 'idx_calendar_dates_service_id', columns: ['service_id'] },\n { name: 'idx_calendar_dates_date', columns: ['date'] },\n { name: 'idx_calendar_dates_service_date', columns: ['service_id', 'date'] },\n ],\n },\n {\n name: 'fare_attributes',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'price', type: 'REAL', required: true },\n { name: 'currency_type', type: 'TEXT', required: true },\n { name: 'payment_method', type: 'INTEGER', required: true },\n { name: 'transfers', type: 'INTEGER', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'transfer_duration', type: 'INTEGER', required: false },\n ],\n },\n {\n name: 'fare_rules',\n columns: [\n { name: 'fare_id', type: 'TEXT', required: true },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'origin_id', type: 'TEXT', required: false },\n { name: 'destination_id', type: 'TEXT', required: false },\n { name: 'contains_id', type: 'TEXT', required: false },\n ],\n indexes: [\n { name: 'idx_fare_rules_fare_id', columns: ['fare_id'] },\n { name: 'idx_fare_rules_route_id', columns: ['route_id'] },\n ],\n },\n {\n name: 'shapes',\n columns: [\n { name: 'shape_id', type: 'TEXT', required: true },\n { name: 'shape_pt_lat', type: 'REAL', required: true },\n { name: 'shape_pt_lon', type: 'REAL', required: true },\n { name: 'shape_pt_sequence', type: 'INTEGER', required: true },\n { name: 'shape_dist_traveled', type: 'REAL', required: false },\n ],\n indexes: [\n { name: 'idx_shapes_shape_id', columns: ['shape_id'] },\n { name: 'idx_shapes_shape_sequence', columns: ['shape_id', 'shape_pt_sequence'] },\n ],\n },\n {\n name: 'frequencies',\n columns: [\n { name: 'trip_id', type: 'TEXT', required: true },\n { name: 'start_time', type: 'TEXT', required: true },\n { name: 'end_time', type: 'TEXT', required: true },\n { name: 'headway_secs', type: 'INTEGER', required: true },\n { name: 'exact_times', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_frequencies_trip_id', columns: ['trip_id'] },\n ],\n },\n {\n name: 'transfers',\n columns: [\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'transfer_type', type: 'INTEGER', required: true },\n { name: 'min_transfer_time', type: 'INTEGER', required: false },\n ],\n indexes: [\n { name: 'idx_transfers_from_stop_id', columns: ['from_stop_id'] },\n { name: 'idx_transfers_to_stop_id', columns: ['to_stop_id'] },\n ],\n },\n {\n name: 'pathways',\n columns: [\n { name: 'pathway_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'from_stop_id', type: 'TEXT', required: true },\n { name: 'to_stop_id', type: 'TEXT', required: true },\n { name: 'pathway_mode', type: 'INTEGER', required: true },\n { name: 'is_bidirectional', type: 'INTEGER', required: true },\n { name: 'length', type: 'REAL', required: false },\n { name: 'traversal_time', type: 'INTEGER', required: false },\n { name: 'stair_count', type: 'INTEGER', required: false },\n { name: 'max_slope', type: 'REAL', required: false },\n { name: 'min_width', type: 'REAL', required: false },\n { name: 'signposted_as', type: 'TEXT', required: false },\n { name: 'reversed_signposted_as', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'levels',\n columns: [\n { name: 'level_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'level_index', type: 'REAL', required: true },\n { name: 'level_name', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'feed_info',\n columns: [\n { name: 'feed_publisher_name', type: 'TEXT', required: true },\n { name: 'feed_publisher_url', type: 'TEXT', required: true },\n { name: 'feed_lang', type: 'TEXT', required: true },\n { name: 'default_lang', type: 'TEXT', required: false },\n { name: 'feed_start_date', type: 'TEXT', required: false },\n { name: 'feed_end_date', type: 'TEXT', required: false },\n { name: 'feed_version', type: 'TEXT', required: false },\n { name: 'feed_contact_email', type: 'TEXT', required: false },\n { name: 'feed_contact_url', type: 'TEXT', required: false },\n ],\n },\n {\n name: 'attributions',\n columns: [\n { name: 'attribution_id', type: 'TEXT', required: true, primaryKey: true },\n { name: 'organization_name', type: 'TEXT', required: true },\n { name: 'agency_id', type: 'TEXT', required: false },\n { name: 'route_id', type: 'TEXT', required: false },\n { name: 'trip_id', type: 'TEXT', required: false },\n { name: 'is_producer', type: 'INTEGER', required: false },\n { name: 'is_operator', type: 'INTEGER', required: false },\n { name: 'is_authority', type: 'INTEGER', required: false },\n { name: 'attribution_url', type: 'TEXT', required: false },\n { name: 'attribution_email', type: 'TEXT', required: false },\n { name: 'attribution_phone', type: 'TEXT', required: false },\n ],\n },\n];\n\n/**\n * Generate CREATE TABLE SQL statement from schema definition\n */\nexport function generateCreateTableSQL(schema: TableSchema): string {\n const columns = schema.columns.map((col) => {\n const parts = [col.name, col.type];\n if (col.primaryKey) {\n parts.push('PRIMARY KEY');\n }\n if (col.required && !col.primaryKey) {\n parts.push('NOT NULL');\n }\n return parts.join(' ');\n });\n\n return `CREATE TABLE IF NOT EXISTS ${schema.name} (${columns.join(', ')})`;\n}\n\n/**\n * Generate CREATE INDEX SQL statements from schema definition\n */\nexport function generateCreateIndexSQL(schema: TableSchema): string[] {\n if (!schema.indexes) {\n return [];\n }\n\n return schema.indexes.map((idx) => {\n const unique = idx.unique ? 'UNIQUE ' : '';\n const columns = idx.columns.join(', ');\n return `CREATE ${unique}INDEX IF NOT EXISTS ${idx.name} ON ${schema.name} (${columns})`;\n });\n}\n\n/**\n * Initialize all GTFS tables in the database\n */\nexport function getAllCreateStatements(): string[] {\n const statements: string[] = [];\n\n for (const schema of GTFS_SCHEMA) {\n statements.push(generateCreateTableSQL(schema));\n statements.push(...generateCreateIndexSQL(schema));\n }\n\n return statements;\n}\n","/**\n * ZIP Loader for GTFS files\n */\n\nimport JSZip from 'jszip';\n\nexport interface GTFSFiles {\n [filename: string]: string;\n}\n\n/**\n * Fetch and extract GTFS ZIP file\n * Works in both browser and Node.js environments\n */\nexport async function loadGTFSZip(source: string | ArrayBuffer | Uint8Array): Promise {\n let zipData: ArrayBuffer | Uint8Array;\n\n // If source is a string, treat it as URL or file path\n if (typeof source === 'string') {\n zipData = await fetchZip(source);\n } else {\n zipData = source;\n }\n\n // Load ZIP file\n const zip = await JSZip.loadAsync(zipData);\n\n // Extract all .txt files (GTFS files)\n const files: GTFSFiles = {};\n const filePromises: Promise[] = [];\n\n zip.forEach((relativePath, file) => {\n // Only process .txt files\n if (!file.dir && relativePath.endsWith('.txt')) {\n const fileName = relativePath.split('/').pop() || relativePath;\n filePromises.push(\n file.async('string').then((content) => {\n files[fileName] = content;\n })\n );\n }\n });\n\n await Promise.all(filePromises);\n\n return files;\n}\n\n/**\n * Fetch ZIP file from URL or file path\n */\nasync function fetchZip(source: string): Promise {\n // Check if source is a URL\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n // For URLs, always use fetch\n if (isUrl) {\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n throw new Error('fetch is not available to load URL');\n }\n\n // For non-URLs, try Node.js fs first, fall back to fetch for browser\n // Check if we're in Node.js environment\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n // In Node.js, treat as file path\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);\n } catch (error) {\n throw new Error(`Failed to read GTFS ZIP file: ${error}`);\n }\n }\n\n // In browser, treat as relative URL and use fetch\n if (typeof fetch !== 'undefined') {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS ZIP: ${response.status} ${response.statusText}`);\n }\n return await response.arrayBuffer();\n }\n\n throw new Error('No method available to load ZIP file');\n}\n\n/**\n * Mapping of GTFS file names to database table names\n */\nexport const GTFS_FILE_MAPPING: Record = {\n 'agency.txt': 'agency',\n 'stops.txt': 'stops',\n 'routes.txt': 'routes',\n 'trips.txt': 'trips',\n 'stop_times.txt': 'stop_times',\n 'calendar.txt': 'calendar',\n 'calendar_dates.txt': 'calendar_dates',\n 'fare_attributes.txt': 'fare_attributes',\n 'fare_rules.txt': 'fare_rules',\n 'shapes.txt': 'shapes',\n 'frequencies.txt': 'frequencies',\n 'transfers.txt': 'transfers',\n 'pathways.txt': 'pathways',\n 'levels.txt': 'levels',\n 'feed_info.txt': 'feed_info',\n 'attributions.txt': 'attributions',\n};\n","/**\n * CSV Parser for GTFS files using papaparse\n */\n\nimport Papa from 'papaparse';\n\nexport interface ParsedCSV {\n headers: string[];\n rows: Record[];\n}\n\n/**\n * Parse CSV text into structured data using papaparse\n */\nexport function parseCSV(text: string): ParsedCSV {\n const result = Papa.parse(text, {\n header: true,\n skipEmptyLines: true,\n transformHeader: (header) => header.trim(),\n transform: (value) => value.trim(),\n });\n\n if (result.errors.length > 0) {\n console.warn('CSV parsing warnings:', result.errors);\n }\n\n const headers = result.meta.fields || [];\n const rows = result.data as Record[];\n\n return { headers, rows };\n}\n\n/**\n * Convert parsed row to typed object with proper type conversions\n */\nexport function convertRowTypes(\n row: Record,\n columnTypes: Record\n): Record {\n const result: Record = {};\n\n // Iterate over all expected columns, not just the ones present in the row\n for (const [key, type] of Object.entries(columnTypes)) {\n const value = row[key];\n\n // Handle missing or empty values\n if (value === undefined || value === null || value === '') {\n result[key] = null;\n continue;\n }\n\n if (type === 'INTEGER') {\n const parsed = parseInt(value, 10);\n result[key] = isNaN(parsed) ? null : parsed;\n } else if (type === 'REAL') {\n const parsed = parseFloat(value);\n result[key] = isNaN(parsed) ? null : parsed;\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n","/**\n * Data Loader - Loads GTFS data into SQLite database\n */\n\nimport type { Database } from 'sql.js';\nimport { parseCSV, convertRowTypes } from './csv-parser';\nimport { GTFS_SCHEMA, type TableSchema } from '../schema/schema';\nimport type { GTFSFiles } from './zip-loader';\n\n/**\n * Load GTFS files into SQLite database\n * @param skipFiles - Optional array of filenames to skip importing (tables will be created but remain empty)\n */\nexport async function loadGTFSData(db: Database, files: GTFSFiles, skipFiles?: string[]): Promise {\n // Map of file names to table schemas\n const fileToSchema: Map = new Map();\n for (const schema of GTFS_SCHEMA) {\n // Match file names like agency.txt to table name 'agency'\n fileToSchema.set(`${schema.name}.txt`, schema);\n }\n\n // Normalize skipFiles to a Set for faster lookup\n const skipSet = new Set(skipFiles?.map(f => f.toLowerCase()) || []);\n\n // Process each file\n for (const [fileName, content] of Object.entries(files)) {\n const schema = fileToSchema.get(fileName);\n if (!schema) {\n // Skip unknown files\n continue;\n }\n\n // Skip if in skip list\n if (skipSet.has(fileName.toLowerCase())) {\n console.log(`Skipping import of ${fileName} (table ${schema.name} created but empty)`);\n continue;\n }\n\n await loadTableData(db, schema, content);\n }\n}\n\n/**\n * Load data for a single table\n */\nasync function loadTableData(db: Database, schema: TableSchema, csvContent: string): Promise {\n const { headers, rows } = parseCSV(csvContent);\n\n if (rows.length === 0) {\n return;\n }\n\n // Build column type map\n const columnTypes: Record = {};\n for (const col of schema.columns) {\n columnTypes[col.name] = col.type;\n }\n\n // Prepare INSERT statement\n const columns = headers.filter((h) => schema.columns.some((c) => c.name === h));\n const placeholders = columns.map(() => '?').join(', ');\n const insertSQL = `INSERT INTO ${schema.name} (${columns.join(', ')}) VALUES (${placeholders})`;\n\n const stmt = db.prepare(insertSQL);\n\n // Insert each row\n for (const row of rows) {\n const typedRow = convertRowTypes(row, columnTypes);\n const values = columns.map((col) => {\n const value = typedRow[col];\n // Handle undefined, null, or empty values\n return value === null || value === undefined ? null : value;\n });\n\n try {\n stmt.run(values);\n } catch (error) {\n console.error(`Error inserting row into ${schema.name}:`, error);\n console.error('Row data:', row);\n throw error;\n }\n }\n\n stmt.free();\n}\n","import type { Database } from 'sql.js';\n\n/**\n * Create GTFS Realtime tables in the database\n */\nexport function createRealtimeTables(db: Database): void {\n // Alerts table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_alerts (\n id TEXT PRIMARY KEY,\n active_period TEXT, -- JSON array of TimeRange objects\n informed_entity TEXT, -- JSON array of EntitySelector objects\n cause INTEGER,\n effect INTEGER,\n url TEXT, -- JSON TranslatedString\n header_text TEXT, -- JSON TranslatedString\n description_text TEXT, -- JSON TranslatedString\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n // Create index on rt_last_updated for staleness filtering\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_alerts_updated ON rt_alerts(rt_last_updated)');\n\n // Vehicle Positions table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_vehicle_positions (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n latitude REAL,\n longitude REAL,\n bearing REAL,\n odometer REAL,\n speed REAL,\n current_stop_sequence INTEGER,\n stop_id TEXT,\n current_status INTEGER,\n timestamp INTEGER,\n congestion_level INTEGER,\n occupancy_status INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_updated ON rt_vehicle_positions(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_vehicle_positions_route ON rt_vehicle_positions(route_id)');\n\n // Trip Updates table\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_trip_updates (\n trip_id TEXT PRIMARY KEY,\n route_id TEXT,\n vehicle_id TEXT,\n vehicle_label TEXT,\n vehicle_license_plate TEXT,\n timestamp INTEGER,\n delay INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_updated ON rt_trip_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_trip_updates_route ON rt_trip_updates(route_id)');\n\n // Stop Time Updates table (child of trip updates)\n db.run(`\n CREATE TABLE IF NOT EXISTS rt_stop_time_updates (\n trip_id TEXT NOT NULL,\n stop_sequence INTEGER,\n stop_id TEXT,\n arrival_delay INTEGER,\n arrival_time INTEGER,\n arrival_uncertainty INTEGER,\n departure_delay INTEGER,\n departure_time INTEGER,\n departure_uncertainty INTEGER,\n schedule_relationship INTEGER,\n rt_last_updated INTEGER NOT NULL,\n PRIMARY KEY (trip_id, stop_sequence),\n FOREIGN KEY (trip_id) REFERENCES rt_trip_updates(trip_id) ON DELETE CASCADE\n )\n `);\n\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_updated ON rt_stop_time_updates(rt_last_updated)');\n db.run('CREATE INDEX IF NOT EXISTS idx_rt_stop_time_updates_stop ON rt_stop_time_updates(stop_id)');\n}\n\n/**\n * Clear all realtime data from the database\n */\nexport function clearRealtimeData(db: Database): void {\n db.run('DELETE FROM rt_alerts');\n db.run('DELETE FROM rt_vehicle_positions');\n db.run('DELETE FROM rt_trip_updates');\n db.run('DELETE FROM rt_stop_time_updates');\n}\n","import type { Database } from 'sql.js';\nimport protobuf from 'protobufjs';\n\n// Types for protobuf decoded objects\ninterface ProtobufTranslation {\n text: string;\n language?: string;\n}\n\ninterface ProtobufTranslatedString {\n translation: ProtobufTranslation[];\n}\n\ninterface ProtobufAlert {\n id: string;\n activePeriod?: unknown[];\n active_period?: unknown[];\n informedEntity?: unknown[];\n informed_entity?: unknown[];\n cause?: number;\n effect?: number;\n url?: ProtobufTranslatedString;\n headerText?: ProtobufTranslatedString;\n header_text?: ProtobufTranslatedString;\n descriptionText?: ProtobufTranslatedString;\n description_text?: ProtobufTranslatedString;\n}\n\ninterface ProtobufTripDescriptor {\n tripId?: string;\n trip_id?: string;\n routeId?: string;\n route_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n}\n\ninterface ProtobufVehicleDescriptor {\n id?: string;\n label?: string;\n licensePlate?: string;\n license_plate?: string;\n}\n\ninterface ProtobufPosition {\n latitude?: number;\n longitude?: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\ninterface ProtobufVehiclePosition {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n position?: ProtobufPosition;\n currentStopSequence?: number;\n current_stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n currentStatus?: number;\n current_status?: number;\n timestamp?: number;\n congestionLevel?: number;\n congestion_level?: number;\n occupancyStatus?: number;\n occupancy_status?: number;\n}\n\ninterface ProtobufStopTimeEvent {\n delay?: number;\n time?: number;\n uncertainty?: number;\n}\n\ninterface ProtobufStopTimeUpdate {\n stopSequence?: number;\n stop_sequence?: number;\n stopId?: string;\n stop_id?: string;\n scheduleRelationship?: number;\n schedule_relationship?: number;\n arrival?: ProtobufStopTimeEvent;\n departure?: ProtobufStopTimeEvent;\n}\n\ninterface ProtobufTripUpdate {\n trip?: ProtobufTripDescriptor;\n vehicle?: ProtobufVehicleDescriptor;\n timestamp?: number;\n delay?: number;\n stopTimeUpdate?: ProtobufStopTimeUpdate[];\n stop_time_update?: ProtobufStopTimeUpdate[];\n}\n\n// GTFS Realtime protobuf definition (v2.0)\n// Source: https://github.com/google/transit/blob/master/gtfs-realtime/proto/gtfs-realtime.proto\nconst GTFS_RT_PROTO = `\nsyntax = \"proto2\";\noption java_package = \"com.google.transit.realtime\";\npackage transit_realtime;\n\nmessage FeedMessage {\n required FeedHeader header = 1;\n repeated FeedEntity entity = 2;\n}\n\nmessage FeedHeader {\n required string gtfs_realtime_version = 1;\n enum Incrementality {\n FULL_DATASET = 0;\n DIFFERENTIAL = 1;\n }\n optional Incrementality incrementality = 2 [default = FULL_DATASET];\n optional uint64 timestamp = 3;\n}\n\nmessage FeedEntity {\n required string id = 1;\n optional bool is_deleted = 2 [default = false];\n optional TripUpdate trip_update = 3;\n optional VehiclePosition vehicle = 4;\n optional Alert alert = 5;\n}\n\nmessage TripUpdate {\n required TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 3;\n repeated StopTimeUpdate stop_time_update = 2;\n optional uint64 timestamp = 4;\n optional int32 delay = 5;\n\n message StopTimeEvent {\n optional int32 delay = 1;\n optional int64 time = 2;\n optional int32 uncertainty = 3;\n }\n\n message StopTimeUpdate {\n optional uint32 stop_sequence = 1;\n optional string stop_id = 4;\n optional StopTimeEvent arrival = 2;\n optional StopTimeEvent departure = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n SKIPPED = 1;\n NO_DATA = 2;\n }\n optional ScheduleRelationship schedule_relationship = 5 [default = SCHEDULED];\n }\n}\n\nmessage VehiclePosition {\n optional TripDescriptor trip = 1;\n optional VehicleDescriptor vehicle = 8;\n optional Position position = 2;\n optional uint32 current_stop_sequence = 3;\n optional string stop_id = 7;\n enum VehicleStopStatus {\n INCOMING_AT = 0;\n STOPPED_AT = 1;\n IN_TRANSIT_TO = 2;\n }\n optional VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];\n optional uint64 timestamp = 5;\n enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0;\n RUNNING_SMOOTHLY = 1;\n STOP_AND_GO = 2;\n CONGESTION = 3;\n SEVERE_CONGESTION = 4;\n }\n optional CongestionLevel congestion_level = 6;\n enum OccupancyStatus {\n EMPTY = 0;\n MANY_SEATS_AVAILABLE = 1;\n FEW_SEATS_AVAILABLE = 2;\n STANDING_ROOM_ONLY = 3;\n CRUSHED_STANDING_ROOM_ONLY = 4;\n FULL = 5;\n NOT_ACCEPTING_PASSENGERS = 6;\n }\n optional OccupancyStatus occupancy_status = 9;\n}\n\nmessage Alert {\n repeated TimeRange active_period = 1;\n repeated EntitySelector informed_entity = 5;\n\n enum Cause {\n UNKNOWN_CAUSE = 1;\n OTHER_CAUSE = 2;\n TECHNICAL_PROBLEM = 3;\n STRIKE = 4;\n DEMONSTRATION = 5;\n ACCIDENT = 6;\n HOLIDAY = 7;\n WEATHER = 8;\n MAINTENANCE = 9;\n CONSTRUCTION = 10;\n POLICE_ACTIVITY = 11;\n MEDICAL_EMERGENCY = 12;\n }\n optional Cause cause = 6 [default = UNKNOWN_CAUSE];\n\n enum Effect {\n NO_SERVICE = 1;\n REDUCED_SERVICE = 2;\n SIGNIFICANT_DELAYS = 3;\n DETOUR = 4;\n ADDITIONAL_SERVICE = 5;\n MODIFIED_SERVICE = 6;\n OTHER_EFFECT = 7;\n UNKNOWN_EFFECT = 8;\n STOP_MOVED = 9;\n NO_EFFECT = 10;\n ACCESSIBILITY_ISSUE = 11;\n }\n optional Effect effect = 7 [default = UNKNOWN_EFFECT];\n optional TranslatedString url = 8;\n optional TranslatedString header_text = 10;\n optional TranslatedString description_text = 11;\n}\n\nmessage TimeRange {\n optional uint64 start = 1;\n optional uint64 end = 2;\n}\n\nmessage Position {\n required float latitude = 1;\n required float longitude = 2;\n optional float bearing = 3;\n optional double odometer = 4;\n optional float speed = 5;\n}\n\nmessage TripDescriptor {\n optional string trip_id = 1;\n optional string route_id = 5;\n optional uint32 direction_id = 6;\n optional string start_time = 2;\n optional string start_date = 3;\n enum ScheduleRelationship {\n SCHEDULED = 0;\n ADDED = 1;\n UNSCHEDULED = 2;\n CANCELED = 3;\n }\n optional ScheduleRelationship schedule_relationship = 4;\n}\n\nmessage VehicleDescriptor {\n optional string id = 1;\n optional string label = 2;\n optional string license_plate = 3;\n}\n\nmessage EntitySelector {\n optional string agency_id = 1;\n optional string route_id = 2;\n optional int32 route_type = 3;\n optional TripDescriptor trip = 4;\n optional string stop_id = 5;\n}\n\nmessage TranslatedString {\n message Translation {\n required string text = 1;\n optional string language = 2;\n }\n repeated Translation translation = 1;\n}\n`;\n\n// Fetch protobuf data from URL or local file\n// Uses fetch API (available in modern browsers and Node.js 18+)\nasync function fetchProtobuf(source: string): Promise {\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n if (isUrl) {\n // Fetch from URL\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n }\n\n // Read from local file (Node.js only)\n const isNode = typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n if (isNode) {\n try {\n const fs = await import('fs');\n const buffer = await fs.promises.readFile(source);\n return new Uint8Array(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));\n } catch (error) {\n throw new Error(`Failed to read GTFS-RT file from ${source}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // In browser, try fetch for relative paths\n const response = await fetch(source, {\n headers: {\n 'Accept': 'application/x-protobuf, application/octet-stream'\n }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch GTFS-RT feed from ${source}: ${response.status} ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n}\n\n// Load and parse GTFS-RT protobuf schema\nlet gtfsRtRoot: protobuf.Root | null = null;\n\nfunction loadGtfsRtProto(): protobuf.Root {\n if (!gtfsRtRoot) {\n gtfsRtRoot = protobuf.parse(GTFS_RT_PROTO).root;\n }\n return gtfsRtRoot;\n}\n\n// Convert camelCase object keys to snake_case\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction convertKeysToSnakeCase(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(convertKeysToSnakeCase);\n }\n if (typeof obj === 'object') {\n const result: Record = {};\n for (const key in obj as Record) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = convertKeysToSnakeCase((obj as Record)[key]);\n }\n }\n return result;\n }\n return obj;\n}\n\n// Parse TranslatedString to JSON\nfunction parseTranslatedString(ts: ProtobufTranslatedString | undefined): string | null {\n if (!ts || !ts.translation || ts.translation.length === 0) {\n return null;\n }\n return JSON.stringify({\n translation: ts.translation.map((t) => ({\n text: t.text,\n language: t.language || undefined\n }))\n });\n}\n\n// Insert alerts into database\nfunction insertAlerts(db: Database, alerts: ProtobufAlert[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_alerts (\n id, active_period, informed_entity, cause, effect,\n url, header_text, description_text, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const alert of alerts) {\n // Map camelCase protobuf fields to snake_case\n const activePeriod = alert.activePeriod || alert.active_period || [];\n const informedEntity = alert.informedEntity || alert.informed_entity || [];\n const headerText = alert.headerText || alert.header_text;\n const descriptionText = alert.descriptionText || alert.description_text;\n\n // Convert nested objects to snake_case\n const activePeriodSnake = convertKeysToSnakeCase(activePeriod);\n const informedEntitySnake = convertKeysToSnakeCase(informedEntity);\n\n stmt.run([\n alert.id,\n JSON.stringify(activePeriodSnake),\n JSON.stringify(informedEntitySnake),\n alert.cause || null,\n alert.effect || null,\n parseTranslatedString(alert.url),\n parseTranslatedString(headerText),\n parseTranslatedString(descriptionText),\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert vehicle positions into database\nfunction insertVehiclePositions(db: Database, positions: ProtobufVehiclePosition[], timestamp: number): void {\n const stmt = db.prepare(`\n INSERT OR REPLACE INTO rt_vehicle_positions (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n latitude, longitude, bearing, odometer, speed,\n current_stop_sequence, stop_id, current_status, timestamp,\n congestion_level, occupancy_status, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const vp of positions) {\n const trip = vp.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = vp.vehicle?.id;\n const vehicleLabel = vp.vehicle?.label;\n const vehicleLicensePlate = vp.vehicle?.licensePlate || vp.vehicle?.license_plate;\n const currentStopSequence = vp.currentStopSequence || vp.current_stop_sequence;\n const stopId = vp.stopId || vp.stop_id;\n const currentStatus = vp.currentStatus || vp.current_status;\n const congestionLevel = vp.congestionLevel || vp.congestion_level;\n const occupancyStatus = vp.occupancyStatus || vp.occupancy_status;\n\n stmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n vp.position?.latitude || null,\n vp.position?.longitude || null,\n vp.position?.bearing || null,\n vp.position?.odometer || null,\n vp.position?.speed || null,\n currentStopSequence || null,\n stopId || null,\n currentStatus || null,\n vp.timestamp || null,\n congestionLevel || null,\n occupancyStatus || null,\n timestamp\n ]);\n }\n\n stmt.free();\n}\n\n// Insert trip updates into database\nfunction insertTripUpdates(db: Database, updates: ProtobufTripUpdate[], timestamp: number): void {\n const tripStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_trip_updates (\n trip_id, route_id, vehicle_id, vehicle_label, vehicle_license_plate,\n timestamp, delay, schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const stopTimeStmt = db.prepare(`\n INSERT OR REPLACE INTO rt_stop_time_updates (\n trip_id, stop_sequence, stop_id,\n arrival_delay, arrival_time, arrival_uncertainty,\n departure_delay, departure_time, departure_uncertainty,\n schedule_relationship, rt_last_updated\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const tu of updates) {\n const trip = tu.trip;\n if (!trip || !(trip.tripId || trip.trip_id)) continue;\n\n // Map camelCase protobuf fields to snake_case\n const tripId = (trip.tripId || trip.trip_id)!; // Safe: checked above\n const routeId = trip.routeId || trip.route_id;\n const vehicleId = tu.vehicle?.id;\n const vehicleLabel = tu.vehicle?.label;\n const vehicleLicensePlate = tu.vehicle?.licensePlate || tu.vehicle?.license_plate;\n const scheduleRelationship = trip.scheduleRelationship || trip.schedule_relationship;\n const stopTimeUpdate = tu.stopTimeUpdate || tu.stop_time_update;\n\n // Insert trip update\n tripStmt.run([\n tripId,\n routeId || null,\n vehicleId || null,\n vehicleLabel || null,\n vehicleLicensePlate || null,\n tu.timestamp || null,\n tu.delay || null,\n scheduleRelationship || null,\n timestamp\n ]);\n\n // Insert stop time updates\n if (stopTimeUpdate) {\n for (const stu of stopTimeUpdate) {\n const stopSequence = stu.stopSequence || stu.stop_sequence;\n const stopId = stu.stopId || stu.stop_id;\n const scheduleRel = stu.scheduleRelationship || stu.schedule_relationship;\n\n stopTimeStmt.run([\n tripId,\n stopSequence || null,\n stopId || null,\n stu.arrival?.delay || null,\n stu.arrival?.time || null,\n stu.arrival?.uncertainty || null,\n stu.departure?.delay || null,\n stu.departure?.time || null,\n stu.departure?.uncertainty || null,\n scheduleRel || null,\n timestamp\n ]);\n }\n }\n }\n\n tripStmt.free();\n stopTimeStmt.free();\n}\n\n/**\n * Fetch and load GTFS Realtime data from multiple feed URLs\n * All feeds are fetched in parallel. If any feed fails, an error is thrown.\n */\nexport async function loadRealtimeData(db: Database, feedUrls: string[]): Promise {\n const root = loadGtfsRtProto();\n const FeedMessage = root.lookupType('transit_realtime.FeedMessage');\n\n // Fetch all feeds in parallel\n const fetchPromises = feedUrls.map(async (url) => {\n try {\n const data = await fetchProtobuf(url);\n const message = FeedMessage.decode(data);\n return FeedMessage.toObject(message, {\n longs: Number,\n enums: Number,\n bytes: String,\n defaults: false,\n arrays: true,\n objects: true,\n oneofs: true\n });\n } catch (error) {\n throw new Error(`Failed to fetch or parse GTFS-RT feed from ${url}: ${error instanceof Error ? error.message : String(error)}`);\n }\n });\n\n // Wait for all feeds - if any fails, this will throw\n const feeds = await Promise.all(fetchPromises);\n\n // Current timestamp for staleness tracking\n const now = Math.floor(Date.now() / 1000);\n\n // Collect all entities by type\n const allAlerts: ProtobufAlert[] = [];\n const allVehiclePositions: ProtobufVehiclePosition[] = [];\n const allTripUpdates: ProtobufTripUpdate[] = [];\n\n for (const feed of feeds) {\n if (!feed.entity) continue;\n\n for (const entity of feed.entity) {\n if (entity.alert) {\n allAlerts.push({ id: entity.id, ...entity.alert });\n }\n if (entity.vehicle) {\n allVehiclePositions.push(entity.vehicle);\n }\n if (entity.tripUpdate) {\n allTripUpdates.push(entity.tripUpdate);\n }\n }\n }\n\n // Insert into database\n if (allAlerts.length > 0) {\n insertAlerts(db, allAlerts, now);\n }\n if (allVehiclePositions.length > 0) {\n insertVehiclePositions(db, allVehiclePositions, now);\n }\n if (allTripUpdates.length > 0) {\n insertTripUpdates(db, allTripUpdates, now);\n }\n}\n","/**\n * Agency Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Agency } from '../types/gtfs';\n\nexport interface AgencyFilters {\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get agencies with optional filters\n */\nexport function getAgencies(db: Database, filters: AgencyFilters = {}): Agency[] {\n const { agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM agency';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY agency_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Get an agency by its agency_id\n */\nexport function getAgencyById(db: Database, agencyId: string): Agency | null {\n const stmt = db.prepare('SELECT * FROM agency WHERE agency_id = ?');\n stmt.bind([agencyId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToAgency(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all agencies\n */\nexport function getAllAgencies(db: Database, limit?: number): Agency[] {\n const sql = limit\n ? `SELECT * FROM agency ORDER BY agency_name LIMIT ${limit}`\n : 'SELECT * FROM agency ORDER BY agency_name';\n\n const stmt = db.prepare(sql);\n\n const agencies: Agency[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n agencies.push(rowToAgency(row));\n }\n\n stmt.free();\n return agencies;\n}\n\n/**\n * Convert database row to Agency object\n */\nfunction rowToAgency(row: Record): Agency {\n return {\n agency_id: String(row.agency_id),\n agency_name: String(row.agency_name),\n agency_url: String(row.agency_url),\n agency_timezone: String(row.agency_timezone),\n agency_lang: row.agency_lang ? String(row.agency_lang) : undefined,\n agency_phone: row.agency_phone ? String(row.agency_phone) : undefined,\n agency_fare_url: row.agency_fare_url ? String(row.agency_fare_url) : undefined,\n agency_email: row.agency_email ? String(row.agency_email) : undefined,\n };\n}\n","/**\n * Stop Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Stop } from '../types/gtfs';\n\nexport interface StopFilters {\n stopId?: string;\n stopCode?: string;\n name?: string;\n tripId?: string;\n limit?: number;\n}\n\n/**\n * Get stops with optional filters\n */\nexport function getStops(db: Database, filters: StopFilters = {}): Stop[] {\n const { stopId, stopCode, name, tripId, limit } = filters;\n\n // Handle special case: get stops by trip (requires JOIN)\n if (tripId) {\n return getStopsByTrip(db, tripId);\n }\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (stopId) {\n conditions.push('stop_id = ?');\n params.push(stopId);\n }\n\n if (stopCode) {\n conditions.push('stop_code = ?');\n params.push(stopCode);\n }\n\n if (name) {\n conditions.push('stop_name LIKE ?');\n params.push(`%${name}%`);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM stops';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY stop_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get a stop by its stop_id\n */\nexport function getStopById(db: Database, stopId: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_id = ?');\n stmt.bind([stopId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get a stop by its stop_code\n */\nexport function getStopByCode(db: Database, stopCode: string): Stop | null {\n const stmt = db.prepare('SELECT * FROM stops WHERE stop_code = ?');\n stmt.bind([stopCode]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToStop(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Search stops by name (case-insensitive, partial match)\n */\nexport function searchStopsByName(db: Database, name: string, limit = 50): Stop[] {\n const stmt = db.prepare(\n 'SELECT * FROM stops WHERE stop_name LIKE ? ORDER BY stop_name LIMIT ?'\n );\n stmt.bind([`%${name}%`, limit]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get all stops\n */\nexport function getAllStops(db: Database, limit?: number): Stop[] {\n const sql = limit\n ? `SELECT * FROM stops ORDER BY stop_name LIMIT ${limit}`\n : 'SELECT * FROM stops ORDER BY stop_name';\n\n const stmt = db.prepare(sql);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Get stops for a given trip (ordered by stop_sequence)\n */\nexport function getStopsByTrip(db: Database, tripId: string): Stop[] {\n const stmt = db.prepare(`\n SELECT s.* FROM stops s\n INNER JOIN stop_times st ON s.stop_id = st.stop_id\n WHERE st.trip_id = ?\n ORDER BY st.stop_sequence\n `);\n stmt.bind([tripId]);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Convert database row to Stop object\n */\nfunction rowToStop(row: Record): Stop {\n return {\n stop_id: String(row.stop_id),\n stop_name: String(row.stop_name),\n stop_lat: Number(row.stop_lat),\n stop_lon: Number(row.stop_lon),\n stop_code: row.stop_code ? String(row.stop_code) : undefined,\n stop_desc: row.stop_desc ? String(row.stop_desc) : undefined,\n zone_id: row.zone_id ? String(row.zone_id) : undefined,\n stop_url: row.stop_url ? String(row.stop_url) : undefined,\n location_type: row.location_type !== null ? Number(row.location_type) : undefined,\n parent_station: row.parent_station ? String(row.parent_station) : undefined,\n stop_timezone: row.stop_timezone ? String(row.stop_timezone) : undefined,\n wheelchair_boarding: row.wheelchair_boarding !== null ? Number(row.wheelchair_boarding) : undefined,\n level_id: row.level_id ? String(row.level_id) : undefined,\n platform_code: row.platform_code ? String(row.platform_code) : undefined,\n };\n}\n","/**\n * Route Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Route } from '../types/gtfs';\n\nexport interface RouteFilters {\n routeId?: string;\n agencyId?: string;\n limit?: number;\n}\n\n/**\n * Get routes with optional filters\n */\nexport function getRoutes(db: Database, filters: RouteFilters = {}): Route[] {\n const { routeId, agencyId, limit } = filters;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n if (agencyId) {\n conditions.push('agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = 'SELECT * FROM routes';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY route_short_name, route_long_name';\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get a route by its route_id\n */\nexport function getRouteById(db: Database, routeId: string): Route | null {\n const stmt = db.prepare('SELECT * FROM routes WHERE route_id = ?');\n stmt.bind([routeId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToRoute(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get all routes\n */\nexport function getAllRoutes(db: Database, limit?: number): Route[] {\n const sql = limit\n ? `SELECT * FROM routes ORDER BY route_short_name, route_long_name LIMIT ${limit}`\n : 'SELECT * FROM routes ORDER BY route_short_name, route_long_name';\n\n const stmt = db.prepare(sql);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Get routes by agency\n */\nexport function getRoutesByAgency(db: Database, agencyId: string): Route[] {\n const stmt = db.prepare(\n 'SELECT * FROM routes WHERE agency_id = ? ORDER BY route_short_name, route_long_name'\n );\n stmt.bind([agencyId]);\n\n const routes: Route[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n routes.push(rowToRoute(row));\n }\n\n stmt.free();\n return routes;\n}\n\n/**\n * Convert database row to Route object\n */\nfunction rowToRoute(row: Record): Route {\n return {\n route_id: String(row.route_id),\n route_short_name: String(row.route_short_name),\n route_long_name: String(row.route_long_name),\n route_type: Number(row.route_type),\n agency_id: row.agency_id ? String(row.agency_id) : undefined,\n route_desc: row.route_desc ? String(row.route_desc) : undefined,\n route_url: row.route_url ? String(row.route_url) : undefined,\n route_color: row.route_color ? String(row.route_color) : undefined,\n route_text_color: row.route_text_color ? String(row.route_text_color) : undefined,\n route_sort_order: row.route_sort_order !== null ? Number(row.route_sort_order) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n };\n}\n","/**\n * Calendar Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Calendar, CalendarDate } from '../types/gtfs';\n\n/**\n * Get active service IDs for a given date\n */\nexport function getActiveServiceIds(db: Database, date: string): string[] {\n const serviceIds = new Set();\n\n // Parse date (format: YYYYMMDD)\n const year = parseInt(date.substring(0, 4));\n const month = parseInt(date.substring(4, 6));\n const day = parseInt(date.substring(6, 8));\n const dateObj = new Date(year, month - 1, day);\n const dayOfWeek = dateObj.getDay(); // 0 = Sunday, 1 = Monday, etc.\n\n // Map day of week to GTFS calendar field\n const dayFields = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];\n const dayField = dayFields[dayOfWeek];\n\n // Check calendar.txt for regular service\n const calendarStmt = db.prepare(\n `SELECT service_id FROM calendar\n WHERE ${dayField} = 1\n AND start_date <= ?\n AND end_date >= ?`\n );\n calendarStmt.bind([date, date]);\n\n while (calendarStmt.step()) {\n const row = calendarStmt.getAsObject() as { service_id: string };\n serviceIds.add(row.service_id);\n }\n calendarStmt.free();\n\n // Check calendar_dates.txt for exceptions\n const exceptionsStmt = db.prepare('SELECT service_id, exception_type FROM calendar_dates WHERE date = ?');\n exceptionsStmt.bind([date]);\n\n while (exceptionsStmt.step()) {\n const row = exceptionsStmt.getAsObject() as { service_id: string; exception_type: number };\n if (row.exception_type === 1) {\n // Service added\n serviceIds.add(row.service_id);\n } else if (row.exception_type === 2) {\n // Service removed\n serviceIds.delete(row.service_id);\n }\n }\n exceptionsStmt.free();\n\n return Array.from(serviceIds);\n}\n\n/**\n * Get calendar entry by service_id\n */\nexport function getCalendarByServiceId(db: Database, serviceId: string): Calendar | null {\n const stmt = db.prepare('SELECT * FROM calendar WHERE service_id = ?');\n stmt.bind([serviceId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToCalendar(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get calendar date exceptions for a service\n */\nexport function getCalendarDates(db: Database, serviceId: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE service_id = ? ORDER BY date');\n stmt.bind([serviceId]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Get calendar date exceptions for a specific date\n */\nexport function getCalendarDatesForDate(db: Database, date: string): CalendarDate[] {\n const stmt = db.prepare('SELECT * FROM calendar_dates WHERE date = ?');\n stmt.bind([date]);\n\n const dates: CalendarDate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n dates.push(rowToCalendarDate(row));\n }\n\n stmt.free();\n return dates;\n}\n\n/**\n * Convert database row to Calendar object\n */\nfunction rowToCalendar(row: Record): Calendar {\n return {\n service_id: String(row.service_id),\n monday: Number(row.monday),\n tuesday: Number(row.tuesday),\n wednesday: Number(row.wednesday),\n thursday: Number(row.thursday),\n friday: Number(row.friday),\n saturday: Number(row.saturday),\n sunday: Number(row.sunday),\n start_date: String(row.start_date),\n end_date: String(row.end_date),\n };\n}\n\n/**\n * Convert database row to CalendarDate object\n */\nfunction rowToCalendarDate(row: Record): CalendarDate {\n return {\n service_id: String(row.service_id),\n date: String(row.date),\n exception_type: Number(row.exception_type),\n };\n}\n","import type { Database} from 'sql.js';\nimport type { VehiclePosition } from '../types/gtfs-rt';\nimport type { VehiclePositionFilters } from '../types/gtfs-rt';\n\nexport type { VehiclePositionFilters };\n\n/**\n * Parse vehicle position from database row\n */\nexport function parseVehiclePosition(row: Record): VehiclePosition {\n const vp: VehiclePosition = {\n trip_id: String(row.trip_id),\n route_id: row.route_id ? String(row.route_id) : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n\n // Vehicle descriptor\n if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) {\n vp.vehicle = {\n id: row.vehicle_id ? String(row.vehicle_id) : undefined,\n label: row.vehicle_label ? String(row.vehicle_label) : undefined,\n license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : undefined\n };\n }\n\n // Position\n if (row.latitude !== null && row.longitude !== null) {\n vp.position = {\n latitude: Number(row.latitude),\n longitude: Number(row.longitude),\n bearing: row.bearing !== null ? Number(row.bearing) : undefined,\n odometer: row.odometer !== null ? Number(row.odometer) : undefined,\n speed: row.speed !== null ? Number(row.speed) : undefined\n };\n }\n\n // Other fields\n if (row.current_stop_sequence !== null) {\n vp.current_stop_sequence = Number(row.current_stop_sequence);\n }\n if (row.stop_id) {\n vp.stop_id = String(row.stop_id);\n }\n if (row.current_status !== null) {\n vp.current_status = Number(row.current_status);\n }\n if (row.timestamp !== null) {\n vp.timestamp = Number(row.timestamp);\n }\n if (row.congestion_level !== null) {\n vp.congestion_level = Number(row.congestion_level);\n }\n if (row.occupancy_status !== null) {\n vp.occupancy_status = Number(row.occupancy_status);\n }\n\n return vp;\n}\n\n/**\n * Get vehicle positions with optional filters\n */\nexport function getVehiclePositions(\n db: Database,\n filters: VehiclePositionFilters = {},\n stalenessThreshold: number = 120\n): VehiclePosition[] {\n const { tripId, routeId, vehicleId, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by route_id\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n // Filter by vehicle_id\n if (vehicleId) {\n conditions.push('vehicle_id = ?');\n params.push(vehicleId);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_vehicle_positions';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const positions: VehiclePosition[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n positions.push(parseVehiclePosition(row));\n }\n\n stmt.free();\n return positions;\n}\n\n/**\n * Get vehicle position by trip ID\n */\nexport function getVehiclePositionByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): VehiclePosition | null {\n const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold);\n return positions.length > 0 ? positions[0] : null;\n}\n\n/**\n * Get all vehicle positions without staleness filtering (for debugging)\n */\nexport function getAllVehiclePositions(db: Database): VehiclePosition[] {\n const sql = 'SELECT * FROM rt_vehicle_positions ORDER BY rt_last_updated DESC';\n const stmt = db.prepare(sql);\n\n const positions: VehiclePosition[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n positions.push(parseVehiclePosition(row));\n }\n\n stmt.free();\n return positions;\n}\n","/**\n * Trip Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Trip } from '../types/gtfs';\nimport type { TripRealtime, VehiclePosition } from '../types/gtfs-rt';\nimport { parseVehiclePosition } from './rt-vehicle-positions';\n\nexport interface TripFilters {\n tripId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface TripWithRealtime extends Trip {\n realtime?: TripRealtime;\n}\n\n/**\n * Merge realtime data with trips\n */\nfunction mergeRealtimeData(\n trips: Trip[],\n db: Database,\n stalenessThreshold: number\n): TripWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n const tripIds = trips.map(t => t.trip_id);\n if (tripIds.length === 0) return trips;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n\n // Get vehicle positions\n const vpStmt = db.prepare(`\n SELECT * FROM rt_vehicle_positions\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n vpStmt.bind([...tripIds, staleThreshold]);\n\n const vpMap = new Map();\n while (vpStmt.step()) {\n const row = vpStmt.getAsObject() as Record;\n const vp = parseVehiclePosition(row);\n vpMap.set(vp.trip_id, vp);\n }\n vpStmt.free();\n\n // Get trip updates\n const tuStmt = db.prepare(`\n SELECT * FROM rt_trip_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n tuStmt.bind([...tripIds, staleThreshold]);\n\n const tuMap = new Map();\n while (tuStmt.step()) {\n const row = tuStmt.getAsObject() as Record;\n const tripId = String(row.trip_id);\n tuMap.set(tripId, {\n delay: row.delay !== null ? Number(row.delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n });\n }\n tuStmt.free();\n\n // Merge realtime data\n return trips.map((trip): TripWithRealtime => {\n const vp = vpMap.get(trip.trip_id);\n const tu = tuMap.get(trip.trip_id);\n\n if (!vp && !tu) {\n return { ...trip, realtime: { vehicle_position: null, trip_update: null } };\n }\n\n return {\n ...trip,\n realtime: {\n vehicle_position: vp || null,\n trip_update: tu || null\n }\n };\n });\n}\n\n/**\n * Get trips with optional filters\n */\nexport function getTrips(\n db: Database,\n filters: TripFilters = {},\n stalenessThreshold: number = 120\n): Trip[] | TripWithRealtime[] {\n const { tripId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with routes table\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsRoutesJoin ? 't.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (routeId) {\n conditions.push(needsRoutesJoin ? 't.route_id = ?' : 'route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.service_id IN (${placeholders})` : `service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push(needsRoutesJoin ? 't.direction_id = ?' : 'direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql = needsRoutesJoin\n ? 'SELECT t.* FROM trips t INNER JOIN routes r ON t.route_id = r.route_id'\n : 'SELECT * FROM trips';\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(trips, db, stalenessThreshold);\n }\n\n return trips;\n}\n\n/**\n * Get a trip by its trip_id\n */\nexport function getTripById(db: Database, tripId: string): Trip | null {\n const stmt = db.prepare('SELECT * FROM trips WHERE trip_id = ?');\n stmt.bind([tripId]);\n\n if (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stmt.free();\n return rowToTrip(row);\n }\n\n stmt.free();\n return null;\n}\n\n/**\n * Get trips for a route\n */\nexport function getTripsByRoute(db: Database, routeId: string): Trip[] {\n const stmt = db.prepare('SELECT * FROM trips WHERE route_id = ?');\n stmt.bind([routeId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route and service (active on a given date)\n */\nexport function getTripsByRouteAndService(\n db: Database,\n routeId: string,\n serviceIds: string[]\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders})`\n );\n stmt.bind([routeId, ...serviceIds]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get trips for a route, service, and direction\n */\nexport function getTripsByRouteServiceAndDirection(\n db: Database,\n routeId: string,\n serviceIds: string[],\n directionId: number\n): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM trips WHERE route_id = ? AND service_id IN (${placeholders}) AND direction_id = ?`\n );\n stmt.bind([routeId, ...serviceIds, directionId]);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Get all trips for a service (active on a given date)\n */\nexport function getTripsByService(db: Database, serviceIds: string[]): Trip[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n const stmt = db.prepare(`SELECT * FROM trips WHERE service_id IN (${placeholders})`);\n stmt.bind(serviceIds);\n\n const trips: Trip[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n trips.push(rowToTrip(row));\n }\n\n stmt.free();\n return trips;\n}\n\n/**\n * Convert database row to Trip object\n */\nfunction rowToTrip(row: Record): Trip {\n return {\n trip_id: String(row.trip_id),\n route_id: String(row.route_id),\n service_id: String(row.service_id),\n trip_headsign: row.trip_headsign ? String(row.trip_headsign) : undefined,\n trip_short_name: row.trip_short_name ? String(row.trip_short_name) : undefined,\n direction_id: row.direction_id !== null ? Number(row.direction_id) : undefined,\n block_id: row.block_id ? String(row.block_id) : undefined,\n shape_id: row.shape_id ? String(row.shape_id) : undefined,\n wheelchair_accessible: row.wheelchair_accessible !== null ? Number(row.wheelchair_accessible) : undefined,\n bikes_allowed: row.bikes_allowed !== null ? Number(row.bikes_allowed) : undefined,\n };\n}\n","/**\n * Stop Time Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { StopTime } from '../types/gtfs';\nimport type { StopTimeRealtime } from '../types/gtfs-rt';\n\nexport interface StopTimeFilters {\n tripId?: string;\n stopId?: string;\n routeId?: string;\n serviceIds?: string[];\n directionId?: number;\n agencyId?: string;\n includeRealtime?: boolean;\n limit?: number;\n}\n\nexport interface StopTimeWithRealtime extends StopTime {\n realtime?: StopTimeRealtime;\n}\n\n/**\n * Merge realtime data with stop times\n */\nfunction mergeRealtimeData(\n stopTimes: StopTime[],\n db: Database,\n stalenessThreshold: number\n): StopTimeWithRealtime[] {\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n\n // Build map of trip_id -> stop times for this query\n const tripIds = Array.from(new Set(stopTimes.map(st => st.trip_id)));\n if (tripIds.length === 0) return stopTimes;\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(`\n SELECT trip_id, stop_sequence, stop_id,\n arrival_delay, departure_delay, schedule_relationship\n FROM rt_stop_time_updates\n WHERE trip_id IN (${placeholders})\n AND rt_last_updated >= ?\n `);\n stmt.bind([...tripIds, staleThreshold]);\n\n // Build map of trip_id+stop_sequence -> RT data\n const rtMap = new Map();\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const key = `${row.trip_id}_${row.stop_sequence}`;\n rtMap.set(key, {\n arrival_delay: row.arrival_delay !== null ? Number(row.arrival_delay) : undefined,\n departure_delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n });\n }\n stmt.free();\n\n // Merge RT data with stop times\n return stopTimes.map((st): StopTimeWithRealtime => {\n const key = `${st.trip_id}_${st.stop_sequence}`;\n const rtData = rtMap.get(key);\n\n if (rtData) {\n return { ...st, realtime: rtData };\n }\n return st;\n });\n}\n\n/**\n * Get stop times with optional filters\n */\nexport function getStopTimes(\n db: Database,\n filters: StopTimeFilters = {},\n stalenessThreshold: number = 120\n): StopTime[] | StopTimeWithRealtime[] {\n const { tripId, stopId, routeId, serviceIds, directionId, agencyId, includeRealtime, limit } = filters;\n\n // Determine if we need to join with trips and/or routes table\n const needsTripsJoin = routeId || serviceIds || directionId !== undefined || agencyId !== undefined;\n const needsRoutesJoin = agencyId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (tripId) {\n conditions.push(needsTripsJoin ? 'st.trip_id = ?' : 'trip_id = ?');\n params.push(tripId);\n }\n\n if (stopId) {\n conditions.push(needsTripsJoin ? 'st.stop_id = ?' : 'stop_id = ?');\n params.push(stopId);\n }\n\n if (routeId) {\n conditions.push('t.route_id = ?');\n params.push(routeId);\n }\n\n if (serviceIds && serviceIds.length > 0) {\n const placeholders = serviceIds.map(() => '?').join(', ');\n conditions.push(`t.service_id IN (${placeholders})`);\n params.push(...serviceIds);\n }\n\n if (directionId !== undefined) {\n conditions.push('t.direction_id = ?');\n params.push(directionId);\n }\n\n if (agencyId) {\n conditions.push('r.agency_id = ?');\n params.push(agencyId);\n }\n\n // Build SQL query\n let sql: string;\n if (needsRoutesJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id INNER JOIN routes r ON t.route_id = r.route_id';\n } else if (needsTripsJoin) {\n sql = 'SELECT st.* FROM stop_times st INNER JOIN trips t ON st.trip_id = t.trip_id';\n } else {\n sql = 'SELECT * FROM stop_times';\n }\n\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n\n // Order by stop_sequence if filtering by trip, otherwise by arrival_time\n sql += tripId ? ' ORDER BY stop_sequence' : ' ORDER BY arrival_time';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n\n // Merge realtime data if requested\n if (includeRealtime) {\n return mergeRealtimeData(stopTimes, db, stalenessThreshold);\n }\n\n return stopTimes;\n}\n\n/**\n * Get stop times for a trip\n */\nexport function getStopTimesByTrip(db: Database, tripId: string): StopTime[] {\n const stmt = db.prepare('SELECT * FROM stop_times WHERE trip_id = ? ORDER BY stop_sequence');\n stmt.bind([tripId]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop\n */\nexport function getStopTimesByStop(db: Database, stopId: string, limit = 100): StopTime[] {\n const stmt = db.prepare(\n 'SELECT * FROM stop_times WHERE stop_id = ? ORDER BY arrival_time LIMIT ?'\n );\n stmt.bind([stopId, limit]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop and specific trips (filtered by route/date)\n */\nexport function getStopTimesByStopAndTrips(\n db: Database,\n stopId: string,\n tripIds: string[]\n): StopTime[] {\n if (tripIds.length === 0) {\n return [];\n }\n\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(\n `SELECT * FROM stop_times\n WHERE stop_id = ? AND trip_id IN (${placeholders})\n ORDER BY arrival_time`\n );\n stmt.bind([stopId, ...tripIds]);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Get stop times for a stop, route, and direction on a specific date\n */\nexport function getStopTimesForStopRouteDirection(\n db: Database,\n stopId: string,\n routeId: string,\n serviceIds: string[],\n directionId?: number\n): StopTime[] {\n if (serviceIds.length === 0) {\n return [];\n }\n\n const placeholders = serviceIds.map(() => '?').join(', ');\n\n let sql = `\n SELECT st.* FROM stop_times st\n INNER JOIN trips t ON st.trip_id = t.trip_id\n WHERE st.stop_id = ?\n AND t.route_id = ?\n AND t.service_id IN (${placeholders})\n `;\n\n const params: (string | number)[] = [stopId, routeId, ...serviceIds];\n\n if (directionId !== undefined) {\n sql += ' AND t.direction_id = ?';\n params.push(directionId);\n }\n\n sql += ' ORDER BY st.arrival_time';\n\n const stmt = db.prepare(sql);\n stmt.bind(params);\n\n const stopTimes: StopTime[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimes.push(rowToStopTime(row));\n }\n\n stmt.free();\n return stopTimes;\n}\n\n/**\n * Convert database row to StopTime object\n */\nfunction rowToStopTime(row: Record): StopTime {\n return {\n trip_id: String(row.trip_id),\n arrival_time: String(row.arrival_time),\n departure_time: String(row.departure_time),\n stop_id: String(row.stop_id),\n stop_sequence: Number(row.stop_sequence),\n stop_headsign: row.stop_headsign ? String(row.stop_headsign) : undefined,\n pickup_type: row.pickup_type !== null ? Number(row.pickup_type) : undefined,\n drop_off_type: row.drop_off_type !== null ? Number(row.drop_off_type) : undefined,\n continuous_pickup: row.continuous_pickup !== null ? Number(row.continuous_pickup) : undefined,\n continuous_drop_off: row.continuous_drop_off !== null ? Number(row.continuous_drop_off) : undefined,\n shape_dist_traveled: row.shape_dist_traveled !== null ? Number(row.shape_dist_traveled) : undefined,\n timepoint: row.timepoint !== null ? Number(row.timepoint) : undefined,\n };\n}\n","import type { Database } from 'sql.js';\nimport type { Alert, EntitySelector, TimeRange, TranslatedString } from '../types/gtfs-rt';\nimport type { AlertFilters } from '../types/gtfs-rt';\n\nexport type { AlertFilters };\n\n/**\n * Parse JSON fields from database\n */\nfunction parseAlert(row: Record): Alert {\n return {\n id: String(row.id),\n active_period: row.active_period ? JSON.parse(String(row.active_period)) as TimeRange[] : [],\n informed_entity: row.informed_entity ? JSON.parse(String(row.informed_entity)) as EntitySelector[] : [],\n cause: row.cause ? Number(row.cause) : undefined,\n effect: row.effect ? Number(row.effect) : undefined,\n url: row.url ? JSON.parse(String(row.url)) as TranslatedString : undefined,\n header_text: row.header_text ? JSON.parse(String(row.header_text)) as TranslatedString : undefined,\n description_text: row.description_text ? JSON.parse(String(row.description_text)) as TranslatedString : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n}\n\n/**\n * Check if an alert is currently active based on its active_period\n */\nfunction isAlertActive(alert: Alert, now: number): boolean {\n // If no active periods defined, assume always active\n if (!alert.active_period || alert.active_period.length === 0) {\n return true;\n }\n\n // Check if current time falls within any active period\n for (const period of alert.active_period) {\n const start = period.start || 0;\n const end = period.end || Number.MAX_SAFE_INTEGER;\n\n if (now >= start && now <= end) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if an alert affects the specified entity\n */\nfunction alertAffectsEntity(alert: Alert, filters: AlertFilters): boolean {\n if (!alert.informed_entity || alert.informed_entity.length === 0) {\n return true; // No specific entities, assume it affects all\n }\n\n for (const entity of alert.informed_entity) {\n // Check route_id\n if (filters.routeId && entity.route_id === filters.routeId) {\n return true;\n }\n\n // Check stop_id\n if (filters.stopId && entity.stop_id === filters.stopId) {\n return true;\n }\n\n // Check trip_id\n if (filters.tripId && entity.trip?.trip_id === filters.tripId) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Get alerts with optional filters\n */\nexport function getAlerts(db: Database, filters: AlertFilters = {}, stalenessThreshold: number = 120): Alert[] {\n const {\n alertId,\n activeOnly,\n routeId,\n stopId,\n tripId,\n cause,\n effect,\n limit\n } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by alert ID\n if (alertId) {\n conditions.push('id = ?');\n params.push(alertId);\n }\n\n // Filter by cause\n if (cause !== undefined) {\n conditions.push('cause = ?');\n params.push(cause);\n }\n\n // Filter by effect\n if (effect !== undefined) {\n conditions.push('effect = ?');\n params.push(effect);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_alerts';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const alerts: Alert[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n const alert = parseAlert(row);\n\n // Apply activeOnly filter in application code\n if (activeOnly && !isAlertActive(alert, now)) {\n continue;\n }\n\n // Apply entity filters in application code (since informed_entity is JSON)\n if (routeId || stopId || tripId) {\n if (!alertAffectsEntity(alert, filters)) {\n continue;\n }\n }\n\n alerts.push(alert);\n }\n\n stmt.free();\n return alerts;\n}\n\n/**\n * Get alert by ID\n */\nexport function getAlertById(db: Database, alertId: string, stalenessThreshold: number = 120): Alert | null {\n const alerts = getAlerts(db, { alertId, limit: 1 }, stalenessThreshold);\n return alerts.length > 0 ? alerts[0] : null;\n}\n\n/**\n * Get all alerts without staleness filtering (for debugging)\n */\nexport function getAllAlerts(db: Database): Alert[] {\n const sql = 'SELECT * FROM rt_alerts ORDER BY rt_last_updated DESC';\n const stmt = db.prepare(sql);\n\n const alerts: Alert[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n alerts.push(parseAlert(row));\n }\n\n stmt.free();\n return alerts;\n}\n","import type { Database } from 'sql.js';\nimport type { TripUpdate } from '../types/gtfs-rt';\n\nexport interface TripUpdateFilters {\n tripId?: string;\n routeId?: string;\n vehicleId?: string;\n limit?: number;\n}\n\n/**\n * Parse trip update from database row\n */\nexport function parseTripUpdate(row: Record): TripUpdate {\n const tu: TripUpdate = {\n trip_id: String(row.trip_id),\n route_id: row.route_id ? String(row.route_id) : undefined,\n stop_time_update: [], // Will be populated separately\n timestamp: row.timestamp !== null ? Number(row.timestamp) : undefined,\n delay: row.delay !== null ? Number(row.delay) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined,\n rt_last_updated: Number(row.rt_last_updated)\n };\n\n // Vehicle descriptor\n if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) {\n tu.vehicle = {\n id: row.vehicle_id ? String(row.vehicle_id) : undefined,\n label: row.vehicle_label ? String(row.vehicle_label) : undefined,\n license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : undefined\n };\n }\n\n return tu;\n}\n\n/**\n * Get trip updates with optional filters\n */\nexport function getTripUpdates(\n db: Database,\n filters: TripUpdateFilters = {},\n stalenessThreshold: number = 120\n): TripUpdate[] {\n const { tripId, routeId, vehicleId, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by route_id\n if (routeId) {\n conditions.push('route_id = ?');\n params.push(routeId);\n }\n\n // Filter by vehicle_id\n if (vehicleId) {\n conditions.push('vehicle_id = ?');\n params.push(vehicleId);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_trip_updates';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY rt_last_updated DESC';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const tripUpdates: TripUpdate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n tripUpdates.push(parseTripUpdate(row));\n }\n\n stmt.free();\n return tripUpdates;\n}\n\n/**\n * Get trip update by trip ID\n */\nexport function getTripUpdateByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): TripUpdate | null {\n const updates = getTripUpdates(db, { tripId, limit: 1 }, stalenessThreshold);\n return updates.length > 0 ? updates[0] : null;\n}\n\n/**\n * Get all trip updates without staleness filtering (for debugging)\n */\nexport function getAllTripUpdates(db: Database): TripUpdate[] {\n const sql = 'SELECT * FROM rt_trip_updates ORDER BY rt_last_updated DESC';\n const stmt = db.prepare(sql);\n\n const tripUpdates: TripUpdate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n tripUpdates.push(parseTripUpdate(row));\n }\n\n stmt.free();\n return tripUpdates;\n}\n","import type { Database } from 'sql.js';\nimport type { StopTimeUpdate } from '../types/gtfs-rt';\n\nexport interface StopTimeUpdateFilters {\n tripId?: string;\n stopId?: string;\n stopSequence?: number;\n limit?: number;\n}\n\n/**\n * Parse stop time update from database row\n */\nfunction parseStopTimeUpdate(row: Record): StopTimeUpdate {\n const stu: StopTimeUpdate = {\n stop_sequence: row.stop_sequence !== null ? Number(row.stop_sequence) : undefined,\n stop_id: row.stop_id ? String(row.stop_id) : undefined,\n schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined\n };\n\n // Arrival event\n if (row.arrival_delay !== null || row.arrival_time !== null || row.arrival_uncertainty !== null) {\n stu.arrival = {\n delay: row.arrival_delay !== null ? Number(row.arrival_delay) : undefined,\n time: row.arrival_time !== null ? Number(row.arrival_time) : undefined,\n uncertainty: row.arrival_uncertainty !== null ? Number(row.arrival_uncertainty) : undefined\n };\n }\n\n // Departure event\n if (row.departure_delay !== null || row.departure_time !== null || row.departure_uncertainty !== null) {\n stu.departure = {\n delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined,\n time: row.departure_time !== null ? Number(row.departure_time) : undefined,\n uncertainty: row.departure_uncertainty !== null ? Number(row.departure_uncertainty) : undefined\n };\n }\n\n return stu;\n}\n\n/**\n * Extended StopTimeUpdate with trip_id and rt_last_updated for debugging\n */\nexport interface StopTimeUpdateWithMetadata extends StopTimeUpdate {\n trip_id: string;\n rt_last_updated: number;\n}\n\n/**\n * Parse stop time update with metadata from database row\n */\nfunction parseStopTimeUpdateWithMetadata(row: Record): StopTimeUpdateWithMetadata {\n const stu = parseStopTimeUpdate(row) as StopTimeUpdateWithMetadata;\n stu.trip_id = String(row.trip_id);\n stu.rt_last_updated = Number(row.rt_last_updated);\n return stu;\n}\n\n/**\n * Get stop time updates with optional filters\n */\nexport function getStopTimeUpdates(\n db: Database,\n filters: StopTimeUpdateFilters = {},\n stalenessThreshold: number = 120\n): StopTimeUpdate[] {\n const { tripId, stopId, stopSequence, limit } = filters;\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n // Filter by trip_id\n if (tripId) {\n conditions.push('trip_id = ?');\n params.push(tripId);\n }\n\n // Filter by stop_id\n if (stopId) {\n conditions.push('stop_id = ?');\n params.push(stopId);\n }\n\n // Filter by stop_sequence\n if (stopSequence !== undefined) {\n conditions.push('stop_sequence = ?');\n params.push(stopSequence);\n }\n\n // Staleness filter (always applied)\n const now = Math.floor(Date.now() / 1000);\n const staleThreshold = now - stalenessThreshold;\n conditions.push('rt_last_updated >= ?');\n params.push(staleThreshold);\n\n // Build query\n let sql = 'SELECT * FROM rt_stop_time_updates';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY trip_id, stop_sequence';\n\n if (limit) {\n sql += ' LIMIT ?';\n params.push(limit);\n }\n\n // Execute query\n const stmt = db.prepare(sql);\n if (params.length > 0) {\n stmt.bind(params);\n }\n\n const stopTimeUpdates: StopTimeUpdate[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimeUpdates.push(parseStopTimeUpdate(row));\n }\n\n stmt.free();\n return stopTimeUpdates;\n}\n\n/**\n * Get stop time updates for a specific trip\n */\nexport function getStopTimeUpdatesByTripId(\n db: Database,\n tripId: string,\n stalenessThreshold: number = 120\n): StopTimeUpdate[] {\n return getStopTimeUpdates(db, { tripId }, stalenessThreshold);\n}\n\n/**\n * Get all stop time updates without staleness filtering (for debugging)\n * Returns extended type with trip_id and rt_last_updated for debugging purposes\n */\nexport function getAllStopTimeUpdates(db: Database): StopTimeUpdateWithMetadata[] {\n const sql = 'SELECT * FROM rt_stop_time_updates ORDER BY trip_id, stop_sequence';\n const stmt = db.prepare(sql);\n\n const stopTimeUpdates: StopTimeUpdateWithMetadata[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record;\n stopTimeUpdates.push(parseStopTimeUpdateWithMetadata(row));\n }\n\n stmt.free();\n return stopTimeUpdates;\n}\n","/**\n * GTFS Realtime TypeScript types\n * Based on GTFS Realtime v2.0 specification\n */\n\n// Enum types from GTFS-RT specification\n\nexport enum ScheduleRelationship {\n SCHEDULED = 0,\n ADDED = 1,\n UNSCHEDULED = 2,\n CANCELED = 3,\n SKIPPED = 4,\n NO_DATA = 5\n}\n\nexport enum VehicleStopStatus {\n INCOMING_AT = 0,\n STOPPED_AT = 1,\n IN_TRANSIT_TO = 2\n}\n\nexport enum CongestionLevel {\n UNKNOWN_CONGESTION_LEVEL = 0,\n RUNNING_SMOOTHLY = 1,\n STOP_AND_GO = 2,\n CONGESTION = 3,\n SEVERE_CONGESTION = 4\n}\n\nexport enum OccupancyStatus {\n EMPTY = 0,\n MANY_SEATS_AVAILABLE = 1,\n FEW_SEATS_AVAILABLE = 2,\n STANDING_ROOM_ONLY = 3,\n CRUSHED_STANDING_ROOM_ONLY = 4,\n FULL = 5,\n NOT_ACCEPTING_PASSENGERS = 6\n}\n\nexport enum AlertCause {\n UNKNOWN_CAUSE = 1,\n OTHER_CAUSE = 2,\n TECHNICAL_PROBLEM = 3,\n STRIKE = 4,\n DEMONSTRATION = 5,\n ACCIDENT = 6,\n HOLIDAY = 7,\n WEATHER = 8,\n MAINTENANCE = 9,\n CONSTRUCTION = 10,\n POLICE_ACTIVITY = 11,\n MEDICAL_EMERGENCY = 12\n}\n\nexport enum AlertEffect {\n NO_SERVICE = 1,\n REDUCED_SERVICE = 2,\n SIGNIFICANT_DELAYS = 3,\n DETOUR = 4,\n ADDITIONAL_SERVICE = 5,\n MODIFIED_SERVICE = 6,\n OTHER_EFFECT = 7,\n UNKNOWN_EFFECT = 8,\n STOP_MOVED = 9,\n NO_EFFECT = 10,\n ACCESSIBILITY_ISSUE = 11\n}\n\n// Main GTFS-RT types\n\nexport interface TranslatedString {\n translation: Array<{\n text: string;\n language?: string;\n }>;\n}\n\nexport interface EntitySelector {\n agency_id?: string;\n route_id?: string;\n route_type?: number;\n trip?: {\n trip_id?: string;\n route_id?: string;\n direction_id?: number;\n start_time?: string;\n start_date?: string;\n schedule_relationship?: ScheduleRelationship;\n };\n stop_id?: string;\n}\n\nexport interface TimeRange {\n start?: number; // UNIX timestamp\n end?: number; // UNIX timestamp\n}\n\nexport interface Alert {\n id: string;\n active_period: TimeRange[];\n informed_entity: EntitySelector[];\n cause?: AlertCause;\n effect?: AlertEffect;\n url?: TranslatedString;\n header_text?: TranslatedString;\n description_text?: TranslatedString;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface Position {\n latitude: number;\n longitude: number;\n bearing?: number;\n odometer?: number;\n speed?: number;\n}\n\nexport interface VehicleDescriptor {\n id?: string;\n label?: string;\n license_plate?: string;\n}\n\nexport interface VehiclePosition {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n position?: Position;\n current_stop_sequence?: number;\n stop_id?: string;\n current_status?: VehicleStopStatus;\n timestamp?: number;\n congestion_level?: CongestionLevel;\n occupancy_status?: OccupancyStatus;\n rt_last_updated: number; // UNIX timestamp\n}\n\nexport interface StopTimeEvent {\n delay?: number; // seconds\n time?: number; // UNIX timestamp (absolute time)\n uncertainty?: number;\n}\n\nexport interface StopTimeUpdate {\n stop_sequence?: number;\n stop_id?: string;\n arrival?: StopTimeEvent;\n departure?: StopTimeEvent;\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripUpdate {\n trip_id: string;\n route_id?: string;\n vehicle?: VehicleDescriptor;\n stop_time_update: StopTimeUpdate[];\n timestamp?: number;\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n rt_last_updated: number; // UNIX timestamp\n}\n\n// Enhanced types for queries with realtime data\n\nexport interface StopTimeRealtime {\n arrival_delay?: number; // seconds\n departure_delay?: number; // seconds\n schedule_relationship?: ScheduleRelationship;\n}\n\nexport interface TripRealtime {\n vehicle_position?: VehiclePosition | null;\n trip_update?: {\n delay?: number;\n schedule_relationship?: ScheduleRelationship;\n } | null;\n}\n\n// Filter types for realtime queries\n\nexport interface AlertFilters {\n alertId?: string;\n activeOnly?: boolean;\n routeId?: string;\n stopId?: string;\n tripId?: string;\n cause?: AlertCause;\n effect?: AlertEffect;\n limit?: number;\n}\n\nexport interface VehiclePositionFilters {\n tripId?: string;\n routeId?: string;\n vehicleId?: string;\n limit?: number;\n}\n\n// Configuration\n\nexport interface RealtimeConfig {\n feedUrls?: string[];\n stalenessThreshold?: number; // seconds, default 120\n}\n"],"mappings":";AAIA,OAAO,eAAoD;;;ACoBpD,IAAM,cAA6B;AAAA,EACxC;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MACpE,EAAE,MAAM,eAAe,MAAM,QAAQ,UAAU,KAAK;AAAA,MACpD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,mBAAmB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACxD,EAAE,MAAM,eAAe,MAAM,QAAQ,UAAU,MAAM;AAAA,MACrD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACtD,EAAE,MAAM,mBAAmB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACzD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,IACxD;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MAClE,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,KAAK;AAAA,MAClD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,KAAK;AAAA,MACjD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,KAAK;AAAA,MACjD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,MAAM;AAAA,MACjD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM;AAAA,MAClD,EAAE,MAAM,iBAAiB,MAAM,WAAW,UAAU,MAAM;AAAA,MAC1D,EAAE,MAAM,kBAAkB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACxD,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACvD,EAAE,MAAM,uBAAuB,MAAM,WAAW,UAAU,MAAM;AAAA,MAChE,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM;AAAA,MAClD,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,MAAM;AAAA,IACzD;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,uBAAuB,SAAS,CAAC,WAAW,EAAE;AAAA,MACtD,EAAE,MAAM,uBAAuB,SAAS,CAAC,WAAW,EAAE;AAAA,MACtD,EAAE,MAAM,4BAA4B,SAAS,CAAC,gBAAgB,EAAE;AAAA,IAClE;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MACnE,EAAE,MAAM,oBAAoB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACzD,EAAE,MAAM,mBAAmB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACxD,EAAE,MAAM,cAAc,MAAM,WAAW,UAAU,KAAK;AAAA,MACtD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,MAAM;AAAA,MACpD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,eAAe,MAAM,QAAQ,UAAU,MAAM;AAAA,MACrD,EAAE,MAAM,oBAAoB,MAAM,QAAQ,UAAU,MAAM;AAAA,MAC1D,EAAE,MAAM,oBAAoB,MAAM,WAAW,UAAU,MAAM;AAAA,MAC7D,EAAE,MAAM,qBAAqB,MAAM,WAAW,UAAU,MAAM;AAAA,MAC9D,EAAE,MAAM,uBAAuB,MAAM,WAAW,UAAU,MAAM;AAAA,IAClE;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,wBAAwB,SAAS,CAAC,WAAW,EAAE;AAAA,IACzD;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MAClE,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,KAAK;AAAA,MACjD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACvD,EAAE,MAAM,mBAAmB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACzD,EAAE,MAAM,gBAAgB,MAAM,WAAW,UAAU,MAAM;AAAA,MACzD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM;AAAA,MAClD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM;AAAA,MAClD,EAAE,MAAM,yBAAyB,MAAM,WAAW,UAAU,MAAM;AAAA,MAClE,EAAE,MAAM,iBAAiB,MAAM,WAAW,UAAU,MAAM;AAAA,IAC5D;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,sBAAsB,SAAS,CAAC,UAAU,EAAE;AAAA,MACpD,EAAE,MAAM,wBAAwB,SAAS,CAAC,YAAY,EAAE;AAAA,MACxD,EAAE,MAAM,2BAA2B,SAAS,CAAC,YAAY,YAAY,EAAE;AAAA,IACzE;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,KAAK;AAAA,MAChD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACrD,EAAE,MAAM,kBAAkB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACvD,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,KAAK;AAAA,MAChD,EAAE,MAAM,iBAAiB,MAAM,WAAW,UAAU,KAAK;AAAA,MACzD,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACvD,EAAE,MAAM,eAAe,MAAM,WAAW,UAAU,MAAM;AAAA,MACxD,EAAE,MAAM,iBAAiB,MAAM,WAAW,UAAU,MAAM;AAAA,MAC1D,EAAE,MAAM,qBAAqB,MAAM,WAAW,UAAU,MAAM;AAAA,MAC9D,EAAE,MAAM,uBAAuB,MAAM,WAAW,UAAU,MAAM;AAAA,MAChE,EAAE,MAAM,uBAAuB,MAAM,QAAQ,UAAU,MAAM;AAAA,MAC7D,EAAE,MAAM,aAAa,MAAM,WAAW,UAAU,MAAM;AAAA,IACxD;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,0BAA0B,SAAS,CAAC,SAAS,EAAE;AAAA,MACvD,EAAE,MAAM,0BAA0B,SAAS,CAAC,SAAS,EAAE;AAAA,MACvD,EAAE,MAAM,gCAAgC,SAAS,CAAC,WAAW,eAAe,EAAE;AAAA,IAChF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MACrE,EAAE,MAAM,UAAU,MAAM,WAAW,UAAU,KAAK;AAAA,MAClD,EAAE,MAAM,WAAW,MAAM,WAAW,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,aAAa,MAAM,WAAW,UAAU,KAAK;AAAA,MACrD,EAAE,MAAM,YAAY,MAAM,WAAW,UAAU,KAAK;AAAA,MACpD,EAAE,MAAM,UAAU,MAAM,WAAW,UAAU,KAAK;AAAA,MAClD,EAAE,MAAM,YAAY,MAAM,WAAW,UAAU,KAAK;AAAA,MACpD,EAAE,MAAM,UAAU,MAAM,WAAW,UAAU,KAAK;AAAA,MAClD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,KAAK;AAAA,IACnD;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,QAAQ,MAAM,QAAQ,UAAU,KAAK;AAAA,MAC7C,EAAE,MAAM,kBAAkB,MAAM,WAAW,UAAU,KAAK;AAAA,IAC5D;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,iCAAiC,SAAS,CAAC,YAAY,EAAE;AAAA,MACjE,EAAE,MAAM,2BAA2B,SAAS,CAAC,MAAM,EAAE;AAAA,MACrD,EAAE,MAAM,mCAAmC,SAAS,CAAC,cAAc,MAAM,EAAE;AAAA,IAC7E;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MAClE,EAAE,MAAM,SAAS,MAAM,QAAQ,UAAU,KAAK;AAAA,MAC9C,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACtD,EAAE,MAAM,kBAAkB,MAAM,WAAW,UAAU,KAAK;AAAA,MAC1D,EAAE,MAAM,aAAa,MAAM,WAAW,UAAU,KAAK;AAAA,MACrD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,qBAAqB,MAAM,WAAW,UAAU,MAAM;AAAA,IAChE;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,KAAK;AAAA,MAChD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM;AAAA,MAClD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,kBAAkB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACxD,EAAE,MAAM,eAAe,MAAM,QAAQ,UAAU,MAAM;AAAA,IACvD;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,0BAA0B,SAAS,CAAC,SAAS,EAAE;AAAA,MACvD,EAAE,MAAM,2BAA2B,SAAS,CAAC,UAAU,EAAE;AAAA,IAC3D;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,KAAK;AAAA,MACjD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACrD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACrD,EAAE,MAAM,qBAAqB,MAAM,WAAW,UAAU,KAAK;AAAA,MAC7D,EAAE,MAAM,uBAAuB,MAAM,QAAQ,UAAU,MAAM;AAAA,IAC/D;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,uBAAuB,SAAS,CAAC,UAAU,EAAE;AAAA,MACrD,EAAE,MAAM,6BAA6B,SAAS,CAAC,YAAY,mBAAmB,EAAE;AAAA,IAClF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,KAAK;AAAA,MAChD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,KAAK;AAAA,MACjD,EAAE,MAAM,gBAAgB,MAAM,WAAW,UAAU,KAAK;AAAA,MACxD,EAAE,MAAM,eAAe,MAAM,WAAW,UAAU,MAAM;AAAA,IAC1D;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,2BAA2B,SAAS,CAAC,SAAS,EAAE;AAAA,IAC1D;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACrD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,iBAAiB,MAAM,WAAW,UAAU,KAAK;AAAA,MACzD,EAAE,MAAM,qBAAqB,MAAM,WAAW,UAAU,MAAM;AAAA,IAChE;AAAA,IACA,SAAS;AAAA,MACP,EAAE,MAAM,8BAA8B,SAAS,CAAC,cAAc,EAAE;AAAA,MAChE,EAAE,MAAM,4BAA4B,SAAS,CAAC,YAAY,EAAE;AAAA,IAC9D;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MACrE,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,KAAK;AAAA,MACrD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,MACnD,EAAE,MAAM,gBAAgB,MAAM,WAAW,UAAU,KAAK;AAAA,MACxD,EAAE,MAAM,oBAAoB,MAAM,WAAW,UAAU,KAAK;AAAA,MAC5D,EAAE,MAAM,UAAU,MAAM,QAAQ,UAAU,MAAM;AAAA,MAChD,EAAE,MAAM,kBAAkB,MAAM,WAAW,UAAU,MAAM;AAAA,MAC3D,EAAE,MAAM,eAAe,MAAM,WAAW,UAAU,MAAM;AAAA,MACxD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACvD,EAAE,MAAM,0BAA0B,MAAM,QAAQ,UAAU,MAAM;AAAA,IAClE;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MACnE,EAAE,MAAM,eAAe,MAAM,QAAQ,UAAU,KAAK;AAAA,MACpD,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,MAAM;AAAA,IACtD;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,uBAAuB,MAAM,QAAQ,UAAU,KAAK;AAAA,MAC5D,EAAE,MAAM,sBAAsB,MAAM,QAAQ,UAAU,KAAK;AAAA,MAC3D,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,KAAK;AAAA,MAClD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACtD,EAAE,MAAM,mBAAmB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACzD,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACvD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACtD,EAAE,MAAM,sBAAsB,MAAM,QAAQ,UAAU,MAAM;AAAA,MAC5D,EAAE,MAAM,oBAAoB,MAAM,QAAQ,UAAU,MAAM;AAAA,IAC5D;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,MACP,EAAE,MAAM,kBAAkB,MAAM,QAAQ,UAAU,MAAM,YAAY,KAAK;AAAA,MACzE,EAAE,MAAM,qBAAqB,MAAM,QAAQ,UAAU,KAAK;AAAA,MAC1D,EAAE,MAAM,aAAa,MAAM,QAAQ,UAAU,MAAM;AAAA,MACnD,EAAE,MAAM,YAAY,MAAM,QAAQ,UAAU,MAAM;AAAA,MAClD,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,MAAM;AAAA,MACjD,EAAE,MAAM,eAAe,MAAM,WAAW,UAAU,MAAM;AAAA,MACxD,EAAE,MAAM,eAAe,MAAM,WAAW,UAAU,MAAM;AAAA,MACxD,EAAE,MAAM,gBAAgB,MAAM,WAAW,UAAU,MAAM;AAAA,MACzD,EAAE,MAAM,mBAAmB,MAAM,QAAQ,UAAU,MAAM;AAAA,MACzD,EAAE,MAAM,qBAAqB,MAAM,QAAQ,UAAU,MAAM;AAAA,MAC3D,EAAE,MAAM,qBAAqB,MAAM,QAAQ,UAAU,MAAM;AAAA,IAC7D;AAAA,EACF;AACF;AAKO,SAAS,uBAAuB,QAA6B;AAClE,QAAM,UAAU,OAAO,QAAQ,IAAI,CAAC,QAAQ;AAC1C,UAAM,QAAQ,CAAC,IAAI,MAAM,IAAI,IAAI;AACjC,QAAI,IAAI,YAAY;AAClB,YAAM,KAAK,aAAa;AAAA,IAC1B;AACA,QAAI,IAAI,YAAY,CAAC,IAAI,YAAY;AACnC,YAAM,KAAK,UAAU;AAAA,IACvB;AACA,WAAO,MAAM,KAAK,GAAG;AAAA,EACvB,CAAC;AAED,SAAO,8BAA8B,OAAO,IAAI,KAAK,QAAQ,KAAK,IAAI,CAAC;AACzE;AAKO,SAAS,uBAAuB,QAA+B;AACpE,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,OAAO,QAAQ,IAAI,CAAC,QAAQ;AACjC,UAAM,SAAS,IAAI,SAAS,YAAY;AACxC,UAAM,UAAU,IAAI,QAAQ,KAAK,IAAI;AACrC,WAAO,UAAU,MAAM,uBAAuB,IAAI,IAAI,OAAO,OAAO,IAAI,KAAK,OAAO;AAAA,EACtF,CAAC;AACH;AAKO,SAAS,yBAAmC;AACjD,QAAM,aAAuB,CAAC;AAE9B,aAAW,UAAU,aAAa;AAChC,eAAW,KAAK,uBAAuB,MAAM,CAAC;AAC9C,eAAW,KAAK,GAAG,uBAAuB,MAAM,CAAC;AAAA,EACnD;AAEA,SAAO;AACT;;;AC5TA,OAAO,WAAW;AAUlB,eAAsB,YAAY,QAA+D;AAC/F,MAAI;AAGJ,MAAI,OAAO,WAAW,UAAU;AAC9B,cAAU,MAAM,SAAS,MAAM;AAAA,EACjC,OAAO;AACL,cAAU;AAAA,EACZ;AAGA,QAAM,MAAM,MAAM,MAAM,UAAU,OAAO;AAGzC,QAAM,QAAmB,CAAC;AAC1B,QAAM,eAAgC,CAAC;AAEvC,MAAI,QAAQ,CAAC,cAAc,SAAS;AAElC,QAAI,CAAC,KAAK,OAAO,aAAa,SAAS,MAAM,GAAG;AAC9C,YAAM,WAAW,aAAa,MAAM,GAAG,EAAE,IAAI,KAAK;AAClD,mBAAa;AAAA,QACX,KAAK,MAAM,QAAQ,EAAE,KAAK,CAAC,YAAY;AACrC,gBAAM,QAAQ,IAAI;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,IAAI,YAAY;AAE9B,SAAO;AACT;AAKA,eAAe,SAAS,QAAsC;AAE5D,QAAM,QAAQ,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU;AAG1E,MAAI,OAAO;AACT,QAAI,OAAO,UAAU,aAAa;AAChC,YAAM,WAAW,MAAM,MAAM,MAAM;AACnC,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,6BAA6B,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,MACvF;AACA,aAAO,MAAM,SAAS,YAAY;AAAA,IACpC;AACA,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AAIA,QAAM,SAAS,OAAO,YAAY,eACnB,QAAQ,YAAY,QACpB,QAAQ,SAAS,QAAQ;AAExC,MAAI,QAAQ;AAEV,QAAI;AACF,YAAM,KAAK,MAAM,OAAO,IAAI;AAC5B,YAAM,SAAS,MAAM,GAAG,SAAS,SAAS,MAAM;AAChD,aAAO,OAAO,OAAO,MAAM,OAAO,YAAY,OAAO,aAAa,OAAO,UAAU;AAAA,IACrF,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,iCAAiC,KAAK,EAAE;AAAA,IAC1D;AAAA,EACF;AAGA,MAAI,OAAO,UAAU,aAAa;AAChC,UAAM,WAAW,MAAM,MAAM,MAAM;AACnC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,6BAA6B,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,IACvF;AACA,WAAO,MAAM,SAAS,YAAY;AAAA,EACpC;AAEA,QAAM,IAAI,MAAM,sCAAsC;AACxD;;;AC1FA,OAAO,UAAU;AAUV,SAAS,SAAS,MAAyB;AAChD,QAAM,SAAS,KAAK,MAAM,MAAM;AAAA,IAC9B,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,iBAAiB,CAAC,WAAW,OAAO,KAAK;AAAA,IACzC,WAAW,CAAC,UAAU,MAAM,KAAK;AAAA,EACnC,CAAC;AAED,MAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,YAAQ,KAAK,yBAAyB,OAAO,MAAM;AAAA,EACrD;AAEA,QAAM,UAAU,OAAO,KAAK,UAAU,CAAC;AACvC,QAAM,OAAO,OAAO;AAEpB,SAAO,EAAE,SAAS,KAAK;AACzB;AAKO,SAAS,gBACd,KACA,aACwC;AACxC,QAAM,SAAiD,CAAC;AAGxD,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AACrD,UAAM,QAAQ,IAAI,GAAG;AAGrB,QAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AACzD,aAAO,GAAG,IAAI;AACd;AAAA,IACF;AAEA,QAAI,SAAS,WAAW;AACtB,YAAM,SAAS,SAAS,OAAO,EAAE;AACjC,aAAO,GAAG,IAAI,MAAM,MAAM,IAAI,OAAO;AAAA,IACvC,WAAW,SAAS,QAAQ;AAC1B,YAAM,SAAS,WAAW,KAAK;AAC/B,aAAO,GAAG,IAAI,MAAM,MAAM,IAAI,OAAO;AAAA,IACvC,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;;;AClDA,eAAsB,aAAa,IAAc,OAAkB,WAAqC;AAEtG,QAAM,eAAyC,oBAAI,IAAI;AACvD,aAAW,UAAU,aAAa;AAEhC,iBAAa,IAAI,GAAG,OAAO,IAAI,QAAQ,MAAM;AAAA,EAC/C;AAGA,QAAM,UAAU,IAAI,IAAI,WAAW,IAAI,OAAK,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;AAGlE,aAAW,CAAC,UAAU,OAAO,KAAK,OAAO,QAAQ,KAAK,GAAG;AACvD,UAAM,SAAS,aAAa,IAAI,QAAQ;AACxC,QAAI,CAAC,QAAQ;AAEX;AAAA,IACF;AAGA,QAAI,QAAQ,IAAI,SAAS,YAAY,CAAC,GAAG;AACvC,cAAQ,IAAI,sBAAsB,QAAQ,WAAW,OAAO,IAAI,qBAAqB;AACrF;AAAA,IACF;AAEA,UAAM,cAAc,IAAI,QAAQ,OAAO;AAAA,EACzC;AACF;AAKA,eAAe,cAAc,IAAc,QAAqB,YAAmC;AACjG,QAAM,EAAE,SAAS,KAAK,IAAI,SAAS,UAAU;AAE7C,MAAI,KAAK,WAAW,GAAG;AACrB;AAAA,EACF;AAGA,QAAM,cAA2D,CAAC;AAClE,aAAW,OAAO,OAAO,SAAS;AAChC,gBAAY,IAAI,IAAI,IAAI,IAAI;AAAA,EAC9B;AAGA,QAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC9E,QAAM,eAAe,QAAQ,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACrD,QAAM,YAAY,eAAe,OAAO,IAAI,KAAK,QAAQ,KAAK,IAAI,CAAC,aAAa,YAAY;AAE5F,QAAM,OAAO,GAAG,QAAQ,SAAS;AAGjC,aAAW,OAAO,MAAM;AACtB,UAAM,WAAW,gBAAgB,KAAK,WAAW;AACjD,UAAM,SAAS,QAAQ,IAAI,CAAC,QAAQ;AAClC,YAAM,QAAQ,SAAS,GAAG;AAE1B,aAAO,UAAU,QAAQ,UAAU,SAAY,OAAO;AAAA,IACxD,CAAC;AAED,QAAI;AACF,WAAK,IAAI,MAAM;AAAA,IACjB,SAAS,OAAO;AACd,cAAQ,MAAM,4BAA4B,OAAO,IAAI,KAAK,KAAK;AAC/D,cAAQ,MAAM,aAAa,GAAG;AAC9B,YAAM;AAAA,IACR;AAAA,EACF;AAEA,OAAK,KAAK;AACZ;;;AC/EO,SAAS,qBAAqB,IAAoB;AAEvD,KAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAYN;AAGD,KAAG,IAAI,gFAAgF;AAGvF,KAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAoBN;AAED,KAAG,IAAI,sGAAsG;AAC7G,KAAG,IAAI,6FAA6F;AAGpG,KAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAYN;AAED,KAAG,IAAI,4FAA4F;AACnG,KAAG,IAAI,mFAAmF;AAG1F,KAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAgBN;AAED,KAAG,IAAI,sGAAsG;AAC7G,KAAG,IAAI,2FAA2F;AACpG;AAKO,SAAS,kBAAkB,IAAoB;AACpD,KAAG,IAAI,uBAAuB;AAC9B,KAAG,IAAI,kCAAkC;AACzC,KAAG,IAAI,6BAA6B;AACpC,KAAG,IAAI,kCAAkC;AAC3C;;;AClGA,OAAO,cAAc;AAgGrB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoLtB,eAAe,cAAc,QAAqC;AAChE,QAAM,QAAQ,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU;AAE1E,MAAI,OAAO;AAET,UAAMA,YAAW,MAAM,MAAM,QAAQ;AAAA,MACnC,SAAS;AAAA,QACP,UAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAED,QAAI,CAACA,UAAS,IAAI;AAChB,YAAM,IAAI,MAAM,qCAAqC,MAAM,KAAKA,UAAS,MAAM,IAAIA,UAAS,UAAU,EAAE;AAAA,IAC1G;AAEA,UAAMC,eAAc,MAAMD,UAAS,YAAY;AAC/C,WAAO,IAAI,WAAWC,YAAW;AAAA,EACnC;AAGA,QAAM,SAAS,OAAO,YAAY,eACnB,QAAQ,YAAY,QACpB,QAAQ,SAAS,QAAQ;AAExC,MAAI,QAAQ;AACV,QAAI;AACF,YAAM,KAAK,MAAM,OAAO,IAAI;AAC5B,YAAM,SAAS,MAAM,GAAG,SAAS,SAAS,MAAM;AAChD,aAAO,IAAI,WAAW,OAAO,OAAO,MAAM,OAAO,YAAY,OAAO,aAAa,OAAO,UAAU,CAAC;AAAA,IACrG,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,oCAAoC,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,IACzH;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,MAAM,QAAQ;AAAA,IACnC,SAAS;AAAA,MACP,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,qCAAqC,MAAM,KAAK,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,EAC1G;AAEA,QAAM,cAAc,MAAM,SAAS,YAAY;AAC/C,SAAO,IAAI,WAAW,WAAW;AACnC;AAGA,IAAI,aAAmC;AAEvC,SAAS,kBAAiC;AACxC,MAAI,CAAC,YAAY;AACf,iBAAa,SAAS,MAAM,aAAa,EAAE;AAAA,EAC7C;AACA,SAAO;AACT;AAGA,SAAS,aAAa,KAAqB;AACzC,SAAO,IAAI,QAAQ,UAAU,YAAU,IAAI,OAAO,YAAY,CAAC,EAAE;AACnE;AAEA,SAAS,uBAAuB,KAAuB;AACrD,MAAI,QAAQ,QAAQ,QAAQ,QAAW;AACrC,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,sBAAsB;AAAA,EACvC;AACA,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,SAAkC,CAAC;AACzC,eAAW,OAAO,KAAgC;AAChD,UAAI,OAAO,UAAU,eAAe,KAAK,KAAK,GAAG,GAAG;AAClD,cAAM,WAAW,aAAa,GAAG;AACjC,eAAO,QAAQ,IAAI,uBAAwB,IAAgC,GAAG,CAAC;AAAA,MACjF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGA,SAAS,sBAAsB,IAAyD;AACtF,MAAI,CAAC,MAAM,CAAC,GAAG,eAAe,GAAG,YAAY,WAAW,GAAG;AACzD,WAAO;AAAA,EACT;AACA,SAAO,KAAK,UAAU;AAAA,IACpB,aAAa,GAAG,YAAY,IAAI,CAAC,OAAO;AAAA,MACtC,MAAM,EAAE;AAAA,MACR,UAAU,EAAE,YAAY;AAAA,IAC1B,EAAE;AAAA,EACJ,CAAC;AACH;AAGA,SAAS,aAAa,IAAc,QAAyB,WAAyB;AACpF,QAAM,OAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,GAKvB;AAED,aAAW,SAAS,QAAQ;AAE1B,UAAM,eAAe,MAAM,gBAAgB,MAAM,iBAAiB,CAAC;AACnE,UAAM,iBAAiB,MAAM,kBAAkB,MAAM,mBAAmB,CAAC;AACzE,UAAM,aAAa,MAAM,cAAc,MAAM;AAC7C,UAAM,kBAAkB,MAAM,mBAAmB,MAAM;AAGvD,UAAM,oBAAoB,uBAAuB,YAAY;AAC7D,UAAM,sBAAsB,uBAAuB,cAAc;AAEjE,SAAK,IAAI;AAAA,MACP,MAAM;AAAA,MACN,KAAK,UAAU,iBAAiB;AAAA,MAChC,KAAK,UAAU,mBAAmB;AAAA,MAClC,MAAM,SAAS;AAAA,MACf,MAAM,UAAU;AAAA,MAChB,sBAAsB,MAAM,GAAG;AAAA,MAC/B,sBAAsB,UAAU;AAAA,MAChC,sBAAsB,eAAe;AAAA,MACrC;AAAA,IACF,CAAC;AAAA,EACH;AAEA,OAAK,KAAK;AACZ;AAGA,SAAS,uBAAuB,IAAc,WAAsC,WAAyB;AAC3G,QAAM,OAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAOvB;AAED,aAAW,MAAM,WAAW;AAC1B,UAAM,OAAO,GAAG;AAChB,QAAI,CAAC,QAAQ,EAAE,KAAK,UAAU,KAAK,SAAU;AAG7C,UAAM,SAAU,KAAK,UAAU,KAAK;AACpC,UAAM,UAAU,KAAK,WAAW,KAAK;AACrC,UAAM,YAAY,GAAG,SAAS;AAC9B,UAAM,eAAe,GAAG,SAAS;AACjC,UAAM,sBAAsB,GAAG,SAAS,gBAAgB,GAAG,SAAS;AACpE,UAAM,sBAAsB,GAAG,uBAAuB,GAAG;AACzD,UAAM,SAAS,GAAG,UAAU,GAAG;AAC/B,UAAM,gBAAgB,GAAG,iBAAiB,GAAG;AAC7C,UAAM,kBAAkB,GAAG,mBAAmB,GAAG;AACjD,UAAM,kBAAkB,GAAG,mBAAmB,GAAG;AAEjD,SAAK,IAAI;AAAA,MACP;AAAA,MACA,WAAW;AAAA,MACX,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,uBAAuB;AAAA,MACvB,GAAG,UAAU,YAAY;AAAA,MACzB,GAAG,UAAU,aAAa;AAAA,MAC1B,GAAG,UAAU,WAAW;AAAA,MACxB,GAAG,UAAU,YAAY;AAAA,MACzB,GAAG,UAAU,SAAS;AAAA,MACtB,uBAAuB;AAAA,MACvB,UAAU;AAAA,MACV,iBAAiB;AAAA,MACjB,GAAG,aAAa;AAAA,MAChB,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,OAAK,KAAK;AACZ;AAGA,SAAS,kBAAkB,IAAc,SAA+B,WAAyB;AAC/F,QAAM,WAAW,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,GAK3B;AAED,QAAM,eAAe,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAO/B;AAED,aAAW,MAAM,SAAS;AACxB,UAAM,OAAO,GAAG;AAChB,QAAI,CAAC,QAAQ,EAAE,KAAK,UAAU,KAAK,SAAU;AAG7C,UAAM,SAAU,KAAK,UAAU,KAAK;AACpC,UAAM,UAAU,KAAK,WAAW,KAAK;AACrC,UAAM,YAAY,GAAG,SAAS;AAC9B,UAAM,eAAe,GAAG,SAAS;AACjC,UAAM,sBAAsB,GAAG,SAAS,gBAAgB,GAAG,SAAS;AACpE,UAAM,uBAAuB,KAAK,wBAAwB,KAAK;AAC/D,UAAM,iBAAiB,GAAG,kBAAkB,GAAG;AAG/C,aAAS,IAAI;AAAA,MACX;AAAA,MACA,WAAW;AAAA,MACX,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,uBAAuB;AAAA,MACvB,GAAG,aAAa;AAAA,MAChB,GAAG,SAAS;AAAA,MACZ,wBAAwB;AAAA,MACxB;AAAA,IACF,CAAC;AAGD,QAAI,gBAAgB;AAClB,iBAAW,OAAO,gBAAgB;AAChC,cAAM,eAAe,IAAI,gBAAgB,IAAI;AAC7C,cAAM,SAAS,IAAI,UAAU,IAAI;AACjC,cAAM,cAAc,IAAI,wBAAwB,IAAI;AAEpD,qBAAa,IAAI;AAAA,UACf;AAAA,UACA,gBAAgB;AAAA,UAChB,UAAU;AAAA,UACV,IAAI,SAAS,SAAS;AAAA,UACtB,IAAI,SAAS,QAAQ;AAAA,UACrB,IAAI,SAAS,eAAe;AAAA,UAC5B,IAAI,WAAW,SAAS;AAAA,UACxB,IAAI,WAAW,QAAQ;AAAA,UACvB,IAAI,WAAW,eAAe;AAAA,UAC9B,eAAe;AAAA,UACf;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,WAAS,KAAK;AACd,eAAa,KAAK;AACpB;AAMA,eAAsB,iBAAiB,IAAc,UAAmC;AACtF,QAAM,OAAO,gBAAgB;AAC7B,QAAM,cAAc,KAAK,WAAW,8BAA8B;AAGlE,QAAM,gBAAgB,SAAS,IAAI,OAAO,QAAQ;AAChD,QAAI;AACF,YAAM,OAAO,MAAM,cAAc,GAAG;AACpC,YAAM,UAAU,YAAY,OAAO,IAAI;AACvC,aAAO,YAAY,SAAS,SAAS;AAAA,QACnC,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,QACP,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,8CAA8C,GAAG,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,IAChI;AAAA,EACF,CAAC;AAGD,QAAM,QAAQ,MAAM,QAAQ,IAAI,aAAa;AAG7C,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAGxC,QAAM,YAA6B,CAAC;AACpC,QAAM,sBAAiD,CAAC;AACxD,QAAM,iBAAuC,CAAC;AAE9C,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,OAAQ;AAElB,eAAW,UAAU,KAAK,QAAQ;AAChC,UAAI,OAAO,OAAO;AAChB,kBAAU,KAAK,EAAE,IAAI,OAAO,IAAI,GAAG,OAAO,MAAM,CAAC;AAAA,MACnD;AACA,UAAI,OAAO,SAAS;AAClB,4BAAoB,KAAK,OAAO,OAAO;AAAA,MACzC;AACA,UAAI,OAAO,YAAY;AACrB,uBAAe,KAAK,OAAO,UAAU;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAGA,MAAI,UAAU,SAAS,GAAG;AACxB,iBAAa,IAAI,WAAW,GAAG;AAAA,EACjC;AACA,MAAI,oBAAoB,SAAS,GAAG;AAClC,2BAAuB,IAAI,qBAAqB,GAAG;AAAA,EACrD;AACA,MAAI,eAAe,SAAS,GAAG;AAC7B,sBAAkB,IAAI,gBAAgB,GAAG;AAAA,EAC3C;AACF;;;ACtkBO,SAAS,YAAY,IAAc,UAAyB,CAAC,GAAa;AAC/E,QAAM,EAAE,UAAU,MAAM,IAAI;AAG5B,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAErC,MAAI,UAAU;AACZ,eAAW,KAAK,eAAe;AAC/B,WAAO,KAAK,QAAQ;AAAA,EACtB;AAGA,MAAI,MAAM;AACV,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,SAAO;AACP,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,WAAqB,CAAC;AAC5B,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,aAAS,KAAK,YAAY,GAAG,CAAC;AAAA,EAChC;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,cAAc,IAAc,UAAiC;AAC3E,QAAM,OAAO,GAAG,QAAQ,0CAA0C;AAClE,OAAK,KAAK,CAAC,QAAQ,CAAC;AAEpB,MAAI,KAAK,KAAK,GAAG;AACf,UAAM,MAAM,KAAK,YAAY;AAC7B,SAAK,KAAK;AACV,WAAO,YAAY,GAAG;AAAA,EACxB;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAyBA,SAAS,YAAY,KAAsC;AACzD,SAAO;AAAA,IACL,WAAW,OAAO,IAAI,SAAS;AAAA,IAC/B,aAAa,OAAO,IAAI,WAAW;AAAA,IACnC,YAAY,OAAO,IAAI,UAAU;AAAA,IACjC,iBAAiB,OAAO,IAAI,eAAe;AAAA,IAC3C,aAAa,IAAI,cAAc,OAAO,IAAI,WAAW,IAAI;AAAA,IACzD,cAAc,IAAI,eAAe,OAAO,IAAI,YAAY,IAAI;AAAA,IAC5D,iBAAiB,IAAI,kBAAkB,OAAO,IAAI,eAAe,IAAI;AAAA,IACrE,cAAc,IAAI,eAAe,OAAO,IAAI,YAAY,IAAI;AAAA,EAC9D;AACF;;;ACtFO,SAAS,SAAS,IAAc,UAAuB,CAAC,GAAW;AACxE,QAAM,EAAE,QAAQ,UAAU,MAAM,QAAQ,MAAM,IAAI;AAGlD,MAAI,QAAQ;AACV,WAAO,eAAe,IAAI,MAAM;AAAA,EAClC;AAGA,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAErC,MAAI,QAAQ;AACV,eAAW,KAAK,aAAa;AAC7B,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,MAAI,UAAU;AACZ,eAAW,KAAK,eAAe;AAC/B,WAAO,KAAK,QAAQ;AAAA,EACtB;AAEA,MAAI,MAAM;AACR,eAAW,KAAK,kBAAkB;AAClC,WAAO,KAAK,IAAI,IAAI,GAAG;AAAA,EACzB;AAGA,MAAI,MAAM;AACV,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,SAAO;AACP,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,QAAgB,CAAC;AACvB,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,KAAK,UAAU,GAAG,CAAC;AAAA,EAC3B;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,YAAY,IAAc,QAA6B;AACrE,QAAM,OAAO,GAAG,QAAQ,uCAAuC;AAC/D,OAAK,KAAK,CAAC,MAAM,CAAC;AAElB,MAAI,KAAK,KAAK,GAAG;AACf,UAAM,MAAM,KAAK,YAAY;AAC7B,SAAK,KAAK;AACV,WAAO,UAAU,GAAG;AAAA,EACtB;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AA6DO,SAAS,eAAe,IAAc,QAAwB;AACnE,QAAM,OAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,GAKvB;AACD,OAAK,KAAK,CAAC,MAAM,CAAC;AAElB,QAAM,QAAgB,CAAC;AACvB,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,KAAK,UAAU,GAAG,CAAC;AAAA,EAC3B;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKA,SAAS,UAAU,KAAoC;AACrD,SAAO;AAAA,IACL,SAAS,OAAO,IAAI,OAAO;AAAA,IAC3B,WAAW,OAAO,IAAI,SAAS;AAAA,IAC/B,UAAU,OAAO,IAAI,QAAQ;AAAA,IAC7B,UAAU,OAAO,IAAI,QAAQ;AAAA,IAC7B,WAAW,IAAI,YAAY,OAAO,IAAI,SAAS,IAAI;AAAA,IACnD,WAAW,IAAI,YAAY,OAAO,IAAI,SAAS,IAAI;AAAA,IACnD,SAAS,IAAI,UAAU,OAAO,IAAI,OAAO,IAAI;AAAA,IAC7C,UAAU,IAAI,WAAW,OAAO,IAAI,QAAQ,IAAI;AAAA,IAChD,eAAe,IAAI,kBAAkB,OAAO,OAAO,IAAI,aAAa,IAAI;AAAA,IACxE,gBAAgB,IAAI,iBAAiB,OAAO,IAAI,cAAc,IAAI;AAAA,IAClE,eAAe,IAAI,gBAAgB,OAAO,IAAI,aAAa,IAAI;AAAA,IAC/D,qBAAqB,IAAI,wBAAwB,OAAO,OAAO,IAAI,mBAAmB,IAAI;AAAA,IAC1F,UAAU,IAAI,WAAW,OAAO,IAAI,QAAQ,IAAI;AAAA,IAChD,eAAe,IAAI,gBAAgB,OAAO,IAAI,aAAa,IAAI;AAAA,EACjE;AACF;;;AC1KO,SAAS,UAAU,IAAc,UAAwB,CAAC,GAAY;AAC3E,QAAM,EAAE,SAAS,UAAU,MAAM,IAAI;AAGrC,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAErC,MAAI,SAAS;AACX,eAAW,KAAK,cAAc;AAC9B,WAAO,KAAK,OAAO;AAAA,EACrB;AAEA,MAAI,UAAU;AACZ,eAAW,KAAK,eAAe;AAC/B,WAAO,KAAK,QAAQ;AAAA,EACtB;AAGA,MAAI,MAAM;AACV,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,SAAO;AACP,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,SAAkB,CAAC;AACzB,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,WAAO,KAAK,WAAW,GAAG,CAAC;AAAA,EAC7B;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,aAAa,IAAc,SAA+B;AACxE,QAAM,OAAO,GAAG,QAAQ,yCAAyC;AACjE,OAAK,KAAK,CAAC,OAAO,CAAC;AAEnB,MAAI,KAAK,KAAK,GAAG;AACf,UAAM,MAAM,KAAK,YAAY;AAC7B,SAAK,KAAK;AACV,WAAO,WAAW,GAAG;AAAA,EACvB;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AA4CA,SAAS,WAAW,KAAqC;AACvD,SAAO;AAAA,IACL,UAAU,OAAO,IAAI,QAAQ;AAAA,IAC7B,kBAAkB,OAAO,IAAI,gBAAgB;AAAA,IAC7C,iBAAiB,OAAO,IAAI,eAAe;AAAA,IAC3C,YAAY,OAAO,IAAI,UAAU;AAAA,IACjC,WAAW,IAAI,YAAY,OAAO,IAAI,SAAS,IAAI;AAAA,IACnD,YAAY,IAAI,aAAa,OAAO,IAAI,UAAU,IAAI;AAAA,IACtD,WAAW,IAAI,YAAY,OAAO,IAAI,SAAS,IAAI;AAAA,IACnD,aAAa,IAAI,cAAc,OAAO,IAAI,WAAW,IAAI;AAAA,IACzD,kBAAkB,IAAI,mBAAmB,OAAO,IAAI,gBAAgB,IAAI;AAAA,IACxE,kBAAkB,IAAI,qBAAqB,OAAO,OAAO,IAAI,gBAAgB,IAAI;AAAA,IACjF,mBAAmB,IAAI,sBAAsB,OAAO,OAAO,IAAI,iBAAiB,IAAI;AAAA,IACpF,qBAAqB,IAAI,wBAAwB,OAAO,OAAO,IAAI,mBAAmB,IAAI;AAAA,EAC5F;AACF;;;AC3HO,SAAS,oBAAoB,IAAc,MAAwB;AACxE,QAAM,aAAa,oBAAI,IAAY;AAGnC,QAAM,OAAO,SAAS,KAAK,UAAU,GAAG,CAAC,CAAC;AAC1C,QAAM,QAAQ,SAAS,KAAK,UAAU,GAAG,CAAC,CAAC;AAC3C,QAAM,MAAM,SAAS,KAAK,UAAU,GAAG,CAAC,CAAC;AACzC,QAAM,UAAU,IAAI,KAAK,MAAM,QAAQ,GAAG,GAAG;AAC7C,QAAM,YAAY,QAAQ,OAAO;AAGjC,QAAM,YAAY,CAAC,UAAU,UAAU,WAAW,aAAa,YAAY,UAAU,UAAU;AAC/F,QAAM,WAAW,UAAU,SAAS;AAGpC,QAAM,eAAe,GAAG;AAAA,IACtB;AAAA,aACS,QAAQ;AAAA;AAAA;AAAA,EAGnB;AACA,eAAa,KAAK,CAAC,MAAM,IAAI,CAAC;AAE9B,SAAO,aAAa,KAAK,GAAG;AAC1B,UAAM,MAAM,aAAa,YAAY;AACrC,eAAW,IAAI,IAAI,UAAU;AAAA,EAC/B;AACA,eAAa,KAAK;AAGlB,QAAM,iBAAiB,GAAG,QAAQ,sEAAsE;AACxG,iBAAe,KAAK,CAAC,IAAI,CAAC;AAE1B,SAAO,eAAe,KAAK,GAAG;AAC5B,UAAM,MAAM,eAAe,YAAY;AACvC,QAAI,IAAI,mBAAmB,GAAG;AAE5B,iBAAW,IAAI,IAAI,UAAU;AAAA,IAC/B,WAAW,IAAI,mBAAmB,GAAG;AAEnC,iBAAW,OAAO,IAAI,UAAU;AAAA,IAClC;AAAA,EACF;AACA,iBAAe,KAAK;AAEpB,SAAO,MAAM,KAAK,UAAU;AAC9B;AAKO,SAAS,uBAAuB,IAAc,WAAoC;AACvF,QAAM,OAAO,GAAG,QAAQ,6CAA6C;AACrE,OAAK,KAAK,CAAC,SAAS,CAAC;AAErB,MAAI,KAAK,KAAK,GAAG;AACf,UAAM,MAAM,KAAK,YAAY;AAC7B,SAAK,KAAK;AACV,WAAO,cAAc,GAAG;AAAA,EAC1B;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,iBAAiB,IAAc,WAAmC;AAChF,QAAM,OAAO,GAAG,QAAQ,iEAAiE;AACzF,OAAK,KAAK,CAAC,SAAS,CAAC;AAErB,QAAM,QAAwB,CAAC;AAC/B,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,KAAK,kBAAkB,GAAG,CAAC;AAAA,EACnC;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,wBAAwB,IAAc,MAA8B;AAClF,QAAM,OAAO,GAAG,QAAQ,6CAA6C;AACrE,OAAK,KAAK,CAAC,IAAI,CAAC;AAEhB,QAAM,QAAwB,CAAC;AAC/B,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,KAAK,kBAAkB,GAAG,CAAC;AAAA,EACnC;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKA,SAAS,cAAc,KAAwC;AAC7D,SAAO;AAAA,IACL,YAAY,OAAO,IAAI,UAAU;AAAA,IACjC,QAAQ,OAAO,IAAI,MAAM;AAAA,IACzB,SAAS,OAAO,IAAI,OAAO;AAAA,IAC3B,WAAW,OAAO,IAAI,SAAS;AAAA,IAC/B,UAAU,OAAO,IAAI,QAAQ;AAAA,IAC7B,QAAQ,OAAO,IAAI,MAAM;AAAA,IACzB,UAAU,OAAO,IAAI,QAAQ;AAAA,IAC7B,QAAQ,OAAO,IAAI,MAAM;AAAA,IACzB,YAAY,OAAO,IAAI,UAAU;AAAA,IACjC,UAAU,OAAO,IAAI,QAAQ;AAAA,EAC/B;AACF;AAKA,SAAS,kBAAkB,KAA4C;AACrE,SAAO;AAAA,IACL,YAAY,OAAO,IAAI,UAAU;AAAA,IACjC,MAAM,OAAO,IAAI,IAAI;AAAA,IACrB,gBAAgB,OAAO,IAAI,cAAc;AAAA,EAC3C;AACF;;;AC/HO,SAAS,qBAAqB,KAA+C;AAClF,QAAM,KAAsB;AAAA,IAC1B,SAAS,OAAO,IAAI,OAAO;AAAA,IAC3B,UAAU,IAAI,WAAW,OAAO,IAAI,QAAQ,IAAI;AAAA,IAChD,iBAAiB,OAAO,IAAI,eAAe;AAAA,EAC7C;AAGA,MAAI,IAAI,cAAc,IAAI,iBAAiB,IAAI,uBAAuB;AACpE,OAAG,UAAU;AAAA,MACX,IAAI,IAAI,aAAa,OAAO,IAAI,UAAU,IAAI;AAAA,MAC9C,OAAO,IAAI,gBAAgB,OAAO,IAAI,aAAa,IAAI;AAAA,MACvD,eAAe,IAAI,wBAAwB,OAAO,IAAI,qBAAqB,IAAI;AAAA,IACjF;AAAA,EACF;AAGA,MAAI,IAAI,aAAa,QAAQ,IAAI,cAAc,MAAM;AACnD,OAAG,WAAW;AAAA,MACZ,UAAU,OAAO,IAAI,QAAQ;AAAA,MAC7B,WAAW,OAAO,IAAI,SAAS;AAAA,MAC/B,SAAS,IAAI,YAAY,OAAO,OAAO,IAAI,OAAO,IAAI;AAAA,MACtD,UAAU,IAAI,aAAa,OAAO,OAAO,IAAI,QAAQ,IAAI;AAAA,MACzD,OAAO,IAAI,UAAU,OAAO,OAAO,IAAI,KAAK,IAAI;AAAA,IAClD;AAAA,EACF;AAGA,MAAI,IAAI,0BAA0B,MAAM;AACtC,OAAG,wBAAwB,OAAO,IAAI,qBAAqB;AAAA,EAC7D;AACA,MAAI,IAAI,SAAS;AACf,OAAG,UAAU,OAAO,IAAI,OAAO;AAAA,EACjC;AACA,MAAI,IAAI,mBAAmB,MAAM;AAC/B,OAAG,iBAAiB,OAAO,IAAI,cAAc;AAAA,EAC/C;AACA,MAAI,IAAI,cAAc,MAAM;AAC1B,OAAG,YAAY,OAAO,IAAI,SAAS;AAAA,EACrC;AACA,MAAI,IAAI,qBAAqB,MAAM;AACjC,OAAG,mBAAmB,OAAO,IAAI,gBAAgB;AAAA,EACnD;AACA,MAAI,IAAI,qBAAqB,MAAM;AACjC,OAAG,mBAAmB,OAAO,IAAI,gBAAgB;AAAA,EACnD;AAEA,SAAO;AACT;AAKO,SAAS,oBACd,IACA,UAAkC,CAAC,GACnC,qBAA6B,KACV;AACnB,QAAM,EAAE,QAAQ,SAAS,WAAW,MAAM,IAAI;AAE9C,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAGrC,MAAI,QAAQ;AACV,eAAW,KAAK,aAAa;AAC7B,WAAO,KAAK,MAAM;AAAA,EACpB;AAGA,MAAI,SAAS;AACX,eAAW,KAAK,cAAc;AAC9B,WAAO,KAAK,OAAO;AAAA,EACrB;AAGA,MAAI,WAAW;AACb,eAAW,KAAK,gBAAgB;AAChC,WAAO,KAAK,SAAS;AAAA,EACvB;AAGA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,iBAAiB,MAAM;AAC7B,aAAW,KAAK,sBAAsB;AACtC,SAAO,KAAK,cAAc;AAG1B,MAAI,MAAM;AACV,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,SAAO;AAEP,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAGA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,YAA+B,CAAC;AACtC,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,cAAU,KAAK,qBAAqB,GAAG,CAAC;AAAA,EAC1C;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,2BACd,IACA,QACA,qBAA6B,KACL;AACxB,QAAM,YAAY,oBAAoB,IAAI,EAAE,QAAQ,OAAO,EAAE,GAAG,kBAAkB;AAClF,SAAO,UAAU,SAAS,IAAI,UAAU,CAAC,IAAI;AAC/C;AAKO,SAAS,uBAAuB,IAAiC;AACtE,QAAM,MAAM;AACZ,QAAM,OAAO,GAAG,QAAQ,GAAG;AAE3B,QAAM,YAA+B,CAAC;AACtC,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,cAAU,KAAK,qBAAqB,GAAG,CAAC;AAAA,EAC1C;AAEA,OAAK,KAAK;AACV,SAAO;AACT;;;AC7HA,SAAS,kBACP,OACA,IACA,oBACoB;AACpB,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,iBAAiB,MAAM;AAE7B,QAAM,UAAU,MAAM,IAAI,OAAK,EAAE,OAAO;AACxC,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,eAAe,QAAQ,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AAGrD,QAAM,SAAS,GAAG,QAAQ;AAAA;AAAA,wBAEJ,YAAY;AAAA;AAAA,GAEjC;AACD,SAAO,KAAK,CAAC,GAAG,SAAS,cAAc,CAAC;AAExC,QAAM,QAAQ,oBAAI,IAA6B;AAC/C,SAAO,OAAO,KAAK,GAAG;AACpB,UAAM,MAAM,OAAO,YAAY;AAC/B,UAAM,KAAK,qBAAqB,GAAG;AACnC,UAAM,IAAI,GAAG,SAAS,EAAE;AAAA,EAC1B;AACA,SAAO,KAAK;AAGZ,QAAM,SAAS,GAAG,QAAQ;AAAA;AAAA,wBAEJ,YAAY;AAAA;AAAA,GAEjC;AACD,SAAO,KAAK,CAAC,GAAG,SAAS,cAAc,CAAC;AAExC,QAAM,QAAQ,oBAAI,IAAgE;AAClF,SAAO,OAAO,KAAK,GAAG;AACpB,UAAM,MAAM,OAAO,YAAY;AAC/B,UAAM,SAAS,OAAO,IAAI,OAAO;AACjC,UAAM,IAAI,QAAQ;AAAA,MAChB,OAAO,IAAI,UAAU,OAAO,OAAO,IAAI,KAAK,IAAI;AAAA,MAChD,uBAAuB,IAAI,0BAA0B,OAAO,OAAO,IAAI,qBAAqB,IAAI;AAAA,IAClG,CAAC;AAAA,EACH;AACA,SAAO,KAAK;AAGZ,SAAO,MAAM,IAAI,CAAC,SAA2B;AAC3C,UAAM,KAAK,MAAM,IAAI,KAAK,OAAO;AACjC,UAAM,KAAK,MAAM,IAAI,KAAK,OAAO;AAEjC,QAAI,CAAC,MAAM,CAAC,IAAI;AACd,aAAO,EAAE,GAAG,MAAM,UAAU,EAAE,kBAAkB,MAAM,aAAa,KAAK,EAAE;AAAA,IAC5E;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,QACR,kBAAkB,MAAM;AAAA,QACxB,aAAa,MAAM;AAAA,MACrB;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAKO,SAAS,SACd,IACA,UAAuB,CAAC,GACxB,qBAA6B,KACA;AAC7B,QAAM,EAAE,QAAQ,SAAS,YAAY,aAAa,UAAU,iBAAiB,MAAM,IAAI;AAGvF,QAAM,kBAAkB,aAAa;AAGrC,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAErC,MAAI,QAAQ;AACV,eAAW,KAAK,kBAAkB,kBAAkB,aAAa;AACjE,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,MAAI,SAAS;AACX,eAAW,KAAK,kBAAkB,mBAAmB,cAAc;AACnE,WAAO,KAAK,OAAO;AAAA,EACrB;AAEA,MAAI,cAAc,WAAW,SAAS,GAAG;AACvC,UAAM,eAAe,WAAW,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACxD,eAAW,KAAK,kBAAkB,oBAAoB,YAAY,MAAM,kBAAkB,YAAY,GAAG;AACzG,WAAO,KAAK,GAAG,UAAU;AAAA,EAC3B;AAEA,MAAI,gBAAgB,QAAW;AAC7B,eAAW,KAAK,kBAAkB,uBAAuB,kBAAkB;AAC3E,WAAO,KAAK,WAAW;AAAA,EACzB;AAEA,MAAI,UAAU;AACZ,eAAW,KAAK,iBAAiB;AACjC,WAAO,KAAK,QAAQ;AAAA,EACtB;AAGA,MAAI,MAAM,kBACN,2EACA;AAEJ,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,QAAgB,CAAC;AACvB,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,KAAK,UAAU,GAAG,CAAC;AAAA,EAC3B;AAEA,OAAK,KAAK;AAGV,MAAI,iBAAiB;AACnB,WAAO,kBAAkB,OAAO,IAAI,kBAAkB;AAAA,EACxD;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,IAAc,QAA6B;AACrE,QAAM,OAAO,GAAG,QAAQ,uCAAuC;AAC/D,OAAK,KAAK,CAAC,MAAM,CAAC;AAElB,MAAI,KAAK,KAAK,GAAG;AACf,UAAM,MAAM,KAAK,YAAY;AAC7B,SAAK,KAAK;AACV,WAAO,UAAU,GAAG;AAAA,EACtB;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAqGA,SAAS,UAAU,KAAoC;AACrD,SAAO;AAAA,IACL,SAAS,OAAO,IAAI,OAAO;AAAA,IAC3B,UAAU,OAAO,IAAI,QAAQ;AAAA,IAC7B,YAAY,OAAO,IAAI,UAAU;AAAA,IACjC,eAAe,IAAI,gBAAgB,OAAO,IAAI,aAAa,IAAI;AAAA,IAC/D,iBAAiB,IAAI,kBAAkB,OAAO,IAAI,eAAe,IAAI;AAAA,IACrE,cAAc,IAAI,iBAAiB,OAAO,OAAO,IAAI,YAAY,IAAI;AAAA,IACrE,UAAU,IAAI,WAAW,OAAO,IAAI,QAAQ,IAAI;AAAA,IAChD,UAAU,IAAI,WAAW,OAAO,IAAI,QAAQ,IAAI;AAAA,IAChD,uBAAuB,IAAI,0BAA0B,OAAO,OAAO,IAAI,qBAAqB,IAAI;AAAA,IAChG,eAAe,IAAI,kBAAkB,OAAO,OAAO,IAAI,aAAa,IAAI;AAAA,EAC1E;AACF;;;ACjRA,SAASC,mBACP,WACA,IACA,oBACwB;AACxB,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,iBAAiB,MAAM;AAG7B,QAAM,UAAU,MAAM,KAAK,IAAI,IAAI,UAAU,IAAI,QAAM,GAAG,OAAO,CAAC,CAAC;AACnE,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,eAAe,QAAQ,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACrD,QAAM,OAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA,wBAIF,YAAY;AAAA;AAAA,GAEjC;AACD,OAAK,KAAK,CAAC,GAAG,SAAS,cAAc,CAAC;AAGtC,QAAM,QAAQ,oBAAI,IAA8B;AAChD,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,MAAM,GAAG,IAAI,OAAO,IAAI,IAAI,aAAa;AAC/C,UAAM,IAAI,KAAK;AAAA,MACb,eAAe,IAAI,kBAAkB,OAAO,OAAO,IAAI,aAAa,IAAI;AAAA,MACxE,iBAAiB,IAAI,oBAAoB,OAAO,OAAO,IAAI,eAAe,IAAI;AAAA,MAC9E,uBAAuB,IAAI,0BAA0B,OAAO,OAAO,IAAI,qBAAqB,IAAI;AAAA,IAClG,CAAC;AAAA,EACH;AACA,OAAK,KAAK;AAGV,SAAO,UAAU,IAAI,CAAC,OAA6B;AACjD,UAAM,MAAM,GAAG,GAAG,OAAO,IAAI,GAAG,aAAa;AAC7C,UAAM,SAAS,MAAM,IAAI,GAAG;AAE5B,QAAI,QAAQ;AACV,aAAO,EAAE,GAAG,IAAI,UAAU,OAAO;AAAA,IACnC;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAKO,SAAS,aACd,IACA,UAA2B,CAAC,GAC5B,qBAA6B,KACQ;AACrC,QAAM,EAAE,QAAQ,QAAQ,SAAS,YAAY,aAAa,UAAU,iBAAiB,MAAM,IAAI;AAG/F,QAAM,iBAAiB,WAAW,cAAc,gBAAgB,UAAa,aAAa;AAC1F,QAAM,kBAAkB,aAAa;AAGrC,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAErC,MAAI,QAAQ;AACV,eAAW,KAAK,iBAAiB,mBAAmB,aAAa;AACjE,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,MAAI,QAAQ;AACV,eAAW,KAAK,iBAAiB,mBAAmB,aAAa;AACjE,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,MAAI,SAAS;AACX,eAAW,KAAK,gBAAgB;AAChC,WAAO,KAAK,OAAO;AAAA,EACrB;AAEA,MAAI,cAAc,WAAW,SAAS,GAAG;AACvC,UAAM,eAAe,WAAW,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACxD,eAAW,KAAK,oBAAoB,YAAY,GAAG;AACnD,WAAO,KAAK,GAAG,UAAU;AAAA,EAC3B;AAEA,MAAI,gBAAgB,QAAW;AAC7B,eAAW,KAAK,oBAAoB;AACpC,WAAO,KAAK,WAAW;AAAA,EACzB;AAEA,MAAI,UAAU;AACZ,eAAW,KAAK,iBAAiB;AACjC,WAAO,KAAK,QAAQ;AAAA,EACtB;AAGA,MAAI;AACJ,MAAI,iBAAiB;AACnB,UAAM;AAAA,EACR,WAAW,gBAAgB;AACzB,UAAM;AAAA,EACR,OAAO;AACL,UAAM;AAAA,EACR;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AAGA,SAAO,SAAS,4BAA4B;AAE5C,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,YAAwB,CAAC;AAC/B,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,cAAU,KAAK,cAAc,GAAG,CAAC;AAAA,EACnC;AAEA,OAAK,KAAK;AAGV,MAAI,iBAAiB;AACnB,WAAOA,mBAAkB,WAAW,IAAI,kBAAkB;AAAA,EAC5D;AAEA,SAAO;AACT;AAKO,SAAS,mBAAmB,IAAc,QAA4B;AAC3E,QAAM,OAAO,GAAG,QAAQ,mEAAmE;AAC3F,OAAK,KAAK,CAAC,MAAM,CAAC;AAElB,QAAM,YAAwB,CAAC;AAC/B,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,cAAU,KAAK,cAAc,GAAG,CAAC;AAAA,EACnC;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAoGA,SAAS,cAAc,KAAwC;AAC7D,SAAO;AAAA,IACL,SAAS,OAAO,IAAI,OAAO;AAAA,IAC3B,cAAc,OAAO,IAAI,YAAY;AAAA,IACrC,gBAAgB,OAAO,IAAI,cAAc;AAAA,IACzC,SAAS,OAAO,IAAI,OAAO;AAAA,IAC3B,eAAe,OAAO,IAAI,aAAa;AAAA,IACvC,eAAe,IAAI,gBAAgB,OAAO,IAAI,aAAa,IAAI;AAAA,IAC/D,aAAa,IAAI,gBAAgB,OAAO,OAAO,IAAI,WAAW,IAAI;AAAA,IAClE,eAAe,IAAI,kBAAkB,OAAO,OAAO,IAAI,aAAa,IAAI;AAAA,IACxE,mBAAmB,IAAI,sBAAsB,OAAO,OAAO,IAAI,iBAAiB,IAAI;AAAA,IACpF,qBAAqB,IAAI,wBAAwB,OAAO,OAAO,IAAI,mBAAmB,IAAI;AAAA,IAC1F,qBAAqB,IAAI,wBAAwB,OAAO,OAAO,IAAI,mBAAmB,IAAI;AAAA,IAC1F,WAAW,IAAI,cAAc,OAAO,OAAO,IAAI,SAAS,IAAI;AAAA,EAC9D;AACF;;;AC9RA,SAAS,WAAW,KAAqC;AACvD,SAAO;AAAA,IACL,IAAI,OAAO,IAAI,EAAE;AAAA,IACjB,eAAe,IAAI,gBAAgB,KAAK,MAAM,OAAO,IAAI,aAAa,CAAC,IAAmB,CAAC;AAAA,IAC3F,iBAAiB,IAAI,kBAAkB,KAAK,MAAM,OAAO,IAAI,eAAe,CAAC,IAAwB,CAAC;AAAA,IACtG,OAAO,IAAI,QAAQ,OAAO,IAAI,KAAK,IAAI;AAAA,IACvC,QAAQ,IAAI,SAAS,OAAO,IAAI,MAAM,IAAI;AAAA,IAC1C,KAAK,IAAI,MAAM,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,IAAwB;AAAA,IACjE,aAAa,IAAI,cAAc,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,IAAwB;AAAA,IACzF,kBAAkB,IAAI,mBAAmB,KAAK,MAAM,OAAO,IAAI,gBAAgB,CAAC,IAAwB;AAAA,IACxG,iBAAiB,OAAO,IAAI,eAAe;AAAA,EAC7C;AACF;AAKA,SAAS,cAAc,OAAc,KAAsB;AAEzD,MAAI,CAAC,MAAM,iBAAiB,MAAM,cAAc,WAAW,GAAG;AAC5D,WAAO;AAAA,EACT;AAGA,aAAW,UAAU,MAAM,eAAe;AACxC,UAAM,QAAQ,OAAO,SAAS;AAC9B,UAAM,MAAM,OAAO,OAAO,OAAO;AAEjC,QAAI,OAAO,SAAS,OAAO,KAAK;AAC9B,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,OAAc,SAAgC;AACxE,MAAI,CAAC,MAAM,mBAAmB,MAAM,gBAAgB,WAAW,GAAG;AAChE,WAAO;AAAA,EACT;AAEA,aAAW,UAAU,MAAM,iBAAiB;AAE1C,QAAI,QAAQ,WAAW,OAAO,aAAa,QAAQ,SAAS;AAC1D,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ,UAAU,OAAO,YAAY,QAAQ,QAAQ;AACvD,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ,UAAU,OAAO,MAAM,YAAY,QAAQ,QAAQ;AAC7D,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,UAAU,IAAc,UAAwB,CAAC,GAAG,qBAA6B,KAAc;AAC7G,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAGrC,MAAI,SAAS;AACX,eAAW,KAAK,QAAQ;AACxB,WAAO,KAAK,OAAO;AAAA,EACrB;AAGA,MAAI,UAAU,QAAW;AACvB,eAAW,KAAK,WAAW;AAC3B,WAAO,KAAK,KAAK;AAAA,EACnB;AAGA,MAAI,WAAW,QAAW;AACxB,eAAW,KAAK,YAAY;AAC5B,WAAO,KAAK,MAAM;AAAA,EACpB;AAGA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,iBAAiB,MAAM;AAC7B,aAAW,KAAK,sBAAsB;AACtC,SAAO,KAAK,cAAc;AAG1B,MAAI,MAAM;AACV,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,SAAO;AAEP,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAGA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,SAAkB,CAAC;AACzB,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,QAAQ,WAAW,GAAG;AAG5B,QAAI,cAAc,CAAC,cAAc,OAAO,GAAG,GAAG;AAC5C;AAAA,IACF;AAGA,QAAI,WAAW,UAAU,QAAQ;AAC/B,UAAI,CAAC,mBAAmB,OAAO,OAAO,GAAG;AACvC;AAAA,MACF;AAAA,IACF;AAEA,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,aAAa,IAAc,SAAiB,qBAA6B,KAAmB;AAC1G,QAAM,SAAS,UAAU,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,kBAAkB;AACtE,SAAO,OAAO,SAAS,IAAI,OAAO,CAAC,IAAI;AACzC;AAKO,SAAS,aAAa,IAAuB;AAClD,QAAM,MAAM;AACZ,QAAM,OAAO,GAAG,QAAQ,GAAG;AAE3B,QAAM,SAAkB,CAAC;AACzB,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,WAAO,KAAK,WAAW,GAAG,CAAC;AAAA,EAC7B;AAEA,OAAK,KAAK;AACV,SAAO;AACT;;;ACvKO,SAAS,gBAAgB,KAA0C;AACxE,QAAM,KAAiB;AAAA,IACrB,SAAS,OAAO,IAAI,OAAO;AAAA,IAC3B,UAAU,IAAI,WAAW,OAAO,IAAI,QAAQ,IAAI;AAAA,IAChD,kBAAkB,CAAC;AAAA;AAAA,IACnB,WAAW,IAAI,cAAc,OAAO,OAAO,IAAI,SAAS,IAAI;AAAA,IAC5D,OAAO,IAAI,UAAU,OAAO,OAAO,IAAI,KAAK,IAAI;AAAA,IAChD,uBAAuB,IAAI,0BAA0B,OAAO,OAAO,IAAI,qBAAqB,IAAI;AAAA,IAChG,iBAAiB,OAAO,IAAI,eAAe;AAAA,EAC7C;AAGA,MAAI,IAAI,cAAc,IAAI,iBAAiB,IAAI,uBAAuB;AACpE,OAAG,UAAU;AAAA,MACX,IAAI,IAAI,aAAa,OAAO,IAAI,UAAU,IAAI;AAAA,MAC9C,OAAO,IAAI,gBAAgB,OAAO,IAAI,aAAa,IAAI;AAAA,MACvD,eAAe,IAAI,wBAAwB,OAAO,IAAI,qBAAqB,IAAI;AAAA,IACjF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,eACd,IACA,UAA6B,CAAC,GAC9B,qBAA6B,KACf;AACd,QAAM,EAAE,QAAQ,SAAS,WAAW,MAAM,IAAI;AAE9C,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAGrC,MAAI,QAAQ;AACV,eAAW,KAAK,aAAa;AAC7B,WAAO,KAAK,MAAM;AAAA,EACpB;AAGA,MAAI,SAAS;AACX,eAAW,KAAK,cAAc;AAC9B,WAAO,KAAK,OAAO;AAAA,EACrB;AAGA,MAAI,WAAW;AACb,eAAW,KAAK,gBAAgB;AAChC,WAAO,KAAK,SAAS;AAAA,EACvB;AAGA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,iBAAiB,MAAM;AAC7B,aAAW,KAAK,sBAAsB;AACtC,SAAO,KAAK,cAAc;AAG1B,MAAI,MAAM;AACV,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,SAAO;AAEP,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAGA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,cAA4B,CAAC;AACnC,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,gBAAY,KAAK,gBAAgB,GAAG,CAAC;AAAA,EACvC;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,sBACd,IACA,QACA,qBAA6B,KACV;AACnB,QAAM,UAAU,eAAe,IAAI,EAAE,QAAQ,OAAO,EAAE,GAAG,kBAAkB;AAC3E,SAAO,QAAQ,SAAS,IAAI,QAAQ,CAAC,IAAI;AAC3C;AAKO,SAAS,kBAAkB,IAA4B;AAC5D,QAAM,MAAM;AACZ,QAAM,OAAO,GAAG,QAAQ,GAAG;AAE3B,QAAM,cAA4B,CAAC;AACnC,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,gBAAY,KAAK,gBAAgB,GAAG,CAAC;AAAA,EACvC;AAEA,OAAK,KAAK;AACV,SAAO;AACT;;;ACnHA,SAAS,oBAAoB,KAA8C;AACzE,QAAM,MAAsB;AAAA,IAC1B,eAAe,IAAI,kBAAkB,OAAO,OAAO,IAAI,aAAa,IAAI;AAAA,IACxE,SAAS,IAAI,UAAU,OAAO,IAAI,OAAO,IAAI;AAAA,IAC7C,uBAAuB,IAAI,0BAA0B,OAAO,OAAO,IAAI,qBAAqB,IAAI;AAAA,EAClG;AAGA,MAAI,IAAI,kBAAkB,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,wBAAwB,MAAM;AAC/F,QAAI,UAAU;AAAA,MACZ,OAAO,IAAI,kBAAkB,OAAO,OAAO,IAAI,aAAa,IAAI;AAAA,MAChE,MAAM,IAAI,iBAAiB,OAAO,OAAO,IAAI,YAAY,IAAI;AAAA,MAC7D,aAAa,IAAI,wBAAwB,OAAO,OAAO,IAAI,mBAAmB,IAAI;AAAA,IACpF;AAAA,EACF;AAGA,MAAI,IAAI,oBAAoB,QAAQ,IAAI,mBAAmB,QAAQ,IAAI,0BAA0B,MAAM;AACrG,QAAI,YAAY;AAAA,MACd,OAAO,IAAI,oBAAoB,OAAO,OAAO,IAAI,eAAe,IAAI;AAAA,MACpE,MAAM,IAAI,mBAAmB,OAAO,OAAO,IAAI,cAAc,IAAI;AAAA,MACjE,aAAa,IAAI,0BAA0B,OAAO,OAAO,IAAI,qBAAqB,IAAI;AAAA,IACxF;AAAA,EACF;AAEA,SAAO;AACT;AAaA,SAAS,gCAAgC,KAA0D;AACjG,QAAM,MAAM,oBAAoB,GAAG;AACnC,MAAI,UAAU,OAAO,IAAI,OAAO;AAChC,MAAI,kBAAkB,OAAO,IAAI,eAAe;AAChD,SAAO;AACT;AAKO,SAAS,mBACd,IACA,UAAiC,CAAC,GAClC,qBAA6B,KACX;AAClB,QAAM,EAAE,QAAQ,QAAQ,cAAc,MAAM,IAAI;AAEhD,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAA8B,CAAC;AAGrC,MAAI,QAAQ;AACV,eAAW,KAAK,aAAa;AAC7B,WAAO,KAAK,MAAM;AAAA,EACpB;AAGA,MAAI,QAAQ;AACV,eAAW,KAAK,aAAa;AAC7B,WAAO,KAAK,MAAM;AAAA,EACpB;AAGA,MAAI,iBAAiB,QAAW;AAC9B,eAAW,KAAK,mBAAmB;AACnC,WAAO,KAAK,YAAY;AAAA,EAC1B;AAGA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,iBAAiB,MAAM;AAC7B,aAAW,KAAK,sBAAsB;AACtC,SAAO,KAAK,cAAc;AAG1B,MAAI,MAAM;AACV,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,YAAY,WAAW,KAAK,OAAO;AAAA,EAC5C;AACA,SAAO;AAEP,MAAI,OAAO;AACT,WAAO;AACP,WAAO,KAAK,KAAK;AAAA,EACnB;AAGA,QAAM,OAAO,GAAG,QAAQ,GAAG;AAC3B,MAAI,OAAO,SAAS,GAAG;AACrB,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,QAAM,kBAAoC,CAAC;AAC3C,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,oBAAgB,KAAK,oBAAoB,GAAG,CAAC;AAAA,EAC/C;AAEA,OAAK,KAAK;AACV,SAAO;AACT;AAKO,SAAS,2BACd,IACA,QACA,qBAA6B,KACX;AAClB,SAAO,mBAAmB,IAAI,EAAE,OAAO,GAAG,kBAAkB;AAC9D;AAMO,SAAS,sBAAsB,IAA4C;AAChF,QAAM,MAAM;AACZ,QAAM,OAAO,GAAG,QAAQ,GAAG;AAE3B,QAAM,kBAAgD,CAAC;AACvD,SAAO,KAAK,KAAK,GAAG;AAClB,UAAM,MAAM,KAAK,YAAY;AAC7B,oBAAgB,KAAK,gCAAgC,GAAG,CAAC;AAAA,EAC3D;AAEA,OAAK,KAAK;AACV,SAAO;AACT;;;AhB3EO,IAAM,YAAN,MAAM,WAAU;AAAA;AAAA;AAAA;AAAA,EASb,cAAc;AARtB,SAAQ,KAAsB;AAC9B,SAAQ,MAA0B;AAClC,SAAQ,mBAA6B,CAAC;AACtC,SAAQ,qBAA6B;AAAA,EAKd;AAAA;AAAA;AAAA;AAAA,EAKvB,aAAa,QACX,SACA,UAA0D,CAAC,GACvC;AACpB,UAAM,WAAW,IAAI,WAAU;AAC/B,UAAM,SAAS,YAAY,SAAS,OAAO;AAC3C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,aACX,UACA,UAA0D,CAAC,GACvC;AACpB,UAAM,WAAW,IAAI,WAAU;AAC/B,UAAM,SAAS,iBAAiB,UAAU,OAAO;AACjD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YAAY,SAAiB,SAAwE;AAEjH,SAAK,MAAM,QAAQ,OAAQ,MAAM,UAAU,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC,CAAC;AAGvG,SAAK,KAAK,IAAI,KAAK,IAAI,SAAS;AAGhC,UAAM,mBAAmB,uBAAuB;AAChD,eAAW,aAAa,kBAAkB;AACxC,WAAK,GAAG,IAAI,SAAS;AAAA,IACvB;AAGA,yBAAqB,KAAK,EAAE;AAG5B,UAAM,QAAQ,MAAM,YAAY,OAAO;AACvC,UAAM,aAAa,KAAK,IAAI,OAAO,QAAQ,SAAS;AAGpD,QAAI,QAAQ,kBAAkB;AAC5B,WAAK,mBAAmB,QAAQ;AAAA,IAClC;AACA,QAAI,QAAQ,uBAAuB,QAAW;AAC5C,WAAK,qBAAqB,QAAQ;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBACZ,UACA,SACe;AAEf,SAAK,MAAM,QAAQ,OAAQ,MAAM,UAAU,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC,CAAC;AAGvG,SAAK,KAAK,IAAI,KAAK,IAAI,SAAS,IAAI,WAAW,QAAQ,CAAC;AAGxD,yBAAqB,KAAK,EAAE;AAG5B,QAAI,QAAQ,kBAAkB;AAC5B,WAAK,mBAAmB,QAAQ;AAAA,IAClC;AACA,QAAI,QAAQ,uBAAuB,QAAW;AAC5C,WAAK,qBAAqB,QAAQ;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAsB;AACpB,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,OAAO,KAAK,GAAG,OAAO;AAE5B,UAAM,SAAS,IAAI,YAAY,KAAK,MAAM;AAC1C,QAAI,WAAW,MAAM,EAAE,IAAI,IAAI;AAC/B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAM;AACd,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAwB;AACtB,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,UAAiC;AAC7C,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,cAAc,KAAK,IAAI,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAAmC;AAC7C,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,YAAY,KAAK,IAAI,OAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,QAA6B;AACvC,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,YAAY,KAAK,IAAI,MAAM;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,SAA+B;AACtC,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,SAAS,KAAK,IAAI,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,SAA+B;AAC1C,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,aAAa,KAAK,IAAI,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,SAAiC;AACzC,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,UAAU,KAAK,IAAI,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,MAAwB;AAC1C,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,oBAAoB,KAAK,IAAI,IAAI;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAuB,WAAoC;AACzD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,uBAAuB,KAAK,IAAI,SAAS;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,WAAmC;AAClD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,iBAAiB,KAAK,IAAI,SAAS;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAwB,MAA8B;AACpD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,wBAAwB,KAAK,IAAI,IAAI;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,QAA6B;AACvC,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,YAAY,KAAK,IAAI,MAAM;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,SAAS,SAAmD;AAC1D,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AAGxD,UAAM,EAAE,MAAM,GAAG,YAAY,IAAI,WAAW,CAAC;AAC7C,UAAM,eAAe,EAAE,GAAG,YAAY;AAEtC,QAAI,MAAM;AACR,YAAM,aAAa,oBAAoB,KAAK,IAAI,IAAI;AACpD,mBAAa,aAAa;AAAA,IAC5B;AAEA,WAAO,SAAS,KAAK,IAAI,cAAc,KAAK,kBAAkB;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,QAA4B;AAC7C,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,mBAAmB,KAAK,IAAI,MAAM;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BA,aAAa,SAA2D;AACtE,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AAGxD,UAAM,EAAE,MAAM,GAAG,YAAY,IAAI,WAAW,CAAC;AAC7C,UAAM,eAAe,EAAE,GAAG,YAAY;AAEtC,QAAI,MAAM;AACR,YAAM,aAAa,oBAAoB,KAAK,IAAI,IAAI;AACpD,mBAAa,aAAa;AAAA,IAC5B;AAEA,WAAO,aAAa,KAAK,IAAI,cAAc,KAAK,kBAAkB;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,MAAsB;AACxC,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAgC;AAC9B,WAAO,CAAC,GAAG,KAAK,gBAAgB;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,SAAuB;AAC3C,SAAK,qBAAqB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAgC;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAkB,MAAgC;AACtD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AAExD,UAAM,WAAW,QAAQ,KAAK;AAC9B,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,MAAM,qFAAqF;AAAA,IACvG;AAEA,UAAM,iBAAiB,KAAK,IAAI,QAAQ;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,sBAAY,KAAK,EAAE;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,SAAiC;AACzC,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,UAAe,KAAK,IAAI,SAAS,KAAK,kBAAkB;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAA+B;AAC1C,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,aAAa,KAAK,IAAI,SAAS,KAAK,kBAAkB;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,SAAqD;AACvE,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,oBAAyB,KAAK,IAAI,SAAS,KAAK,kBAAkB;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA,EAKA,2BAA2B,QAAwC;AACjE,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,2BAA2B,KAAK,IAAI,QAAQ,KAAK,kBAAkB;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,SAA2C;AACxD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,eAAe,KAAK,IAAI,SAAS,KAAK,kBAAkB;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,QAAmC;AACvD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,sBAAsB,KAAK,IAAI,QAAQ,KAAK,kBAAkB;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,SAA6E;AAC9F,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,mBAAmB,KAAK,IAAI,SAAS,KAAK,kBAAkB;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAKA,2BAA2B,QAA4D;AACrF,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,2BAA2B,KAAK,IAAI,QAAQ,KAAK,kBAAkB;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,uBAAgC;AAC9B,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,aAAa,KAAK,EAAE;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,iCAAoD;AAClD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,uBAAuB,KAAK,EAAE;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,4BAA0C;AACxC,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,kBAAkB,KAAK,EAAE;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gCAA8D;AAC5D,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACxD,WAAO,sBAAsB,KAAK,EAAE;AAAA,EACtC;AACF;;;AiBlhBO,IAAK,uBAAL,kBAAKC,0BAAL;AACL,EAAAA,4CAAA,eAAY,KAAZ;AACA,EAAAA,4CAAA,WAAQ,KAAR;AACA,EAAAA,4CAAA,iBAAc,KAAd;AACA,EAAAA,4CAAA,cAAW,KAAX;AACA,EAAAA,4CAAA,aAAU,KAAV;AACA,EAAAA,4CAAA,aAAU,KAAV;AANU,SAAAA;AAAA,GAAA;AASL,IAAK,oBAAL,kBAAKC,uBAAL;AACL,EAAAA,sCAAA,iBAAc,KAAd;AACA,EAAAA,sCAAA,gBAAa,KAAb;AACA,EAAAA,sCAAA,mBAAgB,KAAhB;AAHU,SAAAA;AAAA,GAAA;AAML,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,kCAAA,8BAA2B,KAA3B;AACA,EAAAA,kCAAA,sBAAmB,KAAnB;AACA,EAAAA,kCAAA,iBAAc,KAAd;AACA,EAAAA,kCAAA,gBAAa,KAAb;AACA,EAAAA,kCAAA,uBAAoB,KAApB;AALU,SAAAA;AAAA,GAAA;AAQL,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,kCAAA,WAAQ,KAAR;AACA,EAAAA,kCAAA,0BAAuB,KAAvB;AACA,EAAAA,kCAAA,yBAAsB,KAAtB;AACA,EAAAA,kCAAA,wBAAqB,KAArB;AACA,EAAAA,kCAAA,gCAA6B,KAA7B;AACA,EAAAA,kCAAA,UAAO,KAAP;AACA,EAAAA,kCAAA,8BAA2B,KAA3B;AAPU,SAAAA;AAAA,GAAA;AAUL,IAAK,aAAL,kBAAKC,gBAAL;AACL,EAAAA,wBAAA,mBAAgB,KAAhB;AACA,EAAAA,wBAAA,iBAAc,KAAd;AACA,EAAAA,wBAAA,uBAAoB,KAApB;AACA,EAAAA,wBAAA,YAAS,KAAT;AACA,EAAAA,wBAAA,mBAAgB,KAAhB;AACA,EAAAA,wBAAA,cAAW,KAAX;AACA,EAAAA,wBAAA,aAAU,KAAV;AACA,EAAAA,wBAAA,aAAU,KAAV;AACA,EAAAA,wBAAA,iBAAc,KAAd;AACA,EAAAA,wBAAA,kBAAe,MAAf;AACA,EAAAA,wBAAA,qBAAkB,MAAlB;AACA,EAAAA,wBAAA,uBAAoB,MAApB;AAZU,SAAAA;AAAA,GAAA;AAeL,IAAK,cAAL,kBAAKC,iBAAL;AACL,EAAAA,0BAAA,gBAAa,KAAb;AACA,EAAAA,0BAAA,qBAAkB,KAAlB;AACA,EAAAA,0BAAA,wBAAqB,KAArB;AACA,EAAAA,0BAAA,YAAS,KAAT;AACA,EAAAA,0BAAA,wBAAqB,KAArB;AACA,EAAAA,0BAAA,sBAAmB,KAAnB;AACA,EAAAA,0BAAA,kBAAe,KAAf;AACA,EAAAA,0BAAA,oBAAiB,KAAjB;AACA,EAAAA,0BAAA,gBAAa,KAAb;AACA,EAAAA,0BAAA,eAAY,MAAZ;AACA,EAAAA,0BAAA,yBAAsB,MAAtB;AAXU,SAAAA;AAAA,GAAA;","names":["response","arrayBuffer","mergeRealtimeData","ScheduleRelationship","VehicleStopStatus","CongestionLevel","OccupancyStatus","AlertCause","AlertEffect"]} \ No newline at end of file diff --git a/src/gtfs-sqljs.ts b/src/gtfs-sqljs.ts index d83132b..4f3225c 100644 --- a/src/gtfs-sqljs.ts +++ b/src/gtfs-sqljs.ts @@ -21,17 +21,19 @@ import { } from './queries/calendar'; import { getTripById, getTrips, type TripFilters, type TripWithRealtime } from './queries/trips'; import { getStopTimesByTrip, getStopTimes, type StopTimeFilters, type StopTimeWithRealtime } from './queries/stop-times'; -import { getAlerts as getAlertsQuery, getAlertById, type AlertFilters } from './queries/rt-alerts'; -import { getVehiclePositions as getVehiclePositionsQuery, getVehiclePositionByTripId, type VehiclePositionFilters } from './queries/rt-vehicle-positions'; +import { getAlerts as getAlertsQuery, getAlertById, getAllAlerts, type AlertFilters } from './queries/rt-alerts'; +import { getVehiclePositions as getVehiclePositionsQuery, getVehiclePositionByTripId, getAllVehiclePositions, type VehiclePositionFilters } from './queries/rt-vehicle-positions'; +import { getTripUpdates, getTripUpdateByTripId, getAllTripUpdates, type TripUpdateFilters } from './queries/rt-trip-updates'; +import { getStopTimeUpdates, getStopTimeUpdatesByTripId, getAllStopTimeUpdates, type StopTimeUpdateFilters, type StopTimeUpdateWithMetadata } from './queries/rt-stop-time-updates'; // Types import type { Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate } from './types/gtfs'; -import type { Alert, VehiclePosition } from './types/gtfs-rt'; +import type { Alert, VehiclePosition, TripUpdate } from './types/gtfs-rt'; // Export filter types for users -export type { AgencyFilters, StopFilters, RouteFilters, TripFilters, StopTimeFilters, AlertFilters, VehiclePositionFilters }; +export type { AgencyFilters, StopFilters, RouteFilters, TripFilters, StopTimeFilters, AlertFilters, VehiclePositionFilters, TripUpdateFilters, StopTimeUpdateFilters }; // Export RT types -export type { Alert, VehiclePosition, TripWithRealtime, StopTimeWithRealtime }; +export type { Alert, VehiclePosition, TripUpdate, StopTimeUpdateWithMetadata, TripWithRealtime, StopTimeWithRealtime }; export interface GtfsSqlJsOptions { /** @@ -464,4 +466,73 @@ export class GtfsSqlJs { if (!this.db) throw new Error('Database not initialized'); return getVehiclePositionByTripId(this.db, tripId, this.stalenessThreshold); } + + /** + * Get trip updates with optional filters + */ + getTripUpdates(filters?: TripUpdateFilters): TripUpdate[] { + if (!this.db) throw new Error('Database not initialized'); + return getTripUpdates(this.db, filters, this.stalenessThreshold); + } + + /** + * Get trip update by trip ID + */ + getTripUpdateByTripId(tripId: string): TripUpdate | null { + if (!this.db) throw new Error('Database not initialized'); + return getTripUpdateByTripId(this.db, tripId, this.stalenessThreshold); + } + + /** + * Get stop time updates with optional filters + */ + getStopTimeUpdates(filters?: StopTimeUpdateFilters): import('./types/gtfs-rt').StopTimeUpdate[] { + if (!this.db) throw new Error('Database not initialized'); + return getStopTimeUpdates(this.db, filters, this.stalenessThreshold); + } + + /** + * Get stop time updates for a specific trip + */ + getStopTimeUpdatesByTripId(tripId: string): import('./types/gtfs-rt').StopTimeUpdate[] { + if (!this.db) throw new Error('Database not initialized'); + return getStopTimeUpdatesByTripId(this.db, tripId, this.stalenessThreshold); + } + + // ==================== Debug Export Methods ==================== + // These methods export all realtime data without staleness filtering + // for debugging purposes + + /** + * Export all alerts without staleness filtering (for debugging) + */ + debugExportAllAlerts(): Alert[] { + if (!this.db) throw new Error('Database not initialized'); + return getAllAlerts(this.db); + } + + /** + * Export all vehicle positions without staleness filtering (for debugging) + */ + debugExportAllVehiclePositions(): VehiclePosition[] { + if (!this.db) throw new Error('Database not initialized'); + return getAllVehiclePositions(this.db); + } + + /** + * Export all trip updates without staleness filtering (for debugging) + */ + debugExportAllTripUpdates(): TripUpdate[] { + if (!this.db) throw new Error('Database not initialized'); + return getAllTripUpdates(this.db); + } + + /** + * Export all stop time updates without staleness filtering (for debugging) + * Returns extended type with trip_id and rt_last_updated for debugging purposes + */ + debugExportAllStopTimeUpdates(): StopTimeUpdateWithMetadata[] { + if (!this.db) throw new Error('Database not initialized'); + return getAllStopTimeUpdates(this.db); + } } diff --git a/src/index.ts b/src/index.ts index ab4eeec..e11551a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,8 +14,12 @@ export { type StopTimeFilters, type AlertFilters, type VehiclePositionFilters, + type TripUpdateFilters, + type StopTimeUpdateFilters, type Alert, type VehiclePosition, + type TripUpdate, + type StopTimeUpdateWithMetadata, type TripWithRealtime, type StopTimeWithRealtime } from './gtfs-sqljs'; @@ -49,7 +53,6 @@ export type { VehicleDescriptor, StopTimeEvent, StopTimeUpdate, - TripUpdate, StopTimeRealtime, TripRealtime, RealtimeConfig diff --git a/src/queries/rt-alerts.ts b/src/queries/rt-alerts.ts index 218aeca..283a42b 100644 --- a/src/queries/rt-alerts.ts +++ b/src/queries/rt-alerts.ts @@ -162,3 +162,20 @@ export function getAlertById(db: Database, alertId: string, stalenessThreshold: const alerts = getAlerts(db, { alertId, limit: 1 }, stalenessThreshold); return alerts.length > 0 ? alerts[0] : null; } + +/** + * Get all alerts without staleness filtering (for debugging) + */ +export function getAllAlerts(db: Database): Alert[] { + const sql = 'SELECT * FROM rt_alerts ORDER BY rt_last_updated DESC'; + const stmt = db.prepare(sql); + + const alerts: Alert[] = []; + while (stmt.step()) { + const row = stmt.getAsObject() as Record; + alerts.push(parseAlert(row)); + } + + stmt.free(); + return alerts; +} diff --git a/src/queries/rt-stop-time-updates.ts b/src/queries/rt-stop-time-updates.ts new file mode 100644 index 0000000..1116414 --- /dev/null +++ b/src/queries/rt-stop-time-updates.ts @@ -0,0 +1,152 @@ +import type { Database } from 'sql.js'; +import type { StopTimeUpdate } from '../types/gtfs-rt'; + +export interface StopTimeUpdateFilters { + tripId?: string; + stopId?: string; + stopSequence?: number; + limit?: number; +} + +/** + * Parse stop time update from database row + */ +function parseStopTimeUpdate(row: Record): StopTimeUpdate { + const stu: StopTimeUpdate = { + stop_sequence: row.stop_sequence !== null ? Number(row.stop_sequence) : undefined, + stop_id: row.stop_id ? String(row.stop_id) : undefined, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined + }; + + // Arrival event + if (row.arrival_delay !== null || row.arrival_time !== null || row.arrival_uncertainty !== null) { + stu.arrival = { + delay: row.arrival_delay !== null ? Number(row.arrival_delay) : undefined, + time: row.arrival_time !== null ? Number(row.arrival_time) : undefined, + uncertainty: row.arrival_uncertainty !== null ? Number(row.arrival_uncertainty) : undefined + }; + } + + // Departure event + if (row.departure_delay !== null || row.departure_time !== null || row.departure_uncertainty !== null) { + stu.departure = { + delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined, + time: row.departure_time !== null ? Number(row.departure_time) : undefined, + uncertainty: row.departure_uncertainty !== null ? Number(row.departure_uncertainty) : undefined + }; + } + + return stu; +} + +/** + * Extended StopTimeUpdate with trip_id and rt_last_updated for debugging + */ +export interface StopTimeUpdateWithMetadata extends StopTimeUpdate { + trip_id: string; + rt_last_updated: number; +} + +/** + * Parse stop time update with metadata from database row + */ +function parseStopTimeUpdateWithMetadata(row: Record): StopTimeUpdateWithMetadata { + const stu = parseStopTimeUpdate(row) as StopTimeUpdateWithMetadata; + stu.trip_id = String(row.trip_id); + stu.rt_last_updated = Number(row.rt_last_updated); + return stu; +} + +/** + * Get stop time updates with optional filters + */ +export function getStopTimeUpdates( + db: Database, + filters: StopTimeUpdateFilters = {}, + stalenessThreshold: number = 120 +): StopTimeUpdate[] { + const { tripId, stopId, stopSequence, limit } = filters; + + const conditions: string[] = []; + const params: (string | number)[] = []; + + // Filter by trip_id + if (tripId) { + conditions.push('trip_id = ?'); + params.push(tripId); + } + + // Filter by stop_id + if (stopId) { + conditions.push('stop_id = ?'); + params.push(stopId); + } + + // Filter by stop_sequence + if (stopSequence !== undefined) { + conditions.push('stop_sequence = ?'); + params.push(stopSequence); + } + + // Staleness filter (always applied) + const now = Math.floor(Date.now() / 1000); + const staleThreshold = now - stalenessThreshold; + conditions.push('rt_last_updated >= ?'); + params.push(staleThreshold); + + // Build query + let sql = 'SELECT * FROM rt_stop_time_updates'; + if (conditions.length > 0) { + sql += ' WHERE ' + conditions.join(' AND '); + } + sql += ' ORDER BY trip_id, stop_sequence'; + + if (limit) { + sql += ' LIMIT ?'; + params.push(limit); + } + + // Execute query + const stmt = db.prepare(sql); + if (params.length > 0) { + stmt.bind(params); + } + + const stopTimeUpdates: StopTimeUpdate[] = []; + while (stmt.step()) { + const row = stmt.getAsObject() as Record; + stopTimeUpdates.push(parseStopTimeUpdate(row)); + } + + stmt.free(); + return stopTimeUpdates; +} + +/** + * Get stop time updates for a specific trip + */ +export function getStopTimeUpdatesByTripId( + db: Database, + tripId: string, + stalenessThreshold: number = 120 +): StopTimeUpdate[] { + return getStopTimeUpdates(db, { tripId }, stalenessThreshold); +} + +/** + * Get all stop time updates without staleness filtering (for debugging) + * Returns extended type with trip_id and rt_last_updated for debugging purposes + */ +export function getAllStopTimeUpdates(db: Database): StopTimeUpdateWithMetadata[] { + const sql = 'SELECT * FROM rt_stop_time_updates ORDER BY trip_id, stop_sequence'; + const stmt = db.prepare(sql); + + const stopTimeUpdates: StopTimeUpdateWithMetadata[] = []; + while (stmt.step()) { + const row = stmt.getAsObject() as Record; + stopTimeUpdates.push(parseStopTimeUpdateWithMetadata(row)); + } + + stmt.free(); + return stopTimeUpdates; +} diff --git a/src/queries/rt-trip-updates.ts b/src/queries/rt-trip-updates.ts new file mode 100644 index 0000000..7aeb55e --- /dev/null +++ b/src/queries/rt-trip-updates.ts @@ -0,0 +1,129 @@ +import type { Database } from 'sql.js'; +import type { TripUpdate } from '../types/gtfs-rt'; + +export interface TripUpdateFilters { + tripId?: string; + routeId?: string; + vehicleId?: string; + limit?: number; +} + +/** + * Parse trip update from database row + */ +export function parseTripUpdate(row: Record): TripUpdate { + const tu: TripUpdate = { + trip_id: String(row.trip_id), + route_id: row.route_id ? String(row.route_id) : undefined, + stop_time_update: [], // Will be populated separately + timestamp: row.timestamp !== null ? Number(row.timestamp) : undefined, + delay: row.delay !== null ? Number(row.delay) : undefined, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined, + rt_last_updated: Number(row.rt_last_updated) + }; + + // Vehicle descriptor + if (row.vehicle_id || row.vehicle_label || row.vehicle_license_plate) { + tu.vehicle = { + id: row.vehicle_id ? String(row.vehicle_id) : undefined, + label: row.vehicle_label ? String(row.vehicle_label) : undefined, + license_plate: row.vehicle_license_plate ? String(row.vehicle_license_plate) : undefined + }; + } + + return tu; +} + +/** + * Get trip updates with optional filters + */ +export function getTripUpdates( + db: Database, + filters: TripUpdateFilters = {}, + stalenessThreshold: number = 120 +): TripUpdate[] { + const { tripId, routeId, vehicleId, limit } = filters; + + const conditions: string[] = []; + const params: (string | number)[] = []; + + // Filter by trip_id + if (tripId) { + conditions.push('trip_id = ?'); + params.push(tripId); + } + + // Filter by route_id + if (routeId) { + conditions.push('route_id = ?'); + params.push(routeId); + } + + // Filter by vehicle_id + if (vehicleId) { + conditions.push('vehicle_id = ?'); + params.push(vehicleId); + } + + // Staleness filter (always applied) + const now = Math.floor(Date.now() / 1000); + const staleThreshold = now - stalenessThreshold; + conditions.push('rt_last_updated >= ?'); + params.push(staleThreshold); + + // Build query + let sql = 'SELECT * FROM rt_trip_updates'; + if (conditions.length > 0) { + sql += ' WHERE ' + conditions.join(' AND '); + } + sql += ' ORDER BY rt_last_updated DESC'; + + if (limit) { + sql += ' LIMIT ?'; + params.push(limit); + } + + // Execute query + const stmt = db.prepare(sql); + if (params.length > 0) { + stmt.bind(params); + } + + const tripUpdates: TripUpdate[] = []; + while (stmt.step()) { + const row = stmt.getAsObject() as Record; + tripUpdates.push(parseTripUpdate(row)); + } + + stmt.free(); + return tripUpdates; +} + +/** + * Get trip update by trip ID + */ +export function getTripUpdateByTripId( + db: Database, + tripId: string, + stalenessThreshold: number = 120 +): TripUpdate | null { + const updates = getTripUpdates(db, { tripId, limit: 1 }, stalenessThreshold); + return updates.length > 0 ? updates[0] : null; +} + +/** + * Get all trip updates without staleness filtering (for debugging) + */ +export function getAllTripUpdates(db: Database): TripUpdate[] { + const sql = 'SELECT * FROM rt_trip_updates ORDER BY rt_last_updated DESC'; + const stmt = db.prepare(sql); + + const tripUpdates: TripUpdate[] = []; + while (stmt.step()) { + const row = stmt.getAsObject() as Record; + tripUpdates.push(parseTripUpdate(row)); + } + + stmt.free(); + return tripUpdates; +} diff --git a/src/queries/rt-vehicle-positions.ts b/src/queries/rt-vehicle-positions.ts index 6bef3de..de08851 100644 --- a/src/queries/rt-vehicle-positions.ts +++ b/src/queries/rt-vehicle-positions.ts @@ -7,7 +7,7 @@ export type { VehiclePositionFilters }; /** * Parse vehicle position from database row */ -function parseVehiclePosition(row: Record): VehiclePosition { +export function parseVehiclePosition(row: Record): VehiclePosition { const vp: VehiclePosition = { trip_id: String(row.trip_id), route_id: row.route_id ? String(row.route_id) : undefined, @@ -133,3 +133,20 @@ export function getVehiclePositionByTripId( const positions = getVehiclePositions(db, { tripId, limit: 1 }, stalenessThreshold); return positions.length > 0 ? positions[0] : null; } + +/** + * Get all vehicle positions without staleness filtering (for debugging) + */ +export function getAllVehiclePositions(db: Database): VehiclePosition[] { + const sql = 'SELECT * FROM rt_vehicle_positions ORDER BY rt_last_updated DESC'; + const stmt = db.prepare(sql); + + const positions: VehiclePosition[] = []; + while (stmt.step()) { + const row = stmt.getAsObject() as Record; + positions.push(parseVehiclePosition(row)); + } + + stmt.free(); + return positions; +} diff --git a/src/queries/trips.ts b/src/queries/trips.ts index ce36ec3..3660ac8 100644 --- a/src/queries/trips.ts +++ b/src/queries/trips.ts @@ -5,6 +5,7 @@ import type { Database } from 'sql.js'; import type { Trip } from '../types/gtfs'; import type { TripRealtime, VehiclePosition } from '../types/gtfs-rt'; +import { parseVehiclePosition } from './rt-vehicle-positions'; export interface TripFilters { tripId?: string; @@ -44,10 +45,11 @@ function mergeRealtimeData( `); vpStmt.bind([...tripIds, staleThreshold]); - const vpMap = new Map>(); + const vpMap = new Map(); while (vpStmt.step()) { const row = vpStmt.getAsObject() as Record; - vpMap.set(String(row.trip_id), row); + const vp = parseVehiclePosition(row); + vpMap.set(vp.trip_id, vp); } vpStmt.free(); @@ -59,72 +61,33 @@ function mergeRealtimeData( `); tuStmt.bind([...tripIds, staleThreshold]); - const tuMap = new Map>(); + const tuMap = new Map(); while (tuStmt.step()) { const row = tuStmt.getAsObject() as Record; - tuMap.set(String(row.trip_id), row); + const tripId = String(row.trip_id); + tuMap.set(tripId, { + delay: row.delay !== null ? Number(row.delay) : undefined, + schedule_relationship: row.schedule_relationship !== null ? Number(row.schedule_relationship) : undefined + }); } tuStmt.free(); // Merge realtime data return trips.map((trip): TripWithRealtime => { - const vpRow = vpMap.get(trip.trip_id); - const tuRow = tuMap.get(trip.trip_id); + const vp = vpMap.get(trip.trip_id); + const tu = tuMap.get(trip.trip_id); - if (!vpRow && !tuRow) { + if (!vp && !tu) { return { ...trip, realtime: { vehicle_position: null, trip_update: null } }; } - const realtime: TripRealtime = { - vehicle_position: null, - trip_update: null - }; - - // Parse vehicle position - if (vpRow) { - const vp: VehiclePosition = { - trip_id: String(vpRow.trip_id), - route_id: vpRow.route_id ? String(vpRow.route_id) : undefined, - rt_last_updated: Number(vpRow.rt_last_updated) - }; - - if (vpRow.vehicle_id || vpRow.vehicle_label || vpRow.vehicle_license_plate) { - vp.vehicle = { - id: vpRow.vehicle_id ? String(vpRow.vehicle_id) : undefined, - label: vpRow.vehicle_label ? String(vpRow.vehicle_label) : undefined, - license_plate: vpRow.vehicle_license_plate ? String(vpRow.vehicle_license_plate) : undefined - }; - } - - if (vpRow.latitude !== null && vpRow.longitude !== null) { - vp.position = { - latitude: Number(vpRow.latitude), - longitude: Number(vpRow.longitude), - bearing: vpRow.bearing !== null ? Number(vpRow.bearing) : undefined, - odometer: vpRow.odometer !== null ? Number(vpRow.odometer) : undefined, - speed: vpRow.speed !== null ? Number(vpRow.speed) : undefined - }; + return { + ...trip, + realtime: { + vehicle_position: vp || null, + trip_update: tu || null } - - if (vpRow.current_stop_sequence !== null) vp.current_stop_sequence = Number(vpRow.current_stop_sequence); - if (vpRow.stop_id) vp.stop_id = String(vpRow.stop_id); - if (vpRow.current_status !== null) vp.current_status = Number(vpRow.current_status); - if (vpRow.timestamp !== null) vp.timestamp = Number(vpRow.timestamp); - if (vpRow.congestion_level !== null) vp.congestion_level = Number(vpRow.congestion_level); - if (vpRow.occupancy_status !== null) vp.occupancy_status = Number(vpRow.occupancy_status); - - realtime.vehicle_position = vp; - } - - // Parse trip update - if (tuRow) { - realtime.trip_update = { - delay: tuRow.delay !== null ? Number(tuRow.delay) : undefined, - schedule_relationship: tuRow.schedule_relationship !== null ? Number(tuRow.schedule_relationship) : undefined - }; - } - - return { ...trip, realtime }; + }; }); }