bengaluru-transit 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.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +507 -0
  3. package/dist/api/info.d.ts +77 -0
  4. package/dist/api/info.d.ts.map +1 -0
  5. package/dist/api/info.js +197 -0
  6. package/dist/api/info.js.map +1 -0
  7. package/dist/api/locations.d.ts +26 -0
  8. package/dist/api/locations.d.ts.map +1 -0
  9. package/dist/api/locations.js +57 -0
  10. package/dist/api/locations.js.map +1 -0
  11. package/dist/api/routes.d.ts +341 -0
  12. package/dist/api/routes.d.ts.map +1 -0
  13. package/dist/api/routes.js +1133 -0
  14. package/dist/api/routes.js.map +1 -0
  15. package/dist/api/stops.d.ts +92 -0
  16. package/dist/api/stops.d.ts.map +1 -0
  17. package/dist/api/stops.js +237 -0
  18. package/dist/api/stops.js.map +1 -0
  19. package/dist/api/vehicles.d.ts +49 -0
  20. package/dist/api/vehicles.d.ts.map +1 -0
  21. package/dist/api/vehicles.js +154 -0
  22. package/dist/api/vehicles.js.map +1 -0
  23. package/dist/client/base-client.d.ts +52 -0
  24. package/dist/client/base-client.d.ts.map +1 -0
  25. package/dist/client/base-client.js +76 -0
  26. package/dist/client/base-client.js.map +1 -0
  27. package/dist/client/transit-client.d.ts +91 -0
  28. package/dist/client/transit-client.d.ts.map +1 -0
  29. package/dist/client/transit-client.js +98 -0
  30. package/dist/client/transit-client.js.map +1 -0
  31. package/dist/constants/api.d.ts +16 -0
  32. package/dist/constants/api.d.ts.map +1 -0
  33. package/dist/constants/api.js +16 -0
  34. package/dist/constants/api.js.map +1 -0
  35. package/dist/constants/routes.d.ts +16 -0
  36. package/dist/constants/routes.d.ts.map +1 -0
  37. package/dist/constants/routes.js +16 -0
  38. package/dist/constants/routes.js.map +1 -0
  39. package/dist/index.d.ts +11 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +10 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/schemas/common.d.ts +34 -0
  44. package/dist/schemas/common.d.ts.map +1 -0
  45. package/dist/schemas/common.js +20 -0
  46. package/dist/schemas/common.js.map +1 -0
  47. package/dist/schemas/index.d.ts +7 -0
  48. package/dist/schemas/index.d.ts.map +1 -0
  49. package/dist/schemas/index.js +7 -0
  50. package/dist/schemas/index.js.map +1 -0
  51. package/dist/schemas/info.d.ts +390 -0
  52. package/dist/schemas/info.d.ts.map +1 -0
  53. package/dist/schemas/info.js +110 -0
  54. package/dist/schemas/info.js.map +1 -0
  55. package/dist/schemas/locations.d.ts +84 -0
  56. package/dist/schemas/locations.d.ts.map +1 -0
  57. package/dist/schemas/locations.js +31 -0
  58. package/dist/schemas/locations.js.map +1 -0
  59. package/dist/schemas/routes.d.ts +3967 -0
  60. package/dist/schemas/routes.d.ts.map +1 -0
  61. package/dist/schemas/routes.js +532 -0
  62. package/dist/schemas/routes.js.map +1 -0
  63. package/dist/schemas/stops.d.ts +543 -0
  64. package/dist/schemas/stops.d.ts.map +1 -0
  65. package/dist/schemas/stops.js +129 -0
  66. package/dist/schemas/stops.js.map +1 -0
  67. package/dist/schemas/vehicles.d.ts +602 -0
  68. package/dist/schemas/vehicles.d.ts.map +1 -0
  69. package/dist/schemas/vehicles.js +116 -0
  70. package/dist/schemas/vehicles.js.map +1 -0
  71. package/dist/types/api.d.ts +9 -0
  72. package/dist/types/api.d.ts.map +1 -0
  73. package/dist/types/api.js +5 -0
  74. package/dist/types/api.js.map +1 -0
  75. package/dist/types/coordinates.d.ts +7 -0
  76. package/dist/types/coordinates.d.ts.map +1 -0
  77. package/dist/types/coordinates.js +2 -0
  78. package/dist/types/coordinates.js.map +1 -0
  79. package/dist/types/geojson.d.ts +84 -0
  80. package/dist/types/geojson.d.ts.map +1 -0
  81. package/dist/types/geojson.js +2 -0
  82. package/dist/types/geojson.js.map +1 -0
  83. package/dist/types/index.d.ts +16 -0
  84. package/dist/types/index.d.ts.map +1 -0
  85. package/dist/types/index.js +12 -0
  86. package/dist/types/index.js.map +1 -0
  87. package/dist/types/info.d.ts +133 -0
  88. package/dist/types/info.d.ts.map +1 -0
  89. package/dist/types/info.js +5 -0
  90. package/dist/types/info.js.map +1 -0
  91. package/dist/types/locations.d.ts +59 -0
  92. package/dist/types/locations.d.ts.map +1 -0
  93. package/dist/types/locations.js +5 -0
  94. package/dist/types/locations.js.map +1 -0
  95. package/dist/types/routes.d.ts +1137 -0
  96. package/dist/types/routes.d.ts.map +1 -0
  97. package/dist/types/routes.js +14 -0
  98. package/dist/types/routes.js.map +1 -0
  99. package/dist/types/stops.d.ts +286 -0
  100. package/dist/types/stops.d.ts.map +1 -0
  101. package/dist/types/stops.js +26 -0
  102. package/dist/types/stops.js.map +1 -0
  103. package/dist/types/vehicles.d.ts +138 -0
  104. package/dist/types/vehicles.d.ts.map +1 -0
  105. package/dist/types/vehicles.js +5 -0
  106. package/dist/types/vehicles.js.map +1 -0
  107. package/dist/utils/date.d.ts +35 -0
  108. package/dist/utils/date.d.ts.map +1 -0
  109. package/dist/utils/date.js +49 -0
  110. package/dist/utils/date.js.map +1 -0
  111. package/dist/utils/errors.d.ts +34 -0
  112. package/dist/utils/errors.d.ts.map +1 -0
  113. package/dist/utils/errors.js +41 -0
  114. package/dist/utils/errors.js.map +1 -0
  115. package/dist/utils/geojson.d.ts +36 -0
  116. package/dist/utils/geojson.d.ts.map +1 -0
  117. package/dist/utils/geojson.js +115 -0
  118. package/dist/utils/geojson.js.map +1 -0
  119. package/dist/utils/validation.d.ts +40 -0
  120. package/dist/utils/validation.d.ts.map +1 -0
  121. package/dist/utils/validation.js +62 -0
  122. package/dist/utils/validation.js.map +1 -0
  123. package/package.json +77 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,507 @@
1
+ # Bengaluru Transit SDK
2
+
3
+ A type-safe TypeScript SDK for Bengaluru public transit APIs with Zod validation and GeoJSON support.
4
+
5
+ > **⚠️ Disclaimer**: This is an **unofficial** SDK. It is not affiliated with, endorsed by, or connected to any official transit authority. This project is developed independently to provide better API design and consumption patterns for transit data that deserves better tooling.
6
+
7
+ ## Intent
8
+
9
+ The underlying transit API contains valuable real-time and schedule data, but the API design and consumption patterns could be significantly improved. This SDK aims to:
10
+
11
+ - **Improve API Design**: Provide a clean, type-safe interface that makes the data more accessible
12
+ - **Better Consumption**: Normalize responses, validate inputs, and provide consistent data structures
13
+ - **Reduce Waste**: Make valuable transit data easier to use in applications, reducing the barrier to building transit-focused tools
14
+
15
+ This project is built with the intent of making public transit data more accessible to developers and ultimately improving the transit experience for commuters.
16
+
17
+ ## Features
18
+
19
+ - 🎯 **Type Safety**: Full TypeScript support with comprehensive type definitions
20
+ - ✅ **Validation**: Runtime validation using Zod schemas
21
+ - 🗺️ **GeoJSON**: Standard GeoJSON format for all spatial data (routes, stops, locations)
22
+ - 🚀 **Modern**: Built with modern TypeScript and ES modules
23
+ - 📦 **Lightweight**: Minimal dependencies
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install bengaluru-transit
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```typescript
34
+ import { BengaluruTransitClient } from "bengaluru-transit";
35
+
36
+ const client = new BengaluruTransitClient({ language: "en" });
37
+
38
+ // Example: Search for nearby bus stops
39
+ const stops = await client.stops.findNearbyStops({
40
+ coordinates: [13.09784, 77.59167],
41
+ radius: 1
42
+ });
43
+ console.log(stops.items.length, "stops found");
44
+ ```
45
+
46
+ ## Common Flows
47
+
48
+ ### 1. Plan a Trip
49
+
50
+ Plan a trip from your location to a destination:
51
+
52
+ ```typescript
53
+ // Plan trip from coordinates to a station
54
+ const trip = await client.routes.planTrip({
55
+ fromCoordinates: [13.09784, 77.59167],
56
+ toStopId: "20922", // Kempegowda Bus Station
57
+ });
58
+
59
+ // Find the fastest route with no transfers
60
+ const directRoutes = trip.routes.filter(r => r.transferCount === 0);
61
+ const fastest = directRoutes.sort((a, b) => a.totalDurationSeconds - b.totalDurationSeconds)[0];
62
+
63
+ console.log(`Fastest route: ${fastest.totalDuration} (${fastest.totalDurationSeconds}s)`);
64
+ console.log(`Fare: ₹${fastest.totalFare}`);
65
+ console.log(`Distance: ${fastest.totalDistance} km`);
66
+
67
+ // Show route details
68
+ fastest.legs.forEach(leg => {
69
+ if (leg.routeNo.startsWith('walk')) {
70
+ console.log(`Walk: ${leg.fromStationName} → ${leg.toStationName}`);
71
+ } else {
72
+ console.log(`Bus ${leg.routeNo}: ${leg.fromStationName} → ${leg.toStationName}`);
73
+ }
74
+ });
75
+ ```
76
+
77
+ ### 2. Find Nearby Bus Stops
78
+
79
+ Find bus stops near your location:
80
+
81
+ ```typescript
82
+ // Find stops within 1km
83
+ const nearby = await client.stops.findNearbyStops({
84
+ coordinates: [13.09784, 77.59167], // [latitude, longitude]
85
+ radius: 1 // radius in km
86
+ });
87
+
88
+ console.log(`Found ${nearby.items.length} stops nearby`);
89
+
90
+ // Each stop has location and distance information
91
+ nearby.items.forEach(stop => {
92
+ console.log(`${stop.stationName} - Distance: ${stop.distance} km`);
93
+ console.log(`Location: [${stop.latitude}, ${stop.longitude}]`);
94
+ });
95
+ ```
96
+
97
+ ### 3. Search for Places
98
+
99
+ Search for locations by name:
100
+
101
+ ```typescript
102
+ const places = await client.locations.searchPlaces({ query: "Kempegowda Bus Station" });
103
+
104
+ places.items.forEach(place => {
105
+ console.log(`${place.title} - [${place.latitude}, ${place.longitude}]`);
106
+ });
107
+ ```
108
+
109
+ ### 4. Track a Vehicle
110
+
111
+ Find and track a bus by registration number:
112
+
113
+ ```typescript
114
+ // Search for vehicle
115
+ const vehicles = await client.vehicles.searchVehicles({ query: "KA57F2403" });
116
+
117
+ if (vehicles.items.length > 0) {
118
+ const vehicle = vehicles.items[0];
119
+
120
+ // Get live trip details
121
+ const trip = await client.vehicles.getVehicleTrip({ vehicleId: vehicle.vehicleId });
122
+
123
+ // Access route information from route stops
124
+ const firstStop = trip.routeStops.features[0];
125
+ console.log(`Route: ${firstStop.properties.routeNo}`);
126
+
127
+ // Access live vehicle location
128
+ const location = trip.vehicleLocation.features[0];
129
+ const [lng, lat] = location.geometry.coordinates;
130
+ console.log(`Current location: [${lat}, ${lng}]`);
131
+ console.log(`Next stop: ${firstStop.properties.nextStop}`);
132
+ console.log(`ETA: ${firstStop.properties.eta}`);
133
+ }
134
+ ```
135
+
136
+ ### 5. Visualize Trip Path on Map
137
+
138
+ Get trip stops and path as GeoJSON for map visualization:
139
+
140
+ ```typescript
141
+ // 1. Plan the trip
142
+ const tripPlan = await client.routes.planTrip({
143
+ fromStopId: "22357",
144
+ toStopId: "21447"
145
+ });
146
+
147
+ // 2. Get all stops along the trip (GeoJSON Points)
148
+ const tripLegs = tripPlan.routes[0].legs
149
+ .filter(leg => !leg.routeNo.startsWith('walk'))
150
+ .map(leg => ({
151
+ tripId: leg.tripId,
152
+ fromStopId: leg.fromStopId,
153
+ toStopId: leg.toStopId
154
+ }));
155
+
156
+ const stops = await client.routes.getTripStops({ trips: tripLegs });
157
+ // Returns: FeatureCollection with Point features
158
+ // Use stops.features in your map library (Leaflet, Mapbox, etc.)
159
+
160
+ // 3. Get route path segments (GeoJSON LineStrings)
161
+ const path = await client.routes.getTripPath({ viaPoints: stops });
162
+ // Returns: FeatureCollection with LineString features
163
+ // Use path.features to draw the route path on your map
164
+
165
+ // Example with Leaflet:
166
+ // stops.features.forEach(stop => {
167
+ // L.marker(stop.geometry.coordinates.reverse()).addTo(map);
168
+ // });
169
+ // path.features.forEach(segment => {
170
+ // L.polyline(segment.geometry.coordinates).addTo(map);
171
+ // });
172
+ ```
173
+
174
+ ### 6. Search Routes
175
+
176
+ Search for routes by name or number:
177
+
178
+ ```typescript
179
+ // Search routes
180
+ const routes = await client.routes.searchRoutes({ query: "285-M" });
181
+
182
+ routes.items.forEach(route => {
183
+ console.log(`${route.routeNo} - ${route.routeName}`);
184
+ console.log(`From: ${route.fromStop}`);
185
+ console.log(`To: ${route.toStop}`);
186
+ });
187
+ ```
188
+
189
+ ### 7. Get Route Details
190
+
191
+ Get live vehicles and stops for a specific route:
192
+
193
+ ```typescript
194
+ // Search for route
195
+ const routes = await client.routes.searchRoutes({ query: "500-CA" });
196
+ const routeId = routes.items[0].parentRouteId;
197
+
198
+ // Get route details (live vehicles + stops)
199
+ const details = await client.routes.searchByRouteDetails({ parentRouteId: routeId });
200
+
201
+ console.log(`Live vehicles (up): ${details.up.liveVehicles.features.length}`);
202
+ console.log(`Stops (up): ${details.up.stops.features.length}`);
203
+ console.log(`Live vehicles (down): ${details.down.liveVehicles.features.length}`);
204
+ console.log(`Stops (down): ${details.down.stops.features.length}`);
205
+
206
+ // Live vehicles are GeoJSON Points
207
+ details.up.liveVehicles.features.forEach(vehicle => {
208
+ const [lng, lat] = vehicle.geometry.coordinates;
209
+ console.log(`Vehicle ${vehicle.properties.vehicleNumber} at [${lat}, ${lng}]`);
210
+ });
211
+ ```
212
+
213
+ ## API Reference
214
+
215
+ ### Routes API
216
+
217
+ - `planTrip({ fromStopId|fromCoordinates, toStopId|toCoordinates, serviceTypeId?, fromDateTime?, filterBy? })` - Complete trip planning with transfers
218
+ - `getTripStops({ trips })` - Get all stops along trip legs (GeoJSON Points)
219
+ - `getTripPath({ viaPoints })` - Get route path segments (GeoJSON LineStrings)
220
+ - `searchRoutes({ query })` - Search routes by name/number
221
+ - `getAllRoutes()` - Get complete list of all routes
222
+ - `getRoutePoints({ routeId })` - Get route path as GeoJSON
223
+ - `getTimetableByRoute({ routeId, startTime?, endTime?, fromStopId?, toStopId? })` - Get timetable for a route
224
+ - `searchByRouteDetails({ parentRouteId, serviceTypeId? })` - Get live vehicles and stops for a route
225
+ - `getFares({ routeNo, subrouteId, routeDirection, sourceCode, destinationCode })` - Get fare information
226
+ - `getRoutesBetweenStops({ fromStopId, toStopId })` - Find routes between two stops
227
+ - `getRoutesThroughStations({ fromStopId, toStopId, routeId?, date? })` - Routes passing through both stops
228
+
229
+ ### Stops API
230
+
231
+ - `findNearbyStops({ coordinates, radius, stationType?, bmtcCategory? })` - Find stops within radius (GeoJSON)
232
+ - `findNearbyStations({ coordinates })` - Find nearby stations with facilities (GeoJSON)
233
+ - `searchBusStops({ stationName, stationType? })` - Search stops by name
234
+
235
+ ### Vehicles API
236
+
237
+ - `searchVehicles({ query })` - Search vehicles by registration number
238
+ - `getVehicleTrip({ vehicleId })` - Get live vehicle location and trip details
239
+
240
+ ### Locations API
241
+
242
+ - `searchPlaces({ query })` - Search locations/places by name (GeoJSON)
243
+
244
+ ### Info API
245
+
246
+ - `getHelpline()` - Get transit helpline contact information
247
+ - `getServiceTypes()` - Get available service types (AC, Non-AC, etc.)
248
+ - `getAbout()` - Get general transit information
249
+ - `getEmergencyMessages()` - Get emergency alerts and messages
250
+ - `getFareScrollMessages()` - Get fare-related announcements
251
+
252
+ ## More Examples
253
+
254
+ ### Find Routes Between Two Stops
255
+
256
+ ```typescript
257
+ // Find all routes connecting two stops
258
+ const routes = await client.routes.getRoutesBetweenStops({
259
+ fromStopId: "22357",
260
+ toStopId: "21447"
261
+ });
262
+
263
+ routes.items.forEach(route => {
264
+ console.log(`Route ${route.routeNo}: ${route.fromDisplayName} → ${route.toDisplayName}`);
265
+ });
266
+ ```
267
+
268
+ ### Get Routes Through Stops
269
+
270
+ ```typescript
271
+ // Find routes that pass through both stops (with schedule info)
272
+ const routes = await client.routes.getRoutesThroughStations({
273
+ fromStopId: "30475",
274
+ toStopId: "35376",
275
+ date: new Date() // Optional: defaults to current date
276
+ });
277
+
278
+ routes.items.forEach(route => {
279
+ console.log(`Route ${route.routeNo} starts at ${route.startTime}`);
280
+ console.log(`Travel time: ${route.travelTime}, Distance: ${route.distance} km`);
281
+ });
282
+ ```
283
+
284
+ ### Get Fare Information
285
+
286
+ ```typescript
287
+ // First, get routes between stops
288
+ const routes = await client.routes.getRoutesBetweenStops({
289
+ fromStopId: "22357",
290
+ toStopId: "21447"
291
+ });
292
+
293
+ // Then get fare for a specific route
294
+ const route = routes.items[0];
295
+ const fare = await client.routes.getFares({
296
+ routeNo: route.routeNo,
297
+ subrouteId: route.subrouteId,
298
+ routeDirection: route.routeDirection,
299
+ sourceCode: route.sourceCode,
300
+ destinationCode: route.destinationCode
301
+ });
302
+
303
+ fare.items.forEach(item => {
304
+ console.log(`Service: ${item.serviceType}, Fare: ₹${item.fare}`);
305
+ });
306
+ ```
307
+
308
+ ### Search and Track Vehicle
309
+
310
+ ```typescript
311
+ // Complete workflow: search → track
312
+ const vehicles = await client.vehicles.searchVehicles({ query: "KA57" });
313
+
314
+ if (vehicles.items.length > 0) {
315
+ const vehicle = vehicles.items[0];
316
+ const trip = await client.vehicles.getVehicleTrip({ vehicleId: vehicle.vehicleId });
317
+
318
+ console.log(`Vehicle ${vehicle.vehicleRegNo} is on route ${trip.routeStops.features[0].properties.routeNo}`);
319
+ console.log(`Current location:`, trip.vehicleLocation.features[0].geometry.coordinates);
320
+ }
321
+ ```
322
+
323
+ ### Get Service Types and Filter Trip
324
+
325
+ ```typescript
326
+ // Get service types and use to filter trip planning
327
+ const serviceTypes = await client.info.getServiceTypes();
328
+ const acService = serviceTypes.items.find(s => s.serviceTypeName.includes("AC"));
329
+
330
+ if (acService) {
331
+ const trip = await client.routes.planTrip({
332
+ fromCoordinates: [13.09784, 77.59167],
333
+ toStopId: "20922",
334
+ serviceTypeId: acService.serviceTypeId
335
+ });
336
+
337
+ console.log(`Found ${trip.routes.length} AC bus routes`);
338
+ }
339
+ ```
340
+
341
+ ### Check Emergency Messages
342
+
343
+ ```typescript
344
+ // Get current emergency messages and alerts
345
+ const messages = await client.info.getEmergencyMessages();
346
+ const activeMessages = messages.items.filter(m => m.isDisplay);
347
+
348
+ if (activeMessages.length > 0) {
349
+ console.log("Active alerts:");
350
+ activeMessages.forEach(msg => {
351
+ console.log(`${msg.displayKey}: ${msg.messageEn}`);
352
+ });
353
+ }
354
+ ```
355
+
356
+ For complete API documentation and agentic workflows, see [AGENTIC_CAPABILITIES.md](./AGENTIC_CAPABILITIES.md)
357
+
358
+ ## Agent Integration
359
+
360
+ This wrapper is designed to work seamlessly with AI agents and function calling frameworks. All methods are fully typed, validated, and include comprehensive JSDoc documentation.
361
+
362
+ ### Key Features for Agents
363
+
364
+ ✅ **Type-Safe Parameters** - All inputs are validated with Zod schemas
365
+ ✅ **Structured Responses** - Consistent, normalized data formats
366
+ ✅ **Proper Error Types** - `TransitValidationError` for validation errors, `HTTPError` (from ky) for network/API errors
367
+ ✅ **GeoJSON Support** - Standard format for spatial data (compatible with mapping libraries)
368
+ ✅ **String IDs** - All IDs are strings (agent-friendly, no type confusion)
369
+ ✅ **Date Objects** - Consistent Date object handling (no string parsing needed)
370
+ ✅ **JSDoc Documentation** - Complete `@param`, `@returns`, `@throws`, and `@example` tags
371
+
372
+ ### Error Handling
373
+
374
+ ```typescript
375
+ import { BengaluruTransitClient, TransitError, TransitValidationError } from "bengaluru-transit";
376
+ import type { HTTPError } from "ky";
377
+
378
+ const client = new BengaluruTransitClient({ language: "en" });
379
+
380
+ try {
381
+ const trip = await client.routes.planTrip({
382
+ fromStopId: "22357",
383
+ toStopId: "21447"
384
+ });
385
+ } catch (error) {
386
+ if (error instanceof TransitValidationError) {
387
+ // Validation error with detailed field information
388
+ console.error("Validation failed:", error.message);
389
+ console.error("Details:", error.details);
390
+ } else if (error instanceof TransitError) {
391
+ // Other transit errors
392
+ console.error("Transit error:", error.message);
393
+ console.error("Code:", error.code);
394
+ } else if ((error as HTTPError).response) {
395
+ // HTTP error from network/API
396
+ const httpError = error as HTTPError;
397
+ console.error("HTTP error:", httpError.message);
398
+ console.error("Status:", httpError.response.status);
399
+ }
400
+ }
401
+ ```
402
+
403
+ ### Function Calling Example
404
+
405
+ See [examples/function-calling.ts](./examples/function-calling.ts) for a complete example of how to use the wrapper with AI agents that support structured function calling (OpenAI, Anthropic, etc.).
406
+
407
+ For detailed agent workflows and capabilities, see [AGENTIC_CAPABILITIES.md](./AGENTIC_CAPABILITIES.md)
408
+
409
+ ## Development
410
+
411
+ ```bash
412
+ # Install dependencies
413
+ npm install
414
+
415
+ # Build
416
+ npm run build
417
+
418
+ # Run unit tests (with mocks)
419
+ npm run test:unit
420
+
421
+ # Run all tests
422
+ npm test
423
+
424
+ # Watch tests
425
+ npm run test:watch
426
+
427
+ # Run integration tests against real transit API
428
+ npm run test:integration
429
+
430
+ # Run specific endpoint integration test
431
+ npm run test:integration:helpline
432
+ npm run test:integration:service
433
+ npm run test:integration:about
434
+ npm run test:integration:emergency
435
+ npm run test:integration:vehicle
436
+
437
+ # Or use TEST_ENDPOINT environment variable
438
+ TEST_ENDPOINT=helpline npm run test:integration
439
+ ```
440
+
441
+ ### Testing
442
+
443
+ This project includes comprehensive testing with both unit tests (mocked) and integration tests (real API).
444
+
445
+ #### Unit Tests
446
+
447
+ Unit tests use mocked HTTP responses and don't require network access. They're fast and can be run frequently during development.
448
+
449
+ ```bash
450
+ # Run all unit tests
451
+ npm run test:unit
452
+
453
+ # Run tests in watch mode
454
+ npm run test:watch
455
+
456
+ # Run tests with UI
457
+ npm run test:ui
458
+ ```
459
+
460
+ #### Integration Tests
461
+
462
+ Integration tests make actual HTTP requests to the real transit API. They verify that the SDK works correctly with the actual API endpoints.
463
+
464
+ **⚠️ Important Notes:**
465
+
466
+ - Integration tests require network access
467
+ - Tests are rate-limited with a 2-second delay between requests to prevent IP blocking
468
+ - Tests run sequentially to avoid overwhelming the API
469
+ - Tests are skipped by default unless explicitly enabled
470
+
471
+ **Running Integration Tests:**
472
+
473
+ ```bash
474
+ # Run all integration tests
475
+ npm run test:integration
476
+
477
+ # Run specific endpoint tests (recommended for faster testing)
478
+ npm run test:integration:helpline
479
+ npm run test:integration:service
480
+ npm run test:integration:about
481
+ npm run test:integration:emergency
482
+ npm run test:integration:vehicle
483
+
484
+ # Or use environment variable for custom filtering
485
+ TEST_ENDPOINT=helpline npm run test:integration
486
+ ```
487
+
488
+ **Environment Variables:**
489
+
490
+ - `RUN_REAL_API_TESTS`: Set to `true` or `1` to enable integration tests (automatically set by `test:integration` scripts)
491
+ - `TEST_ENDPOINT`: Filter tests by endpoint name (e.g., `helpline`, `vehicle`, `service`, `about`, `emergency`)
492
+
493
+ **Test Output:**
494
+
495
+ Integration tests print formatted JSON responses to the console, making it easy to inspect the actual API responses and verify the normalization is working correctly.
496
+
497
+ **Rate Limiting:**
498
+
499
+ The integration tests include a 2-second delay between each test to prevent rate limiting. Tests are configured to run sequentially (single fork) to ensure proper rate limiting behavior.
500
+
501
+ ## Acknowledgments
502
+
503
+ Thanks to [open-bmtc](https://github.com/Vonter/open-bmtc) for helping understand the BMTC API structure.
504
+
505
+ ## License
506
+
507
+ MIT
@@ -0,0 +1,77 @@
1
+ import type { BaseClient } from "../client/base-client";
2
+ import type { HelplineResponse, ServiceTypesResponse, AboutDataResponse, EmergencyMessagesResponse, FareScrollMessagesResponse } from "../types/info";
3
+ /**
4
+ * Info/General API methods
5
+ */
6
+ export declare class InfoAPI {
7
+ private client;
8
+ constructor(client: BaseClient);
9
+ /**
10
+ * Get transit helpline information
11
+ * @returns Helpline information including contact numbers in normalized format
12
+ * @throws {HTTPError} If the API request fails (network error, 4xx, 5xx)
13
+ * @example
14
+ * ```typescript
15
+ * const helpline = await client.info.getHelpline();
16
+ * helpline.items.forEach(item => {
17
+ * console.log(`${item.title}: ${item.contactNumber}`);
18
+ * });
19
+ * ```
20
+ */
21
+ getHelpline(): Promise<HelplineResponse>;
22
+ /**
23
+ * Get service types (e.g., AC, Non AC/Ordinary)
24
+ * @returns List of available service types in normalized format
25
+ * @throws {HTTPError} If the API request fails (network error, 4xx, 5xx)
26
+ * @example
27
+ * ```typescript
28
+ * const serviceTypes = await client.info.getServiceTypes();
29
+ * const acService = serviceTypes.items.find(s => s.serviceTypeName.includes("AC"));
30
+ * // Use acService.serviceTypeId in planTrip({ serviceTypeId })
31
+ * ```
32
+ */
33
+ getServiceTypes(): Promise<ServiceTypesResponse>;
34
+ /**
35
+ * Get about information including URLs and airport information
36
+ * @returns About data with terms, URLs, and airport coordinates in normalized format
37
+ * @throws {HTTPError} If the API request fails (network error, 4xx, 5xx)
38
+ * @example
39
+ * ```typescript
40
+ * const about = await client.info.getAbout();
41
+ * console.log(`Airport coordinates: [${about.airportLatitude}, ${about.airportLongitude}]`);
42
+ * console.log(`Terms URL: ${about.termsUrl}`);
43
+ * ```
44
+ */
45
+ getAbout(): Promise<AboutDataResponse>;
46
+ /**
47
+ * Get emergency messages (English and Kannada)
48
+ * @returns List of emergency messages with display settings in normalized format
49
+ * @throws {HTTPError} If the API request fails (network error, 4xx, 5xx)
50
+ * @example
51
+ * ```typescript
52
+ * const messages = await client.info.getEmergencyMessages();
53
+ * const activeMessages = messages.items.filter(m => m.isDisplay);
54
+ *
55
+ * activeMessages.forEach(msg => {
56
+ * console.log(`${msg.displayKey}: ${msg.messageEn}`);
57
+ * });
58
+ * ```
59
+ */
60
+ getEmergencyMessages(): Promise<EmergencyMessagesResponse>;
61
+ /**
62
+ * Get fare scroll messages (English and Kannada)
63
+ * @returns List of fare scroll messages with display settings in normalized format
64
+ * @throws {HTTPError} If the API request fails (network error, 4xx, 5xx)
65
+ * @example
66
+ * ```typescript
67
+ * const messages = await client.info.getFareScrollMessages();
68
+ * messages.items.forEach(msg => {
69
+ * if (msg.isDisplay) {
70
+ * console.log(`Fare update: ${msg.messageEn}`);
71
+ * }
72
+ * });
73
+ * ```
74
+ */
75
+ getFareScrollMessages(): Promise<FareScrollMessagesResponse>;
76
+ }
77
+ //# sourceMappingURL=info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/api/info.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EACX,gBAAgB,EAGhB,oBAAoB,EAEpB,iBAAiB,EACjB,yBAAyB,EAEzB,0BAA0B,EAG1B,MAAM,eAAe,CAAC;AAiGvB;;GAEG;AACH,qBAAa,OAAO;IACP,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,UAAU;IAEtC;;;;;;;;;;;OAWG;IACG,WAAW,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAkB9C;;;;;;;;;;OAUG;IACG,eAAe,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAkBtD;;;;;;;;;;OAUG;IACG,QAAQ,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAkB5C;;;;;;;;;;;;;OAaG;IACG,oBAAoB,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAoBhE;;;;;;;;;;;;;OAaG;IACG,qBAAqB,IAAI,OAAO,CAAC,0BAA0B,CAAC;CAmBlE"}