gtfs-sqljs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1263 -0
- package/dist/index.d.ts +1089 -0
- package/dist/index.js +3154 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cache/utils.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/cache/checksum.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/shapes.ts","../src/queries/rt-alerts.ts","../src/queries/rt-stop-time-updates.ts","../src/queries/rt-trip-updates.ts","../src/types/gtfs-rt.ts","../src/index.ts"],"sourcesContent":["import type { CacheMetadata, CacheEntry } from './types';\n\n/**\n * Default cache expiration time in milliseconds (7 days)\n */\nexport const DEFAULT_CACHE_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * Check if a cache entry is expired\n * @param metadata - Cache metadata\n * @param expirationMs - Expiration time in milliseconds (default: 7 days)\n * @returns true if the cache entry is expired\n */\nexport function isCacheExpired(\n metadata: CacheMetadata,\n expirationMs: number = DEFAULT_CACHE_EXPIRATION_MS\n): boolean {\n const now = Date.now();\n const age = now - metadata.timestamp;\n return age > expirationMs;\n}\n\n/**\n * Filter out expired cache entries\n * @param entries - Array of cache entries\n * @param expirationMs - Expiration time in milliseconds (default: 7 days)\n * @returns Filtered array of non-expired entries\n */\nexport function filterExpiredEntries(\n entries: CacheEntry[],\n expirationMs: number = DEFAULT_CACHE_EXPIRATION_MS\n): CacheEntry[] {\n return entries.filter(entry => !isCacheExpired(entry.metadata, expirationMs));\n}\n\n/**\n * Get cache statistics\n * @param entries - Array of cache entries\n * @returns Cache statistics\n */\nexport function getCacheStats(entries: CacheEntry[]) {\n const totalSize = entries.reduce((sum, entry) => sum + entry.metadata.size, 0);\n const expiredEntries = entries.filter(entry => isCacheExpired(entry.metadata));\n const activeEntries = entries.filter(entry => !isCacheExpired(entry.metadata));\n\n return {\n totalEntries: entries.length,\n activeEntries: activeEntries.length,\n expiredEntries: expiredEntries.length,\n totalSize,\n totalSizeMB: (totalSize / 1024 / 1024).toFixed(2),\n oldestEntry: entries.length > 0\n ? Math.min(...entries.map(e => e.metadata.timestamp))\n : null,\n newestEntry: entries.length > 0\n ? Math.max(...entries.map(e => e.metadata.timestamp))\n : null,\n };\n}\n","/**\n * Main GtfsSqlJs Class\n */\n\nimport initSqlJs, { type Database, type SqlJsStatic } from 'sql.js';\nimport { getAllCreateTableStatements, getAllCreateIndexStatements } from './schema/schema';\nimport { loadGTFSZip, fetchZip } 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';\nimport type { CacheStore } from './cache/types';\nimport { computeZipChecksum, generateCacheKey } from './cache/checksum';\nimport { DEFAULT_CACHE_EXPIRATION_MS, isCacheExpired } from './cache/utils';\n\n// Library version from package.json\nconst LIB_VERSION = '0.1.0';\n\n// Query methods\nimport { getAgencies, type AgencyFilters } from './queries/agencies';\nimport { getStops, type StopFilters } from './queries/stops';\nimport { getRoutes, type RouteFilters } from './queries/routes';\nimport {\n getActiveServiceIds,\n getCalendarByServiceId,\n getCalendarDates,\n getCalendarDatesForDate,\n} from './queries/calendar';\nimport { getTrips, type TripFilters, type TripWithRealtime } from './queries/trips';\nimport { getStopTimes, buildOrderedStopList, type StopTimeFilters, type StopTimeWithRealtime } from './queries/stop-times';\nimport { getShapes, getShapesToGeojson, type ShapeFilters, type GeoJsonFeatureCollection } from './queries/shapes';\nimport { getAlerts as getAlertsQuery, getAllAlerts, type AlertFilters } from './queries/rt-alerts';\nimport { getVehiclePositions as getVehiclePositionsQuery, getAllVehiclePositions, type VehiclePositionFilters } from './queries/rt-vehicle-positions';\nimport { getTripUpdates, getAllTripUpdates, type TripUpdateFilters } from './queries/rt-trip-updates';\nimport { getStopTimeUpdates, getAllStopTimeUpdates, type StopTimeUpdateFilters } from './queries/rt-stop-time-updates';\n\n// Types\nimport type { Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate, Shape } from './types/gtfs';\nimport type { Alert, VehiclePosition, TripUpdate, StopTimeUpdate } from './types/gtfs-rt';\n\n// Export filter types for users\nexport type { AgencyFilters, StopFilters, RouteFilters, TripFilters, StopTimeFilters, ShapeFilters, AlertFilters, VehiclePositionFilters, TripUpdateFilters, StopTimeUpdateFilters };\n// Export RT types\nexport type { Alert, VehiclePosition, TripUpdate, TripWithRealtime, StopTimeWithRealtime };\n// Export GeoJSON types\nexport type { GeoJsonFeatureCollection };\n\n/**\n * Progress information for GTFS data loading\n */\nexport interface ProgressInfo {\n phase: 'checking_cache' | 'loading_from_cache' | 'downloading' | 'extracting' | 'creating_schema' | 'inserting_data' | 'creating_indexes' | 'analyzing' | 'loading_realtime' | 'saving_cache' | 'complete';\n currentFile: string | null;\n filesCompleted: number;\n totalFiles: number;\n rowsProcessed: number;\n totalRows: number;\n bytesDownloaded?: number; // Bytes downloaded (used during 'downloading' phase)\n totalBytes?: number; // Total bytes to download (used during 'downloading' phase)\n percentComplete: number; // 0-100\n message: string;\n}\n\n/**\n * Progress callback function type\n */\nexport type ProgressCallback = (progress: ProgressInfo) => void;\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 /**\n * Optional: Progress callback for tracking load progress\n * Useful for displaying progress in UI or web workers\n */\n onProgress?: ProgressCallback;\n\n /**\n * Optional: Cache store for persisting processed GTFS databases\n * Implement your own CacheStore or copy one from examples/cache/:\n * - IndexedDBCacheStore (browser)\n * - FileSystemCacheStore (Node.js only)\n *\n * If not provided, caching is disabled.\n */\n cache?: CacheStore | null;\n\n /**\n * Optional: Data version string\n * When changed, cached databases are invalidated and reprocessed\n * Default: '1.0'\n */\n cacheVersion?: string;\n\n /**\n * Optional: Cache expiration time in milliseconds\n * Cached databases older than this will be invalidated\n * Default: 7 days (604800000 ms)\n */\n cacheExpirationMs?: 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 private lastRealtimeFetchTimestamp: number | null = null;\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<GtfsSqlJsOptions, 'zipPath' | 'database'> = {}\n ): Promise<GtfsSqlJs> {\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<GtfsSqlJsOptions, 'zipPath' | 'database'> = {}\n ): Promise<GtfsSqlJs> {\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<GtfsSqlJsOptions, 'zipPath' | 'database'>): Promise<void> {\n const onProgress = options.onProgress;\n const {\n cache: userCache,\n cacheVersion = '1.0',\n cacheExpirationMs = DEFAULT_CACHE_EXPIRATION_MS,\n skipFiles\n } = options;\n\n // Initialize SQL.js\n this.SQL = options.SQL || (await initSqlJs(options.locateFile ? { locateFile: options.locateFile } : {}));\n\n // Determine cache store to use\n // Cache store must be provided explicitly by the user\n // See examples/cache/ for available implementations\n const cache: CacheStore | null = userCache === null ? null : (userCache || null);\n\n // Check cache if enabled\n if (cache) {\n onProgress?.({\n phase: 'checking_cache',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 0,\n message: 'Checking cache...',\n });\n\n // Fetch raw zip data for checksum (only if zipPath is a string)\n let zipData: ArrayBuffer;\n if (typeof zipPath === 'string') {\n zipData = await fetchZip(zipPath, onProgress);\n } else {\n // zipPath is already ArrayBuffer or Uint8Array\n zipData = zipPath as ArrayBuffer;\n }\n\n // Calculate filesize\n const filesize = zipData.byteLength;\n\n // Compute checksum\n const checksum = await computeZipChecksum(zipData);\n\n // Generate cache key with all parameters\n const cacheKey = generateCacheKey(\n checksum,\n LIB_VERSION,\n cacheVersion,\n filesize,\n typeof zipPath === 'string' ? zipPath : undefined,\n skipFiles\n );\n\n // Check if cache exists\n const cacheEntry = await cache.get(cacheKey);\n\n if (cacheEntry) {\n // Check if cache entry is expired\n const expired = isCacheExpired(cacheEntry.metadata, cacheExpirationMs);\n\n if (expired) {\n // Cache is expired, delete it and continue with normal loading\n onProgress?.({\n phase: 'checking_cache',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 2,\n message: 'Cache expired, reprocessing...',\n });\n\n await cache.delete(cacheKey);\n } else {\n // Cache is valid, load from it\n onProgress?.({\n phase: 'loading_from_cache',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 50,\n message: 'Loading from cache...',\n });\n\n this.db = new this.SQL.Database(new Uint8Array(cacheEntry.data));\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 onProgress?.({\n phase: 'complete',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 100,\n message: 'GTFS data loaded from cache',\n });\n\n return;\n }\n }\n\n // Cache miss - continue with normal loading but use already-fetched zip data\n await this.loadFromZipData(zipData, options, onProgress);\n\n // Save to cache\n onProgress?.({\n phase: 'saving_cache',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 98,\n message: 'Saving to cache...',\n });\n\n const dbBuffer = this.export();\n await cache.set(cacheKey, dbBuffer, {\n checksum,\n version: cacheVersion,\n timestamp: Date.now(),\n source: typeof zipPath === 'string' ? zipPath : undefined,\n size: dbBuffer.byteLength,\n skipFiles,\n });\n\n onProgress?.({\n phase: 'complete',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 100,\n message: 'GTFS data loaded successfully',\n });\n\n return;\n }\n\n // No cache - use normal loading flow\n // Fetch zip data\n let zipData: ArrayBuffer;\n if (typeof zipPath === 'string') {\n zipData = await fetchZip(zipPath, onProgress);\n } else {\n zipData = zipPath as ArrayBuffer;\n }\n\n // Load from zip data\n await this.loadFromZipData(zipData, options, onProgress);\n\n onProgress?.({\n phase: 'complete',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 100,\n message: 'GTFS data loaded successfully',\n });\n }\n\n /**\n * Helper method to load GTFS data from zip data (ArrayBuffer)\n * Used by both cache-enabled and cache-disabled paths\n */\n private async loadFromZipData(\n zipData: ArrayBuffer,\n options: Omit<GtfsSqlJsOptions, 'zipPath' | 'database'>,\n onProgress?: ProgressCallback\n ): Promise<void> {\n // Create new database\n this.db = new this.SQL!.Database();\n\n // Apply performance PRAGMAs for bulk loading\n this.db.run('PRAGMA synchronous = OFF'); // Skip fsync for performance\n this.db.run('PRAGMA journal_mode = MEMORY'); // Keep journal in memory\n this.db.run('PRAGMA temp_store = MEMORY'); // Temp tables in memory\n this.db.run('PRAGMA cache_size = -64000'); // 64MB cache\n this.db.run('PRAGMA locking_mode = EXCLUSIVE'); // No locking overhead\n\n // Create GTFS tables (without indexes)\n onProgress?.({\n phase: 'creating_schema',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 40,\n message: 'Creating database tables',\n });\n\n const createTableStatements = getAllCreateTableStatements();\n for (const statement of createTableStatements) {\n this.db.run(statement);\n }\n\n // Create GTFS-RT tables\n createRealtimeTables(this.db);\n\n // Extract files from zip\n onProgress?.({\n phase: 'extracting',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 35,\n message: 'Extracting GTFS ZIP file',\n });\n\n const files = await loadGTFSZip(zipData);\n\n // Load GTFS data\n onProgress?.({\n phase: 'inserting_data',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: Object.keys(files).length,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 40,\n message: 'Starting data import',\n });\n\n await loadGTFSData(this.db, files, options.skipFiles, onProgress);\n\n // Create indexes after data is loaded\n onProgress?.({\n phase: 'creating_indexes',\n currentFile: null,\n filesCompleted: Object.keys(files).length,\n totalFiles: Object.keys(files).length,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 75,\n message: 'Creating database indexes',\n });\n\n const createIndexStatements = getAllCreateIndexStatements();\n let indexCount = 0;\n for (const statement of createIndexStatements) {\n this.db.run(statement);\n indexCount++;\n const indexProgress = 75 + Math.floor((indexCount / createIndexStatements.length) * 10);\n onProgress?.({\n phase: 'creating_indexes',\n currentFile: null,\n filesCompleted: Object.keys(files).length,\n totalFiles: Object.keys(files).length,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: indexProgress,\n message: `Creating indexes (${indexCount}/${createIndexStatements.length})`,\n });\n }\n\n // Run ANALYZE to update query planner statistics\n onProgress?.({\n phase: 'analyzing',\n currentFile: null,\n filesCompleted: Object.keys(files).length,\n totalFiles: Object.keys(files).length,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 85,\n message: 'Optimizing query performance',\n });\n\n this.db.run('ANALYZE');\n\n // Restore normal SQLite settings\n this.db.run('PRAGMA synchronous = FULL');\n this.db.run('PRAGMA locking_mode = NORMAL');\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 // Auto-fetch realtime data if feed URLs are configured\n if (this.realtimeFeedUrls.length > 0) {\n onProgress?.({\n phase: 'loading_realtime',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: this.realtimeFeedUrls.length,\n rowsProcessed: 0,\n totalRows: 0,\n percentComplete: 90,\n message: `Loading realtime data from ${this.realtimeFeedUrls.length} feed${this.realtimeFeedUrls.length > 1 ? 's' : ''}`,\n });\n\n try {\n await loadRealtimeData(this.db, this.realtimeFeedUrls);\n } catch (error) {\n // Don't fail the entire load if RT data fetch fails\n console.warn('Failed to fetch initial realtime data:', error);\n }\n }\n }\n\n /**\n * Initialize from existing database\n */\n private async initFromDatabase(\n database: ArrayBuffer,\n options: Omit<GtfsSqlJsOptions, 'zipPath' | 'database'>\n ): Promise<void> {\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 agencies with optional filters\n * Pass agencyId filter to get a specific agency\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 stops with optional filters\n * Pass stopId filter to get a specific stop\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 routes with optional filters\n * Pass routeId filter to get a specific route\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 trips with optional filters\n * Pass tripId filter to get a specific trip\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID (single value or array)\n * @param filters.routeId - Filter by route ID (single value or array)\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID (single value or array)\n * @param filters.agencyId - Filter by agency ID (single value or array)\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 * @example\n * // Get a specific trip\n * const trips = gtfs.getTrips({ tripId: 'TRIP_123' });\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 // ==================== Shape Methods ====================\n\n /**\n * Get shapes with optional filters\n *\n * @param filters - Optional filters\n * @param filters.shapeId - Filter by shape ID (single value or array)\n * @param filters.routeId - Filter by route ID (single value or array) - joins with trips table\n * @param filters.tripId - Filter by trip ID (single value or array) - joins with trips table\n * @param filters.limit - Limit number of results\n *\n * @example\n * // Get all points for a specific shape\n * const shapes = gtfs.getShapes({ shapeId: 'SHAPE_1' });\n *\n * @example\n * // Get shapes for a specific route\n * const shapes = gtfs.getShapes({ routeId: 'ROUTE_1' });\n *\n * @example\n * // Get shapes for multiple trips\n * const shapes = gtfs.getShapes({ tripId: ['TRIP_1', 'TRIP_2'] });\n */\n getShapes(filters?: ShapeFilters): Shape[] {\n if (!this.db) throw new Error('Database not initialized');\n return getShapes(this.db, filters);\n }\n\n /**\n * Get shapes as GeoJSON FeatureCollection\n *\n * Each shape is converted to a LineString Feature with route properties.\n * Coordinates are in [longitude, latitude] format per GeoJSON spec.\n *\n * @param filters - Optional filters (same as getShapes)\n * @param filters.shapeId - Filter by shape ID (single value or array)\n * @param filters.routeId - Filter by route ID (single value or array)\n * @param filters.tripId - Filter by trip ID (single value or array)\n * @param filters.limit - Limit number of results\n * @param precision - Number of decimal places for coordinates (default: 6, ~10cm precision)\n *\n * @returns GeoJSON FeatureCollection with LineString features\n *\n * @example\n * // Get all shapes as GeoJSON\n * const geojson = gtfs.getShapesToGeojson();\n *\n * @example\n * // Get shapes for a route with lower precision\n * const geojson = gtfs.getShapesToGeojson({ routeId: 'ROUTE_1' }, 5);\n *\n * @example\n * // Result structure:\n * // {\n * // type: 'FeatureCollection',\n * // features: [{\n * // type: 'Feature',\n * // properties: {\n * // shape_id: 'SHAPE_1',\n * // route_id: 'ROUTE_1',\n * // route_short_name: '1',\n * // route_long_name: 'Main Street',\n * // route_type: 3,\n * // route_color: 'FF0000'\n * // },\n * // geometry: {\n * // type: 'LineString',\n * // coordinates: [[-122.123456, 37.123456], ...]\n * // }\n * // }]\n * // }\n */\n getShapesToGeojson(filters?: ShapeFilters, precision: number = 6): GeoJsonFeatureCollection {\n if (!this.db) throw new Error('Database not initialized');\n return getShapesToGeojson(this.db, filters, precision);\n }\n\n // ==================== Stop Time Methods ====================\n\n /**\n * Get stop times with optional filters\n *\n * @param filters - Optional filters\n * @param filters.tripId - Filter by trip ID (single value or array)\n * @param filters.stopId - Filter by stop ID (single value or array)\n * @param filters.routeId - Filter by route ID (single value or array)\n * @param filters.date - Filter by date (YYYYMMDD format) - will get active services for that date\n * @param filters.directionId - Filter by direction ID (single value or array)\n * @param filters.agencyId - Filter by agency ID (single value or array)\n * @param filters.includeRealtime - Include realtime data (delay and time fields)\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 * @example\n * // Get stop times with realtime data\n * const stopTimes = gtfs.getStopTimes({\n * tripId: 'TRIP_123',\n * includeRealtime: true\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 /**\n * Build an ordered list of stops from multiple trips\n *\n * This is useful when you need to display a timetable for a route where different trips\n * may stop at different sets of stops (e.g., express vs local service, or trips with\n * different start/end points).\n *\n * The method intelligently merges stop sequences from all provided trips to create\n * a comprehensive ordered list of all unique stops.\n *\n * @param tripIds - Array of trip IDs to analyze\n * @returns Ordered array of Stop objects representing all unique stops\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 * const tripIds = trips.map(t => t.trip_id);\n *\n * // Build ordered stop list for all these trips\n * const stops = gtfs.buildOrderedStopList(tripIds);\n *\n * // Now you can display a timetable with all possible stops\n * stops.forEach(stop => {\n * console.log(stop.stop_name);\n * });\n */\n buildOrderedStopList(tripIds: string[]): Stop[] {\n if (!this.db) throw new Error('Database not initialized');\n return buildOrderedStopList(this.db, tripIds);\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 * Get timestamp of the last successful realtime data fetch and insertion\n * @returns Unix timestamp in seconds, or null if no realtime data has been fetched\n */\n getLastRealtimeFetchTimestamp(): number | null {\n return this.lastRealtimeFetchTimestamp;\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<void> {\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 this.lastRealtimeFetchTimestamp = Math.floor(Date.now() / 1000);\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 * Pass alertId filter to get a specific alert\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 vehicle positions with optional filters\n * Pass tripId filter to get vehicle position for a specific trip\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 trip updates with optional filters\n * Pass tripId filter to get trip update for a specific trip\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 stop time updates with optional filters\n * Pass tripId filter to get stop time updates for a specific trip\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 // ==================== 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 stop time updates with trip_id and rt_last_updated populated\n */\n debugExportAllStopTimeUpdates(): StopTimeUpdate[] {\n if (!this.db) throw new Error('Database not initialized');\n return getAllStopTimeUpdates(this.db);\n }\n\n // ==================== Cache Management Methods ====================\n\n /**\n * Get cache statistics\n * @param cacheStore - Cache store to query (required)\n * @returns Cache statistics including size, entry count, and age information\n */\n static async getCacheStats(cacheStore: CacheStore) {\n const { getCacheStats } = await import('./cache/utils');\n\n if (!cacheStore) {\n throw new Error('Cache store is required');\n }\n\n const entries = await cacheStore.list?.() || [];\n return getCacheStats(entries);\n }\n\n /**\n * Clean expired cache entries\n * @param cacheStore - Cache store to clean (required)\n * @param expirationMs - Expiration time in milliseconds (default: 7 days)\n * @returns Number of entries deleted\n */\n static async cleanExpiredCache(\n cacheStore: CacheStore,\n expirationMs: number = DEFAULT_CACHE_EXPIRATION_MS\n ): Promise<number> {\n const { filterExpiredEntries } = await import('./cache/utils');\n\n if (!cacheStore || !cacheStore.list) {\n throw new Error('Cache store is required and must support listing');\n }\n\n const allEntries = await cacheStore.list();\n const expiredEntries = allEntries.filter(entry =>\n !filterExpiredEntries([entry], expirationMs).length\n );\n\n // Delete expired entries\n await Promise.all(expiredEntries.map(entry => cacheStore.delete(entry.key)));\n\n return expiredEntries.length;\n }\n\n /**\n * Clear all cache entries\n * @param cacheStore - Cache store to clear (required)\n */\n static async clearCache(cacheStore: CacheStore): Promise<void> {\n if (!cacheStore) {\n throw new Error('Cache store is required');\n }\n\n await cacheStore.clear();\n }\n\n /**\n * List all cache entries\n * @param cacheStore - Cache store to query (required)\n * @param includeExpired - Include expired entries (default: false)\n * @returns Array of cache entries with metadata\n */\n static async listCache(\n cacheStore: CacheStore,\n includeExpired: boolean = false\n ) {\n const { filterExpiredEntries } = await import('./cache/utils');\n\n if (!cacheStore || !cacheStore.list) {\n throw new Error('Cache store is required and must support listing');\n }\n\n const entries = await cacheStore.list();\n\n if (includeExpired) {\n return entries;\n }\n\n return filterExpiredEntries(entries);\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 * Get CREATE TABLE statements only (without indexes)\n */\nexport function getAllCreateTableStatements(): string[] {\n const statements: string[] = [];\n\n for (const schema of GTFS_SCHEMA) {\n statements.push(generateCreateTableSQL(schema));\n }\n\n return statements;\n}\n\n/**\n * Get CREATE INDEX statements only\n */\nexport function getAllCreateIndexStatements(): string[] {\n const statements: string[] = [];\n\n for (const schema of GTFS_SCHEMA) {\n statements.push(...generateCreateIndexSQL(schema));\n }\n\n return statements;\n}\n\n/**\n * Initialize all GTFS tables in the database (tables + indexes)\n * @deprecated Use getAllCreateTableStatements() and getAllCreateIndexStatements() separately for better performance\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';\nimport type { ProgressCallback } from '../gtfs-sqljs';\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<GTFSFiles> {\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<void>[] = [];\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 (exported for checksum computation)\n * @param source - URL or file path to GTFS ZIP file\n * @param onProgress - Optional progress callback for download tracking\n */\nexport async function fetchZip(source: string, onProgress?: ProgressCallback): Promise<ArrayBuffer> {\n // Check if source is a URL\n const isUrl = source.startsWith('http://') || source.startsWith('https://');\n\n // For URLs, always use fetch with progress tracking\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\n // Get content length for progress calculation\n const contentLength = response.headers.get('content-length');\n const total = contentLength ? parseInt(contentLength, 10) : null;\n\n // If no progress callback or no content-length, just use arrayBuffer()\n if (!onProgress || !total || !response.body) {\n return await response.arrayBuffer();\n }\n\n // Stream the response with progress tracking\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let receivedLength = 0;\n let done = false;\n\n while (!done) {\n const result = await reader.read();\n done = result.done;\n\n if (done || !result.value) break;\n\n chunks.push(result.value);\n receivedLength += result.value.length;\n\n // Calculate download progress (0-100%)\n const downloadPercent = (receivedLength / total) * 100;\n // Map download progress to overall progress (1% → 30%)\n const percentComplete = Math.floor(1 + (downloadPercent * 29 / 100));\n\n // Report progress\n onProgress({\n phase: 'downloading',\n currentFile: null,\n filesCompleted: 0,\n totalFiles: 0,\n rowsProcessed: 0,\n totalRows: 0,\n bytesDownloaded: receivedLength,\n totalBytes: total,\n percentComplete: Math.min(percentComplete, 30),\n message: `Downloading GTFS ZIP (${(receivedLength / 1024 / 1024).toFixed(1)} MB / ${(total / 1024 / 1024).toFixed(1)} MB)`,\n });\n }\n\n // Combine chunks into a single ArrayBuffer\n const allChunks = new Uint8Array(receivedLength);\n let position = 0;\n for (const chunk of chunks) {\n allChunks.set(chunk, position);\n position += chunk.length;\n }\n\n return allChunks.buffer;\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<string, string> = {\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<string, string>[];\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<string, string>[];\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<string, string>,\n columnTypes: Record<string, 'TEXT' | 'INTEGER' | 'REAL'>\n): Record<string, string | number | null> {\n const result: Record<string, string | number | null> = {};\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 } from './csv-parser';\nimport { GTFS_SCHEMA, type TableSchema } from '../schema/schema';\nimport type { GTFSFiles } from './zip-loader';\nimport type { ProgressCallback } from '../gtfs-sqljs';\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 * @param onProgress - Optional progress callback\n */\nexport async function loadGTFSData(\n db: Database,\n files: GTFSFiles,\n skipFiles?: string[],\n onProgress?: ProgressCallback\n): Promise<void> {\n // Map of file names to table schemas\n const fileToSchema: Map<string, TableSchema> = 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 // Define file priority order (small files first, largest last)\n const filePriority = [\n 'agency.txt',\n 'feed_info.txt',\n 'attributions.txt',\n 'levels.txt',\n 'routes.txt',\n 'calendar.txt',\n 'calendar_dates.txt',\n 'fare_attributes.txt',\n 'fare_rules.txt',\n 'stops.txt',\n 'pathways.txt',\n 'transfers.txt',\n 'trips.txt',\n 'frequencies.txt',\n 'shapes.txt',\n 'stop_times.txt', // Largest file - process last\n ];\n\n // Sort files by priority\n const sortedFiles: [string, string][] = [];\n for (const priorityFile of filePriority) {\n if (files[priorityFile]) {\n sortedFiles.push([priorityFile, files[priorityFile]]);\n }\n }\n // Add any files not in priority list\n for (const [fileName, content] of Object.entries(files)) {\n if (!filePriority.includes(fileName)) {\n sortedFiles.push([fileName, content]);\n }\n }\n\n // Calculate total rows for progress tracking\n let totalRows = 0;\n const fileRowCounts = new Map<string, number>();\n for (const [fileName, content] of sortedFiles) {\n const schema = fileToSchema.get(fileName);\n if (schema && !skipSet.has(fileName.toLowerCase())) {\n const { rows } = parseCSV(content);\n fileRowCounts.set(fileName, rows.length);\n totalRows += rows.length;\n }\n }\n\n let rowsProcessed = 0;\n let filesCompleted = 0;\n\n // Process each file\n for (const [fileName, content] of sortedFiles) {\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 filesCompleted++;\n continue;\n }\n\n const fileRows = fileRowCounts.get(fileName) || 0;\n\n onProgress?.({\n phase: 'inserting_data',\n currentFile: fileName,\n filesCompleted,\n totalFiles: sortedFiles.length,\n rowsProcessed,\n totalRows,\n percentComplete: 40 + Math.floor((rowsProcessed / totalRows) * 35),\n message: `Loading ${fileName} (${fileRows.toLocaleString()} rows)`,\n });\n\n await loadTableData(db, schema, content, (processedInFile) => {\n const currentProgress = rowsProcessed + processedInFile;\n onProgress?.({\n phase: 'inserting_data',\n currentFile: fileName,\n filesCompleted,\n totalFiles: sortedFiles.length,\n rowsProcessed: currentProgress,\n totalRows,\n percentComplete: 40 + Math.floor((currentProgress / totalRows) * 35),\n message: `Loading ${fileName} (${processedInFile.toLocaleString()}/${fileRows.toLocaleString()} rows)`,\n });\n });\n\n rowsProcessed += fileRows;\n filesCompleted++;\n\n onProgress?.({\n phase: 'inserting_data',\n currentFile: null,\n filesCompleted,\n totalFiles: sortedFiles.length,\n rowsProcessed,\n totalRows,\n percentComplete: 40 + Math.floor((rowsProcessed / totalRows) * 35),\n message: `Completed ${fileName}`,\n });\n }\n}\n\n/**\n * Load data for a single table with batch inserts and transaction\n */\nasync function loadTableData(\n db: Database,\n schema: TableSchema,\n csvContent: string,\n onProgress?: (rowsProcessed: number) => void\n): Promise<void> {\n const { headers, rows } = parseCSV(csvContent);\n\n if (rows.length === 0) {\n return;\n }\n\n // Prepare INSERT statement\n const columns = headers.filter((h) => schema.columns.some((c) => c.name === h));\n if (columns.length === 0) {\n return;\n }\n\n const BATCH_SIZE = 1000;\n let rowsProcessed = 0;\n\n // Start transaction for better performance\n db.run('BEGIN TRANSACTION');\n\n try {\n // Process in batches\n for (let i = 0; i < rows.length; i += BATCH_SIZE) {\n const batchRows = rows.slice(i, Math.min(i + BATCH_SIZE, rows.length));\n\n // Build multi-row INSERT statement\n const placeholders = batchRows.map(() => `(${columns.map(() => '?').join(', ')})`).join(', ');\n const insertSQL = `INSERT INTO ${schema.name} (${columns.join(', ')}) VALUES ${placeholders}`;\n\n // Collect all values for the batch\n const allValues: (string | number | null)[] = [];\n for (const row of batchRows) {\n for (const col of columns) {\n const value = row[col];\n // Let SQLite handle type conversion - just pass empty strings as NULL\n allValues.push(value === null || value === undefined || value === '' ? null : value);\n }\n }\n\n // Execute batch insert\n const stmt = db.prepare(insertSQL);\n try {\n stmt.run(allValues);\n } catch (error) {\n console.error(`Error inserting batch into ${schema.name}:`, error);\n console.error('Batch size:', batchRows.length);\n throw error;\n } finally {\n stmt.free();\n }\n\n rowsProcessed += batchRows.length;\n onProgress?.(rowsProcessed);\n }\n\n // Commit transaction\n db.run('COMMIT');\n } catch (error) {\n // Rollback on error\n try {\n db.run('ROLLBACK');\n } catch (rollbackError) {\n console.error('Error rolling back transaction:', rollbackError);\n }\n throw error;\n }\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 informedEntity?: unknown[];\n cause?: number;\n effect?: number;\n url?: ProtobufTranslatedString;\n headerText?: ProtobufTranslatedString;\n descriptionText?: ProtobufTranslatedString;\n}\n\ninterface ProtobufTripDescriptor {\n tripId?: string;\n routeId?: string;\n scheduleRelationship?: number;\n}\n\ninterface ProtobufVehicleDescriptor {\n id?: string;\n label?: string;\n licensePlate?: 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 stopId?: string;\n currentStatus?: number;\n timestamp?: number;\n congestionLevel?: number;\n occupancyStatus?: number;\n}\n\ninterface ProtobufStopTimeEvent {\n delay?: number;\n time?: number;\n uncertainty?: number;\n}\n\ninterface ProtobufStopTimeUpdate {\n stopSequence?: number;\n stopId?: string;\n scheduleRelationship?: 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}\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<Uint8Array> {\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<string, unknown> = {};\n for (const key in obj as Record<string, unknown>) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = convertKeysToSnakeCase((obj as Record<string, unknown>)[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 // Convert nested objects to snake_case for database storage\n const activePeriodSnake = convertKeysToSnakeCase(alert.activePeriod || []);\n const informedEntitySnake = convertKeysToSnakeCase(alert.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(alert.headerText),\n parseTranslatedString(alert.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) continue;\n\n stmt.run([\n trip.tripId,\n trip.routeId || null,\n vp.vehicle?.id || null,\n vp.vehicle?.label || null,\n vp.vehicle?.licensePlate || 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 vp.currentStopSequence || null,\n vp.stopId || null,\n vp.currentStatus || null,\n vp.timestamp || null,\n vp.congestionLevel || null,\n vp.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) continue;\n\n // Insert trip update\n tripStmt.run([\n trip.tripId,\n trip.routeId || null,\n tu.vehicle?.id || null,\n tu.vehicle?.label || null,\n tu.vehicle?.licensePlate || null,\n tu.timestamp || null,\n tu.delay || null,\n trip.scheduleRelationship || null,\n timestamp\n ]);\n\n // Insert stop time updates\n if (tu.stopTimeUpdate) {\n for (const stu of tu.stopTimeUpdate) {\n stopTimeStmt.run([\n trip.tripId,\n stu.stopSequence || null,\n stu.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 stu.scheduleRelationship || 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<void> {\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 // Clear old data and insert new data in a single transaction\n db.run('BEGIN TRANSACTION');\n try {\n // Clear all realtime tables\n db.run('DELETE FROM rt_stop_time_updates');\n db.run('DELETE FROM rt_trip_updates');\n db.run('DELETE FROM rt_vehicle_positions');\n db.run('DELETE FROM rt_alerts');\n\n // Insert new data\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 db.run('COMMIT');\n } catch (error) {\n db.run('ROLLBACK');\n throw error;\n }\n}\n","/**\n * Get crypto object (browser or Node.js)\n */\nasync function getCrypto(): Promise<Crypto> {\n // Browser environment\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n return crypto;\n }\n\n // Node.js environment - import webcrypto\n if (typeof globalThis !== 'undefined') {\n try {\n const { webcrypto } = await import('crypto');\n return webcrypto as unknown as Crypto;\n } catch {\n // Fallback for older Node.js versions\n throw new Error('Web Crypto API not available');\n }\n }\n\n throw new Error('Crypto not available in this environment');\n}\n\n/**\n * Compute SHA-256 checksum of data\n * Uses Web Crypto API (available in both browser and Node.js 18+)\n */\nexport async function computeChecksum(data: ArrayBuffer | Uint8Array): Promise<string> {\n // Get crypto instance\n const cryptoInstance = await getCrypto();\n\n // Ensure we have a BufferSource for crypto.subtle.digest\n // Use type assertion to handle ArrayBufferLike compatibility\n const bufferSource = (data instanceof Uint8Array ? data : new Uint8Array(data)) as BufferSource;\n const hashBuffer = await cryptoInstance.subtle.digest('SHA-256', bufferSource);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\n return hashHex;\n}\n\n/**\n * Compute checksum for a zip file\n * @param zipData - The zip file data (ArrayBuffer or Uint8Array)\n * @returns SHA-256 checksum as hex string\n */\nexport async function computeZipChecksum(zipData: ArrayBuffer | Uint8Array): Promise<string> {\n return computeChecksum(zipData);\n}\n\n/**\n * Generate a cache key from checksum, version, filesize, source, and options\n * Format: v{libVersion}_{dataVersion}_{filesize}_{checksum}_{source}_{skipFiles}\n *\n * @param checksum - SHA-256 checksum of zip file\n * @param libVersion - Library version from package.json\n * @param dataVersion - User-specified data version\n * @param filesize - Size of the zip file in bytes\n * @param source - Source URL or filename (optional)\n * @param skipFiles - Files that were skipped during import\n * @returns Cache key string\n */\nexport function generateCacheKey(\n checksum: string,\n libVersion: string,\n dataVersion: string,\n filesize: number,\n source?: string,\n skipFiles?: string[]\n): string {\n // Start with versions and filesize\n let key = `v${libVersion}_d${dataVersion}_${filesize}_${checksum}`;\n\n // Add source (sanitized)\n if (source) {\n // Extract filename from URL/path and sanitize\n const filename = source.split('/').pop() || source;\n const sanitized = filename.replace(/[^a-zA-Z0-9._-]/g, '_');\n key += `_${sanitized}`;\n }\n\n // Add skip files if any\n if (skipFiles && skipFiles.length > 0) {\n // Sort to ensure consistent key regardless of order\n const sortedSkips = [...skipFiles].sort();\n const skipsSuffix = sortedSkips.join(',').replace(/\\.txt/g, '');\n key += `_skip-${skipsSuffix}`;\n }\n\n return key;\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 | string[];\n limit?: number;\n}\n\n/**\n * Get agencies with optional filters\n * - Filters support both single values and arrays\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 const agencyIds = Array.isArray(agencyId) ? agencyId : [agencyId];\n if (agencyIds.length > 0) {\n const placeholders = agencyIds.map(() => '?').join(', ');\n conditions.push(`agency_id IN (${placeholders})`);\n params.push(...agencyIds);\n }\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<string, unknown>;\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<string, unknown>): 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 | string[];\n stopCode?: string | string[];\n name?: string;\n tripId?: string | string[];\n limit?: number;\n}\n\n/**\n * Get stops with optional filters\n * - Filters support both single values and arrays\n * - Use name filter for partial name matching\n * - Use tripId filter to get stops for a specific trip (ordered by stop_sequence)\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 const tripIds = Array.isArray(tripId) ? tripId : [tripId];\n if (tripIds.length === 0) return [];\n\n const placeholders = tripIds.map(() => '?').join(', ');\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 IN (${placeholders})\n ORDER BY st.stop_sequence\n `);\n stmt.bind(tripIds);\n\n const stops: Stop[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record<string, unknown>;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n }\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (stopId) {\n const stopIds = Array.isArray(stopId) ? stopId : [stopId];\n if (stopIds.length > 0) {\n const placeholders = stopIds.map(() => '?').join(', ');\n conditions.push(`stop_id IN (${placeholders})`);\n params.push(...stopIds);\n }\n }\n\n if (stopCode) {\n const stopCodes = Array.isArray(stopCode) ? stopCode : [stopCode];\n if (stopCodes.length > 0) {\n const placeholders = stopCodes.map(() => '?').join(', ');\n conditions.push(`stop_code IN (${placeholders})`);\n params.push(...stopCodes);\n }\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<string, unknown>;\n stops.push(rowToStop(row));\n }\n\n stmt.free();\n return stops;\n}\n\n/**\n * Search stops by name (case-insensitive, partial match)\n * This is a convenience method for name-based searches\n */\nexport function searchStopsByName(db: Database, name: string, limit = 50): Stop[] {\n return getStops(db, { name, limit });\n}\n\n/**\n * Convert database row to Stop object\n */\nfunction rowToStop(row: Record<string, unknown>): 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 | string[];\n agencyId?: string | string[];\n limit?: number;\n}\n\n/**\n * Get routes with optional filters\n * - Filters support both single values and arrays\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 const routeIds = Array.isArray(routeId) ? routeId : [routeId];\n if (routeIds.length > 0) {\n const placeholders = routeIds.map(() => '?').join(', ');\n conditions.push(`route_id IN (${placeholders})`);\n params.push(...routeIds);\n }\n }\n\n if (agencyId) {\n const agencyIds = Array.isArray(agencyId) ? agencyId : [agencyId];\n if (agencyIds.length > 0) {\n const placeholders = agencyIds.map(() => '?').join(', ');\n conditions.push(`agency_id IN (${placeholders})`);\n params.push(...agencyIds);\n }\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<string, unknown>;\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<string, unknown>): 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<string>();\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<string, unknown>;\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<string, unknown>;\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<string, unknown>;\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<string, unknown>): 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<string, unknown>): 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<string, unknown>): 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<string, unknown>;\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<string, unknown>;\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 | string[];\n routeId?: string | string[];\n serviceIds?: string | string[];\n directionId?: number | number[];\n agencyId?: string | 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<string, VehiclePosition>();\n while (vpStmt.step()) {\n const row = vpStmt.getAsObject() as Record<string, unknown>;\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<string, { delay?: number; schedule_relationship?: number }>();\n while (tuStmt.step()) {\n const row = tuStmt.getAsObject() as Record<string, unknown>;\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 * - Filters support both single values and arrays\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 const tripIds = Array.isArray(tripId) ? tripId : [tripId];\n if (tripIds.length > 0) {\n const placeholders = tripIds.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.trip_id IN (${placeholders})` : `trip_id IN (${placeholders})`);\n params.push(...tripIds);\n }\n }\n\n if (routeId) {\n const routeIds = Array.isArray(routeId) ? routeId : [routeId];\n if (routeIds.length > 0) {\n const placeholders = routeIds.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.route_id IN (${placeholders})` : `route_id IN (${placeholders})`);\n params.push(...routeIds);\n }\n }\n\n if (serviceIds) {\n const serviceIdArray = Array.isArray(serviceIds) ? serviceIds : [serviceIds];\n if (serviceIdArray.length > 0) {\n const placeholders = serviceIdArray.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.service_id IN (${placeholders})` : `service_id IN (${placeholders})`);\n params.push(...serviceIdArray);\n }\n }\n\n if (directionId !== undefined) {\n const directionIds = Array.isArray(directionId) ? directionId : [directionId];\n if (directionIds.length > 0) {\n const placeholders = directionIds.map(() => '?').join(', ');\n conditions.push(needsRoutesJoin ? `t.direction_id IN (${placeholders})` : `direction_id IN (${placeholders})`);\n params.push(...directionIds);\n }\n }\n\n if (agencyId) {\n const agencyIds = Array.isArray(agencyId) ? agencyId : [agencyId];\n if (agencyIds.length > 0) {\n const placeholders = agencyIds.map(() => '?').join(', ');\n conditions.push(`r.agency_id IN (${placeholders})`);\n params.push(...agencyIds);\n }\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<string, unknown>;\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 * Convert database row to Trip object\n */\nfunction rowToTrip(row: Record<string, unknown>): 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, Stop } from '../types/gtfs';\nimport type { StopTimeRealtime } from '../types/gtfs-rt';\nimport { getStops } from './stops';\n\nexport interface StopTimeFilters {\n tripId?: string | string[];\n stopId?: string | string[];\n routeId?: string | string[];\n serviceIds?: string | string[];\n directionId?: number | number[];\n agencyId?: string | 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, arrival_time, departure_delay, departure_time, 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<string, StopTimeRealtime>();\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record<string, unknown>;\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 arrival_time: row.arrival_time !== null ? Number(row.arrival_time) : undefined,\n departure_delay: row.departure_delay !== null ? Number(row.departure_delay) : undefined,\n departure_time: row.departure_time !== null ? Number(row.departure_time) : 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 * - Filters support both single values and arrays\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 const tripIds = Array.isArray(tripId) ? tripId : [tripId];\n if (tripIds.length > 0) {\n const placeholders = tripIds.map(() => '?').join(', ');\n conditions.push(needsTripsJoin ? `st.trip_id IN (${placeholders})` : `trip_id IN (${placeholders})`);\n params.push(...tripIds);\n }\n }\n\n if (stopId) {\n const stopIds = Array.isArray(stopId) ? stopId : [stopId];\n if (stopIds.length > 0) {\n const placeholders = stopIds.map(() => '?').join(', ');\n conditions.push(needsTripsJoin ? `st.stop_id IN (${placeholders})` : `stop_id IN (${placeholders})`);\n params.push(...stopIds);\n }\n }\n\n if (routeId) {\n const routeIds = Array.isArray(routeId) ? routeId : [routeId];\n if (routeIds.length > 0) {\n const placeholders = routeIds.map(() => '?').join(', ');\n conditions.push(`t.route_id IN (${placeholders})`);\n params.push(...routeIds);\n }\n }\n\n if (serviceIds) {\n const serviceIdArray = Array.isArray(serviceIds) ? serviceIds : [serviceIds];\n if (serviceIdArray.length > 0) {\n const placeholders = serviceIdArray.map(() => '?').join(', ');\n conditions.push(`t.service_id IN (${placeholders})`);\n params.push(...serviceIdArray);\n }\n }\n\n if (directionId !== undefined) {\n const directionIds = Array.isArray(directionId) ? directionId : [directionId];\n if (directionIds.length > 0) {\n const placeholders = directionIds.map(() => '?').join(', ');\n conditions.push(`t.direction_id IN (${placeholders})`);\n params.push(...directionIds);\n }\n }\n\n if (agencyId) {\n const agencyIds = Array.isArray(agencyId) ? agencyId : [agencyId];\n if (agencyIds.length > 0) {\n const placeholders = agencyIds.map(() => '?').join(', ');\n conditions.push(`r.agency_id IN (${placeholders})`);\n params.push(...agencyIds);\n }\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<string, unknown>;\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 * Build an ordered list of stops from multiple trips\n *\n * This method handles cases where trips for the same route/direction may have:\n * - Different starting or ending stops\n * - Different numbers of stops (e.g., express vs local service)\n * - Variations in which stops are served\n *\n * Algorithm:\n * 1. Fetch stop times for all provided trips\n * 2. Process each trip's stops in sequence order\n * 3. When encountering a new stop, find the best insertion position by:\n * - Looking at stops before and after it in the current trip\n * - Finding where those stops exist in the result list\n * - Inserting the new stop to maintain ordering constraints\n *\n * @param db - Database instance\n * @param tripIds - Array of trip IDs to analyze\n * @returns Ordered array of Stop objects representing all unique stops\n */\nexport function buildOrderedStopList(db: Database, tripIds: string[]): Stop[] {\n if (tripIds.length === 0) {\n return [];\n }\n\n // Fetch all stop times for the given trips, ordered by trip and sequence\n const placeholders = tripIds.map(() => '?').join(', ');\n const stmt = db.prepare(`\n SELECT trip_id, stop_id, stop_sequence\n FROM stop_times\n WHERE trip_id IN (${placeholders})\n ORDER BY trip_id, stop_sequence\n `);\n stmt.bind(tripIds);\n\n // Group stop times by trip\n const tripStopSequences = new Map<string, Array<{ stop_id: string; stop_sequence: number }>>();\n\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record<string, unknown>;\n const tripId = String(row.trip_id);\n const stopId = String(row.stop_id);\n const stopSequence = Number(row.stop_sequence);\n\n if (!tripStopSequences.has(tripId)) {\n tripStopSequences.set(tripId, []);\n }\n tripStopSequences.get(tripId)!.push({ stop_id: stopId, stop_sequence: stopSequence });\n }\n stmt.free();\n\n // Build the ordered list of stop IDs\n const orderedStopIds: string[] = [];\n const stopIdSet = new Set<string>();\n\n // Process each trip's stops\n for (const [, stopSequence] of tripStopSequences) {\n for (let i = 0; i < stopSequence.length; i++) {\n const currentStop = stopSequence[i];\n\n // Skip if we've already added this stop\n if (stopIdSet.has(currentStop.stop_id)) {\n continue;\n }\n\n // Find the best insertion position for this new stop\n const insertIndex = findInsertionPosition(\n orderedStopIds,\n currentStop.stop_id,\n stopSequence,\n i\n );\n\n // Insert the stop at the determined position\n orderedStopIds.splice(insertIndex, 0, currentStop.stop_id);\n stopIdSet.add(currentStop.stop_id);\n }\n }\n\n // Fetch and return the full Stop objects in order\n if (orderedStopIds.length === 0) {\n return [];\n }\n\n // Get all stops in a single query\n const stops = getStops(db, { stopId: orderedStopIds });\n\n // Create a map for quick lookup\n const stopMap = new Map<string, Stop>();\n stops.forEach(stop => stopMap.set(stop.stop_id, stop));\n\n // Return stops in the determined order\n return orderedStopIds\n .map(stopId => stopMap.get(stopId))\n .filter((stop): stop is Stop => stop !== undefined);\n}\n\n/**\n * Find the best insertion position for a new stop in the ordered list\n *\n * @param orderedStopIds - Current ordered list of stop IDs\n * @param newStopId - The stop ID to insert\n * @param tripStops - All stops in the current trip being processed\n * @param currentIndex - Index of the new stop in the current trip\n * @returns The index where the new stop should be inserted\n */\nfunction findInsertionPosition(\n orderedStopIds: string[],\n newStopId: string,\n tripStops: Array<{ stop_id: string; stop_sequence: number }>,\n currentIndex: number\n): number {\n // If the ordered list is empty, insert at the beginning\n if (orderedStopIds.length === 0) {\n return 0;\n }\n\n // Find the closest previous stop that exists in our ordered list\n let beforeIndex = -1;\n for (let i = currentIndex - 1; i >= 0; i--) {\n const idx = orderedStopIds.indexOf(tripStops[i].stop_id);\n if (idx !== -1) {\n beforeIndex = idx;\n break;\n }\n }\n\n // Find the closest next stop that exists in our ordered list\n let afterIndex = orderedStopIds.length;\n for (let i = currentIndex + 1; i < tripStops.length; i++) {\n const idx = orderedStopIds.indexOf(tripStops[i].stop_id);\n if (idx !== -1) {\n afterIndex = idx;\n break;\n }\n }\n\n // Insert after the last known previous stop, but before any known next stop\n // This maintains the ordering constraints from the current trip\n const insertPosition = beforeIndex + 1;\n\n // Validate that this position is before the next known stop\n if (insertPosition <= afterIndex) {\n return insertPosition;\n }\n\n // If there's a conflict (shouldn't happen with consistent data),\n // default to inserting after the previous stop\n return beforeIndex + 1;\n}\n\n/**\n * Convert database row to StopTime object\n */\nfunction rowToStopTime(row: Record<string, unknown>): 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","/**\n * Shape Query Methods\n */\n\nimport type { Database } from 'sql.js';\nimport type { Shape, Route } from '../types/gtfs';\n\nexport interface ShapeFilters {\n shapeId?: string | string[];\n routeId?: string | string[];\n tripId?: string | string[];\n limit?: number;\n}\n\nexport interface GeoJsonGeometry {\n type: 'LineString';\n coordinates: number[][];\n}\n\nexport interface GeoJsonFeature {\n type: 'Feature';\n properties: {\n shape_id: string;\n route_id?: string;\n route_short_name?: string;\n route_long_name?: string;\n route_type?: number;\n route_color?: string;\n route_text_color?: string;\n agency_id?: string;\n };\n geometry: GeoJsonGeometry;\n}\n\nexport interface GeoJsonFeatureCollection {\n type: 'FeatureCollection';\n features: GeoJsonFeature[];\n}\n\n/**\n * Get shapes with optional filters\n * - Filters support both single values and arrays\n */\nexport function getShapes(\n db: Database,\n filters: ShapeFilters = {}\n): Shape[] {\n const { shapeId, routeId, tripId, limit } = filters;\n\n // Determine if we need to join with trips table\n const needsTripsJoin = routeId !== undefined || tripId !== undefined;\n\n // Build WHERE clause dynamically\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (shapeId) {\n const shapeIds = Array.isArray(shapeId) ? shapeId : [shapeId];\n if (shapeIds.length > 0) {\n const placeholders = shapeIds.map(() => '?').join(', ');\n conditions.push(needsTripsJoin ? `s.shape_id IN (${placeholders})` : `shape_id IN (${placeholders})`);\n params.push(...shapeIds);\n }\n }\n\n if (tripId) {\n const tripIds = Array.isArray(tripId) ? tripId : [tripId];\n if (tripIds.length > 0) {\n const placeholders = tripIds.map(() => '?').join(', ');\n conditions.push(`t.trip_id IN (${placeholders})`);\n params.push(...tripIds);\n }\n }\n\n if (routeId) {\n const routeIds = Array.isArray(routeId) ? routeId : [routeId];\n if (routeIds.length > 0) {\n const placeholders = routeIds.map(() => '?').join(', ');\n conditions.push(`t.route_id IN (${placeholders})`);\n params.push(...routeIds);\n }\n }\n\n // Build SQL query\n let sql: string;\n if (needsTripsJoin) {\n // Join with trips to filter by route_id or trip_id\n // Use DISTINCT shape_id to get unique shapes, then join back to get all points\n sql = `\n SELECT s.* FROM shapes s\n WHERE s.shape_id IN (\n SELECT DISTINCT t.shape_id FROM trips t\n WHERE t.shape_id IS NOT NULL\n ${conditions.length > 0 ? ' AND ' + conditions.join(' AND ') : ''}\n )\n ORDER BY s.shape_id, s.shape_pt_sequence\n `;\n } else {\n sql = 'SELECT * FROM shapes';\n if (conditions.length > 0) {\n sql += ' WHERE ' + conditions.join(' AND ');\n }\n sql += ' ORDER BY shape_id, shape_pt_sequence';\n }\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 shapes: Shape[] = [];\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record<string, unknown>;\n shapes.push(rowToShape(row));\n }\n\n stmt.free();\n\n return shapes;\n}\n\n/**\n * Convert shapes to GeoJSON FeatureCollection with optional precision\n * @param db - Database instance\n * @param filters - Same filters as getShapes\n * @param precision - Number of decimal places for coordinates (default: 6)\n */\nexport function getShapesToGeojson(\n db: Database,\n filters: ShapeFilters = {},\n precision: number = 6\n): GeoJsonFeatureCollection {\n const shapes = getShapes(db, filters);\n\n // Group shapes by shape_id\n const shapeGroups = new Map<string, Shape[]>();\n for (const shape of shapes) {\n const group = shapeGroups.get(shape.shape_id);\n if (group) {\n group.push(shape);\n } else {\n shapeGroups.set(shape.shape_id, [shape]);\n }\n }\n\n // Get route information for each shape\n const shapeRouteMap = getRoutesByShapeIds(db, Array.from(shapeGroups.keys()));\n\n // Build GeoJSON features\n const features: GeoJsonFeature[] = [];\n const multiplier = Math.pow(10, precision);\n\n for (const [shapeId, points] of shapeGroups) {\n // Sort points by sequence (should already be sorted, but ensure)\n points.sort((a, b) => a.shape_pt_sequence - b.shape_pt_sequence);\n\n // Build coordinates array [lon, lat] with specified precision\n const coordinates: number[][] = points.map(point => [\n Math.round(point.shape_pt_lon * multiplier) / multiplier,\n Math.round(point.shape_pt_lat * multiplier) / multiplier\n ]);\n\n // Get route properties\n const route = shapeRouteMap.get(shapeId);\n const properties: GeoJsonFeature['properties'] = {\n shape_id: shapeId,\n };\n\n if (route) {\n properties.route_id = route.route_id;\n properties.route_short_name = route.route_short_name;\n properties.route_long_name = route.route_long_name;\n properties.route_type = route.route_type;\n if (route.route_color) properties.route_color = route.route_color;\n if (route.route_text_color) properties.route_text_color = route.route_text_color;\n if (route.agency_id) properties.agency_id = route.agency_id;\n }\n\n features.push({\n type: 'Feature',\n properties,\n geometry: {\n type: 'LineString',\n coordinates\n }\n });\n }\n\n return {\n type: 'FeatureCollection',\n features\n };\n}\n\n/**\n * Get the first matching route for each shape_id\n */\nfunction getRoutesByShapeIds(\n db: Database,\n shapeIds: string[]\n): Map<string, Route> {\n if (shapeIds.length === 0) {\n return new Map();\n }\n\n const placeholders = shapeIds.map(() => '?').join(', ');\n\n // Get first route for each shape via trips table\n const sql = `\n SELECT DISTINCT t.shape_id, r.*\n FROM trips t\n INNER JOIN routes r ON t.route_id = r.route_id\n WHERE t.shape_id IN (${placeholders})\n GROUP BY t.shape_id\n `;\n\n const stmt = db.prepare(sql);\n stmt.bind(shapeIds);\n\n const result = new Map<string, Route>();\n while (stmt.step()) {\n const row = stmt.getAsObject() as Record<string, unknown>;\n const shapeId = String(row.shape_id);\n result.set(shapeId, rowToRoute(row));\n }\n\n stmt.free();\n\n return result;\n}\n\n/**\n * Convert database row to Shape object\n */\nfunction rowToShape(row: Record<string, unknown>): Shape {\n return {\n shape_id: String(row.shape_id),\n shape_pt_lat: Number(row.shape_pt_lat),\n shape_pt_lon: Number(row.shape_pt_lon),\n shape_pt_sequence: Number(row.shape_pt_sequence),\n shape_dist_traveled: row.shape_dist_traveled !== null ? Number(row.shape_dist_traveled) : undefined,\n };\n}\n\n/**\n * Convert database row to Route object\n */\nfunction rowToRoute(row: Record<string, unknown>): Route {\n return {\n route_id: String(row.route_id),\n route_short_name: row.route_short_name ? String(row.route_short_name) : '',\n route_long_name: row.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","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<string, unknown>): 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<string, unknown>;\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<string, unknown>;\n alerts.push(parseAlert(row));\n }\n\n stmt.free();\n return alerts;\n}\n","import type { Database } from 'sql.js';\nimport type { StopTimeUpdate } from '../types/gtfs-rt';\n\nexport interface StopTimeUpdateFilters {\n tripId?: string | string[];\n stopId?: string | string[];\n stopSequence?: number | number[];\n limit?: number;\n}\n\n/**\n * Parse stop time update from database row (includes trip_id and rt_last_updated)\n */\nfunction parseStopTimeUpdate(row: Record<string, unknown>): 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 trip_id: String(row.trip_id),\n rt_last_updated: Number(row.rt_last_updated)\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 * Get stop time updates with optional filters\n * - Filters support both single values and arrays\n * - Returns stop time updates with trip_id and rt_last_updated populated\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 const tripIds = Array.isArray(tripId) ? tripId : [tripId];\n if (tripIds.length > 0) {\n const placeholders = tripIds.map(() => '?').join(', ');\n conditions.push(`trip_id IN (${placeholders})`);\n params.push(...tripIds);\n }\n }\n\n // Filter by stop_id\n if (stopId) {\n const stopIds = Array.isArray(stopId) ? stopId : [stopId];\n if (stopIds.length > 0) {\n const placeholders = stopIds.map(() => '?').join(', ');\n conditions.push(`stop_id IN (${placeholders})`);\n params.push(...stopIds);\n }\n }\n\n // Filter by stop_sequence\n if (stopSequence !== undefined) {\n const stopSequences = Array.isArray(stopSequence) ? stopSequence : [stopSequence];\n if (stopSequences.length > 0) {\n const placeholders = stopSequences.map(() => '?').join(', ');\n conditions.push(`stop_sequence IN (${placeholders})`);\n params.push(...stopSequences);\n }\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<string, unknown>;\n stopTimeUpdates.push(parseStopTimeUpdate(row));\n }\n\n stmt.free();\n return stopTimeUpdates;\n}\n\n/**\n * Get all stop time updates without staleness filtering (for debugging)\n * Convenience wrapper for getStopTimeUpdates() with no staleness threshold\n */\nexport function getAllStopTimeUpdates(db: Database): StopTimeUpdate[] {\n return getStopTimeUpdates(db, {}, Number.MAX_SAFE_INTEGER);\n}\n","import type { Database } from 'sql.js';\nimport type { TripUpdate, StopTimeUpdate } from '../types/gtfs-rt';\nimport { getStopTimeUpdates } from './rt-stop-time-updates';\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<string, unknown>): 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<string, unknown>;\n tripUpdates.push(parseTripUpdate(row));\n }\n\n stmt.free();\n\n // Populate stop_time_update arrays\n if (tripUpdates.length > 0) {\n const tripIds = tripUpdates.map(tu => tu.trip_id);\n\n // Query stop time updates for all retrieved trip IDs\n const stopTimeUpdates = getStopTimeUpdates(db, { tripId: tripIds }, stalenessThreshold);\n\n // Group stop time updates by trip_id\n const stopTimesByTripId = new Map<string, StopTimeUpdate[]>();\n for (const stu of stopTimeUpdates) {\n if (!stu.trip_id) continue; // Skip if trip_id is not populated\n if (!stopTimesByTripId.has(stu.trip_id)) {\n stopTimesByTripId.set(stu.trip_id, []);\n }\n stopTimesByTripId.get(stu.trip_id)!.push(stu);\n }\n\n // Populate each trip update's stop_time_update array\n for (const tu of tripUpdates) {\n tu.stop_time_update = stopTimesByTripId.get(tu.trip_id) || [];\n }\n }\n\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<string, unknown>;\n tripUpdates.push(parseTripUpdate(row));\n }\n\n stmt.free();\n\n // Populate stop_time_update arrays (no staleness filtering for debug function)\n if (tripUpdates.length > 0) {\n const tripIds = tripUpdates.map(tu => tu.trip_id);\n\n // Query stop time updates for all retrieved trip IDs (use very large threshold to disable staleness filtering)\n const stopTimeUpdates = getStopTimeUpdates(db, { tripId: tripIds }, Number.MAX_SAFE_INTEGER);\n\n // Group stop time updates by trip_id\n const stopTimesByTripId = new Map<string, StopTimeUpdate[]>();\n for (const stu of stopTimeUpdates) {\n if (!stu.trip_id) continue; // Skip if trip_id is not populated\n if (!stopTimesByTripId.has(stu.trip_id)) {\n stopTimesByTripId.set(stu.trip_id, []);\n }\n stopTimesByTripId.get(stu.trip_id)!.push(stu);\n }\n\n // Populate each trip update's stop_time_update array\n for (const tu of tripUpdates) {\n tu.stop_time_update = stopTimesByTripId.get(tu.trip_id) || [];\n }\n }\n\n return tripUpdates;\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 trip_id?: string; // Present when queried from database\n rt_last_updated?: number; // Present when queried from database (UNIX timestamp)\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 arrival_time?: number; // UNIX timestamp (absolute time)\n departure_delay?: number; // seconds\n departure_time?: number; // UNIX timestamp (absolute time)\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","/**\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 ShapeFilters,\n type AlertFilters,\n type VehiclePositionFilters,\n type TripUpdateFilters,\n type StopTimeUpdateFilters,\n type Alert,\n type VehiclePosition,\n type TripUpdate,\n type TripWithRealtime,\n type StopTimeWithRealtime,\n type GeoJsonFeatureCollection\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// Export cache types and interfaces\nexport type {\n CacheStore,\n CacheMetadata,\n CacheEntry,\n CacheEntryWithData,\n CacheStoreOptions\n} from './cache/types';\n\n// Export cache utilities\nexport { computeChecksum, computeZipChecksum, generateCacheKey } from './cache/checksum';\nexport { isCacheExpired, filterExpiredEntries, getCacheStats, DEFAULT_CACHE_EXPIRATION_MS } from './cache/utils';\n\n// Note: Cache store implementations (IndexedDBCacheStore, FileSystemCacheStore) are available\n// in examples/cache/ directory. Copy them to your project as needed.\n"],"mappings":"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","names":["response","arrayBuffer","stmt","stops","mergeRealtimeData","rowToRoute","zipData","getCacheStats","filterExpiredEntries","ScheduleRelationship","VehicleStopStatus","CongestionLevel","OccupancyStatus","AlertCause","AlertEffect"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gtfs-sqljs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Load GTFS data into sql.js SQLite database for querying in browser and Node.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"prepare": "npm run build",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"lint": "eslint src --ext .ts",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"prepublishOnly": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"gtfs",
|
|
30
|
+
"transit",
|
|
31
|
+
"sqlite",
|
|
32
|
+
"sql.js",
|
|
33
|
+
"browser",
|
|
34
|
+
"nodejs"
|
|
35
|
+
],
|
|
36
|
+
"author": "Théophile Helleboid/SysDevRun",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/sysdevrun/gtfs-sqljs.git"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"jszip": "^3.10.1",
|
|
44
|
+
"papaparse": "^5.5.3",
|
|
45
|
+
"protobufjs": "^7.2.5",
|
|
46
|
+
"sql.js": "^1.10.3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.11.5",
|
|
50
|
+
"@types/papaparse": "^5.5.0",
|
|
51
|
+
"@types/sql.js": "^1.4.9",
|
|
52
|
+
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
|
53
|
+
"@typescript-eslint/parser": "^6.19.0",
|
|
54
|
+
"eslint": "^8.56.0",
|
|
55
|
+
"tsup": "^8.0.1",
|
|
56
|
+
"typescript": "^5.3.3",
|
|
57
|
+
"vitest": "^1.2.1"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18.0.0"
|
|
61
|
+
}
|
|
62
|
+
}
|