gtfs 4.18.3 → 4.18.5
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/dist/bin/gtfs-export.js +33 -4
- package/dist/bin/gtfs-export.js.map +1 -1
- package/dist/bin/gtfs-import.js +381 -74
- package/dist/bin/gtfs-import.js.map +1 -1
- package/dist/bin/gtfsrealtime-update.js +135 -19
- package/dist/bin/gtfsrealtime-update.js.map +1 -1
- package/dist/index.d.ts +73 -1
- package/dist/index.js +501 -92
- package/dist/index.js.map +1 -1
- package/package.json +15 -15
|
@@ -96,7 +96,8 @@ async function getConfig(argv2) {
|
|
|
96
96
|
} catch (error) {
|
|
97
97
|
if (error instanceof SyntaxError) {
|
|
98
98
|
throw new Error(
|
|
99
|
-
`Cannot parse configuration file. Check to ensure that it is valid JSON. Error: ${error.message}
|
|
99
|
+
`Cannot parse configuration file. Check to ensure that it is valid JSON. Error: ${error.message}`,
|
|
100
|
+
{ cause: error }
|
|
100
101
|
);
|
|
101
102
|
}
|
|
102
103
|
throw error;
|
|
@@ -583,6 +584,61 @@ var serviceAlertInformedEntities = {
|
|
|
583
584
|
|
|
584
585
|
// src/lib/db.ts
|
|
585
586
|
import Database from "better-sqlite3";
|
|
587
|
+
|
|
588
|
+
// src/lib/errors.ts
|
|
589
|
+
var GtfsError = class extends Error {
|
|
590
|
+
code;
|
|
591
|
+
category;
|
|
592
|
+
isOperational;
|
|
593
|
+
statusCode;
|
|
594
|
+
details;
|
|
595
|
+
constructor(message, options) {
|
|
596
|
+
super(message, { cause: options.cause });
|
|
597
|
+
this.name = "GtfsError";
|
|
598
|
+
this.code = options.code;
|
|
599
|
+
this.category = options.category;
|
|
600
|
+
this.isOperational = options.isOperational ?? true;
|
|
601
|
+
this.statusCode = options.statusCode;
|
|
602
|
+
this.details = options.details;
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
function isGtfsError(error) {
|
|
606
|
+
if (!error || typeof error !== "object") {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
const candidate = error;
|
|
610
|
+
return candidate.name === "GtfsError" && typeof candidate.message === "string" && typeof candidate.code === "string" && typeof candidate.category === "string" && typeof candidate.isOperational === "boolean";
|
|
611
|
+
}
|
|
612
|
+
function toGtfsError(error, fallback) {
|
|
613
|
+
if (isGtfsError(error)) {
|
|
614
|
+
return error;
|
|
615
|
+
}
|
|
616
|
+
return new GtfsError(fallback.message, {
|
|
617
|
+
...fallback,
|
|
618
|
+
cause: error
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
function addImportError(report, error) {
|
|
622
|
+
report.errors.push(error);
|
|
623
|
+
report.errorCountsByCode[error.code] = (report.errorCountsByCode[error.code] ?? 0) + 1;
|
|
624
|
+
}
|
|
625
|
+
function formatGtfsError(error, options = { verbosity: "developer" }) {
|
|
626
|
+
if (!isGtfsError(error)) {
|
|
627
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
628
|
+
return options.verbosity === "user" ? message : `UNKNOWN_ERROR: ${message}`;
|
|
629
|
+
}
|
|
630
|
+
if (options.verbosity === "user") {
|
|
631
|
+
return error.message;
|
|
632
|
+
}
|
|
633
|
+
return [
|
|
634
|
+
`${error.code}: ${error.message}`,
|
|
635
|
+
`category=${error.category}`,
|
|
636
|
+
error.statusCode !== void 0 ? `statusCode=${error.statusCode}` : null,
|
|
637
|
+
error.details ? `details=${JSON.stringify(error.details)}` : null
|
|
638
|
+
].filter(Boolean).join(" | ");
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// src/lib/db.ts
|
|
586
642
|
var dbs = {};
|
|
587
643
|
function setupDb(sqlitePath) {
|
|
588
644
|
const db = new Database(untildify(sqlitePath));
|
|
@@ -611,11 +667,19 @@ function openDb(config = null) {
|
|
|
611
667
|
return dbs[filename];
|
|
612
668
|
}
|
|
613
669
|
if (Object.keys(dbs).length > 1) {
|
|
614
|
-
throw new
|
|
615
|
-
"Multiple databases open, please specify which one to use."
|
|
670
|
+
throw new GtfsError(
|
|
671
|
+
"Multiple databases open, please specify which one to use.",
|
|
672
|
+
{
|
|
673
|
+
code: "GTFS_DB_OPERATION_FAILED" /* GTFS_DB_OPERATION_FAILED */,
|
|
674
|
+
category: "database" /* DATABASE */,
|
|
675
|
+
details: { openDatabaseCount: Object.keys(dbs).length }
|
|
676
|
+
}
|
|
616
677
|
);
|
|
617
678
|
}
|
|
618
|
-
throw new
|
|
679
|
+
throw new GtfsError("Unable to find database connection.", {
|
|
680
|
+
code: "GTFS_DB_OPERATION_FAILED" /* GTFS_DB_OPERATION_FAILED */,
|
|
681
|
+
category: "database" /* DATABASE */
|
|
682
|
+
});
|
|
619
683
|
}
|
|
620
684
|
|
|
621
685
|
// src/lib/geojson-utils.ts
|
|
@@ -641,12 +705,21 @@ import sqlString from "sqlstring-sqlite";
|
|
|
641
705
|
import Long from "long";
|
|
642
706
|
function validateConfigForImport(config) {
|
|
643
707
|
if (!config.agencies || config.agencies.length === 0) {
|
|
644
|
-
throw new
|
|
708
|
+
throw new GtfsError("No `agencies` specified in config", {
|
|
709
|
+
code: "GTFS_CONFIG_INVALID" /* GTFS_CONFIG_INVALID */,
|
|
710
|
+
category: "config" /* CONFIG */,
|
|
711
|
+
details: { field: "agencies" }
|
|
712
|
+
});
|
|
645
713
|
}
|
|
646
714
|
for (const [index, agency2] of config.agencies.entries()) {
|
|
647
715
|
if (!agency2.path && !agency2.url) {
|
|
648
|
-
throw new
|
|
649
|
-
`No Agency \`url\` or \`path\` specified in config for agency index ${index}
|
|
716
|
+
throw new GtfsError(
|
|
717
|
+
`No Agency \`url\` or \`path\` specified in config for agency index ${index}.`,
|
|
718
|
+
{
|
|
719
|
+
code: "GTFS_CONFIG_INVALID" /* GTFS_CONFIG_INVALID */,
|
|
720
|
+
category: "config" /* CONFIG */,
|
|
721
|
+
details: { agencyIndex: index }
|
|
722
|
+
}
|
|
650
723
|
);
|
|
651
724
|
}
|
|
652
725
|
}
|
|
@@ -743,7 +816,16 @@ async function fetchGtfsRealtimeData(type, task) {
|
|
|
743
816
|
signal: task.downloadTimeout ? AbortSignal.timeout(task.downloadTimeout) : void 0
|
|
744
817
|
});
|
|
745
818
|
if (response.status !== 200) {
|
|
746
|
-
throw new
|
|
819
|
+
throw new GtfsError(`HTTP ${response.status}: ${response.statusText}`, {
|
|
820
|
+
code: "GTFS_DOWNLOAD_HTTP" /* GTFS_DOWNLOAD_HTTP */,
|
|
821
|
+
category: "download" /* DOWNLOAD */,
|
|
822
|
+
statusCode: response.status,
|
|
823
|
+
details: {
|
|
824
|
+
url: urlConfig.url,
|
|
825
|
+
status: response.status,
|
|
826
|
+
statusText: response.statusText
|
|
827
|
+
}
|
|
828
|
+
});
|
|
747
829
|
}
|
|
748
830
|
const buffer = await response.arrayBuffer();
|
|
749
831
|
const message = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(
|
|
@@ -760,17 +842,27 @@ async function fetchGtfsRealtimeData(type, task) {
|
|
|
760
842
|
});
|
|
761
843
|
return feedMessage;
|
|
762
844
|
} catch (error) {
|
|
763
|
-
const
|
|
845
|
+
const gtfsError = toGtfsError(error, {
|
|
846
|
+
message: error instanceof Error ? error.message : String(error),
|
|
847
|
+
code: "GTFS_DOWNLOAD_FAILED" /* GTFS_DOWNLOAD_FAILED */,
|
|
848
|
+
category: "download" /* DOWNLOAD */,
|
|
849
|
+
details: { type, url: urlConfig.url }
|
|
850
|
+
});
|
|
764
851
|
if (attempt === MAX_RETRIES) {
|
|
765
852
|
if (task.ignoreErrors) {
|
|
766
853
|
task.logError(
|
|
767
|
-
`Failed to fetch ${type} after ${MAX_RETRIES} attempts: ${
|
|
854
|
+
`Failed to fetch ${type} after ${MAX_RETRIES} attempts: ${gtfsError.message}`
|
|
768
855
|
);
|
|
856
|
+
if (task.report) {
|
|
857
|
+
addImportError(task.report, gtfsError);
|
|
858
|
+
}
|
|
769
859
|
return null;
|
|
770
860
|
}
|
|
771
|
-
throw
|
|
861
|
+
throw gtfsError;
|
|
772
862
|
}
|
|
773
|
-
task.logWarning(
|
|
863
|
+
task.logWarning(
|
|
864
|
+
`Attempt ${attempt} failed for ${type}: ${gtfsError.message}`
|
|
865
|
+
);
|
|
774
866
|
await new Promise(
|
|
775
867
|
(resolve) => setTimeout(resolve, RETRY_DELAY * attempt)
|
|
776
868
|
);
|
|
@@ -977,8 +1069,9 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
977
1069
|
);
|
|
978
1070
|
removeExpiredRealtimeData(config);
|
|
979
1071
|
await mapSeries(config.agencies, async (agency2) => {
|
|
1072
|
+
let task;
|
|
980
1073
|
try {
|
|
981
|
-
|
|
1074
|
+
task = {
|
|
982
1075
|
realtimeAlerts: agency2.realtimeAlerts,
|
|
983
1076
|
realtimeTripUpdates: agency2.realtimeTripUpdates,
|
|
984
1077
|
realtimeVehiclePositions: agency2.realtimeVehiclePositions,
|
|
@@ -994,11 +1087,19 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
994
1087
|
};
|
|
995
1088
|
await updateGtfsRealtimeData(task);
|
|
996
1089
|
} catch (error) {
|
|
997
|
-
const
|
|
1090
|
+
const gtfsError = toGtfsError(error, {
|
|
1091
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1092
|
+
code: "GTFS_DB_OPERATION_FAILED" /* GTFS_DB_OPERATION_FAILED */,
|
|
1093
|
+
category: "database" /* DATABASE */,
|
|
1094
|
+
details: { sqlitePath: task?.sqlitePath ?? config.sqlitePath }
|
|
1095
|
+
});
|
|
998
1096
|
if (config.ignoreErrors) {
|
|
999
|
-
logError(config)(
|
|
1097
|
+
logError(config)(formatGtfsError(gtfsError));
|
|
1098
|
+
if (task?.report) {
|
|
1099
|
+
addImportError(task.report, gtfsError);
|
|
1100
|
+
}
|
|
1000
1101
|
} else {
|
|
1001
|
-
throw
|
|
1102
|
+
throw gtfsError;
|
|
1002
1103
|
}
|
|
1003
1104
|
}
|
|
1004
1105
|
});
|
|
@@ -1012,11 +1113,26 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
1012
1113
|
);
|
|
1013
1114
|
} catch (error) {
|
|
1014
1115
|
if (error.code === "SQLITE_CANTOPEN") {
|
|
1015
|
-
|
|
1016
|
-
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json
|
|
1116
|
+
const dbOpenError = new GtfsError(
|
|
1117
|
+
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`,
|
|
1118
|
+
{
|
|
1119
|
+
code: "DB_OPEN_FAILED" /* DB_OPEN_FAILED */,
|
|
1120
|
+
category: "database" /* DATABASE */,
|
|
1121
|
+
details: {
|
|
1122
|
+
sqlitePath: config.sqlitePath,
|
|
1123
|
+
dbCode: error.code
|
|
1124
|
+
},
|
|
1125
|
+
cause: error
|
|
1126
|
+
}
|
|
1017
1127
|
);
|
|
1128
|
+
logError(config)(dbOpenError.message);
|
|
1129
|
+
throw dbOpenError;
|
|
1018
1130
|
}
|
|
1019
|
-
throw error
|
|
1131
|
+
throw toGtfsError(error, {
|
|
1132
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1133
|
+
code: "GTFS_DB_OPERATION_FAILED" /* GTFS_DB_OPERATION_FAILED */,
|
|
1134
|
+
category: "database" /* DATABASE */
|
|
1135
|
+
});
|
|
1020
1136
|
}
|
|
1021
1137
|
}
|
|
1022
1138
|
|