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.
- package/LICENSE +21 -0
- package/README.md +507 -0
- package/dist/api/info.d.ts +77 -0
- package/dist/api/info.d.ts.map +1 -0
- package/dist/api/info.js +197 -0
- package/dist/api/info.js.map +1 -0
- package/dist/api/locations.d.ts +26 -0
- package/dist/api/locations.d.ts.map +1 -0
- package/dist/api/locations.js +57 -0
- package/dist/api/locations.js.map +1 -0
- package/dist/api/routes.d.ts +341 -0
- package/dist/api/routes.d.ts.map +1 -0
- package/dist/api/routes.js +1133 -0
- package/dist/api/routes.js.map +1 -0
- package/dist/api/stops.d.ts +92 -0
- package/dist/api/stops.d.ts.map +1 -0
- package/dist/api/stops.js +237 -0
- package/dist/api/stops.js.map +1 -0
- package/dist/api/vehicles.d.ts +49 -0
- package/dist/api/vehicles.d.ts.map +1 -0
- package/dist/api/vehicles.js +154 -0
- package/dist/api/vehicles.js.map +1 -0
- package/dist/client/base-client.d.ts +52 -0
- package/dist/client/base-client.d.ts.map +1 -0
- package/dist/client/base-client.js +76 -0
- package/dist/client/base-client.js.map +1 -0
- package/dist/client/transit-client.d.ts +91 -0
- package/dist/client/transit-client.d.ts.map +1 -0
- package/dist/client/transit-client.js +98 -0
- package/dist/client/transit-client.js.map +1 -0
- package/dist/constants/api.d.ts +16 -0
- package/dist/constants/api.d.ts.map +1 -0
- package/dist/constants/api.js +16 -0
- package/dist/constants/api.js.map +1 -0
- package/dist/constants/routes.d.ts +16 -0
- package/dist/constants/routes.d.ts.map +1 -0
- package/dist/constants/routes.js +16 -0
- package/dist/constants/routes.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/common.d.ts +34 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +20 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/index.d.ts +7 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +7 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/info.d.ts +390 -0
- package/dist/schemas/info.d.ts.map +1 -0
- package/dist/schemas/info.js +110 -0
- package/dist/schemas/info.js.map +1 -0
- package/dist/schemas/locations.d.ts +84 -0
- package/dist/schemas/locations.d.ts.map +1 -0
- package/dist/schemas/locations.js +31 -0
- package/dist/schemas/locations.js.map +1 -0
- package/dist/schemas/routes.d.ts +3967 -0
- package/dist/schemas/routes.d.ts.map +1 -0
- package/dist/schemas/routes.js +532 -0
- package/dist/schemas/routes.js.map +1 -0
- package/dist/schemas/stops.d.ts +543 -0
- package/dist/schemas/stops.d.ts.map +1 -0
- package/dist/schemas/stops.js +129 -0
- package/dist/schemas/stops.js.map +1 -0
- package/dist/schemas/vehicles.d.ts +602 -0
- package/dist/schemas/vehicles.d.ts.map +1 -0
- package/dist/schemas/vehicles.js +116 -0
- package/dist/schemas/vehicles.js.map +1 -0
- package/dist/types/api.d.ts +9 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +5 -0
- package/dist/types/api.js.map +1 -0
- package/dist/types/coordinates.d.ts +7 -0
- package/dist/types/coordinates.d.ts.map +1 -0
- package/dist/types/coordinates.js +2 -0
- package/dist/types/coordinates.js.map +1 -0
- package/dist/types/geojson.d.ts +84 -0
- package/dist/types/geojson.d.ts.map +1 -0
- package/dist/types/geojson.js +2 -0
- package/dist/types/geojson.js.map +1 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/info.d.ts +133 -0
- package/dist/types/info.d.ts.map +1 -0
- package/dist/types/info.js +5 -0
- package/dist/types/info.js.map +1 -0
- package/dist/types/locations.d.ts +59 -0
- package/dist/types/locations.d.ts.map +1 -0
- package/dist/types/locations.js +5 -0
- package/dist/types/locations.js.map +1 -0
- package/dist/types/routes.d.ts +1137 -0
- package/dist/types/routes.d.ts.map +1 -0
- package/dist/types/routes.js +14 -0
- package/dist/types/routes.js.map +1 -0
- package/dist/types/stops.d.ts +286 -0
- package/dist/types/stops.d.ts.map +1 -0
- package/dist/types/stops.js +26 -0
- package/dist/types/stops.js.map +1 -0
- package/dist/types/vehicles.d.ts +138 -0
- package/dist/types/vehicles.d.ts.map +1 -0
- package/dist/types/vehicles.js +5 -0
- package/dist/types/vehicles.js.map +1 -0
- package/dist/utils/date.d.ts +35 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +49 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/errors.d.ts +34 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +41 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/geojson.d.ts +36 -0
- package/dist/utils/geojson.d.ts.map +1 -0
- package/dist/utils/geojson.js +115 -0
- package/dist/utils/geojson.js.map +1 -0
- package/dist/utils/validation.d.ts +40 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +62 -0
- package/dist/utils/validation.js.map +1 -0
- 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"}
|