lt-public-transport-sdk 1.0.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.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/assets/architecture.png +0 -0
  4. package/dist/config.d.ts +221 -0
  5. package/dist/config.d.ts.map +1 -0
  6. package/dist/config.js +200 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/enrichment/index.d.ts +6 -0
  9. package/dist/enrichment/index.d.ts.map +1 -0
  10. package/dist/enrichment/index.js +6 -0
  11. package/dist/enrichment/index.js.map +1 -0
  12. package/dist/enrichment/route-matcher.d.ts +64 -0
  13. package/dist/enrichment/route-matcher.d.ts.map +1 -0
  14. package/dist/enrichment/route-matcher.js +121 -0
  15. package/dist/enrichment/route-matcher.js.map +1 -0
  16. package/dist/errors.d.ts +70 -0
  17. package/dist/errors.d.ts.map +1 -0
  18. package/dist/errors.js +104 -0
  19. package/dist/errors.js.map +1 -0
  20. package/dist/gtfs/index.d.ts +7 -0
  21. package/dist/gtfs/index.d.ts.map +1 -0
  22. package/dist/gtfs/index.js +7 -0
  23. package/dist/gtfs/index.js.map +1 -0
  24. package/dist/gtfs/parser.d.ts +39 -0
  25. package/dist/gtfs/parser.d.ts.map +1 -0
  26. package/dist/gtfs/parser.js +189 -0
  27. package/dist/gtfs/parser.js.map +1 -0
  28. package/dist/gtfs/sync.d.ts +72 -0
  29. package/dist/gtfs/sync.d.ts.map +1 -0
  30. package/dist/gtfs/sync.js +271 -0
  31. package/dist/gtfs/sync.js.map +1 -0
  32. package/dist/index.d.ts +203 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +342 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/parsers/gps-full.d.ts +39 -0
  37. package/dist/parsers/gps-full.d.ts.map +1 -0
  38. package/dist/parsers/gps-full.js +212 -0
  39. package/dist/parsers/gps-full.js.map +1 -0
  40. package/dist/parsers/gps-lite.d.ts +60 -0
  41. package/dist/parsers/gps-lite.d.ts.map +1 -0
  42. package/dist/parsers/gps-lite.js +141 -0
  43. package/dist/parsers/gps-lite.js.map +1 -0
  44. package/dist/parsers/index.d.ts +7 -0
  45. package/dist/parsers/index.d.ts.map +1 -0
  46. package/dist/parsers/index.js +7 -0
  47. package/dist/parsers/index.js.map +1 -0
  48. package/dist/schemas.d.ts +129 -0
  49. package/dist/schemas.d.ts.map +1 -0
  50. package/dist/schemas.js +200 -0
  51. package/dist/schemas.js.map +1 -0
  52. package/dist/scripts/test-city-specific.d.ts +2 -0
  53. package/dist/scripts/test-city-specific.d.ts.map +1 -0
  54. package/dist/scripts/test-city-specific.js +264 -0
  55. package/dist/scripts/test-city-specific.js.map +1 -0
  56. package/dist/scripts/test-config-options.d.ts +2 -0
  57. package/dist/scripts/test-config-options.d.ts.map +1 -0
  58. package/dist/scripts/test-config-options.js +166 -0
  59. package/dist/scripts/test-config-options.js.map +1 -0
  60. package/dist/scripts/test-data-quality.d.ts +2 -0
  61. package/dist/scripts/test-data-quality.d.ts.map +1 -0
  62. package/dist/scripts/test-data-quality.js +204 -0
  63. package/dist/scripts/test-data-quality.js.map +1 -0
  64. package/dist/scripts/test-error-handling.d.ts +2 -0
  65. package/dist/scripts/test-error-handling.d.ts.map +1 -0
  66. package/dist/scripts/test-error-handling.js +146 -0
  67. package/dist/scripts/test-error-handling.js.map +1 -0
  68. package/dist/scripts/test-live.d.ts +2 -0
  69. package/dist/scripts/test-live.d.ts.map +1 -0
  70. package/dist/scripts/test-live.js +121 -0
  71. package/dist/scripts/test-live.js.map +1 -0
  72. package/dist/types.d.ts +120 -0
  73. package/dist/types.d.ts.map +1 -0
  74. package/dist/types.js +25 -0
  75. package/dist/types.js.map +1 -0
  76. package/dist/utils/coordinates.d.ts +68 -0
  77. package/dist/utils/coordinates.d.ts.map +1 -0
  78. package/dist/utils/coordinates.js +98 -0
  79. package/dist/utils/coordinates.js.map +1 -0
  80. package/dist/utils/encoding.d.ts +47 -0
  81. package/dist/utils/encoding.d.ts.map +1 -0
  82. package/dist/utils/encoding.js +153 -0
  83. package/dist/utils/encoding.js.map +1 -0
  84. package/dist/utils/index.d.ts +8 -0
  85. package/dist/utils/index.d.ts.map +1 -0
  86. package/dist/utils/index.js +8 -0
  87. package/dist/utils/index.js.map +1 -0
  88. package/dist/utils/time.d.ts +50 -0
  89. package/dist/utils/time.d.ts.map +1 -0
  90. package/dist/utils/time.js +94 -0
  91. package/dist/utils/time.js.map +1 -0
  92. package/package.json +84 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/gtfs/parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAe,MAAM,aAAa,CAAC;AAoE5D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAsDtE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,CAiDzD"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * GTFS file parsers for routes.txt and stops.txt
3
+ * @module gtfs/parser
4
+ */
5
+ import { GTFS_ROUTE_TYPE_MAP } from '../types.js';
6
+ import { cleanTextField } from '../utils/index.js';
7
+ import { gtfsRouteSchema, gtfsStopSchema } from '../schemas.js';
8
+ // =============================================================================
9
+ // CSV Parsing Utilities
10
+ // =============================================================================
11
+ /**
12
+ * Parse a CSV line handling quoted fields.
13
+ */
14
+ function parseCSVLine(line) {
15
+ const result = [];
16
+ let current = '';
17
+ let inQuotes = false;
18
+ for (let i = 0; i < line.length; i++) {
19
+ const char = line[i];
20
+ if (char === '"') {
21
+ if (inQuotes && line[i + 1] === '"') {
22
+ // Escaped quote
23
+ current += '"';
24
+ i++;
25
+ }
26
+ else {
27
+ inQuotes = !inQuotes;
28
+ }
29
+ }
30
+ else if (char === ',' && !inQuotes) {
31
+ result.push(current.trim());
32
+ current = '';
33
+ }
34
+ else if (char !== undefined) {
35
+ current += char;
36
+ }
37
+ }
38
+ result.push(current.trim());
39
+ return result;
40
+ }
41
+ /**
42
+ * Build a header-to-index map from CSV header row.
43
+ */
44
+ function buildHeaderMap(headers) {
45
+ const map = new Map();
46
+ headers.forEach((header, index) => {
47
+ map.set(header.trim(), index);
48
+ });
49
+ return map;
50
+ }
51
+ /**
52
+ * Build a key-value object from a row using header map.
53
+ */
54
+ function buildRowObject(row, headerMap) {
55
+ const obj = {};
56
+ for (const [header, index] of headerMap.entries()) {
57
+ if (index < row.length) {
58
+ obj[header] = row[index]?.trim() ?? '';
59
+ }
60
+ }
61
+ return obj;
62
+ }
63
+ // =============================================================================
64
+ // Routes Parser
65
+ // =============================================================================
66
+ /**
67
+ * Parse routes.txt content into a Map keyed by route short name.
68
+ *
69
+ * GTFS routes.txt fields:
70
+ * - route_id: Unique identifier
71
+ * - agency_id: Agency reference
72
+ * - route_short_name: Short name (e.g., "4G", "N1")
73
+ * - route_long_name: Full name with endpoints
74
+ * - route_desc: Description
75
+ * - route_type: GTFS route type (3=bus, 800=trolleybus)
76
+ * - route_url: URL
77
+ * - route_color: Background color (hex)
78
+ * - route_text_color: Text color (hex)
79
+ *
80
+ * @param content - Raw routes.txt content
81
+ * @returns Map from route short name to Route object
82
+ */
83
+ export function parseRoutesContent(content) {
84
+ const lines = content.split('\n').filter(line => line.trim());
85
+ if (lines.length < 2) {
86
+ return new Map();
87
+ }
88
+ const firstLine = lines[0];
89
+ if (firstLine === undefined || firstLine === '') {
90
+ return new Map();
91
+ }
92
+ const headers = parseCSVLine(firstLine);
93
+ const headerMap = buildHeaderMap(headers);
94
+ const routes = new Map();
95
+ for (let i = 1; i < lines.length; i++) {
96
+ const line = lines[i];
97
+ if (line === undefined || line === '')
98
+ continue;
99
+ const row = parseCSVLine(line);
100
+ try {
101
+ // Build object from row for Zod validation
102
+ const rowObject = buildRowObject(row, headerMap);
103
+ const parseResult = gtfsRouteSchema.safeParse(rowObject);
104
+ if (!parseResult.success) {
105
+ continue;
106
+ }
107
+ const validated = parseResult.data;
108
+ const type = GTFS_ROUTE_TYPE_MAP[validated.route_type] ?? 'unknown';
109
+ const routeObj = {
110
+ id: validated.route_id,
111
+ shortName: cleanTextField(validated.route_short_name),
112
+ longName: cleanTextField(validated.route_long_name),
113
+ type,
114
+ color: validated.route_color.replace('#', ''),
115
+ textColor: validated.route_text_color.replace('#', ''),
116
+ };
117
+ // Key by short name for fast lookup from GPS data
118
+ routes.set(routeObj.shortName, routeObj);
119
+ // Also key by route_id for GTFS trip references
120
+ routes.set(routeObj.id, routeObj);
121
+ }
122
+ catch {
123
+ // Skip malformed rows
124
+ continue;
125
+ }
126
+ }
127
+ return routes;
128
+ }
129
+ // =============================================================================
130
+ // Stops Parser
131
+ // =============================================================================
132
+ /**
133
+ * Parse stops.txt content into an array of Stop objects.
134
+ *
135
+ * GTFS stops.txt fields:
136
+ * - stop_id: Unique identifier
137
+ * - stop_code: Short code
138
+ * - stop_name: Human-readable name
139
+ * - stop_desc: Description
140
+ * - stop_lat: Latitude
141
+ * - stop_lon: Longitude
142
+ *
143
+ * @param content - Raw stops.txt content
144
+ * @returns Array of Stop objects
145
+ */
146
+ export function parseStopsContent(content) {
147
+ const lines = content.split('\n').filter(line => line.trim());
148
+ if (lines.length < 2) {
149
+ return [];
150
+ }
151
+ const firstLine = lines[0];
152
+ if (firstLine === undefined || firstLine === '') {
153
+ return [];
154
+ }
155
+ const headers = parseCSVLine(firstLine);
156
+ const headerMap = buildHeaderMap(headers);
157
+ const stops = [];
158
+ for (let i = 1; i < lines.length; i++) {
159
+ const line = lines[i];
160
+ if (line === undefined || line === '')
161
+ continue;
162
+ const row = parseCSVLine(line);
163
+ try {
164
+ // Build object from row for Zod validation
165
+ const rowObject = buildRowObject(row, headerMap);
166
+ const parseResult = gtfsStopSchema.safeParse(rowObject);
167
+ if (!parseResult.success) {
168
+ continue;
169
+ }
170
+ const validated = parseResult.data;
171
+ stops.push({
172
+ id: validated.stop_id,
173
+ code: validated.stop_code ?? null,
174
+ name: cleanTextField(validated.stop_name),
175
+ description: validated.stop_desc !== undefined && validated.stop_desc !== ''
176
+ ? cleanTextField(validated.stop_desc)
177
+ : null,
178
+ latitude: validated.stop_lat,
179
+ longitude: validated.stop_lon,
180
+ });
181
+ }
182
+ catch {
183
+ // Skip malformed rows
184
+ continue;
185
+ }
186
+ }
187
+ return stops;
188
+ }
189
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/gtfs/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * GTFS sync and caching module
3
+ * @module gtfs/sync
4
+ *
5
+ * Handles downloading, extracting, and caching GTFS data from stops.lt.
6
+ * Uses yauzl-promise for proper ZIP extraction.
7
+ */
8
+ import type { CityId, Route, Stop, SyncResult } from '../types.js';
9
+ /**
10
+ * GTFS cache metadata.
11
+ */
12
+ interface CacheMeta {
13
+ /** Last-Modified header from server */
14
+ lastModified: string | null;
15
+ /** When cache was synced */
16
+ syncedAt: string;
17
+ /** Number of routes in cache */
18
+ routeCount: number;
19
+ /** Number of stops in cache */
20
+ stopCount: number;
21
+ }
22
+ /**
23
+ * Cached GTFS data for a city.
24
+ */
25
+ export interface GtfsCache {
26
+ readonly meta: CacheMeta;
27
+ readonly routes: Map<string, Route>;
28
+ readonly stops: Stop[];
29
+ }
30
+ /**
31
+ * Options for GTFS sync.
32
+ */
33
+ export interface SyncOptions {
34
+ /** Directory for caching GTFS data */
35
+ cacheDir?: string;
36
+ /** Request timeout in ms (default: 30000) */
37
+ timeout?: number;
38
+ /** User-Agent header for requests */
39
+ userAgent?: string;
40
+ /** Force re-download even if cache is current */
41
+ force?: boolean;
42
+ }
43
+ /**
44
+ * Load cached routes for a city.
45
+ */
46
+ export declare function loadCachedRoutes(cacheDir: string, city: CityId): Promise<Map<string, Route> | null>;
47
+ /**
48
+ * Load cached stops for a city.
49
+ */
50
+ export declare function loadCachedStops(cacheDir: string, city: CityId): Promise<Stop[] | null>;
51
+ /**
52
+ * Sync GTFS data for a city.
53
+ *
54
+ * Downloads the GTFS ZIP archive if newer than cached version,
55
+ * extracts routes.txt and stops.txt, and caches the parsed data.
56
+ *
57
+ * @param city - City to sync
58
+ * @param options - Sync options
59
+ * @returns Sync result
60
+ */
61
+ export declare function syncGtfs(city: CityId, options?: SyncOptions): Promise<SyncResult>;
62
+ /**
63
+ * Load GTFS cache for a city.
64
+ * Returns null if not cached.
65
+ *
66
+ * @param city - City to load
67
+ * @param cacheDir - Cache directory
68
+ * @returns Cached GTFS data or null
69
+ */
70
+ export declare function loadGtfsCache(city: CityId, cacheDir?: string): Promise<GtfsCache | null>;
71
+ export {};
72
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/gtfs/sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASnE;;GAEG;AACH,UAAU,SAAS;IACjB,uCAAuC;IACvC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;CACxB;AAMD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAmED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,CAczG;AAYD;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAa5F;AAeD;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAwI3F;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAgB9F"}
@@ -0,0 +1,271 @@
1
+ /**
2
+ * GTFS sync and caching module
3
+ * @module gtfs/sync
4
+ *
5
+ * Handles downloading, extracting, and caching GTFS data from stops.lt.
6
+ * Uses yauzl-promise for proper ZIP extraction.
7
+ */
8
+ import { existsSync } from 'node:fs';
9
+ import { mkdir, readFile, writeFile, unlink } from 'node:fs/promises';
10
+ import { tmpdir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ import * as yauzl from 'yauzl-promise';
13
+ import { CITY_CONFIGS } from '../config.js';
14
+ import { GtfsSyncError } from '../errors.js';
15
+ import { parseRoutesContent, parseStopsContent } from './parser.js';
16
+ // =============================================================================
17
+ // Default Values
18
+ // =============================================================================
19
+ const DEFAULT_TIMEOUT = 30000;
20
+ const DEFAULT_USER_AGENT = 'lt-public-transport-sdk/1.0.0';
21
+ /**
22
+ * Get default cache directory.
23
+ */
24
+ function getDefaultCacheDir() {
25
+ return join(tmpdir(), 'lt-transport-sdk-cache');
26
+ }
27
+ // =============================================================================
28
+ // Helper Functions
29
+ // =============================================================================
30
+ /**
31
+ * Ensure directory exists.
32
+ */
33
+ async function ensureDir(dir) {
34
+ if (!existsSync(dir)) {
35
+ await mkdir(dir, { recursive: true });
36
+ }
37
+ }
38
+ /**
39
+ * Read a stream to string.
40
+ */
41
+ async function streamToString(stream) {
42
+ const chunks = [];
43
+ for await (const chunk of stream) {
44
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
45
+ }
46
+ return Buffer.concat(chunks).toString('utf-8');
47
+ }
48
+ /**
49
+ * Load cache metadata for a city.
50
+ */
51
+ async function loadCacheMeta(cacheDir, city) {
52
+ const metaPath = join(cacheDir, city, 'meta.json');
53
+ if (!existsSync(metaPath)) {
54
+ return null;
55
+ }
56
+ try {
57
+ const content = await readFile(metaPath, 'utf-8');
58
+ return JSON.parse(content);
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ }
64
+ /**
65
+ * Save cache metadata for a city.
66
+ */
67
+ async function saveCacheMeta(cacheDir, city, meta) {
68
+ const cityDir = join(cacheDir, city);
69
+ await ensureDir(cityDir);
70
+ await writeFile(join(cityDir, 'meta.json'), JSON.stringify(meta, null, 2));
71
+ }
72
+ /**
73
+ * Load cached routes for a city.
74
+ */
75
+ export async function loadCachedRoutes(cacheDir, city) {
76
+ const routesPath = join(cacheDir, city, 'routes.json');
77
+ if (!existsSync(routesPath)) {
78
+ return null;
79
+ }
80
+ try {
81
+ const content = await readFile(routesPath, 'utf-8');
82
+ const entries = JSON.parse(content);
83
+ return new Map(entries);
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ /**
90
+ * Save routes to cache.
91
+ */
92
+ async function saveRoutes(cacheDir, city, routes) {
93
+ const cityDir = join(cacheDir, city);
94
+ await ensureDir(cityDir);
95
+ const entries = Array.from(routes.entries());
96
+ await writeFile(join(cityDir, 'routes.json'), JSON.stringify(entries));
97
+ }
98
+ /**
99
+ * Load cached stops for a city.
100
+ */
101
+ export async function loadCachedStops(cacheDir, city) {
102
+ const stopsPath = join(cacheDir, city, 'stops.json');
103
+ if (!existsSync(stopsPath)) {
104
+ return null;
105
+ }
106
+ try {
107
+ const content = await readFile(stopsPath, 'utf-8');
108
+ return JSON.parse(content);
109
+ }
110
+ catch {
111
+ return null;
112
+ }
113
+ }
114
+ /**
115
+ * Save stops to cache.
116
+ */
117
+ async function saveStops(cacheDir, city, stops) {
118
+ const cityDir = join(cacheDir, city);
119
+ await ensureDir(cityDir);
120
+ await writeFile(join(cityDir, 'stops.json'), JSON.stringify(stops));
121
+ }
122
+ // =============================================================================
123
+ // Main Sync Function
124
+ // =============================================================================
125
+ /**
126
+ * Sync GTFS data for a city.
127
+ *
128
+ * Downloads the GTFS ZIP archive if newer than cached version,
129
+ * extracts routes.txt and stops.txt, and caches the parsed data.
130
+ *
131
+ * @param city - City to sync
132
+ * @param options - Sync options
133
+ * @returns Sync result
134
+ */
135
+ export async function syncGtfs(city, options = {}) {
136
+ const { cacheDir = getDefaultCacheDir(), timeout = DEFAULT_TIMEOUT, userAgent = DEFAULT_USER_AGENT, force = false, } = options;
137
+ const config = CITY_CONFIGS[city];
138
+ if (!config.gtfs.enabled) {
139
+ throw new GtfsSyncError(city, 'GTFS not available for this city');
140
+ }
141
+ const gtfsUrl = config.gtfs.url;
142
+ try {
143
+ // Check Last-Modified header
144
+ const headController = new AbortController();
145
+ const headTimeout = setTimeout(() => { headController.abort(); }, timeout);
146
+ let remoteLastModified = null;
147
+ try {
148
+ const headResp = await fetch(gtfsUrl, {
149
+ method: 'HEAD',
150
+ headers: { 'User-Agent': userAgent },
151
+ signal: headController.signal,
152
+ });
153
+ remoteLastModified = headResp.headers.get('Last-Modified');
154
+ }
155
+ finally {
156
+ clearTimeout(headTimeout);
157
+ }
158
+ // Check if cache is current
159
+ const cachedMeta = await loadCacheMeta(cacheDir, city);
160
+ if (!force && cachedMeta?.lastModified === remoteLastModified && remoteLastModified !== null) {
161
+ // Cache is current
162
+ return {
163
+ city,
164
+ status: 'up-to-date',
165
+ routeCount: cachedMeta.routeCount,
166
+ stopCount: cachedMeta.stopCount,
167
+ lastModified: cachedMeta.lastModified,
168
+ syncedAt: new Date(cachedMeta.syncedAt),
169
+ };
170
+ }
171
+ // Download ZIP
172
+ const downloadController = new AbortController();
173
+ const downloadTimeout = setTimeout(() => { downloadController.abort(); }, timeout * 3);
174
+ let zipBuffer;
175
+ try {
176
+ const response = await fetch(gtfsUrl, {
177
+ headers: { 'User-Agent': userAgent },
178
+ signal: downloadController.signal,
179
+ });
180
+ if (!response.ok) {
181
+ throw new GtfsSyncError(city, `HTTP ${String(response.status)}: ${response.statusText}`);
182
+ }
183
+ zipBuffer = Buffer.from(await response.arrayBuffer());
184
+ }
185
+ finally {
186
+ clearTimeout(downloadTimeout);
187
+ }
188
+ // Save to temp file for yauzl
189
+ const tempPath = join(tmpdir(), `gtfs-${city}-${String(Date.now())}.zip`);
190
+ await writeFile(tempPath, zipBuffer);
191
+ let routes = new Map();
192
+ let stops = [];
193
+ try {
194
+ // Extract with yauzl
195
+ const zip = await yauzl.open(tempPath);
196
+ try {
197
+ for await (const entry of zip) {
198
+ if (entry.filename === 'routes.txt') {
199
+ const stream = await entry.openReadStream();
200
+ const content = await streamToString(stream);
201
+ routes = parseRoutesContent(content);
202
+ }
203
+ else if (entry.filename === 'stops.txt') {
204
+ const stream = await entry.openReadStream();
205
+ const content = await streamToString(stream);
206
+ stops = parseStopsContent(content);
207
+ }
208
+ }
209
+ }
210
+ finally {
211
+ await zip.close();
212
+ }
213
+ }
214
+ finally {
215
+ // Clean up temp file
216
+ try {
217
+ await unlink(tempPath);
218
+ }
219
+ catch {
220
+ // Ignore cleanup errors
221
+ }
222
+ }
223
+ // Save to cache
224
+ const syncedAt = new Date();
225
+ const meta = {
226
+ lastModified: remoteLastModified,
227
+ syncedAt: syncedAt.toISOString(),
228
+ routeCount: routes.size,
229
+ stopCount: stops.length,
230
+ };
231
+ await saveCacheMeta(cacheDir, city, meta);
232
+ await saveRoutes(cacheDir, city, routes);
233
+ await saveStops(cacheDir, city, stops);
234
+ return {
235
+ city,
236
+ status: 'updated',
237
+ routeCount: routes.size,
238
+ stopCount: stops.length,
239
+ lastModified: remoteLastModified,
240
+ syncedAt,
241
+ };
242
+ }
243
+ catch (error) {
244
+ if (error instanceof GtfsSyncError) {
245
+ throw error;
246
+ }
247
+ throw new GtfsSyncError(city, error instanceof Error ? error.message : 'Unknown error', error instanceof Error ? error : undefined);
248
+ }
249
+ }
250
+ /**
251
+ * Load GTFS cache for a city.
252
+ * Returns null if not cached.
253
+ *
254
+ * @param city - City to load
255
+ * @param cacheDir - Cache directory
256
+ * @returns Cached GTFS data or null
257
+ */
258
+ export async function loadGtfsCache(city, cacheDir) {
259
+ const dir = cacheDir ?? getDefaultCacheDir();
260
+ const meta = await loadCacheMeta(dir, city);
261
+ if (!meta) {
262
+ return null;
263
+ }
264
+ const routes = await loadCachedRoutes(dir, city);
265
+ const stops = await loadCachedStops(dir, city);
266
+ if (!routes || !stops) {
267
+ return null;
268
+ }
269
+ return { meta, routes, stops };
270
+ }
271
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/gtfs/sync.ts"],"names":[],"mappings":"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"}