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,212 @@
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 { LT_TRANSPORT_TYPE_MAP } from '../types.js';
16
+ import { normalizeCoordinate, isValidLithuaniaCoord, normalizeBearing, normalizeSpeed, cleanTextField, secondsFromMidnightToDate, isDataStale, } from '../utils/index.js';
17
+ import { gpsFullRowSchema } from '../schemas.js';
18
+ /**
19
+ * Build a column map from header row.
20
+ */
21
+ function buildColumnMap(headers) {
22
+ const indexMap = new Map();
23
+ headers.forEach((header, index) => {
24
+ const trimmed = header.trim();
25
+ if (trimmed) {
26
+ indexMap.set(trimmed, index);
27
+ }
28
+ });
29
+ return {
30
+ get(column) {
31
+ return indexMap.get(column);
32
+ },
33
+ getRequired(column) {
34
+ const index = indexMap.get(column);
35
+ if (index === undefined) {
36
+ throw new Error(`Required column '${column}' not found in headers`);
37
+ }
38
+ return index;
39
+ },
40
+ has(column) {
41
+ return indexMap.has(column);
42
+ },
43
+ columns: headers.map(h => h.trim()),
44
+ };
45
+ }
46
+ /**
47
+ * Parse vehicle type from Lithuanian transport name.
48
+ */
49
+ function parseVehicleType(transportName) {
50
+ const type = LT_TRANSPORT_TYPE_MAP[transportName];
51
+ return type ?? 'unknown';
52
+ }
53
+ /**
54
+ * Parse GPS full format stream from a gold-tier city.
55
+ *
56
+ * Uses header-based dynamic column mapping to handle different
57
+ * column layouts across cities.
58
+ *
59
+ * @param text - Raw text content from gps_full.txt
60
+ * @param city - City identifier for context
61
+ * @param options - Parse options
62
+ * @returns Array of normalized Vehicle objects
63
+ */
64
+ export function parseGpsFullStream(text, city, options = {}) {
65
+ const { staleThresholdMs = 5 * 60 * 1000, filterStale = false, filterInvalidCoords = true, } = options;
66
+ const lines = text.split('\n').filter(line => line.trim());
67
+ if (lines.length < 2) {
68
+ // No data (only header or empty)
69
+ return [];
70
+ }
71
+ // Parse header row
72
+ const firstLine = lines[0];
73
+ if (firstLine === undefined) {
74
+ return [];
75
+ }
76
+ // Strip UTF-8 BOM if present (stops.lt sometimes includes BOM)
77
+ const cleanHeader = firstLine.charCodeAt(0) === 0xFEFF
78
+ ? firstLine.slice(1)
79
+ : firstLine;
80
+ const headers = cleanHeader.split(',');
81
+ const columnMap = buildColumnMap(headers);
82
+ // Validate required columns
83
+ const requiredColumns = [
84
+ 'Transportas',
85
+ 'Marsrutas',
86
+ 'MasinosNumeris',
87
+ 'Ilguma',
88
+ 'Platuma',
89
+ ];
90
+ for (const col of requiredColumns) {
91
+ if (!columnMap.has(col)) {
92
+ throw new Error(`Required column '${col}' not found in ${city} GPS data`);
93
+ }
94
+ }
95
+ // Parse data rows
96
+ const vehicles = [];
97
+ for (let i = 1; i < lines.length; i++) {
98
+ const line = lines[i];
99
+ if (line === undefined || line.trim() === '')
100
+ continue;
101
+ const cols = line.split(',');
102
+ try {
103
+ const vehicle = parseVehicleLine(cols, columnMap, city, staleThresholdMs);
104
+ if (vehicle) {
105
+ // Apply filters
106
+ if (filterInvalidCoords && !isValidLithuaniaCoord(vehicle.latitude, vehicle.longitude)) {
107
+ continue;
108
+ }
109
+ if (filterStale && vehicle.isStale) {
110
+ continue;
111
+ }
112
+ vehicles.push(vehicle);
113
+ }
114
+ }
115
+ catch {
116
+ // Skip malformed lines
117
+ continue;
118
+ }
119
+ }
120
+ return vehicles;
121
+ }
122
+ /**
123
+ * Build a row object from CSV columns using the column map.
124
+ */
125
+ function buildRowObject(cols, columnMap) {
126
+ const obj = {};
127
+ for (const colName of columnMap.columns) {
128
+ const idx = columnMap.get(colName);
129
+ if (idx !== undefined) {
130
+ obj[colName] = cols[idx]?.trim() ?? '';
131
+ }
132
+ }
133
+ return obj;
134
+ }
135
+ /**
136
+ * Parse a single vehicle line from GPS full format.
137
+ */
138
+ function parseVehicleLine(cols, columnMap, city, staleThresholdMs) {
139
+ // Build row object from columns for Zod validation
140
+ const rowObject = buildRowObject(cols, columnMap);
141
+ // Validate with Zod schema - this catches format changes early
142
+ const parseResult = gpsFullRowSchema.safeParse(rowObject);
143
+ if (!parseResult.success) {
144
+ // Row doesn't match expected schema - skip it
145
+ return null;
146
+ }
147
+ const row = parseResult.data;
148
+ // Skip if missing essential data
149
+ if (row.MasinosNumeris === '') {
150
+ return null;
151
+ }
152
+ // Normalize coordinates
153
+ const longitude = normalizeCoordinate(row.Ilguma);
154
+ const latitude = normalizeCoordinate(row.Platuma);
155
+ // Extract optional fields
156
+ const speed = normalizeSpeed(row.Greitis);
157
+ const bearing = normalizeBearing(row.Azimutas);
158
+ const delaySeconds = row.NuokrypisSekundemis ?? null;
159
+ // Trip ID - different column name for Kaunas
160
+ const tripId = row.ReisoID ?? row.Grafikas ?? null;
161
+ // Destination name
162
+ const destination = row.KryptiesPavadinimas !== undefined && row.KryptiesPavadinimas !== ''
163
+ ? cleanTextField(row.KryptiesPavadinimas)
164
+ : null;
165
+ // GTFS trip reference (Vilnius only)
166
+ const gtfsTripId = row.ReisoIdGTFS ?? null;
167
+ // Next stop ID (Kaunas only)
168
+ const nextStopId = row.SekanciosStotelesNum !== undefined
169
+ ? String(row.SekanciosStotelesNum)
170
+ : null;
171
+ // Arrival time (Kaunas only) - this is FUTURE prediction, not measurement time
172
+ const arrivalTimeSeconds = row.AtvykimoLaikasSekundemis ?? null;
173
+ // Calculate measurement time
174
+ const measuredAt = calculateMeasuredAtFromRow(row);
175
+ const isStale = isDataStale(measuredAt, staleThresholdMs);
176
+ // Generate unique ID
177
+ const vehicleNumber = row.MasinosNumeris;
178
+ const route = row.Marsrutas;
179
+ const id = `${city}-${vehicleNumber}-${route}`;
180
+ return {
181
+ id,
182
+ vehicleNumber,
183
+ route,
184
+ type: parseVehicleType(row.Transportas),
185
+ latitude,
186
+ longitude,
187
+ bearing,
188
+ speed,
189
+ destination,
190
+ delaySeconds,
191
+ tripId,
192
+ gtfsTripId,
193
+ nextStopId,
194
+ arrivalTimeSeconds,
195
+ isStale,
196
+ measuredAt,
197
+ };
198
+ }
199
+ /**
200
+ * Calculate measurement time from validated row data.
201
+ */
202
+ function calculateMeasuredAtFromRow(row) {
203
+ // Try MatavimoLaikas first (Vilnius, Alytus, Druskininkai)
204
+ if (row.MatavimoLaikas !== undefined && row.MatavimoLaikas > 0) {
205
+ return secondsFromMidnightToDate(row.MatavimoLaikas);
206
+ }
207
+ // Kaunas: AtvykimoLaikasSekundemis is FUTURE arrival, not measurement time.
208
+ // Klaipėda: No time field available.
209
+ // Fallback to server receive time (now) for both cases.
210
+ return new Date();
211
+ }
212
+ //# sourceMappingURL=gps-full.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gps-full.js","sourceRoot":"","sources":["../../src/parsers/gps-full.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * GPS Lite Format Parser for silver-tier cities
3
+ * @module parsers/gps-lite
4
+ *
5
+ * Handles the "lite" GPS format used by silver-tier cities (Panevėžys, Tauragė).
6
+ * These streams have no header row and fewer columns.
7
+ *
8
+ * Column counts by city (empirically verified):
9
+ * - Panevėžys: 9 columns (no header, route often empty)
10
+ * - Tauragė: 8 columns (no header, alphanumeric routes like S11, S19)
11
+ */
12
+ import type { CityId, Vehicle } from '../types.js';
13
+ /**
14
+ * Panevėžys format (9 columns, no header):
15
+ * [0] type - Always "2" (bus?)
16
+ * [1] route - Route name (often empty)
17
+ * [2] longitude - Integer format (÷1,000,000)
18
+ * [3] latitude - Integer format (÷1,000,000)
19
+ * [4] speed - Speed or delay?
20
+ * [5] azimuth - Bearing in degrees
21
+ * [6] (empty) - Unknown
22
+ * [7] vehicleId - Vehicle identifier
23
+ * [8] (empty) - Unknown
24
+ */
25
+ /**
26
+ * Tauragė format (8 columns, no header):
27
+ * [0] type - Always "2" (bus?)
28
+ * [1] route - Route name (S11, S19) - ALPHANUMERIC!
29
+ * [2] longitude - Integer format (÷1,000,000)
30
+ * [3] latitude - Integer format (÷1,000,000)
31
+ * [4] speed - Speed in km/h
32
+ * [5] azimuth - Bearing in degrees
33
+ * [6] vehicleId - Vehicle identifier
34
+ * [7] (empty) - Unknown
35
+ */
36
+ /**
37
+ * Options for GPS lite format parsing.
38
+ */
39
+ export interface GpsLiteParseOptions {
40
+ /** Whether to filter out records with invalid coordinates (default: true) */
41
+ filterInvalidCoords?: boolean;
42
+ }
43
+ /**
44
+ * Cities that use lite GPS format.
45
+ */
46
+ export type LiteCityId = 'panevezys' | 'taurage';
47
+ /**
48
+ * Check if a city uses lite GPS format.
49
+ */
50
+ export declare function isLiteCity(city: CityId): city is LiteCityId;
51
+ /**
52
+ * Parse GPS lite format stream from a silver-tier city.
53
+ *
54
+ * @param text - Raw text content from gps.txt
55
+ * @param city - City identifier (must be 'panevezys' or 'taurage')
56
+ * @param options - Parse options
57
+ * @returns Array of normalized Vehicle objects
58
+ */
59
+ export declare function parseGpsLiteStream(text: string, city: LiteCityId, options?: GpsLiteParseOptions): Vehicle[];
60
+ //# sourceMappingURL=gps-lite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gps-lite.d.ts","sourceRoot":"","sources":["../../src/parsers/gps-lite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAe,MAAM,aAAa,CAAC;AAahE;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;GAUG;AAMH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAMD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;AAEjD;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,UAAU,CAE3D;AAMD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,mBAAwB,GAChC,OAAO,EAAE,CAgCX"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * GPS Lite Format Parser for silver-tier cities
3
+ * @module parsers/gps-lite
4
+ *
5
+ * Handles the "lite" GPS format used by silver-tier cities (Panevėžys, Tauragė).
6
+ * These streams have no header row and fewer columns.
7
+ *
8
+ * Column counts by city (empirically verified):
9
+ * - Panevėžys: 9 columns (no header, route often empty)
10
+ * - Tauragė: 8 columns (no header, alphanumeric routes like S11, S19)
11
+ */
12
+ import { normalizeCoordinate, isValidLithuaniaCoord, normalizeBearing, normalizeSpeed, } from '../utils/index.js';
13
+ import { gpsLitePanevezysSchema, gpsLiteTaurageSchema } from '../schemas.js';
14
+ /**
15
+ * Check if a city uses lite GPS format.
16
+ */
17
+ export function isLiteCity(city) {
18
+ return city === 'panevezys' || city === 'taurage';
19
+ }
20
+ // =============================================================================
21
+ // Main Parser
22
+ // =============================================================================
23
+ /**
24
+ * Parse GPS lite format stream from a silver-tier city.
25
+ *
26
+ * @param text - Raw text content from gps.txt
27
+ * @param city - City identifier (must be 'panevezys' or 'taurage')
28
+ * @param options - Parse options
29
+ * @returns Array of normalized Vehicle objects
30
+ */
31
+ export function parseGpsLiteStream(text, city, options = {}) {
32
+ const { filterInvalidCoords = true } = options;
33
+ const lines = text.split('\n').filter(line => line.trim());
34
+ if (lines.length === 0) {
35
+ return [];
36
+ }
37
+ const vehicles = [];
38
+ for (const line of lines) {
39
+ const cols = line.split(',');
40
+ try {
41
+ const vehicle = city === 'panevezys'
42
+ ? parsePanevezysLine(cols, city)
43
+ : parseTaurageLine(cols, city);
44
+ if (vehicle) {
45
+ if (filterInvalidCoords && !isValidLithuaniaCoord(vehicle.latitude, vehicle.longitude)) {
46
+ continue;
47
+ }
48
+ vehicles.push(vehicle);
49
+ }
50
+ }
51
+ catch {
52
+ // Skip malformed lines
53
+ continue;
54
+ }
55
+ }
56
+ return vehicles;
57
+ }
58
+ // =============================================================================
59
+ // City-Specific Parsers
60
+ // =============================================================================
61
+ /**
62
+ * Parse a line from Panevėžys GPS lite format (9 columns).
63
+ */
64
+ function parsePanevezysLine(cols, city) {
65
+ // Validate with Zod schema
66
+ const parseResult = gpsLitePanevezysSchema.safeParse(cols);
67
+ if (!parseResult.success) {
68
+ return null;
69
+ }
70
+ const row = parseResult.data;
71
+ const vehicleNumber = row[7];
72
+ // Validate essential fields
73
+ if (vehicleNumber === '' || !Number.isFinite(row[2]) || !Number.isFinite(row[3])) {
74
+ return null;
75
+ }
76
+ const longitude = normalizeCoordinate(row[2]);
77
+ const latitude = normalizeCoordinate(row[3]);
78
+ const speed = normalizeSpeed(row[4]);
79
+ const bearing = normalizeBearing(row[5]);
80
+ const route = row[1];
81
+ const id = `${city}-${vehicleNumber}`;
82
+ return {
83
+ id,
84
+ vehicleNumber,
85
+ route,
86
+ type: 'bus', // Lite format doesn't specify type
87
+ latitude,
88
+ longitude,
89
+ bearing,
90
+ speed,
91
+ destination: null, // Needs GTFS enrichment
92
+ delaySeconds: null,
93
+ tripId: null,
94
+ gtfsTripId: null,
95
+ nextStopId: null,
96
+ arrivalTimeSeconds: null,
97
+ isStale: false, // No timestamp in lite format
98
+ measuredAt: new Date(), // Use server receive time
99
+ };
100
+ }
101
+ /**
102
+ * Parse a line from Tauragė GPS lite format (8 columns).
103
+ */
104
+ function parseTaurageLine(cols, city) {
105
+ // Validate with Zod schema
106
+ const parseResult = gpsLiteTaurageSchema.safeParse(cols);
107
+ if (!parseResult.success) {
108
+ return null;
109
+ }
110
+ const row = parseResult.data;
111
+ const vehicleNumber = row[6];
112
+ // Validate essential fields
113
+ if (vehicleNumber === '' || !Number.isFinite(row[2]) || !Number.isFinite(row[3])) {
114
+ return null;
115
+ }
116
+ const longitude = normalizeCoordinate(row[2]);
117
+ const latitude = normalizeCoordinate(row[3]);
118
+ const speed = normalizeSpeed(row[4]);
119
+ const bearing = normalizeBearing(row[5]);
120
+ const route = row[1];
121
+ const id = `${city}-${vehicleNumber}`;
122
+ return {
123
+ id,
124
+ vehicleNumber,
125
+ route,
126
+ type: 'bus', // Lite format doesn't specify type
127
+ latitude,
128
+ longitude,
129
+ bearing,
130
+ speed,
131
+ destination: null, // Needs GTFS enrichment
132
+ delaySeconds: null,
133
+ tripId: null,
134
+ gtfsTripId: null,
135
+ nextStopId: null,
136
+ arrivalTimeSeconds: null,
137
+ isStale: false, // No timestamp in lite format
138
+ measuredAt: new Date(), // Use server receive time
139
+ };
140
+ }
141
+ //# sourceMappingURL=gps-lite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gps-lite.js","sourceRoot":"","sources":["../../src/parsers/gps-lite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Parser module exports
3
+ * @module parsers
4
+ */
5
+ export { parseGpsFullStream, type GpsFullParseOptions, } from './gps-full.js';
6
+ export { parseGpsLiteStream, isLiteCity, type GpsLiteParseOptions, type LiteCityId, } from './gps-lite.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,kBAAkB,EAClB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,KAAK,mBAAmB,EACxB,KAAK,UAAU,GAChB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Parser module exports
3
+ * @module parsers
4
+ */
5
+ export { parseGpsFullStream, } from './gps-full.js';
6
+ export { parseGpsLiteStream, isLiteCity, } from './gps-lite.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,kBAAkB,GAEnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,kBAAkB,EAClB,UAAU,GAGX,MAAM,eAAe,CAAC"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Zod schemas for runtime validation of external data
3
+ * @module schemas
4
+ *
5
+ * These schemas validate data from stops.lt GPS streams and GTFS files.
6
+ * They provide:
7
+ * - Type coercion (string → number)
8
+ * - Clear error messages when format changes
9
+ * - Documentation of expected data structure
10
+ */
11
+ import { z } from 'zod';
12
+ /**
13
+ * Schema for a GPS full format row.
14
+ * Columns vary by city but these are the core fields present in all cities.
15
+ */
16
+ export declare const gpsFullRowSchema: z.ZodObject<{
17
+ Transportas: z.ZodString;
18
+ Marsrutas: z.ZodString;
19
+ MasinosNumeris: z.ZodString;
20
+ Ilguma: z.ZodCoercedNumber<unknown>;
21
+ Platuma: z.ZodCoercedNumber<unknown>;
22
+ Greitis: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
23
+ Azimutas: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
24
+ ReisoID: z.ZodOptional<z.ZodString>;
25
+ Grafikas: z.ZodOptional<z.ZodString>;
26
+ ReisoPradziaMinutemis: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
27
+ NuokrypisSekundemis: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
28
+ MatavimoLaikas: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
29
+ SekanciosStotelesNum: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
30
+ AtvykimoLaikasSekundemis: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
31
+ MasinosTipas: z.ZodOptional<z.ZodString>;
32
+ KryptiesTipas: z.ZodOptional<z.ZodString>;
33
+ KryptiesPavadinimas: z.ZodOptional<z.ZodString>;
34
+ ReisoIdGTFS: z.ZodOptional<z.ZodString>;
35
+ IntervalasPries: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
36
+ IntervalasPaskui: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
37
+ }, z.core.$loose>;
38
+ export type GpsFullRow = z.infer<typeof gpsFullRowSchema>;
39
+ /**
40
+ * Schema for Panevėžys GPS lite format (9 columns, no header).
41
+ * Columns: type, route, lon, lat, speed, azimuth, ?, vehicleId, ?
42
+ */
43
+ export declare const gpsLitePanevezysSchema: z.ZodTuple<[z.ZodString, z.ZodString, z.ZodCoercedNumber<unknown>, z.ZodCoercedNumber<unknown>, z.ZodCoercedNumber<unknown>, z.ZodCoercedNumber<unknown>, z.ZodString, z.ZodString, z.ZodString], null>;
44
+ /**
45
+ * Schema for Tauragė GPS lite format (8 columns, no header).
46
+ * Columns: type, route, lon, lat, speed, azimuth, vehicleId, ?
47
+ */
48
+ export declare const gpsLiteTaurageSchema: z.ZodTuple<[z.ZodString, z.ZodString, z.ZodCoercedNumber<unknown>, z.ZodCoercedNumber<unknown>, z.ZodCoercedNumber<unknown>, z.ZodCoercedNumber<unknown>, z.ZodString, z.ZodString], null>;
49
+ export type GpsLitePanevezysRow = z.infer<typeof gpsLitePanevezysSchema>;
50
+ export type GpsLiteTaurageRow = z.infer<typeof gpsLiteTaurageSchema>;
51
+ /**
52
+ * Schema for a GTFS routes.txt row.
53
+ */
54
+ export declare const gtfsRouteSchema: z.ZodObject<{
55
+ route_id: z.ZodString;
56
+ route_short_name: z.ZodString;
57
+ route_long_name: z.ZodDefault<z.ZodString>;
58
+ route_type: z.ZodCoercedNumber<unknown>;
59
+ route_color: z.ZodDefault<z.ZodString>;
60
+ route_text_color: z.ZodDefault<z.ZodString>;
61
+ agency_id: z.ZodOptional<z.ZodString>;
62
+ route_desc: z.ZodOptional<z.ZodString>;
63
+ route_url: z.ZodOptional<z.ZodString>;
64
+ }, z.core.$loose>;
65
+ export type GtfsRoute = z.infer<typeof gtfsRouteSchema>;
66
+ /**
67
+ * Schema for a GTFS stops.txt row.
68
+ */
69
+ export declare const gtfsStopSchema: z.ZodObject<{
70
+ stop_id: z.ZodString;
71
+ stop_name: z.ZodString;
72
+ stop_lat: z.ZodCoercedNumber<unknown>;
73
+ stop_lon: z.ZodCoercedNumber<unknown>;
74
+ stop_code: z.ZodOptional<z.ZodString>;
75
+ stop_desc: z.ZodOptional<z.ZodString>;
76
+ location_type: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
77
+ parent_station: z.ZodOptional<z.ZodString>;
78
+ }, z.core.$loose>;
79
+ export type GtfsStop = z.infer<typeof gtfsStopSchema>;
80
+ /**
81
+ * Schema for LtTransport client configuration.
82
+ */
83
+ export declare const clientConfigSchema: z.ZodObject<{
84
+ cacheDir: z.ZodOptional<z.ZodString>;
85
+ requestTimeout: z.ZodDefault<z.ZodNumber>;
86
+ userAgent: z.ZodDefault<z.ZodString>;
87
+ staleThresholdMs: z.ZodDefault<z.ZodNumber>;
88
+ autoEnrich: z.ZodDefault<z.ZodBoolean>;
89
+ filterInvalidCoords: z.ZodDefault<z.ZodBoolean>;
90
+ filterStale: z.ZodDefault<z.ZodBoolean>;
91
+ }, z.core.$strict>;
92
+ export type ValidatedClientConfig = z.infer<typeof clientConfigSchema>;
93
+ /**
94
+ * Schema for a fully parsed and normalized Vehicle object.
95
+ * Used to validate output before returning to user.
96
+ */
97
+ export declare const vehicleSchema: z.ZodObject<{
98
+ id: z.ZodString;
99
+ vehicleNumber: z.ZodString;
100
+ route: z.ZodString;
101
+ type: z.ZodEnum<{
102
+ bus: "bus";
103
+ trolleybus: "trolleybus";
104
+ ferry: "ferry";
105
+ unknown: "unknown";
106
+ }>;
107
+ latitude: z.ZodCoercedNumber<unknown>;
108
+ longitude: z.ZodCoercedNumber<unknown>;
109
+ bearing: z.ZodNumber;
110
+ speed: z.ZodNumber;
111
+ destination: z.ZodNullable<z.ZodString>;
112
+ delaySeconds: z.ZodNullable<z.ZodNumber>;
113
+ tripId: z.ZodNullable<z.ZodString>;
114
+ gtfsTripId: z.ZodNullable<z.ZodString>;
115
+ nextStopId: z.ZodNullable<z.ZodString>;
116
+ arrivalTimeSeconds: z.ZodNullable<z.ZodNumber>;
117
+ isStale: z.ZodBoolean;
118
+ measuredAt: z.ZodDate;
119
+ }, z.core.$strip>;
120
+ export type ValidatedVehicle = z.infer<typeof vehicleSchema>;
121
+ /**
122
+ * Safely parse a value with a Zod schema, returning null on failure.
123
+ */
124
+ export declare function safeParse<T>(schema: z.ZodType<T>, data: unknown): T | null;
125
+ /**
126
+ * Parse a value with a Zod schema, throwing a detailed error on failure.
127
+ */
128
+ export declare function parseOrThrow<T>(schema: z.ZodType<T>, data: unknown, context?: string): T;
129
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuCxB;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;iBAwBnB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAM1D;;;GAGG;AACH,eAAO,MAAM,sBAAsB,yMAUjC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,4LAS/B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACzE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAMrE;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;iBAWlB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAMxD;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;iBAUjB,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAMtD;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;kBAqBpB,CAAC;AAEZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAMvE;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;iBAiBxB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAM7D;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAG1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAOxF"}