gtfs 4.14.2 → 4.14.4
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 +1 -1
- package/dist/bin/gtfs-export.js +1 -0
- package/dist/bin/gtfs-export.js.map +1 -1
- package/dist/bin/gtfs-import.js +135 -104
- package/dist/bin/gtfs-import.js.map +1 -1
- package/dist/bin/gtfsrealtime-update.js +121 -89
- package/dist/bin/gtfsrealtime-update.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +146 -108
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3383,6 +3383,7 @@ function setDefaultConfig(initialConfig) {
|
|
|
3383
3383
|
const defaults = {
|
|
3384
3384
|
sqlitePath: ":memory:",
|
|
3385
3385
|
ignoreDuplicates: false,
|
|
3386
|
+
ignoreErrors: false,
|
|
3386
3387
|
gtfsRealtimeExpirationSeconds: 0
|
|
3387
3388
|
};
|
|
3388
3389
|
return {
|
|
@@ -3481,6 +3482,9 @@ function formatOrderByClause(orderBy2) {
|
|
|
3481
3482
|
|
|
3482
3483
|
// src/lib/import.ts
|
|
3483
3484
|
var downloadFiles = async (task) => {
|
|
3485
|
+
if (!task.url) {
|
|
3486
|
+
throw new Error("No `url` specified in config");
|
|
3487
|
+
}
|
|
3484
3488
|
task.log(`Downloading GTFS from ${task.url}`);
|
|
3485
3489
|
task.path = `${task.downloadDir}/gtfs.zip`;
|
|
3486
3490
|
const response = await fetch(task.url, {
|
|
@@ -3489,7 +3493,9 @@ var downloadFiles = async (task) => {
|
|
|
3489
3493
|
signal: task.downloadTimeout ? AbortSignal.timeout(task.downloadTimeout) : void 0
|
|
3490
3494
|
});
|
|
3491
3495
|
if (response.status !== 200) {
|
|
3492
|
-
throw new Error(
|
|
3496
|
+
throw new Error(
|
|
3497
|
+
`Unable to download GTFS from ${task.url}. Got status ${response.status}.`
|
|
3498
|
+
);
|
|
3493
3499
|
}
|
|
3494
3500
|
const buffer = await response.arrayBuffer();
|
|
3495
3501
|
await writeFile(task.path, Buffer.from(buffer));
|
|
@@ -3507,7 +3513,7 @@ var downloadGtfsRealtimeData = async (urlAndHeaders, task) => {
|
|
|
3507
3513
|
});
|
|
3508
3514
|
if (response.status !== 200) {
|
|
3509
3515
|
task.logWarning(
|
|
3510
|
-
`Unable to download GTFS-Realtime from ${urlAndHeaders.url}
|
|
3516
|
+
`Unable to download GTFS-Realtime from ${urlAndHeaders.url}. Got status ${response.status}.`
|
|
3511
3517
|
);
|
|
3512
3518
|
return null;
|
|
3513
3519
|
}
|
|
@@ -3596,103 +3602,127 @@ var updateRealtimeData = async (task) => {
|
|
|
3596
3602
|
sqlitePath: task.sqlitePath
|
|
3597
3603
|
});
|
|
3598
3604
|
if (task.realtimeAlerts?.url) {
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
const
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
try {
|
|
3611
|
-
db.prepare(
|
|
3612
|
-
`REPLACE INTO ${serviceAlerts.filenameBase} (${serviceAlerts.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
3613
|
-
).run();
|
|
3614
|
-
} catch (error) {
|
|
3615
|
-
task.logWarning("Import error: " + error.message);
|
|
3616
|
-
}
|
|
3617
|
-
const alertTargetArray = [];
|
|
3618
|
-
for (const informedEntity of entity.alert.informedEntity) {
|
|
3619
|
-
informedEntity.parent = entity;
|
|
3620
|
-
const subValues = serviceAlertTargets.schema.map(
|
|
3621
|
-
(column) => prepareRealtimeValue(informedEntity, column, task)
|
|
3605
|
+
try {
|
|
3606
|
+
const gtfsRealtimeData = await downloadGtfsRealtimeData(
|
|
3607
|
+
task.realtimeAlerts,
|
|
3608
|
+
task
|
|
3609
|
+
);
|
|
3610
|
+
if (gtfsRealtimeData?.entity) {
|
|
3611
|
+
task.log(`Download successful`);
|
|
3612
|
+
let totalLineCount = 0;
|
|
3613
|
+
for (const entity of gtfsRealtimeData.entity) {
|
|
3614
|
+
const fieldValues = serviceAlerts.schema.map(
|
|
3615
|
+
(column) => prepareRealtimeValue(entity, column, task)
|
|
3622
3616
|
);
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3617
|
+
try {
|
|
3618
|
+
db.prepare(
|
|
3619
|
+
`REPLACE INTO ${serviceAlerts.filenameBase} (${serviceAlerts.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
3620
|
+
).run();
|
|
3621
|
+
} catch (error) {
|
|
3622
|
+
task.logWarning("Import error: " + error.message);
|
|
3623
|
+
}
|
|
3624
|
+
const alertTargetArray = [];
|
|
3625
|
+
for (const informedEntity of entity.alert.informedEntity) {
|
|
3626
|
+
informedEntity.parent = entity;
|
|
3627
|
+
const subValues = serviceAlertTargets.schema.map(
|
|
3628
|
+
(column) => prepareRealtimeValue(informedEntity, column, task)
|
|
3629
|
+
);
|
|
3630
|
+
alertTargetArray.push(`(${subValues.join(", ")})`);
|
|
3631
|
+
totalLineCount++;
|
|
3632
|
+
}
|
|
3633
|
+
try {
|
|
3634
|
+
db.prepare(
|
|
3635
|
+
`REPLACE INTO ${serviceAlertTargets.filenameBase} (${serviceAlertTargets.schema.map((column) => column.name).join(", ")}) VALUES ${alertTargetArray.join(", ")}`
|
|
3636
|
+
).run();
|
|
3637
|
+
} catch (error) {
|
|
3638
|
+
task.logWarning("Import error: " + error.message);
|
|
3639
|
+
}
|
|
3640
|
+
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
3632
3641
|
}
|
|
3633
|
-
|
|
3642
|
+
}
|
|
3643
|
+
} catch (error) {
|
|
3644
|
+
if (task.ignoreErrors) {
|
|
3645
|
+
task.logError(error.message);
|
|
3646
|
+
} else {
|
|
3647
|
+
throw error;
|
|
3634
3648
|
}
|
|
3635
3649
|
}
|
|
3636
3650
|
}
|
|
3637
3651
|
if (task.realtimeTripUpdates?.url) {
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
const
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
try {
|
|
3650
|
-
db.prepare(
|
|
3651
|
-
`REPLACE INTO ${tripUpdates.filenameBase} (${tripUpdates.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
3652
|
-
).run();
|
|
3653
|
-
} catch (error) {
|
|
3654
|
-
task.logWarning("Import error: " + error.message);
|
|
3655
|
-
}
|
|
3656
|
-
const stopTimeUpdateArray = [];
|
|
3657
|
-
for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {
|
|
3658
|
-
stopTimeUpdate.parent = entity;
|
|
3659
|
-
const subValues = stopTimeUpdates.schema.map(
|
|
3660
|
-
(column) => prepareRealtimeValue(stopTimeUpdate, column, task)
|
|
3652
|
+
try {
|
|
3653
|
+
const gtfsRealtimeData = await downloadGtfsRealtimeData(
|
|
3654
|
+
task.realtimeTripUpdates,
|
|
3655
|
+
task
|
|
3656
|
+
);
|
|
3657
|
+
if (gtfsRealtimeData?.entity) {
|
|
3658
|
+
task.log(`Download successful`);
|
|
3659
|
+
let totalLineCount = 0;
|
|
3660
|
+
for (const entity of gtfsRealtimeData.entity) {
|
|
3661
|
+
const fieldValues = tripUpdates.schema.map(
|
|
3662
|
+
(column) => prepareRealtimeValue(entity, column, task)
|
|
3661
3663
|
);
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3664
|
+
try {
|
|
3665
|
+
db.prepare(
|
|
3666
|
+
`REPLACE INTO ${tripUpdates.filenameBase} (${tripUpdates.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
3667
|
+
).run();
|
|
3668
|
+
} catch (error) {
|
|
3669
|
+
task.logWarning("Import error: " + error.message);
|
|
3670
|
+
}
|
|
3671
|
+
const stopTimeUpdateArray = [];
|
|
3672
|
+
for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {
|
|
3673
|
+
stopTimeUpdate.parent = entity;
|
|
3674
|
+
const subValues = stopTimeUpdates.schema.map(
|
|
3675
|
+
(column) => prepareRealtimeValue(stopTimeUpdate, column, task)
|
|
3676
|
+
);
|
|
3677
|
+
stopTimeUpdateArray.push(`(${subValues.join(", ")})`);
|
|
3678
|
+
totalLineCount++;
|
|
3679
|
+
}
|
|
3680
|
+
try {
|
|
3681
|
+
db.prepare(
|
|
3682
|
+
`REPLACE INTO ${stopTimeUpdates.filenameBase} (${stopTimeUpdates.schema.map((column) => column.name).join(", ")}) VALUES ${stopTimeUpdateArray.join(", ")}`
|
|
3683
|
+
).run();
|
|
3684
|
+
} catch (error) {
|
|
3685
|
+
task.logWarning("Import error: " + error.message);
|
|
3686
|
+
}
|
|
3687
|
+
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
3671
3688
|
}
|
|
3672
|
-
|
|
3689
|
+
}
|
|
3690
|
+
} catch (error) {
|
|
3691
|
+
if (task.ignoreErrors) {
|
|
3692
|
+
task.logError(error.message);
|
|
3693
|
+
} else {
|
|
3694
|
+
throw error;
|
|
3673
3695
|
}
|
|
3674
3696
|
}
|
|
3675
3697
|
}
|
|
3676
3698
|
if (task.realtimeVehiclePositions?.url) {
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
const
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3699
|
+
try {
|
|
3700
|
+
const gtfsRealtimeData = await downloadGtfsRealtimeData(
|
|
3701
|
+
task.realtimeVehiclePositions,
|
|
3702
|
+
task
|
|
3703
|
+
);
|
|
3704
|
+
if (gtfsRealtimeData?.entity) {
|
|
3705
|
+
task.log(`Download successful`);
|
|
3706
|
+
let totalLineCount = 0;
|
|
3707
|
+
for (const entity of gtfsRealtimeData.entity) {
|
|
3708
|
+
const fieldValues = vehiclePositions.schema.map(
|
|
3709
|
+
(column) => prepareRealtimeValue(entity, column, task)
|
|
3710
|
+
);
|
|
3711
|
+
try {
|
|
3712
|
+
db.prepare(
|
|
3713
|
+
`REPLACE INTO ${vehiclePositions.filenameBase} (${vehiclePositions.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
3714
|
+
).run();
|
|
3715
|
+
} catch (error) {
|
|
3716
|
+
task.logWarning("Import error: " + error.message);
|
|
3717
|
+
}
|
|
3718
|
+
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
3694
3719
|
}
|
|
3695
|
-
|
|
3720
|
+
}
|
|
3721
|
+
} catch (error) {
|
|
3722
|
+
if (task.ignoreErrors) {
|
|
3723
|
+
task.logError(error.message);
|
|
3724
|
+
} else {
|
|
3725
|
+
throw error;
|
|
3696
3726
|
}
|
|
3697
3727
|
}
|
|
3698
3728
|
}
|
|
@@ -3703,6 +3733,9 @@ var getTextFiles = async (folderPath) => {
|
|
|
3703
3733
|
return files.filter((filename) => filename.slice(-3) === "txt");
|
|
3704
3734
|
};
|
|
3705
3735
|
var readFiles = async (task) => {
|
|
3736
|
+
if (!task.path) {
|
|
3737
|
+
throw new Error("No `path` specified in config");
|
|
3738
|
+
}
|
|
3706
3739
|
const gtfsPath = untildify3(task.path);
|
|
3707
3740
|
task.log(`Importing GTFS from ${task.path}\r`);
|
|
3708
3741
|
if (path.extname(gtfsPath) === ".zip") {
|
|
@@ -3999,9 +4032,8 @@ async function importGtfs(initialConfig) {
|
|
|
3999
4032
|
)} using SQLite database at ${config.sqlitePath}`
|
|
4000
4033
|
);
|
|
4001
4034
|
createTables(db);
|
|
4002
|
-
await mapSeries(
|
|
4003
|
-
|
|
4004
|
-
async (agency2) => {
|
|
4035
|
+
await mapSeries(config.agencies, async (agency2) => {
|
|
4036
|
+
try {
|
|
4005
4037
|
const tempPath = temporaryDirectory();
|
|
4006
4038
|
const task = {
|
|
4007
4039
|
exclude: agency2.exclude,
|
|
@@ -4016,6 +4048,7 @@ async function importGtfs(initialConfig) {
|
|
|
4016
4048
|
path: agency2.path,
|
|
4017
4049
|
csvOptions: config.csvOptions || {},
|
|
4018
4050
|
ignoreDuplicates: config.ignoreDuplicates,
|
|
4051
|
+
ignoreErrors: config.ignoreErrors,
|
|
4019
4052
|
sqlitePath: config.sqlitePath,
|
|
4020
4053
|
prefix: agency2.prefix,
|
|
4021
4054
|
currentTimestamp: Math.floor(Date.now() / 1e3),
|
|
@@ -4023,23 +4056,21 @@ async function importGtfs(initialConfig) {
|
|
|
4023
4056
|
logWarning: logWarning2,
|
|
4024
4057
|
logError: logError2
|
|
4025
4058
|
};
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
throw error;
|
|
4039
|
-
}
|
|
4059
|
+
if (task.url) {
|
|
4060
|
+
await downloadFiles(task);
|
|
4061
|
+
}
|
|
4062
|
+
await readFiles(task);
|
|
4063
|
+
await importFiles(task);
|
|
4064
|
+
await updateRealtimeData(task);
|
|
4065
|
+
await rm2(tempPath, { recursive: true });
|
|
4066
|
+
} catch (error) {
|
|
4067
|
+
if (config.ignoreErrors) {
|
|
4068
|
+
logError2(error.message);
|
|
4069
|
+
} else {
|
|
4070
|
+
throw error;
|
|
4040
4071
|
}
|
|
4041
4072
|
}
|
|
4042
|
-
);
|
|
4073
|
+
});
|
|
4043
4074
|
log2(
|
|
4044
4075
|
`Completed GTFS import for ${pluralize("agency", agencyCount, true)}
|
|
4045
4076
|
`
|
|
@@ -4070,14 +4101,15 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
4070
4101
|
)} using SQLite database at ${config.sqlitePath}`
|
|
4071
4102
|
);
|
|
4072
4103
|
deleteExpiredRealtimeData(config);
|
|
4073
|
-
await
|
|
4074
|
-
|
|
4104
|
+
await mapSeries(config.agencies, async (agency2) => {
|
|
4105
|
+
try {
|
|
4075
4106
|
const task = {
|
|
4076
4107
|
realtimeAlerts: agency2.realtimeAlerts,
|
|
4077
4108
|
realtimeTripUpdates: agency2.realtimeTripUpdates,
|
|
4078
4109
|
realtimeVehiclePositions: agency2.realtimeVehiclePositions,
|
|
4079
4110
|
downloadTimeout: config.downloadTimeout,
|
|
4080
4111
|
gtfsRealtimeExpirationSeconds: config.gtfsRealtimeExpirationSeconds,
|
|
4112
|
+
ignoreErrors: config.ignoreErrors,
|
|
4081
4113
|
sqlitePath: config.sqlitePath,
|
|
4082
4114
|
currentTimestamp: Math.floor(Date.now() / 1e3),
|
|
4083
4115
|
log: log2,
|
|
@@ -4085,8 +4117,14 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
4085
4117
|
logError: logError2
|
|
4086
4118
|
};
|
|
4087
4119
|
await updateRealtimeData(task);
|
|
4088
|
-
})
|
|
4089
|
-
|
|
4120
|
+
} catch (error) {
|
|
4121
|
+
if (config.ignoreErrors) {
|
|
4122
|
+
logError2(error.message);
|
|
4123
|
+
} else {
|
|
4124
|
+
throw error;
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
});
|
|
4090
4128
|
log2(
|
|
4091
4129
|
`Completed GTFS-Realtime refresh for ${pluralize(
|
|
4092
4130
|
"agencies",
|