vulture-wasm 0.5.0 → 0.6.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/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # vulture-wasm
2
2
 
3
- WebAssembly bindings for [vulture](https://github.com/urschrei/vulture) a Rust implementation of RAPTOR public-transit routing exposed as a single browser-friendly ES module via [wasm-bindgen](https://rustwasm.github.io/wasm-bindgen/) and [wasm-pack](https://rustwasm.github.io/wasm-pack/).
3
+ WebAssembly bindings for [vulture](https://github.com/urschrei/vulture), a Rust implementation of [RAPTOR](https://www.microsoft.com/en-us/research/publication/round-based-public-transit-routing/) (Delling, Pajor, Werneck) public-transit routing. Single ES module, built with [wasm-bindgen](https://rustwasm.github.io/wasm-bindgen/) and [wasm-pack](https://rustwasm.github.io/wasm-pack/).
4
4
 
5
- The JS side fetches a GTFS zip with `fetch()`, hands the bytes to `new VultureTimetable(zipBytes, "YYYY-MM-DD")`, and runs queries against it. There is no HTTP code inside the wasm blob.
5
+ Pass GTFS zip bytes to `new VultureTimetable(zipBytes, "YYYY-MM-DD")`, then query the handle. No HTTP code in the wasm blob.
6
6
 
7
- The wasm bundle is currently ~700 KB raw, ~275 KB gzipped.
7
+ Bundle: ~700 KB raw, ~290 KB gzipped.
8
8
 
9
9
  ## Install
10
10
 
@@ -15,7 +15,7 @@ npm install vulture-wasm
15
15
  ```js
16
16
  import init, { VultureTimetable, runArrival, runRange } from "vulture-wasm";
17
17
 
18
- await init(); // loads the wasm module
18
+ await init();
19
19
 
20
20
  const zipBytes = new Uint8Array(
21
21
  await (await fetch("/path/to/feed.zip")).arrayBuffer(),
@@ -49,19 +49,32 @@ const tt = new VultureTimetable(
49
49
  - `tt.stopName(stopIdx)`, `tt.stopCoords(stopIdx)`, `tt.routeName(routeIdx)`, `tt.routeAgency(routeIdx)` — display-data accessors.
50
50
  - `tt.allStops()` — bulk catalogue of `{idx, id, name, lat, lon, location_type, parent_station}` per stop. `location_type` is the GTFS integer (0 = stop or platform, 1 = parent station, 2 = entrance/exit, 3 = generic node, 4 = boarding area); `parent_station` is the parent's GTFS id or `null`.
51
51
  - `tt.allRoutes()` — bulk catalogue of `{idx, id, name, agency, route_type, route_color}` per route. `route_type` is the GTFS integer (0 = tram, 1 = metro, 2 = rail, 3 = bus, 4 = ferry, 5 = cable, 6 = aerial, 7 = funicular, …); `route_color` is `"#rrggbb"` or `null`.
52
- - `tt.stationStops(parentId)` — given a parent station's GTFS id, returns a `Uint32Array` of the platform stop indices that hang off it. Pass the result as `originStops` / `targetStops` to query against every platform of a station; queries rooted at a `location_type = 1` stop return zero journeys without this expansion, because in GTFS vehicles only board at platform-level stops.
52
+ - `tt.stationStops(parentId)` — `Uint32Array` of child platform indices for a parent-station GTFS id. Pass to `originStops` / `targetStops` for any-platform queries. Queries rooted at a `location_type = 1` stop return zero journeys without this expansion.
53
53
  - `tt.withWalkingFootpaths(maxDistMeters, walkSpeedMetersPerSec)` — replace the footpath set with one derived from stop coordinates.
54
54
  - `tt.resetFootpaths()` — restore the original `transfers.txt` set.
55
+ - `tt.features()` — snapshot of the loaded feed as a JS object (camelCase fields): stop / route / trip counts, `transfers.txt` breakdown by `transfer_type`, parent-station and shaped-trip counts, wheelchair-flag counts, and footpath-graph state (`walkingFootpathsAdded`, `footpathsClosed`, `nFootpaths`). Counts are fixed at construction; footpath fields update on mutation.
56
+ - `tt.suggestions()` — advisory string array derived from the snapshot, e.g. `"transfers.txt is empty: call withWalkingFootpaths(...)"`. Empty when the feed is in a happy-path state.
55
57
 
56
58
  Free functions:
57
59
 
58
60
  - `runArrival(tt, originStops, targetStops, maxTransfers, departSeconds, requireWheelchair)` — single-departure query. Returns an array of journeys with timed legs.
59
- - `runRange(tt, originStops, targetStops, maxTransfers, departures, requireWheelchair)` — depart-in-window Pareto profile. Returns `[{depart, journey}]` where each `journey` has the same shape as a `runArrival` entry (`origin`, `target`, `arrival`, `legs`).
61
+ - `runRange(tt, originStops, targetStops, maxTransfers, departures, requireWheelchair)` — depart-in-window Pareto profile. Returns `[{depart, journey}]`; `journey` matches a `runArrival` entry (`origin`, `target`, `arrival`, `legs`).
60
62
 
61
- Each leg in `journey.legs` is `{board_stop, alight_stop, route, trip, route_id, depart, arrive, shape}`. `shape` is a `[lat, lon][]` polyline for that leg's segment of the trip's `shapes.txt` geometry, or `null` if the feed has no shape for the trip.
63
+ Each leg in `journey.legs`: `{board_stop, alight_stop, route, trip, route_id, depart, arrive, shape}`. `shape` is a `[lat, lon][]` polyline from the trip's `shapes.txt`, or `null` when absent.
62
64
 
63
65
  `originStops` / `targetStops` / `departures` are `Uint32Array`s; times are seconds since midnight on the service date. Full type signatures are in the bundled `vulture_wasm.d.ts`.
64
66
 
67
+ ## Native-only features
68
+
69
+ The wasm bindings omit:
70
+
71
+ - **Custom `Label` impls** and the bundled **`ArrivalAndWalk`** / **`ArrivalAndFare`** labels. Generics monomorphise per call-site; a wasm binding can ship only pre-baked label types. `runArrival` / `runRange` use the default arrival-time label.
72
+ - **`assert_footpaths_closed()`** — closed-footpath single-pass `O(E)` relaxation.
73
+ - **`new_with_overnight_days(...)`** — multi-day load for queries that cross the day boundary.
74
+ - **`RaptorCachePool`** — parallel fan-out; browsers do not expose rayon-style threading by default.
75
+
76
+ For any of these, use the native [`vulture`](https://crates.io/crates/vulture) crate.
77
+
65
78
  ## Examples
66
79
 
67
80
  ### 1. Stop-to-stop, single departure
@@ -110,7 +123,7 @@ for (const j of journeys) {
110
123
 
111
124
  ### 2. Departure window (range query)
112
125
 
113
- "Show me the Pareto-optimal options if I leave any time between 09:00 and 10:00."
126
+ Pareto-optimal options across a range of departures (here, every 5 minutes from 09:00 to 10:00):
114
127
 
115
128
  ```js
116
129
  import init, { VultureTimetable, runRange } from "vulture-wasm";
@@ -152,7 +165,7 @@ for (const entry of profile) {
152
165
 
153
166
  ### 3. Walking footpaths from coordinates
154
167
 
155
- GTFS feeds with sparse `transfers.txt` (e.g. Helsinki HSL) leave most station-to-station walks unmodelled. Augment from coordinates and compare:
168
+ Augment a sparse `transfers.txt` (e.g. Helsinki HSL) from stop coordinates and compare:
156
169
 
157
170
  ```js
158
171
  import init, { VultureTimetable, runArrival } from "vulture-wasm";
@@ -185,7 +198,7 @@ console.log(`with footpaths: ${after.length} journey(s)`);
185
198
 
186
199
  ### 4. Querying entire stations (parent-station expansion)
187
200
 
188
- GTFS feeds with deep station hierarchies (regional German rail, French SNCF, UK NaPTAN, etc.) model a single station as one parent stop (`location_type = 1`) with many child platforms (`location_type = 0`) hanging off it. Vehicles only board at platforms; querying directly against a parent station returns zero journeys. Detect parents and expand them into the platform set:
201
+ Parent stations (`location_type = 1`) have no boardings of their own; expand to their child platforms (`location_type = 0`) before querying.
189
202
 
190
203
  ```js
191
204
  import init, { VultureTimetable, runArrival } from "vulture-wasm";
@@ -224,7 +237,17 @@ const journeys = runArrival(
224
237
  console.log(`${journeys.length} journey(s) across all platform combinations`);
225
238
  ```
226
239
 
227
- The same `endpointsFor(stop)` helper is what the bundled demo uses across all three panels.
240
+ The bundled demo uses the same helper across all three panels.
241
+
242
+ ## Perf
243
+
244
+ No automated browser benchmark yet. The [live demo](https://urschrei.github.io/vulture/) runs every query client-side against the bundled Delhi Metro feed; time it in your browser's performance panel.
245
+
246
+ Native single-query latency is in the [main README](https://github.com/urschrei/vulture#perf): single-digit microseconds for a small metro feed, single-digit milliseconds for a large regional feed, tens of milliseconds for the heaviest. Browser numbers are slower than native by an engine- and JIT-dependent factor.
247
+
248
+ ## Soundness
249
+
250
+ The Rust engine is validated by [`vulture-proptest`](https://github.com/urschrei/vulture/tree/main/vulture-proptest), which compares the algorithm against a brute-force reference solver on every test run. Issue-by-issue audit against the paper: [`docs/soundness.md`](https://github.com/urschrei/vulture/blob/main/docs/soundness.md). The bindings layer is exercised by `vulture-wasm/tests/smoke.mjs`.
228
251
 
229
252
  ## Build from source
230
253
 
@@ -237,11 +260,11 @@ The same `endpointsFor(stop)` helper is what the bundled demo uses across all th
237
260
  wasm-pack build vulture-wasm --target web --release
238
261
  ```
239
262
 
240
- The web (ESM) target is the canonical and only output. It works in browsers, in modern Node, and inside any bundler that understands ES modules.
263
+ The web (ESM) target is the only output. It works in browsers, modern Node, and any ES-module bundler.
241
264
 
242
265
  ## Node
243
266
 
244
- Same package, same import Node just needs the wasm bytes passed in explicitly because there's no relative `fetch()` for the bundled `.wasm` file:
267
+ Same package, same import. Node needs the wasm bytes passed in explicitly (no relative `fetch()` for the bundled `.wasm`):
245
268
 
246
269
  ```js
247
270
  import init, { VultureTimetable, runArrival } from "vulture-wasm";
@@ -256,7 +279,7 @@ await init({ module_or_path: readFileSync(wasmPath) });
256
279
  const tt = new VultureTimetable(readFileSync("feed.zip"), "2024-01-15");
257
280
  ```
258
281
 
259
- The smoke test at `vulture-wasm/tests/smoke.mjs` is a runnable example: it loads the bundled Delhi Metro feed and exercises every public function. Run it with:
282
+ `vulture-wasm/tests/smoke.mjs` loads the bundled Delhi Metro feed and exercises every public function:
260
283
 
261
284
  ```sh
262
285
  wasm-pack build vulture-wasm --target web --release
@@ -265,6 +288,14 @@ node vulture-wasm/tests/smoke.mjs
265
288
 
266
289
  ## Demo page
267
290
 
268
- `docs/demo/` is a vanilla-JS / vanilla-CSS demo with three panels stop-to-stop, departure window, walking-footpath comparison running entirely client-side against the bundled Delhi Metro feed. Live at <https://urschrei.github.io/vulture/>.
291
+ `docs/demo/` has three panels (stop-to-stop, departure window, walking-footpath comparison) running client-side against the bundled Delhi Metro feed. Live at <https://urschrei.github.io/vulture/>.
292
+
293
+ Journeys render on a MapLibre dark basemap; geometry from `leg.shape`, per-mode colour from `route.route_color` / `route.route_type`. Wiring in `docs/demo/app.js` (`drawJourney`).
294
+
295
+ ## Changelog
296
+
297
+ [CHANGELOG](https://github.com/urschrei/vulture/blob/main/CHANGELOG.md) in the repo. `vulture` (Rust) and `vulture-wasm` (npm) have independent version streams; entries note both numbers when the bindings move with the engine.
298
+
299
+ ## License
269
300
 
270
- The demo also renders each journey on a MapLibre dark basemap, using `leg.shape` from `runArrival` / `runRange` for the polyline geometry and `route.route_color` / `route.route_type` for the per-mode colour. See `docs/demo/app.js` (`drawJourney`) for the rendering wiring — roughly 80 lines of GeoJSON sources + circle/line layers with a halo+stroke pattern for legibility on the dark tiles.
301
+ [Apache-2.0](https://github.com/urschrei/vulture/blob/main/LICENSE.md), matching the [`vulture`](https://github.com/urschrei/vulture) crate.
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "Stephan Hügel <urschrei@gmail.com>"
6
6
  ],
7
7
  "description": "WebAssembly bindings for vulture (RAPTOR transit routing)",
8
- "version": "0.5.0",
8
+ "version": "0.6.0",
9
9
  "license": "Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",
Binary file