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.
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/assets/architecture.png +0 -0
- package/dist/config.d.ts +221 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +200 -0
- package/dist/config.js.map +1 -0
- package/dist/enrichment/index.d.ts +6 -0
- package/dist/enrichment/index.d.ts.map +1 -0
- package/dist/enrichment/index.js +6 -0
- package/dist/enrichment/index.js.map +1 -0
- package/dist/enrichment/route-matcher.d.ts +64 -0
- package/dist/enrichment/route-matcher.d.ts.map +1 -0
- package/dist/enrichment/route-matcher.js +121 -0
- package/dist/enrichment/route-matcher.js.map +1 -0
- package/dist/errors.d.ts +70 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +104 -0
- package/dist/errors.js.map +1 -0
- package/dist/gtfs/index.d.ts +7 -0
- package/dist/gtfs/index.d.ts.map +1 -0
- package/dist/gtfs/index.js +7 -0
- package/dist/gtfs/index.js.map +1 -0
- package/dist/gtfs/parser.d.ts +39 -0
- package/dist/gtfs/parser.d.ts.map +1 -0
- package/dist/gtfs/parser.js +189 -0
- package/dist/gtfs/parser.js.map +1 -0
- package/dist/gtfs/sync.d.ts +72 -0
- package/dist/gtfs/sync.d.ts.map +1 -0
- package/dist/gtfs/sync.js +271 -0
- package/dist/gtfs/sync.js.map +1 -0
- package/dist/index.d.ts +203 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +342 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/gps-full.d.ts +39 -0
- package/dist/parsers/gps-full.d.ts.map +1 -0
- package/dist/parsers/gps-full.js +212 -0
- package/dist/parsers/gps-full.js.map +1 -0
- package/dist/parsers/gps-lite.d.ts +60 -0
- package/dist/parsers/gps-lite.d.ts.map +1 -0
- package/dist/parsers/gps-lite.js +141 -0
- package/dist/parsers/gps-lite.js.map +1 -0
- package/dist/parsers/index.d.ts +7 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +7 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/schemas.d.ts +129 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +200 -0
- package/dist/schemas.js.map +1 -0
- package/dist/scripts/test-city-specific.d.ts +2 -0
- package/dist/scripts/test-city-specific.d.ts.map +1 -0
- package/dist/scripts/test-city-specific.js +264 -0
- package/dist/scripts/test-city-specific.js.map +1 -0
- package/dist/scripts/test-config-options.d.ts +2 -0
- package/dist/scripts/test-config-options.d.ts.map +1 -0
- package/dist/scripts/test-config-options.js +166 -0
- package/dist/scripts/test-config-options.js.map +1 -0
- package/dist/scripts/test-data-quality.d.ts +2 -0
- package/dist/scripts/test-data-quality.d.ts.map +1 -0
- package/dist/scripts/test-data-quality.js +204 -0
- package/dist/scripts/test-data-quality.js.map +1 -0
- package/dist/scripts/test-error-handling.d.ts +2 -0
- package/dist/scripts/test-error-handling.d.ts.map +1 -0
- package/dist/scripts/test-error-handling.js +146 -0
- package/dist/scripts/test-error-handling.js.map +1 -0
- package/dist/scripts/test-live.d.ts +2 -0
- package/dist/scripts/test-live.d.ts.map +1 -0
- package/dist/scripts/test-live.js +121 -0
- package/dist/scripts/test-live.js.map +1 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/coordinates.d.ts +68 -0
- package/dist/utils/coordinates.d.ts.map +1 -0
- package/dist/utils/coordinates.js +98 -0
- package/dist/utils/coordinates.js.map +1 -0
- package/dist/utils/encoding.d.ts +47 -0
- package/dist/utils/encoding.d.ts.map +1 -0
- package/dist/utils/encoding.js +153 -0
- package/dist/utils/encoding.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/time.d.ts +50 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +94 -0
- package/dist/utils/time.js.map +1 -0
- package/package.json +84 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lithuanian Public Transport SDK
|
|
3
|
+
*
|
|
4
|
+
* A production-grade TypeScript SDK for accessing real-time Lithuanian
|
|
5
|
+
* public transport data from stops.lt infrastructure.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { LtTransport } from 'lt-public-transport-sdk';
|
|
10
|
+
*
|
|
11
|
+
* const transport = new LtTransport();
|
|
12
|
+
*
|
|
13
|
+
* // Sync GTFS data (required for enrichment)
|
|
14
|
+
* await transport.sync('vilnius');
|
|
15
|
+
*
|
|
16
|
+
* // Get real-time vehicle positions
|
|
17
|
+
* const vehicles = await transport.getVehicles('vilnius');
|
|
18
|
+
*
|
|
19
|
+
* // Get static stop data
|
|
20
|
+
* const stops = await transport.getStops('vilnius');
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import type { CityId, Route, Stop, SyncResult, Vehicle } from './types.js';
|
|
26
|
+
import { type CityConfig } from './config.js';
|
|
27
|
+
/**
|
|
28
|
+
* Configuration options for LtTransport client.
|
|
29
|
+
*/
|
|
30
|
+
export interface LtTransportConfig {
|
|
31
|
+
/**
|
|
32
|
+
* Directory for caching GTFS data.
|
|
33
|
+
* Defaults to system temp directory.
|
|
34
|
+
*/
|
|
35
|
+
cacheDir?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Request timeout in milliseconds.
|
|
38
|
+
* @default 10000
|
|
39
|
+
*/
|
|
40
|
+
requestTimeout?: number;
|
|
41
|
+
/**
|
|
42
|
+
* User-Agent header for HTTP requests.
|
|
43
|
+
* @default 'lt-public-transport-sdk/1.0.0'
|
|
44
|
+
*/
|
|
45
|
+
userAgent?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Threshold in milliseconds for marking data as stale.
|
|
48
|
+
* @default 300000 (5 minutes)
|
|
49
|
+
*/
|
|
50
|
+
staleThresholdMs?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Whether to automatically enrich silver-tier cities with GTFS data.
|
|
53
|
+
* Requires prior sync() call for the city.
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
autoEnrich?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Whether to filter out vehicles with invalid (out of Lithuania) coordinates.
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
filterInvalidCoords?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Whether to filter out stale data.
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
filterStale?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Lithuanian Public Transport SDK client.
|
|
70
|
+
*
|
|
71
|
+
* Provides unified access to real-time GPS vehicle positions and
|
|
72
|
+
* static GTFS data for Lithuanian cities.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const transport = new LtTransport();
|
|
77
|
+
*
|
|
78
|
+
* // Get vehicles from Vilnius (gold tier - rich data)
|
|
79
|
+
* const vilniusVehicles = await transport.getVehicles('vilnius');
|
|
80
|
+
*
|
|
81
|
+
* // Get vehicles from Panevėžys (silver tier - needs enrichment)
|
|
82
|
+
* await transport.sync('panevezys'); // Sync GTFS first
|
|
83
|
+
* const panevezysVehicles = await transport.getVehicles('panevezys');
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export declare class LtTransport {
|
|
87
|
+
private readonly cacheDir;
|
|
88
|
+
private readonly requestTimeout;
|
|
89
|
+
private readonly userAgent;
|
|
90
|
+
private readonly staleThresholdMs;
|
|
91
|
+
private readonly autoEnrich;
|
|
92
|
+
private readonly filterInvalidCoords;
|
|
93
|
+
private readonly filterStale;
|
|
94
|
+
/** In-memory route cache for fast enrichment */
|
|
95
|
+
private readonly routeCaches;
|
|
96
|
+
/** Last sync timestamps for throttling */
|
|
97
|
+
private readonly lastSyncTimes;
|
|
98
|
+
/**
|
|
99
|
+
* Create a new LtTransport client.
|
|
100
|
+
*
|
|
101
|
+
* @param config - Client configuration options
|
|
102
|
+
*/
|
|
103
|
+
constructor(config?: LtTransportConfig);
|
|
104
|
+
/**
|
|
105
|
+
* Get real-time vehicle positions for a city.
|
|
106
|
+
*
|
|
107
|
+
* For silver-tier cities (Panevėžys, Tauragė), vehicles will be enriched
|
|
108
|
+
* with GTFS data if `sync()` has been called and `autoEnrich` is enabled.
|
|
109
|
+
*
|
|
110
|
+
* @param city - City identifier
|
|
111
|
+
* @returns Array of vehicle positions
|
|
112
|
+
* @throws {GpsNotAvailableError} If city is bronze tier (no GPS data)
|
|
113
|
+
* @throws {TransportNetworkError} If network request fails
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const vehicles = await transport.getVehicles('vilnius');
|
|
118
|
+
* console.log(`Found ${vehicles.length} vehicles`);
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
getVehicles(city: CityId): Promise<Vehicle[]>;
|
|
122
|
+
/**
|
|
123
|
+
* Sync GTFS static data for a city.
|
|
124
|
+
*
|
|
125
|
+
* Downloads the GTFS ZIP archive if newer than cached version,
|
|
126
|
+
* extracts routes and stops, and caches for future use.
|
|
127
|
+
*
|
|
128
|
+
* Throttled to minimum 60 seconds between calls for same city.
|
|
129
|
+
*
|
|
130
|
+
* @param city - City to sync
|
|
131
|
+
* @param force - Force re-download even if cache is current
|
|
132
|
+
* @returns Sync result with counts and status
|
|
133
|
+
* @throws {GtfsSyncError} If sync fails
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const result = await transport.sync('vilnius');
|
|
138
|
+
* console.log(`Synced ${result.routeCount} routes`);
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
sync(city: CityId, force?: boolean): Promise<SyncResult>;
|
|
142
|
+
/**
|
|
143
|
+
* Get static stop data for a city.
|
|
144
|
+
*
|
|
145
|
+
* Requires prior `sync()` call to download GTFS data.
|
|
146
|
+
*
|
|
147
|
+
* @param city - City to get stops for
|
|
148
|
+
* @returns Array of stops
|
|
149
|
+
* @throws {SyncRequiredError} If GTFS data not synced
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* await transport.sync('vilnius');
|
|
154
|
+
* const stops = await transport.getStops('vilnius');
|
|
155
|
+
* console.log(`Found ${stops.length} stops`);
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
getStops(city: CityId): Promise<Stop[]>;
|
|
159
|
+
/**
|
|
160
|
+
* Get route information for a city.
|
|
161
|
+
*
|
|
162
|
+
* Requires prior `sync()` call to download GTFS data.
|
|
163
|
+
*
|
|
164
|
+
* @param city - City to get routes for
|
|
165
|
+
* @returns Array of routes
|
|
166
|
+
* @throws {SyncRequiredError} If GTFS data not synced
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* await transport.sync('vilnius');
|
|
171
|
+
* const routes = await transport.getRoutes('vilnius');
|
|
172
|
+
* console.log(`Found ${routes.length} routes`);
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
getRoutes(city: CityId): Promise<Route[]>;
|
|
176
|
+
/**
|
|
177
|
+
* Get list of all supported city IDs.
|
|
178
|
+
*/
|
|
179
|
+
getCities(): readonly CityId[];
|
|
180
|
+
/**
|
|
181
|
+
* Get configuration for a specific city.
|
|
182
|
+
*/
|
|
183
|
+
getCityConfig(city: CityId): CityConfig;
|
|
184
|
+
/**
|
|
185
|
+
* Validate that city ID is valid.
|
|
186
|
+
*/
|
|
187
|
+
private validateCity;
|
|
188
|
+
/**
|
|
189
|
+
* Fetch text content from URL.
|
|
190
|
+
*/
|
|
191
|
+
private fetchText;
|
|
192
|
+
/**
|
|
193
|
+
* Get route cache for a city, loading from disk if needed.
|
|
194
|
+
*/
|
|
195
|
+
private getRouteCache;
|
|
196
|
+
}
|
|
197
|
+
export type { CityId, CityTier, VehicleType, Vehicle, Stop, Route, SyncResult, } from './types.js';
|
|
198
|
+
export { GTFS_ROUTE_TYPE_MAP, LT_TRANSPORT_TYPE_MAP } from './types.js';
|
|
199
|
+
export { CITY_CONFIGS, ALL_CITY_IDS, getCityConfig, getCitiesByTier, hasGpsData, hasGtfsData } from './config.js';
|
|
200
|
+
export type { CityConfig, GpsConfig, GtfsConfig } from './config.js';
|
|
201
|
+
export { TransportError, TransportNetworkError, GpsNotAvailableError, SyncRequiredError, GtfsSyncError, ParseError, InvalidCityError, isTransportError, isNetworkError, } from './errors.js';
|
|
202
|
+
export { normalizeCoordinate, isValidLithuaniaCoord, LITHUANIA_BOUNDS, repairMojibake, secondsFromMidnightToDate, isDataStale, } from './utils/index.js';
|
|
203
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lithuanian Public Transport SDK
|
|
3
|
+
*
|
|
4
|
+
* A production-grade TypeScript SDK for accessing real-time Lithuanian
|
|
5
|
+
* public transport data from stops.lt infrastructure.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { LtTransport } from 'lt-public-transport-sdk';
|
|
10
|
+
*
|
|
11
|
+
* const transport = new LtTransport();
|
|
12
|
+
*
|
|
13
|
+
* // Sync GTFS data (required for enrichment)
|
|
14
|
+
* await transport.sync('vilnius');
|
|
15
|
+
*
|
|
16
|
+
* // Get real-time vehicle positions
|
|
17
|
+
* const vehicles = await transport.getVehicles('vilnius');
|
|
18
|
+
*
|
|
19
|
+
* // Get static stop data
|
|
20
|
+
* const stops = await transport.getStops('vilnius');
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import { tmpdir } from 'node:os';
|
|
26
|
+
import { join } from 'node:path';
|
|
27
|
+
import { CITY_CONFIGS, getCityConfig, ALL_CITY_IDS } from './config.js';
|
|
28
|
+
import { TransportNetworkError, GpsNotAvailableError, SyncRequiredError, InvalidCityError, } from './errors.js';
|
|
29
|
+
import { parseGpsFullStream } from './parsers/gps-full.js';
|
|
30
|
+
import { parseGpsLiteStream, isLiteCity } from './parsers/gps-lite.js';
|
|
31
|
+
import { syncGtfs, loadGtfsCache, loadCachedRoutes, loadCachedStops } from './gtfs/sync.js';
|
|
32
|
+
import { enrichVehicles, buildRouteCache } from './enrichment/route-matcher.js';
|
|
33
|
+
import { clientConfigSchema } from './schemas.js';
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Default Values
|
|
36
|
+
// =============================================================================
|
|
37
|
+
const DEFAULT_TIMEOUT = 10000;
|
|
38
|
+
const DEFAULT_USER_AGENT = 'lt-public-transport-sdk/1.0.0';
|
|
39
|
+
const DEFAULT_STALE_THRESHOLD = 5 * 60 * 1000; // 5 minutes
|
|
40
|
+
/**
|
|
41
|
+
* Get default cache directory.
|
|
42
|
+
*/
|
|
43
|
+
function getDefaultCacheDir() {
|
|
44
|
+
return join(tmpdir(), 'lt-transport-sdk-cache');
|
|
45
|
+
}
|
|
46
|
+
// =============================================================================
|
|
47
|
+
// Main Client Class
|
|
48
|
+
// =============================================================================
|
|
49
|
+
/**
|
|
50
|
+
* Lithuanian Public Transport SDK client.
|
|
51
|
+
*
|
|
52
|
+
* Provides unified access to real-time GPS vehicle positions and
|
|
53
|
+
* static GTFS data for Lithuanian cities.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const transport = new LtTransport();
|
|
58
|
+
*
|
|
59
|
+
* // Get vehicles from Vilnius (gold tier - rich data)
|
|
60
|
+
* const vilniusVehicles = await transport.getVehicles('vilnius');
|
|
61
|
+
*
|
|
62
|
+
* // Get vehicles from Panevėžys (silver tier - needs enrichment)
|
|
63
|
+
* await transport.sync('panevezys'); // Sync GTFS first
|
|
64
|
+
* const panevezysVehicles = await transport.getVehicles('panevezys');
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export class LtTransport {
|
|
68
|
+
cacheDir;
|
|
69
|
+
requestTimeout;
|
|
70
|
+
userAgent;
|
|
71
|
+
staleThresholdMs;
|
|
72
|
+
autoEnrich;
|
|
73
|
+
filterInvalidCoords;
|
|
74
|
+
filterStale;
|
|
75
|
+
/** In-memory route cache for fast enrichment */
|
|
76
|
+
routeCaches = new Map();
|
|
77
|
+
/** Last sync timestamps for throttling */
|
|
78
|
+
lastSyncTimes = new Map();
|
|
79
|
+
/**
|
|
80
|
+
* Create a new LtTransport client.
|
|
81
|
+
*
|
|
82
|
+
* @param config - Client configuration options
|
|
83
|
+
*/
|
|
84
|
+
constructor(config = {}) {
|
|
85
|
+
// Validate config with Zod schema for runtime safety
|
|
86
|
+
const validated = clientConfigSchema.parse({
|
|
87
|
+
cacheDir: config.cacheDir,
|
|
88
|
+
requestTimeout: config.requestTimeout ?? DEFAULT_TIMEOUT,
|
|
89
|
+
userAgent: config.userAgent ?? DEFAULT_USER_AGENT,
|
|
90
|
+
staleThresholdMs: config.staleThresholdMs ?? DEFAULT_STALE_THRESHOLD,
|
|
91
|
+
autoEnrich: config.autoEnrich ?? true,
|
|
92
|
+
filterInvalidCoords: config.filterInvalidCoords ?? true,
|
|
93
|
+
filterStale: config.filterStale ?? false,
|
|
94
|
+
});
|
|
95
|
+
this.cacheDir = validated.cacheDir ?? getDefaultCacheDir();
|
|
96
|
+
this.requestTimeout = validated.requestTimeout;
|
|
97
|
+
this.userAgent = validated.userAgent;
|
|
98
|
+
this.staleThresholdMs = validated.staleThresholdMs;
|
|
99
|
+
this.autoEnrich = validated.autoEnrich;
|
|
100
|
+
this.filterInvalidCoords = validated.filterInvalidCoords;
|
|
101
|
+
this.filterStale = validated.filterStale;
|
|
102
|
+
}
|
|
103
|
+
// ===========================================================================
|
|
104
|
+
// Public API
|
|
105
|
+
// ===========================================================================
|
|
106
|
+
/**
|
|
107
|
+
* Get real-time vehicle positions for a city.
|
|
108
|
+
*
|
|
109
|
+
* For silver-tier cities (Panevėžys, Tauragė), vehicles will be enriched
|
|
110
|
+
* with GTFS data if `sync()` has been called and `autoEnrich` is enabled.
|
|
111
|
+
*
|
|
112
|
+
* @param city - City identifier
|
|
113
|
+
* @returns Array of vehicle positions
|
|
114
|
+
* @throws {GpsNotAvailableError} If city is bronze tier (no GPS data)
|
|
115
|
+
* @throws {TransportNetworkError} If network request fails
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const vehicles = await transport.getVehicles('vilnius');
|
|
120
|
+
* console.log(`Found ${vehicles.length} vehicles`);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
async getVehicles(city) {
|
|
124
|
+
this.validateCity(city);
|
|
125
|
+
const config = getCityConfig(city);
|
|
126
|
+
if (!config.gps.enabled || config.gps.url === null) {
|
|
127
|
+
throw new GpsNotAvailableError(city);
|
|
128
|
+
}
|
|
129
|
+
// Fetch GPS data
|
|
130
|
+
const text = await this.fetchText(config.gps.url, city);
|
|
131
|
+
// Parse based on format
|
|
132
|
+
let vehicles;
|
|
133
|
+
if (config.gps.format === 'full') {
|
|
134
|
+
vehicles = parseGpsFullStream(text, city, {
|
|
135
|
+
staleThresholdMs: this.staleThresholdMs,
|
|
136
|
+
filterStale: this.filterStale,
|
|
137
|
+
filterInvalidCoords: this.filterInvalidCoords,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
else if (isLiteCity(city)) {
|
|
141
|
+
vehicles = parseGpsLiteStream(text, city, {
|
|
142
|
+
filterInvalidCoords: this.filterInvalidCoords,
|
|
143
|
+
});
|
|
144
|
+
// Enrich silver-tier cities with GTFS data
|
|
145
|
+
if (this.autoEnrich) {
|
|
146
|
+
const routeCache = await this.getRouteCache(city);
|
|
147
|
+
if (routeCache) {
|
|
148
|
+
vehicles = enrichVehicles(vehicles, routeCache);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Unknown format
|
|
154
|
+
vehicles = [];
|
|
155
|
+
}
|
|
156
|
+
return vehicles;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Sync GTFS static data for a city.
|
|
160
|
+
*
|
|
161
|
+
* Downloads the GTFS ZIP archive if newer than cached version,
|
|
162
|
+
* extracts routes and stops, and caches for future use.
|
|
163
|
+
*
|
|
164
|
+
* Throttled to minimum 60 seconds between calls for same city.
|
|
165
|
+
*
|
|
166
|
+
* @param city - City to sync
|
|
167
|
+
* @param force - Force re-download even if cache is current
|
|
168
|
+
* @returns Sync result with counts and status
|
|
169
|
+
* @throws {GtfsSyncError} If sync fails
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const result = await transport.sync('vilnius');
|
|
174
|
+
* console.log(`Synced ${result.routeCount} routes`);
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
async sync(city, force = false) {
|
|
178
|
+
this.validateCity(city);
|
|
179
|
+
// Throttle sync calls (60s minimum between calls)
|
|
180
|
+
const lastSync = this.lastSyncTimes.get(city);
|
|
181
|
+
const now = Date.now();
|
|
182
|
+
if (!force && lastSync !== undefined && (now - lastSync) < 60000) {
|
|
183
|
+
// Return cached result
|
|
184
|
+
const cache = await loadGtfsCache(city, this.cacheDir);
|
|
185
|
+
if (cache) {
|
|
186
|
+
return {
|
|
187
|
+
city,
|
|
188
|
+
status: 'up-to-date',
|
|
189
|
+
routeCount: cache.meta.routeCount,
|
|
190
|
+
stopCount: cache.meta.stopCount,
|
|
191
|
+
lastModified: cache.meta.lastModified,
|
|
192
|
+
syncedAt: new Date(cache.meta.syncedAt),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const result = await syncGtfs(city, {
|
|
197
|
+
cacheDir: this.cacheDir,
|
|
198
|
+
timeout: this.requestTimeout * 3, // Longer timeout for downloads
|
|
199
|
+
userAgent: this.userAgent,
|
|
200
|
+
force,
|
|
201
|
+
});
|
|
202
|
+
this.lastSyncTimes.set(city, now);
|
|
203
|
+
// Clear in-memory cache to force reload
|
|
204
|
+
this.routeCaches.delete(city);
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get static stop data for a city.
|
|
209
|
+
*
|
|
210
|
+
* Requires prior `sync()` call to download GTFS data.
|
|
211
|
+
*
|
|
212
|
+
* @param city - City to get stops for
|
|
213
|
+
* @returns Array of stops
|
|
214
|
+
* @throws {SyncRequiredError} If GTFS data not synced
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* await transport.sync('vilnius');
|
|
219
|
+
* const stops = await transport.getStops('vilnius');
|
|
220
|
+
* console.log(`Found ${stops.length} stops`);
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
async getStops(city) {
|
|
224
|
+
this.validateCity(city);
|
|
225
|
+
const stops = await loadCachedStops(this.cacheDir, city);
|
|
226
|
+
if (!stops) {
|
|
227
|
+
throw new SyncRequiredError(city);
|
|
228
|
+
}
|
|
229
|
+
return stops;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Get route information for a city.
|
|
233
|
+
*
|
|
234
|
+
* Requires prior `sync()` call to download GTFS data.
|
|
235
|
+
*
|
|
236
|
+
* @param city - City to get routes for
|
|
237
|
+
* @returns Array of routes
|
|
238
|
+
* @throws {SyncRequiredError} If GTFS data not synced
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* await transport.sync('vilnius');
|
|
243
|
+
* const routes = await transport.getRoutes('vilnius');
|
|
244
|
+
* console.log(`Found ${routes.length} routes`);
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
async getRoutes(city) {
|
|
248
|
+
this.validateCity(city);
|
|
249
|
+
const routeCache = await this.getRouteCache(city);
|
|
250
|
+
if (!routeCache) {
|
|
251
|
+
throw new SyncRequiredError(city);
|
|
252
|
+
}
|
|
253
|
+
// Deduplicate (cache has entries by both short name and ID)
|
|
254
|
+
const seen = new Set();
|
|
255
|
+
const routes = [];
|
|
256
|
+
for (const route of routeCache.routes.values()) {
|
|
257
|
+
if (!seen.has(route.id)) {
|
|
258
|
+
seen.add(route.id);
|
|
259
|
+
routes.push(route);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return routes;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Get list of all supported city IDs.
|
|
266
|
+
*/
|
|
267
|
+
getCities() {
|
|
268
|
+
return ALL_CITY_IDS;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Get configuration for a specific city.
|
|
272
|
+
*/
|
|
273
|
+
getCityConfig(city) {
|
|
274
|
+
this.validateCity(city);
|
|
275
|
+
return getCityConfig(city);
|
|
276
|
+
}
|
|
277
|
+
// ===========================================================================
|
|
278
|
+
// Private Helpers
|
|
279
|
+
// ===========================================================================
|
|
280
|
+
/**
|
|
281
|
+
* Validate that city ID is valid.
|
|
282
|
+
*/
|
|
283
|
+
validateCity(city) {
|
|
284
|
+
if (!(city in CITY_CONFIGS)) {
|
|
285
|
+
throw new InvalidCityError(city);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Fetch text content from URL.
|
|
290
|
+
*/
|
|
291
|
+
async fetchText(url, city) {
|
|
292
|
+
const controller = new AbortController();
|
|
293
|
+
const timeout = setTimeout(() => { controller.abort(); }, this.requestTimeout);
|
|
294
|
+
try {
|
|
295
|
+
const response = await fetch(url, {
|
|
296
|
+
headers: { 'User-Agent': this.userAgent },
|
|
297
|
+
signal: controller.signal,
|
|
298
|
+
});
|
|
299
|
+
if (!response.ok) {
|
|
300
|
+
throw new TransportNetworkError(`HTTP ${String(response.status)}: ${response.statusText}`, city, response.status);
|
|
301
|
+
}
|
|
302
|
+
return await response.text();
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
if (error instanceof TransportNetworkError) {
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
309
|
+
throw new TransportNetworkError(message, city, undefined, error instanceof Error ? error : undefined);
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
clearTimeout(timeout);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get route cache for a city, loading from disk if needed.
|
|
317
|
+
*/
|
|
318
|
+
async getRouteCache(city) {
|
|
319
|
+
// Check in-memory cache first
|
|
320
|
+
const cached = this.routeCaches.get(city);
|
|
321
|
+
if (cached) {
|
|
322
|
+
return cached;
|
|
323
|
+
}
|
|
324
|
+
// Load from disk
|
|
325
|
+
const routes = await loadCachedRoutes(this.cacheDir, city);
|
|
326
|
+
if (routes) {
|
|
327
|
+
// Build RouteCache with normalized lookup map for O(1) case-insensitive matching
|
|
328
|
+
const cache = buildRouteCache(routes);
|
|
329
|
+
this.routeCaches.set(city, cache);
|
|
330
|
+
return cache;
|
|
331
|
+
}
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
export { GTFS_ROUTE_TYPE_MAP, LT_TRANSPORT_TYPE_MAP } from './types.js';
|
|
336
|
+
// Config
|
|
337
|
+
export { CITY_CONFIGS, ALL_CITY_IDS, getCityConfig, getCitiesByTier, hasGpsData, hasGtfsData } from './config.js';
|
|
338
|
+
// Errors
|
|
339
|
+
export { TransportError, TransportNetworkError, GpsNotAvailableError, SyncRequiredError, GtfsSyncError, ParseError, InvalidCityError, isTransportError, isNetworkError, } from './errors.js';
|
|
340
|
+
// Utilities
|
|
341
|
+
export { normalizeCoordinate, isValidLithuaniaCoord, LITHUANIA_BOUNDS, repairMojibake, secondsFromMidnightToDate, isDataStale, } from './utils/index.js';
|
|
342
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GPS Full Format Parser with dynamic header-based column mapping
|
|
3
|
+
* @module parsers/gps-full
|
|
4
|
+
*
|
|
5
|
+
* Handles the "full" GPS format used by gold-tier cities (Vilnius, Kaunas, Klaipėda, Alytus, Druskininkai).
|
|
6
|
+
* Each city has different column layouts, so we parse headers dynamically.
|
|
7
|
+
*
|
|
8
|
+
* Column counts by city (empirically verified):
|
|
9
|
+
* - Vilnius: 18 columns
|
|
10
|
+
* - Kaunas: 14 columns
|
|
11
|
+
* - Klaipėda: 12 columns
|
|
12
|
+
* - Alytus: 13 columns
|
|
13
|
+
* - Druskininkai: 13 columns
|
|
14
|
+
*/
|
|
15
|
+
import type { CityId, Vehicle } from '../types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Options for GPS full format parsing.
|
|
18
|
+
*/
|
|
19
|
+
export interface GpsFullParseOptions {
|
|
20
|
+
/** Threshold in ms for marking data as stale (default: 5 minutes) */
|
|
21
|
+
staleThresholdMs?: number;
|
|
22
|
+
/** Whether to filter out stale records (default: false) */
|
|
23
|
+
filterStale?: boolean;
|
|
24
|
+
/** Whether to filter out records with invalid coordinates (default: true) */
|
|
25
|
+
filterInvalidCoords?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse GPS full format stream from a gold-tier city.
|
|
29
|
+
*
|
|
30
|
+
* Uses header-based dynamic column mapping to handle different
|
|
31
|
+
* column layouts across cities.
|
|
32
|
+
*
|
|
33
|
+
* @param text - Raw text content from gps_full.txt
|
|
34
|
+
* @param city - City identifier for context
|
|
35
|
+
* @param options - Parse options
|
|
36
|
+
* @returns Array of normalized Vehicle objects
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseGpsFullStream(text: string, city: CityId, options?: GpsFullParseOptions): Vehicle[];
|
|
39
|
+
//# sourceMappingURL=gps-full.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gps-full.d.ts","sourceRoot":"","sources":["../../src/parsers/gps-full.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAe,MAAM,aAAa,CAAC;AAsGhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,6EAA6E;IAC7E,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,OAAO,EAAE,CAyEX"}
|