@tmlmobilidade/generate-offer-files 20251021.1643.15 → 20251229.1536.41
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/index.d.ts +2 -0
- package/dist/index.js +11 -11
- package/dist/main.d.ts +2 -0
- package/dist/main.js +49 -48
- package/dist/types.d.ts +94 -0
- package/package.json +18 -16
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/* * */
|
|
3
3
|
import { generateOfferOutput } from './main.js';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import { ASCII_CM_SHORT } from '@tmlmobilidade/consts';
|
|
5
|
+
import { Logger } from '@tmlmobilidade/logger';
|
|
6
6
|
import { validateOperationalDate } from '@tmlmobilidade/types';
|
|
7
7
|
import { Command } from 'commander';
|
|
8
8
|
import fs from 'fs';
|
|
@@ -30,29 +30,29 @@ import fs from 'fs';
|
|
|
30
30
|
options.endDate = validateOperationalDate(options.endDate);
|
|
31
31
|
}
|
|
32
32
|
catch (error) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
Logger.divider();
|
|
34
|
+
Logger.error(`--start-date and/or --end-date are not valid:`, error.message);
|
|
35
|
+
Logger.divider();
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
//
|
|
39
39
|
// Ensure the output directory exists and is empty
|
|
40
40
|
if (fs.existsSync(options.outputDir) && !options.override) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
Logger.divider();
|
|
42
|
+
Logger.error(`Output directory "${options.outputDir}" already exists. Please remove it or change it before running the script.`);
|
|
43
|
+
Logger.divider();
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
if (fs.existsSync(options.outputDir) && options.override) {
|
|
47
|
-
|
|
47
|
+
Logger.info(`Output directory "${options.outputDir}" already exists. It will be overridden.`);
|
|
48
48
|
fs.rmSync(options.outputDir, { recursive: true });
|
|
49
49
|
}
|
|
50
50
|
fs.mkdirSync(options.outputDir, { recursive: true });
|
|
51
51
|
//
|
|
52
52
|
// Log the ASCII art
|
|
53
|
-
|
|
53
|
+
Logger.spacer(3);
|
|
54
54
|
console.log(ASCII_CM_SHORT);
|
|
55
|
-
|
|
55
|
+
Logger.spacer(3);
|
|
56
56
|
//
|
|
57
57
|
// Start the offer generation process
|
|
58
58
|
await generateOfferOutput(options.file, options.startDate, options.endDate, options.outputDir, options.feedId);
|
package/dist/main.d.ts
ADDED
package/dist/main.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* * */
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import { Dates, getOperationalDatesFromRange } from '@tmlmobilidade/dates';
|
|
3
|
+
import { toMetersFromKilometersOrMeters } from '@tmlmobilidade/geo';
|
|
4
|
+
import { Logger } from '@tmlmobilidade/logger';
|
|
5
|
+
import { Timer } from '@tmlmobilidade/timer';
|
|
5
6
|
import { validateGtfsCalendar, validateGtfsCalendarDate, validateGtfsRouteExtended, validateGtfsStopExtended, validateGtfsStopTime, validateGtfsTripExtended } from '@tmlmobilidade/types';
|
|
6
|
-
import {
|
|
7
|
+
import { JsonWriter } from '@tmlmobilidade/writers';
|
|
7
8
|
import { parse as csvParser } from 'csv-parse';
|
|
8
9
|
import extract from 'extract-zip';
|
|
9
10
|
import fs from 'fs';
|
|
@@ -11,8 +12,8 @@ import fs from 'fs';
|
|
|
11
12
|
export async function generateOfferOutput(filePath, startDate, endDate, outputDir, feedId) {
|
|
12
13
|
try {
|
|
13
14
|
//
|
|
14
|
-
|
|
15
|
-
const globalTimer = new
|
|
15
|
+
Logger.init();
|
|
16
|
+
const globalTimer = new Timer();
|
|
16
17
|
//
|
|
17
18
|
// Setup the JSON batch writers to speed up the writing process and
|
|
18
19
|
// reduce the number of filesystem operations. These writers keep data
|
|
@@ -39,20 +40,20 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
39
40
|
try {
|
|
40
41
|
fs.rmSync(workdirPath, { recursive: true });
|
|
41
42
|
fs.mkdirSync(workdirPath, { recursive: true });
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
Logger.success('Prepared working directory.');
|
|
44
|
+
Logger.spacer(1);
|
|
44
45
|
}
|
|
45
46
|
catch (error) {
|
|
46
|
-
|
|
47
|
+
Logger.error(`Error preparing workdir path "${workdirPath}".`, error);
|
|
47
48
|
process.exit(1);
|
|
48
49
|
}
|
|
49
50
|
try {
|
|
50
51
|
await unzipFile(filePath, extractDirPath);
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
Logger.success(`Unzipped GTFS file from "${filePath}" to "${extractDirPath}".`);
|
|
53
|
+
Logger.spacer(1);
|
|
53
54
|
}
|
|
54
55
|
catch (error) {
|
|
55
|
-
|
|
56
|
+
Logger.error('Error unzipping the file.', error);
|
|
56
57
|
process.exit(1);
|
|
57
58
|
}
|
|
58
59
|
//
|
|
@@ -71,7 +72,7 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
71
72
|
// that are valid between the given start_date and end_date.
|
|
72
73
|
try {
|
|
73
74
|
//
|
|
74
|
-
|
|
75
|
+
Logger.info(`Reading zip entry "calendar.txt"...`);
|
|
75
76
|
const parseEachRow = async (data) => {
|
|
76
77
|
//
|
|
77
78
|
//
|
|
@@ -120,17 +121,17 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
120
121
|
// Setup the CSV parsing operation only if the file exists
|
|
121
122
|
if (fs.existsSync(`${extractDirPath}/calendar.txt`)) {
|
|
122
123
|
await parseCsvFile(`${extractDirPath}/calendar.txt`, parseEachRow);
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
Logger.success(`Finished processing "calendar.txt"`);
|
|
125
|
+
Logger.spacer(1);
|
|
125
126
|
}
|
|
126
127
|
else {
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
Logger.info(`Optional file "calendar.txt" not found. This may or may not be an error. Proceeding...`);
|
|
129
|
+
Logger.spacer(1);
|
|
129
130
|
}
|
|
130
131
|
//
|
|
131
132
|
}
|
|
132
133
|
catch (error) {
|
|
133
|
-
|
|
134
|
+
Logger.error('Error processing "calendar.txt" file.', error);
|
|
134
135
|
throw new Error('✖︎ Error processing "calendar.txt" file.');
|
|
135
136
|
}
|
|
136
137
|
/* * */
|
|
@@ -141,7 +142,7 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
141
142
|
// present in calendar.txt and are between the given start and end dates.
|
|
142
143
|
try {
|
|
143
144
|
//
|
|
144
|
-
|
|
145
|
+
Logger.info(`Reading zip entry "calendar_dates.txt"...`);
|
|
145
146
|
const parseEachRow = async (data) => {
|
|
146
147
|
//
|
|
147
148
|
//
|
|
@@ -180,17 +181,17 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
180
181
|
// Setup the CSV parsing operation only if the file exists
|
|
181
182
|
if (fs.existsSync(`${extractDirPath}/calendar_dates.txt`)) {
|
|
182
183
|
await parseCsvFile(`${extractDirPath}/calendar_dates.txt`, parseEachRow);
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
Logger.success(`Finished processing "calendar_dates.txt"`);
|
|
185
|
+
Logger.spacer(1);
|
|
185
186
|
}
|
|
186
187
|
else {
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
Logger.info(`Optional file "calendar_dates.txt" not found. This may or may not be an error. Proceeding...`);
|
|
189
|
+
Logger.spacer(1);
|
|
189
190
|
}
|
|
190
191
|
//
|
|
191
192
|
}
|
|
192
193
|
catch (error) {
|
|
193
|
-
|
|
194
|
+
Logger.error('Error processing "calendar_dates.txt" file.', error);
|
|
194
195
|
throw new Error('✖︎ Error processing "calendar_dates.txt" file.');
|
|
195
196
|
}
|
|
196
197
|
/* * */
|
|
@@ -201,7 +202,7 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
201
202
|
// Only include trips which have the referenced service IDs saved before.
|
|
202
203
|
try {
|
|
203
204
|
//
|
|
204
|
-
|
|
205
|
+
Logger.info(`Reading zip entry "trips.txt"...`);
|
|
205
206
|
const parseEachRow = async (data) => {
|
|
206
207
|
// Validate the current row against the proper type
|
|
207
208
|
const validatedData = validateGtfsTripExtended(data);
|
|
@@ -217,12 +218,12 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
217
218
|
//
|
|
218
219
|
// Setup the CSV parsing operation
|
|
219
220
|
await parseCsvFile(`${extractDirPath}/trips.txt`, parseEachRow);
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
Logger.success(`Finished processing "trips.txt"`);
|
|
222
|
+
Logger.spacer(1);
|
|
222
223
|
//
|
|
223
224
|
}
|
|
224
225
|
catch (error) {
|
|
225
|
-
|
|
226
|
+
Logger.error('Error processing "trips.txt" file.', error);
|
|
226
227
|
throw new Error('✖︎ Error processing "trips.txt" file.');
|
|
227
228
|
}
|
|
228
229
|
/* * */
|
|
@@ -232,7 +233,7 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
232
233
|
// For routes, only include the ones referenced in the filtered trips.
|
|
233
234
|
try {
|
|
234
235
|
//
|
|
235
|
-
|
|
236
|
+
Logger.info(`Reading zip entry "routes.txt"...`);
|
|
236
237
|
const parseEachRow = async (data) => {
|
|
237
238
|
// Validate the current row against the proper type
|
|
238
239
|
const validatedData = validateGtfsRouteExtended(data);
|
|
@@ -246,12 +247,12 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
246
247
|
//
|
|
247
248
|
// Setup the CSV parsing operation
|
|
248
249
|
await parseCsvFile(`${extractDirPath}/routes.txt`, parseEachRow);
|
|
249
|
-
|
|
250
|
-
|
|
250
|
+
Logger.success(`Finished processing "routes.txt"`);
|
|
251
|
+
Logger.spacer(1);
|
|
251
252
|
//
|
|
252
253
|
}
|
|
253
254
|
catch (error) {
|
|
254
|
-
|
|
255
|
+
Logger.error('Error processing "routes.txt" file.', error);
|
|
255
256
|
throw new Error('✖︎ Error processing "routes.txt" file.');
|
|
256
257
|
}
|
|
257
258
|
/* * */
|
|
@@ -262,7 +263,7 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
262
263
|
// By saving all of them, we also speed up the processing of each stop_time by including the stop data right away.
|
|
263
264
|
try {
|
|
264
265
|
//
|
|
265
|
-
|
|
266
|
+
Logger.info(`Reading zip entry "stops.txt"...`);
|
|
266
267
|
const parseEachRow = async (data) => {
|
|
267
268
|
// Validate the current row against the proper type
|
|
268
269
|
const validatedData = validateGtfsStopExtended(data);
|
|
@@ -272,12 +273,12 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
272
273
|
//
|
|
273
274
|
// Setup the CSV parsing operation
|
|
274
275
|
await parseCsvFile(`${extractDirPath}/stops.txt`, parseEachRow);
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
Logger.success(`Finished processing "stops.txt"`);
|
|
277
|
+
Logger.spacer(1);
|
|
277
278
|
//
|
|
278
279
|
}
|
|
279
280
|
catch (error) {
|
|
280
|
-
|
|
281
|
+
Logger.error('Error processing "stops.txt" file.', error);
|
|
281
282
|
throw new Error('✖︎ Error processing "stops.txt" file.');
|
|
282
283
|
}
|
|
283
284
|
/* * */
|
|
@@ -289,7 +290,7 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
289
290
|
// right away to avoid another lookup later.
|
|
290
291
|
try {
|
|
291
292
|
//
|
|
292
|
-
|
|
293
|
+
Logger.info(`Reading zip entry "stop_times.txt"...`);
|
|
293
294
|
const parseEachRow = async (data) => {
|
|
294
295
|
//
|
|
295
296
|
//
|
|
@@ -318,12 +319,12 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
318
319
|
//
|
|
319
320
|
// Setup the CSV parsing operation
|
|
320
321
|
await parseCsvFile(`${extractDirPath}/stop_times.txt`, parseEachRow);
|
|
321
|
-
|
|
322
|
-
|
|
322
|
+
Logger.success(`Finished processing "stop_times.txt"`);
|
|
323
|
+
Logger.spacer(1);
|
|
323
324
|
//
|
|
324
325
|
}
|
|
325
326
|
catch (error) {
|
|
326
|
-
|
|
327
|
+
Logger.error('Error processing "stop_times.txt" file.', error);
|
|
327
328
|
throw new Error('✖︎ Error processing "stop_times.txt" file.');
|
|
328
329
|
}
|
|
329
330
|
/* * */
|
|
@@ -341,7 +342,7 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
341
342
|
const stopTimesData = savedStopTimes.get(currentTrip.trip_id);
|
|
342
343
|
const routeData = savedRoutes.get(currentTrip.route_id);
|
|
343
344
|
if (!stopTimesData || stopTimesData.length === 0) {
|
|
344
|
-
|
|
345
|
+
Logger.error(`Trip ${currentTrip.trip_id} has no path data. Skipping...`);
|
|
345
346
|
continue;
|
|
346
347
|
}
|
|
347
348
|
//
|
|
@@ -474,21 +475,21 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
|
|
|
474
475
|
//
|
|
475
476
|
}
|
|
476
477
|
catch (error) {
|
|
477
|
-
|
|
478
|
+
Logger.error('Error transforming or saving Offer documents.', error);
|
|
478
479
|
throw new Error('✖︎ Error transforming or saving Offer documents.');
|
|
479
480
|
}
|
|
480
481
|
//
|
|
481
482
|
offerStopsWriter.close();
|
|
482
483
|
offerJourneysWriter.close();
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
484
|
+
Logger.spacer(1);
|
|
485
|
+
Logger.success(`Total OfferJourneys written: ${totalOfferJourneysCounter}`);
|
|
486
|
+
Logger.success(`Total OfferStops written: ${totalOfferStopsCounter}`);
|
|
487
|
+
Logger.terminate(`Finished processing GTFS file. Run took ${globalTimer.get()}`);
|
|
487
488
|
//
|
|
488
489
|
}
|
|
489
490
|
catch (error) {
|
|
490
|
-
|
|
491
|
-
|
|
491
|
+
Logger.error('An error occurred. Halting execution.', error);
|
|
492
|
+
Logger.error('Retrying in 10 seconds...');
|
|
492
493
|
setTimeout(() => {
|
|
493
494
|
process.exit(0); // End process
|
|
494
495
|
}, 10000); // after 10 seconds
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export interface OfferJourney {
|
|
2
|
+
agencyId: string;
|
|
3
|
+
arrivalTime: string;
|
|
4
|
+
bikesAllowed: number;
|
|
5
|
+
blockId: string;
|
|
6
|
+
circular: number;
|
|
7
|
+
continuousDropOff: number;
|
|
8
|
+
continuousPickup: number;
|
|
9
|
+
date: string;
|
|
10
|
+
dayType: number;
|
|
11
|
+
dayTypeName: string;
|
|
12
|
+
departureTime: string;
|
|
13
|
+
directionId: number;
|
|
14
|
+
endShiftId: string;
|
|
15
|
+
endStopCode: string;
|
|
16
|
+
endStopId: string;
|
|
17
|
+
endStopName: string;
|
|
18
|
+
feedId: string;
|
|
19
|
+
holiday: number;
|
|
20
|
+
holidayName: string;
|
|
21
|
+
lineId: string;
|
|
22
|
+
lineLongName: string;
|
|
23
|
+
lineShortName: string;
|
|
24
|
+
pathType: number;
|
|
25
|
+
patternId: string;
|
|
26
|
+
patternShortName: string;
|
|
27
|
+
period: number;
|
|
28
|
+
periodName: string;
|
|
29
|
+
routeColor: string;
|
|
30
|
+
routeDesc: string;
|
|
31
|
+
routeDestination: string;
|
|
32
|
+
routeId: string;
|
|
33
|
+
routeLongName: string;
|
|
34
|
+
routeOrigin: string;
|
|
35
|
+
routeShortName: string;
|
|
36
|
+
routeTextColor: string;
|
|
37
|
+
routeType: string;
|
|
38
|
+
rowId: number;
|
|
39
|
+
school: string;
|
|
40
|
+
shapeId: string;
|
|
41
|
+
startShiftId: string;
|
|
42
|
+
startStopCode: string;
|
|
43
|
+
startStopId: string;
|
|
44
|
+
startStopName: string;
|
|
45
|
+
tripHeadsign: string;
|
|
46
|
+
tripId: string;
|
|
47
|
+
tripLength: number;
|
|
48
|
+
wheelchairAccessible: number;
|
|
49
|
+
}
|
|
50
|
+
export interface OfferStop {
|
|
51
|
+
arrivalTime: string;
|
|
52
|
+
bench: number;
|
|
53
|
+
continuousDropOff: number;
|
|
54
|
+
continuousPickup: number;
|
|
55
|
+
date: string;
|
|
56
|
+
departureTime: string;
|
|
57
|
+
dropOffType: number;
|
|
58
|
+
entranceRestriction: number;
|
|
59
|
+
equipment: number;
|
|
60
|
+
exitRestriction: number;
|
|
61
|
+
feedId: string;
|
|
62
|
+
locationType: number;
|
|
63
|
+
municipality: number;
|
|
64
|
+
municipalityFare1: null;
|
|
65
|
+
municipalityFare2: null;
|
|
66
|
+
networkMap: number;
|
|
67
|
+
parentStation: string;
|
|
68
|
+
pickupType: number;
|
|
69
|
+
platformCode: string;
|
|
70
|
+
preservationState: number;
|
|
71
|
+
realTimeInformation: number;
|
|
72
|
+
region: string;
|
|
73
|
+
rowId: number;
|
|
74
|
+
schedule: number;
|
|
75
|
+
shapeDistTraveled: number;
|
|
76
|
+
shelter: number;
|
|
77
|
+
signalling: number;
|
|
78
|
+
slot: number;
|
|
79
|
+
stopCode: string;
|
|
80
|
+
stopDesc: string;
|
|
81
|
+
stopHeadsign: string;
|
|
82
|
+
stopId: string;
|
|
83
|
+
stopIdStepp: string;
|
|
84
|
+
stopLat: number;
|
|
85
|
+
stopLon: number;
|
|
86
|
+
stopName: string;
|
|
87
|
+
stopRemarks: string;
|
|
88
|
+
stopSequence: number;
|
|
89
|
+
tariff: number;
|
|
90
|
+
timepoint: number;
|
|
91
|
+
tripId: string;
|
|
92
|
+
wheelchairBoarding: number;
|
|
93
|
+
zoneShift: number;
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,45 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tmlmobilidade/generate-offer-files",
|
|
3
3
|
"description": "A CLI tool to generate legacy offer files for TML Mobilidade.",
|
|
4
|
-
"version": "
|
|
5
|
-
"author":
|
|
4
|
+
"version": "20251229.1536.41",
|
|
5
|
+
"author": {
|
|
6
|
+
"email": "iso@tmlmobilidade.pt",
|
|
7
|
+
"name": "TML-ISO"
|
|
8
|
+
},
|
|
6
9
|
"license": "AGPL-3.0-or-later",
|
|
7
10
|
"type": "module",
|
|
8
11
|
"files": [
|
|
9
12
|
"dist"
|
|
10
13
|
],
|
|
11
|
-
"main": "dist/index.js",
|
|
14
|
+
"main": "./dist/index.js",
|
|
12
15
|
"bin": {
|
|
13
16
|
"generate-offer-files": "dist/index.js"
|
|
14
17
|
},
|
|
15
|
-
"types": "dist/index.d.ts",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
16
19
|
"scripts": {
|
|
17
|
-
"build": "
|
|
18
|
-
"
|
|
19
|
-
"dev": "tsx watch ./src/index.ts",
|
|
20
|
+
"build": "tsc && resolve-tspaths",
|
|
21
|
+
"dev": "tsx watch src/index.ts",
|
|
20
22
|
"lint": "eslint .",
|
|
21
23
|
"lint:fix": "eslint . --fix",
|
|
22
24
|
"start": "tsc && resolve-tspaths && node dist/index.js"
|
|
23
25
|
},
|
|
24
26
|
"dependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"@
|
|
27
|
-
"@helperkits/writer": "20251010.1959.27",
|
|
27
|
+
"@tmlmobilidade/consts": "*",
|
|
28
|
+
"@tmlmobilidade/geo": "*",
|
|
28
29
|
"@tmlmobilidade/interfaces": "*",
|
|
29
|
-
"@tmlmobilidade/
|
|
30
|
+
"@tmlmobilidade/logger": "*",
|
|
31
|
+
"@tmlmobilidade/timer": "*",
|
|
30
32
|
"@tmlmobilidade/utils": "*",
|
|
31
|
-
"
|
|
33
|
+
"@tmlmobilidade/writers": "*",
|
|
34
|
+
"commander": "14.0.2",
|
|
32
35
|
"csv-parse": "6.1.0",
|
|
33
36
|
"extract-zip": "2.0.1",
|
|
34
37
|
"gtfs-types": "5.1.0"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
|
-
"@carrismetropolitana/eslint": "20250622.1204.50",
|
|
38
40
|
"@tmlmobilidade/tsconfig": "*",
|
|
39
41
|
"@tmlmobilidade/types": "*",
|
|
40
|
-
"@types/node": "
|
|
42
|
+
"@types/node": "25.0.3",
|
|
41
43
|
"resolve-tspaths": "0.8.23",
|
|
42
|
-
"tsx": "4.
|
|
44
|
+
"tsx": "4.21.0",
|
|
43
45
|
"typescript": "5.9.3"
|
|
44
46
|
}
|
|
45
|
-
}
|
|
47
|
+
}
|