gtfs-sqljs 0.3.1 → 0.4.1

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
@@ -23,6 +23,7 @@ This project is greatly inspired by [node-gtfs](https://github.com/BlinkTagInc/n
23
23
  - [Documentation and Interactive Demo](https://sysdevrun.github.io/gtfs-sqljs/)
24
24
  - [Usage Guide](https://sysdevrun.github.io/gtfs-sqljs/docs/documents/Usage_Guide.html) — detailed examples for all features
25
25
  - [API Reference](https://sysdevrun.github.io/gtfs-sqljs/docs/) — full TypeDoc-generated API docs
26
+ - [LLM Skill File](.claude/skills/gtfs-sqljs/SKILL.md) — Claude Code skill for LLM code agents
26
27
 
27
28
  ## Features
28
29
 
package/dist/index.d.ts CHANGED
@@ -965,6 +965,11 @@ declare class GtfsSqlJs {
965
965
  * @param urls - Optional array of feed URLs. If not provided, uses configured feed URLs
966
966
  */
967
967
  fetchRealtimeData(urls?: string[]): Promise<void>;
968
+ /**
969
+ * Load GTFS Realtime data from pre-loaded protobuf buffers
970
+ * @param buffers - Array of Uint8Array protobuf-encoded GTFS-RT feed messages
971
+ */
972
+ loadRealtimeDataFromBuffers(buffers: Uint8Array[]): Promise<void>;
968
973
  /**
969
974
  * Clear all realtime data from the database
970
975
  */
package/dist/index.js CHANGED
@@ -340,13 +340,6 @@ function getAllCreateIndexStatements() {
340
340
 
341
341
  // src/loaders/zip-loader.ts
342
342
  import JSZip from "jszip";
343
-
344
- // src/utils/env.ts
345
- function isNodeEnvironment() {
346
- return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
347
- }
348
-
349
- // src/loaders/zip-loader.ts
350
343
  async function loadGTFSZip(zipData, skipFiles) {
351
344
  const zip = await JSZip.loadAsync(zipData);
352
345
  const skipSet = skipFiles ? new Set(skipFiles) : null;
@@ -414,15 +407,6 @@ async function fetchZip(source, onProgress) {
414
407
  }
415
408
  throw new Error("fetch is not available to load URL");
416
409
  }
417
- if (isNodeEnvironment()) {
418
- try {
419
- const fs = await import("fs");
420
- const buffer = await fs.promises.readFile(source);
421
- return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
422
- } catch (error) {
423
- throw new Error(`Failed to read GTFS ZIP file: ${error}`);
424
- }
425
- }
426
410
  if (typeof fetch !== "undefined") {
427
411
  const response = await fetch(source);
428
412
  if (!response.ok) {
@@ -887,15 +871,6 @@ async function fetchProtobuf(source) {
887
871
  const arrayBuffer2 = await response2.arrayBuffer();
888
872
  return new Uint8Array(arrayBuffer2);
889
873
  }
890
- if (isNodeEnvironment()) {
891
- try {
892
- const fs = await import("fs");
893
- const buffer = await fs.promises.readFile(source);
894
- return new Uint8Array(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));
895
- } catch (error) {
896
- throw new Error(`Failed to read GTFS-RT file from ${source}: ${error instanceof Error ? error.message : String(error)}`);
897
- }
898
- }
899
874
  const response = await fetch(source, {
900
875
  headers: {
901
876
  "Accept": "application/x-protobuf, application/octet-stream"
@@ -907,12 +882,13 @@ async function fetchProtobuf(source) {
907
882
  const arrayBuffer = await response.arrayBuffer();
908
883
  return new Uint8Array(arrayBuffer);
909
884
  }
910
- var gtfsRtRoot = null;
911
- function loadGtfsRtProto() {
912
- if (!gtfsRtRoot) {
913
- gtfsRtRoot = protobuf.parse(GTFS_RT_PROTO).root;
885
+ var feedMessageType = null;
886
+ function getFeedMessageType() {
887
+ if (!feedMessageType) {
888
+ const root = protobuf.parse(GTFS_RT_PROTO).root;
889
+ feedMessageType = root.lookupType("transit_realtime.FeedMessage");
914
890
  }
915
- return gtfsRtRoot;
891
+ return feedMessageType;
916
892
  }
917
893
  function camelToSnake(str) {
918
894
  return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
@@ -1044,27 +1020,20 @@ function insertTripUpdates(db, updates, timestamp) {
1044
1020
  tripStmt.free();
1045
1021
  stopTimeStmt.free();
1046
1022
  }
1047
- async function loadRealtimeData(db, feedUrls) {
1048
- const root = loadGtfsRtProto();
1049
- const FeedMessage = root.lookupType("transit_realtime.FeedMessage");
1050
- const fetchPromises = feedUrls.map(async (url) => {
1051
- try {
1052
- const data = await fetchProtobuf(url);
1053
- const message = FeedMessage.decode(data);
1054
- return FeedMessage.toObject(message, {
1055
- longs: Number,
1056
- enums: Number,
1057
- bytes: String,
1058
- defaults: false,
1059
- arrays: true,
1060
- objects: true,
1061
- oneofs: true
1062
- });
1063
- } catch (error) {
1064
- throw new Error(`Failed to fetch or parse GTFS-RT feed from ${url}: ${error instanceof Error ? error.message : String(error)}`);
1065
- }
1023
+ function decodeFeedMessage(data) {
1024
+ const FeedMessage = getFeedMessageType();
1025
+ const message = FeedMessage.decode(data);
1026
+ return FeedMessage.toObject(message, {
1027
+ longs: Number,
1028
+ enums: Number,
1029
+ bytes: String,
1030
+ defaults: false,
1031
+ arrays: true,
1032
+ objects: true,
1033
+ oneofs: true
1066
1034
  });
1067
- const feeds = await Promise.all(fetchPromises);
1035
+ }
1036
+ function processRealtimeFeeds(db, feeds) {
1068
1037
  const now = Math.floor(Date.now() / 1e3);
1069
1038
  const allAlerts = [];
1070
1039
  const allVehiclePositions = [];
@@ -1104,6 +1073,20 @@ async function loadRealtimeData(db, feedUrls) {
1104
1073
  throw error;
1105
1074
  }
1106
1075
  }
1076
+ async function loadRealtimeData(db, feedUrls) {
1077
+ const buffers = await Promise.all(feedUrls.map(async (url) => {
1078
+ try {
1079
+ return await fetchProtobuf(url);
1080
+ } catch (error) {
1081
+ throw new Error(`Failed to fetch GTFS-RT feed from ${url}: ${error instanceof Error ? error.message : String(error)}`);
1082
+ }
1083
+ }));
1084
+ await loadRealtimeDataFromBuffers(db, buffers);
1085
+ }
1086
+ async function loadRealtimeDataFromBuffers(db, buffers) {
1087
+ const feeds = buffers.map((buffer) => decodeFeedMessage(buffer));
1088
+ processRealtimeFeeds(db, feeds);
1089
+ }
1107
1090
 
1108
1091
  // src/cache/checksum.ts
1109
1092
  async function computeChecksum(data) {
@@ -2947,6 +2930,15 @@ var GtfsSqlJs = class _GtfsSqlJs {
2947
2930
  await loadRealtimeData(this.db, feedUrls);
2948
2931
  this.lastRealtimeFetchTimestamp = Math.floor(Date.now() / 1e3);
2949
2932
  }
2933
+ /**
2934
+ * Load GTFS Realtime data from pre-loaded protobuf buffers
2935
+ * @param buffers - Array of Uint8Array protobuf-encoded GTFS-RT feed messages
2936
+ */
2937
+ async loadRealtimeDataFromBuffers(buffers) {
2938
+ if (!this.db) throw new Error("Database not initialized");
2939
+ await loadRealtimeDataFromBuffers(this.db, buffers);
2940
+ this.lastRealtimeFetchTimestamp = Math.floor(Date.now() / 1e3);
2941
+ }
2950
2942
  /**
2951
2943
  * Clear all realtime data from the database
2952
2944
  */