Releases: sysdevrun/gtfs-sqljs
Releases · sysdevrun/gtfs-sqljs
Release list
v0.9.0
- Breaking: drop Node.js 18 support —
engines.nodeis now>=20.0.0. Theawait import('node:crypto')fallback for Node 18's missingglobalThis.cryptois removed, which also fixes vite emittingModule "crypto" has been externalized for browser compatibilityfor the coregtfs-sqljsentry when bundling for the browser. Node 18 has been EOL since April 2025. - Add
getCalendars(filters?)— bulk read of thecalendartable (filters:serviceIdsingle value or array,limit).getCalendarByServiceId()remains as a convenience wrapper. (#46) getCalendarDates()no longer requires a service id — it now accepts an optional filters object (serviceId,date,limit) and returns the wholecalendar_datestable when called without arguments. The legacygetCalendarDates('SERVICE_ID')string form is still accepted. (#46)- Add
getFeedInfo()— returns thefeed_inforows (an array, since the spec allows multiple rows). (#46) - Add
getFrequencies(filters?)— read thefrequenciestable (filters:tripIdsingle value or array,limit).exact_times: 0is preserved. (#46) - Fix:
ProgressInfoandProgressCallbacktypes are now exported from the package entry point. (#45) - README: document that vite
fs/path/cryptowarnings pointing atsql.js/dist/sql-wasm.jscome from sql.js's UMD build, are harmless in the browser, and cannot be fixed from gtfs-sqljs. - CI: test matrix is now Node 20.x / 22.x / 24.x; GitHub Actions bumped across workflows.
v0.8.0
- Add
getTripSchedules(filters)— display-ready trip schedules with everything pre-computed: seconds since the start of the service day (past-midnight times > 86400 supported), unix epochs computed in the agency's timezone (DST-safe "noon minus 12h" rule, zero-dependency viaIntl), realtime delays resolved per the GTFS-RT spec (delay ↔ absolute time cross-computed, arrival ↔ departure borrowed, delay propagated to subsequent stops until the next update, trip-level delay fallback,stop_id-only matching),SKIPPED/NO_DATA/canceled flags,display_epoch(departure, or arrival at the terminus;displayMode: 'arrival'flips it), and stop names joined in. Batched internally — one trip or a whole route's day costs the same five indexed queries. - Add pure time/realtime helpers (exported, usable without a database):
parseGtfsTime,gtfsTimeToEpoch,serviceDayStartEpoch, andresolveRealtime— the resolution engine behindgetTripSchedules. - Update the website demo's stop-times view to
getTripSchedules(timezone-correct times, realtime departures with strikethrough schedule, canceled/skipped indicators, no more per-stop queries). Addexamples/trip-schedules.ts. - Breaking: split
ScheduleRelationshipintoTripScheduleRelationshipandStopTimeScheduleRelationship. The single enum conflated two protobuf enums with different numeric values: at stop level,SKIPPEDis1andNO_DATAis2per the GTFS-RT spec, but the old enum decoded1asADDEDand definedSKIPPED = 4(a value that never occurs in feeds).StopTimeUpdate.schedule_relationshipandStopTimeRealtime.schedule_relationshipare now typed asStopTimeScheduleRelationship; trip-level fields asTripScheduleRelationship.ScheduleRelationshipremains as a deprecated alias ofTripScheduleRelationship. - Fix: GTFS-RT loader dropped legitimate zero values.
delay: 0(explicitly on time),stop_sequence: 0,uncertainty: 0,bearing: 0,speed: 0, andcurrent_status: INCOMING_AT (0)were coerced to NULL; now preserved. - Fix: stop time updates identified by
stop_idonly (withoutstop_sequence, allowed by the spec) are now stored reliably: thert_stop_time_updatestable no longer has a(trip_id, stop_sequence)primary key and gained a(trip_id, stop_sequence)index instead.
v0.7.0
- Add
buildGraph(tripIds)method andGraph/EdgeTrip/EdgeDatatypes. Builds a directed stop-to-stop graph from the given trips, with each deduplicated edge carrying the list of originating trips (plusroute_idanddirection_id). Handles non-contiguousstop_sequencevalues viaLEAD(). HelpersedgeCount()andedges()are also exported.
v0.6.0
Breaking changes — pluggable database adapter
The library now talks to a small async GtfsDatabase interface. sql.js becomes one adapter among others (better-sqlite3 ships in the box; op-sqlite / expo-sqlite / … pluggable by the user). Three things change at every call site: (1) query methods return Promise<T>, (2) an adapter is required, (3) sql.js is an optional peer dependency — you install it yourself.
See the full migration write-up in README and the Usage Guide.
New features
- New
src/adapters/types.tspublic surface:GtfsDatabase,GtfsStatement,GtfsDatabaseAdapter,SqlValue,Row,ExportNotSupportedError. - sql.js adapter at subpath
gtfs-sqljs/adapters/sql-js(exportscreateSqlJsAdapter,wrapSqlJsDatabase). The core module no longer imports sql.js. - better-sqlite3 adapter at subpath
gtfs-sqljs/adapters/better-sqlite3(exportswrapBetterSqlite3,createBetterSqlite3Adapter). First-class Node / file-backed path; the adapter is the only file in the repo that importsbetter-sqlite3, so projects that do not reference this subpath never pull in the native module. Exercised bytests/e2e-better-sqlite3.test.tson every CI run. - Cache layer now catches
ExportNotSupportedErrorfrom adapters that cannot serialize in-memory and logs a warning instead of failing the load; file-backed drivers persist their own DB on disk.
Performance
- Ingestion is ~35-45% faster on medium-to-large feeds: ASTUCE (Rouen, ~430k stop_times rows) drops from ~2650 ms to ~1670 ms; Car Jaune from ~312 ms to ~188 ms. Wins come from parsing each CSV only once (progress totals now use a fast newline-based row-count estimate), loading rows as positional arrays instead of per-row objects, and reusing a single prepared INSERT per table instead of re-preparing a multi-row statement per 1000-row batch.
- Dropped the bulk-load PRAGMA block (
synchronous,journal_mode,temp_store,cache_size,locking_mode) from ingestion. Benchmarked aggregate effect on sql.js is within noise (≤1%); removing them simplifies the code and unblocks the pluggable adapter.
Behaviour changes
ProgressInfo.totalRowsis now an estimate based on CSV line count — typically exact, but may differ by a few rows per file in edge cases (e.g. trailing blank lines). For a precise post-ingest row count, query the database directly withCOUNT(*).
v0.4.1
v0.4.0
Breaking changes
fromZip()no longer reads local file paths in Node.js. Read the file yourself and usefromZipData()insteadfetchRealtimeData()/loadRealtimeData()no longer read local file paths in Node.js. Use the newloadRealtimeDataFromBuffers()method with pre-read data instead
New features
- Add
loadRealtimeDataFromBuffers(buffers)method toGtfsSqlJsfor loading GTFS-RT data from pre-loaded protobufUint8Arraybuffers without fetching
Internal improvements
- Remove all Node.js
fsimports andisNodeEnvironment()checks, making the published module fully platform-neutral
v0.3.1
- Make
route_short_nameandroute_long_nameoptional, matching GTFS spec (conditionally required: at least one must be present) - Allow
transfers.transfer_typeto be empty (defaults to 0 per GTFS spec) - Make
stop_times.arrival_timeandstop_times.departure_timeoptional for intermediate stops per GTFS spec - Make
stops.stop_latandstops.stop_lonoptional for generic nodes (location_type=3) and boarding areas (location_type=4) per GTFS spec
v0.3.0
Breaking changes
fromZip()now only acceptsstring(path or URL). If you were passingArrayBufferorUint8Array, use the newfromZipData()method insteadskipFilesbehavior change: files listed inskipFilesare now skipped during ZIP extraction entirely (not just excluded from DB loading), improving performance for large feeds
New features
- Add
GtfsSqlJs.fromZipData(zipData, options?, source?)static method for loading from pre-loaded ZIP data (ArrayBufferorUint8Array) - Extract only known GTFS files from ZIP, skipping unrecognized files for faster extraction
Internal improvements
- Simplify checksum to use global
crypto.subtledirectly (drop dynamicimport('crypto')fallback) - Extract shared
isNodeEnvironment()helper intoutils/env.ts - Replace
unknown[], widening casts, and non-null assertions with proper types across query files and loaders
v0.2.2
v0.2.0
- Add
pickupTypeanddropOffTypefilters togetStopTimes, withCOALESCEhandling so NULL (empty) is treated as 0 (regular) per GTFS spec - Add
PickupDropOffTypeenum for GTFS static pickup/drop-off type values - Replace
getCalendarByServiceId(serviceId)withgetCalendars(filters?)for consistent filter-based API - Fix README: replace non-existent
getStopByIdwithgetStops({ stopId })