transit-departures-widget 2.7.2 → 2.8.0

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
@@ -54,6 +54,7 @@ An demo of the widget is available at https://transit-departures-widget.blinktag
54
54
 
55
55
  The following transit agencies use `transit-departures-widget` on their websites:
56
56
 
57
+ - [Cascades East Transit](https://cascadeseasttransit.com)
57
58
  - [County Connection](https://countyconnection.com)
58
59
  - [Kings Area Regional Transit](https://kartbus.org)
59
60
  - [Marin Transit](https://marintransit.org/)
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ export { };
package/dist/app/index.js CHANGED
@@ -1,578 +1,107 @@
1
- // src/app/index.ts
2
- import { dirname as dirname2, join as join3 } from "path";
3
- import { fileURLToPath as fileURLToPath2 } from "url";
4
- import { readFileSync } from "fs";
1
+ import { c as getPathToViewsFolder, n as generateTransitDeparturesWidgetJson, r as setDefaultConfig, t as generateTransitDeparturesWidgetHtml } from "../utils-BxiS6d7j.js";
2
+ import { clone, omit } from "lodash-es";
3
+ import { importGtfs, openDb } from "gtfs";
4
+ import untildify from "untildify";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
5
7
  import yargs from "yargs";
6
8
  import { hideBin } from "yargs/helpers";
7
- import { openDb as openDb2, importGtfs } from "gtfs";
9
+ import { readFileSync } from "node:fs";
8
10
  import express from "express";
9
- import { clone, omit } from "lodash-es";
10
- import untildify2 from "untildify";
11
-
12
- // src/lib/file-utils.ts
13
- import { dirname, join, resolve } from "path";
14
- import { fileURLToPath } from "url";
15
- import {
16
- access,
17
- cp,
18
- copyFile,
19
- mkdir,
20
- readdir,
21
- readFile,
22
- rm
23
- } from "fs/promises";
24
- import beautify from "js-beautify";
25
- import pug from "pug";
26
- import untildify from "untildify";
27
- function getPathToThisModuleFolder() {
28
- const __dirname = dirname(fileURLToPath(import.meta.url));
29
- let distFolderPath;
30
- if (__dirname.endsWith("/dist/bin") || __dirname.endsWith("/dist/app")) {
31
- distFolderPath = resolve(__dirname, "../../");
32
- } else if (__dirname.endsWith("/dist")) {
33
- distFolderPath = resolve(__dirname, "../");
34
- } else {
35
- distFolderPath = resolve(__dirname, "../../");
36
- }
37
- return distFolderPath;
38
- }
39
- function getPathToViewsFolder(config2) {
40
- if (config2.templatePath) {
41
- return untildify(config2.templatePath);
42
- }
43
- return join(getPathToThisModuleFolder(), "views/widget");
44
- }
45
- function getPathToTemplateFile(templateFileName, config2) {
46
- const fullTemplateFileName = config2.noHead !== true ? `${templateFileName}_full.pug` : `${templateFileName}.pug`;
47
- return join(getPathToViewsFolder(config2), fullTemplateFileName);
48
- }
49
- async function renderFile(templateFileName, templateVars, config2) {
50
- const templatePath = getPathToTemplateFile(templateFileName, config2);
51
- const html = await pug.renderFile(templatePath, templateVars);
52
- if (config2.beautify === true) {
53
- return beautify.html_beautify(html, { indent_size: 2 });
54
- }
55
- return html;
56
- }
57
-
58
- // src/lib/utils.ts
59
- import { openDb, getDirections, getRoutes, getStops, getTrips } from "gtfs";
60
- import { groupBy, last, maxBy, size, sortBy, uniqBy } from "lodash-es";
61
- import sqlString from "sqlstring-sqlite";
62
- import toposort from "toposort";
63
-
64
- // src/lib/logging/log.ts
65
- import { clearLine, cursorTo } from "readline";
66
- import { noop } from "lodash-es";
67
- import * as colors from "yoctocolors";
68
- var formatWarning = (text) => {
69
- const warningMessage = `${colors.underline("Warning")}: ${text}`;
70
- return colors.yellow(warningMessage);
71
- };
72
- var formatError = (error) => {
73
- const messageText = error instanceof Error ? error.message : error;
74
- const errorMessage = `${colors.underline("Error")}: ${messageText.replace(
75
- "Error: ",
76
- ""
77
- )}`;
78
- return colors.red(errorMessage);
79
- };
80
- var logInfo = (config2) => {
81
- if (config2.verbose === false) {
82
- return noop;
83
- }
84
- if (config2.logFunction) {
85
- return config2.logFunction;
86
- }
87
- return (text, overwrite) => {
88
- if (overwrite === true && process.stdout.isTTY) {
89
- clearLine(process.stdout, 0);
90
- cursorTo(process.stdout, 0);
91
- } else {
92
- process.stdout.write("\n");
93
- }
94
- process.stdout.write(text);
95
- };
96
- };
97
- var logWarn = (config2) => {
98
- if (config2.logFunction) {
99
- return config2.logFunction;
100
- }
101
- return (text) => {
102
- process.stdout.write(`
103
- ${formatWarning(text)}
104
- `);
105
- };
106
- };
107
- var logError = (config2) => {
108
- if (config2.logFunction) {
109
- return config2.logFunction;
110
- }
111
- return (text) => {
112
- process.stdout.write(`
113
- ${formatError(text)}
114
- `);
115
- };
116
- };
117
- function createLogger(config2) {
118
- return {
119
- info: logInfo(config2),
120
- warn: logWarn(config2),
121
- error: logError(config2)
122
- };
123
- }
124
-
125
- // src/lib/logging/messages.ts
126
- var messages = {
127
- noActiveCalendarsGlobal: "No active calendars found for the configured date range - returning empty routes and stops",
128
- noActiveCalendarsForRoute: (routeId) => `route_id ${routeId} has no active calendars in range - skipping directions`,
129
- noActiveCalendarsForDirection: (routeId, directionId) => `route_id ${routeId} direction ${directionId} has no active calendars in range - skipping stops`,
130
- routeHasNoDirections: (routeId) => `route_id ${routeId} has no directions - skipping`,
131
- stopNotFound: (routeId, directionId, stopId) => `stop_id ${stopId} for route ${routeId} direction ${directionId} not found - dropping`
132
- };
133
11
 
134
- // src/lib/config/defaults.ts
135
- import { join as join2 } from "path";
136
- import { I18n } from "i18n";
137
- function setDefaultConfig(initialConfig) {
138
- const defaults = {
139
- beautify: false,
140
- noHead: false,
141
- refreshIntervalSeconds: 20,
142
- skipImport: false,
143
- timeFormat: "12hour",
144
- includeCoordinates: false,
145
- overwriteExistingFiles: true,
146
- verbose: true
147
- };
148
- const config2 = Object.assign(defaults, initialConfig);
149
- const viewsFolderPath = getPathToViewsFolder(config2);
150
- const i18n = new I18n({
151
- directory: join2(viewsFolderPath, "locales"),
152
- defaultLocale: config2.locale,
153
- updateFiles: false
154
- });
155
- const configWithI18n = Object.assign(config2, {
156
- __: i18n.__
157
- });
158
- return configWithI18n;
159
- }
160
-
161
- // src/lib/utils.ts
162
- var getCalendarsForDateRange = (config2) => {
163
- const db = openDb(config2);
164
- let whereClause = "";
165
- const whereClauses = [];
166
- if (config2.endDate) {
167
- whereClauses.push(`start_date <= ${sqlString.escape(config2.endDate)}`);
168
- }
169
- if (config2.startDate) {
170
- whereClauses.push(`end_date >= ${sqlString.escape(config2.startDate)}`);
171
- }
172
- if (whereClauses.length > 0) {
173
- whereClause = `WHERE ${whereClauses.join(" AND ")}`;
174
- }
175
- return db.prepare(`SELECT * FROM calendar ${whereClause}`).all();
176
- };
177
- function formatRouteName(route) {
178
- let routeName = "";
179
- if (route.route_short_name !== null) {
180
- routeName += route.route_short_name;
181
- }
182
- if (route.route_short_name !== null && route.route_long_name !== null) {
183
- routeName += " - ";
184
- }
185
- if (route.route_long_name !== null) {
186
- routeName += route.route_long_name;
187
- }
188
- return routeName;
189
- }
190
- function getDirectionsForRoute(route, config2) {
191
- const logger = createLogger(config2);
192
- const db = openDb(config2);
193
- const directions = getDirections({ route_id: route.route_id }, [
194
- "direction_id",
195
- "direction"
196
- ]).filter((direction) => direction.direction_id !== void 0).map((direction) => ({
197
- direction_id: direction.direction_id,
198
- direction: direction.direction
199
- }));
200
- const calendars = getCalendarsForDateRange(config2);
201
- if (calendars.length === 0) {
202
- logger.warn(messages.noActiveCalendarsForRoute(route.route_id));
203
- return [];
204
- }
205
- if (directions.length === 0) {
206
- const headsigns = db.prepare(
207
- `SELECT direction_id, trip_headsign, count(*) AS count FROM trips WHERE route_id = ? AND service_id IN (${calendars.map((calendar) => `'${calendar.service_id}'`).join(", ")}) GROUP BY direction_id, trip_headsign`
208
- ).all(route.route_id);
209
- for (const group of Object.values(groupBy(headsigns, "direction_id"))) {
210
- const mostCommonHeadsign = maxBy(group, "count");
211
- directions.push({
212
- direction_id: mostCommonHeadsign.direction_id,
213
- direction: config2.__("To {{{headsign}}}", {
214
- headsign: mostCommonHeadsign.trip_headsign
215
- })
216
- });
217
- }
218
- }
219
- return directions;
220
- }
221
- function sortStopIdsBySequence(stoptimes) {
222
- const stoptimesGroupedByTrip = groupBy(stoptimes, "trip_id");
223
- try {
224
- const stopGraph = [];
225
- for (const tripStoptimes of Object.values(stoptimesGroupedByTrip)) {
226
- const sortedStopIds = sortBy(tripStoptimes, "stop_sequence").map(
227
- (stoptime) => stoptime.stop_id
228
- );
229
- for (const [index, stopId] of sortedStopIds.entries()) {
230
- if (index === sortedStopIds.length - 1) {
231
- continue;
232
- }
233
- stopGraph.push([stopId, sortedStopIds[index + 1]]);
234
- }
235
- }
236
- return toposort(
237
- stopGraph
238
- );
239
- } catch {
240
- }
241
- const longestTripStoptimes = maxBy(
242
- Object.values(stoptimesGroupedByTrip),
243
- (stoptimes2) => size(stoptimes2)
244
- );
245
- if (!longestTripStoptimes) {
246
- return [];
247
- }
248
- return longestTripStoptimes.map((stoptime) => stoptime.stop_id);
249
- }
250
- function getStopsForDirection(route, direction, config2, stopCache) {
251
- const logger = createLogger(config2);
252
- const db = openDb(config2);
253
- const calendars = getCalendarsForDateRange(config2);
254
- if (calendars.length === 0) {
255
- logger.warn(
256
- messages.noActiveCalendarsForDirection(
257
- route.route_id,
258
- direction.direction_id
259
- )
260
- );
261
- return [];
262
- }
263
- const whereClause = formatWhereClauses({
264
- direction_id: direction.direction_id,
265
- route_id: route.route_id,
266
- service_id: calendars.map((calendar) => calendar.service_id)
267
- });
268
- const stoptimes = db.prepare(
269
- `SELECT stop_id, stop_sequence, trip_id FROM stop_times WHERE trip_id IN (SELECT trip_id FROM trips ${whereClause}) ORDER BY stop_sequence ASC`
270
- ).all();
271
- const sortedStopIds = sortStopIdsBySequence(stoptimes);
272
- const deduplicatedStopIds = sortedStopIds.reduce(
273
- (memo, stopId) => {
274
- if (last(memo) !== stopId) {
275
- memo.push(stopId);
276
- }
277
- return memo;
278
- },
279
- []
280
- );
281
- deduplicatedStopIds.pop();
282
- const stopFields = [
283
- "stop_id",
284
- "stop_name",
285
- "stop_code",
286
- "parent_station"
287
- ];
288
- if (config2.includeCoordinates) {
289
- stopFields.push("stop_lat", "stop_lon");
290
- }
291
- const missingStopIds = stopCache ? deduplicatedStopIds.filter((stopId) => !stopCache.has(stopId)) : deduplicatedStopIds;
292
- const fetchedStops = missingStopIds.length ? getStops(
293
- { stop_id: missingStopIds },
294
- stopFields
295
- ) : [];
296
- if (stopCache) {
297
- for (const stop of fetchedStops) {
298
- stopCache.set(stop.stop_id, stop);
299
- }
300
- }
301
- return deduplicatedStopIds.map((stopId) => {
302
- const stop = stopCache?.get(stopId) ?? fetchedStops.find((candidate) => candidate.stop_id === stopId);
303
- if (!stop) {
304
- logger.warn(
305
- messages.stopNotFound(route.route_id, direction.direction_id, stopId)
306
- );
307
- }
308
- return stop;
309
- }).filter(Boolean);
310
- }
311
- function generateTransitDeparturesWidgetHtml(config2) {
312
- const templateVars = {
313
- config: config2,
314
- __: config2.__
315
- };
316
- return renderFile("widget", templateVars, config2);
317
- }
318
- function generateTransitDeparturesWidgetJson(config2) {
319
- const logger = createLogger(config2);
320
- const calendars = getCalendarsForDateRange(config2);
321
- if (calendars.length === 0) {
322
- logger.warn(messages.noActiveCalendarsGlobal);
323
- return { routes: [], stops: [] };
324
- }
325
- const routes = getRoutes();
326
- const stops = [];
327
- const filteredRoutes = [];
328
- const stopCache = /* @__PURE__ */ new Map();
329
- for (const route of routes) {
330
- const routeWithFullName = {
331
- ...route,
332
- route_full_name: formatRouteName(route)
333
- };
334
- const directions = getDirectionsForRoute(routeWithFullName, config2);
335
- if (directions.length === 0) {
336
- logger.warn(messages.routeHasNoDirections(route.route_id));
337
- continue;
338
- }
339
- const directionsWithData = directions.map((direction) => {
340
- const directionStops = getStopsForDirection(
341
- routeWithFullName,
342
- direction,
343
- config2,
344
- stopCache
345
- );
346
- if (directionStops.length === 0) {
347
- return null;
348
- }
349
- stops.push(...directionStops);
350
- const trips = getTrips(
351
- {
352
- route_id: route.route_id,
353
- direction_id: direction.direction_id,
354
- service_id: calendars.map(
355
- (calendar) => calendar.service_id
356
- )
357
- },
358
- ["trip_id"]
359
- );
360
- return {
361
- ...direction,
362
- stopIds: directionStops.map((stop) => stop.stop_id),
363
- tripIds: trips.map((trip) => trip.trip_id)
364
- };
365
- }).filter(Boolean);
366
- if (directionsWithData.length === 0) {
367
- continue;
368
- }
369
- filteredRoutes.push({
370
- ...routeWithFullName,
371
- directions: directionsWithData
372
- });
373
- }
374
- const sortedRoutes = [...filteredRoutes].sort((a, b) => {
375
- const aShort = a.route_short_name ?? "";
376
- const bShort = b.route_short_name ?? "";
377
- const aNum = Number.parseInt(aShort, 10);
378
- const bNum = Number.parseInt(bShort, 10);
379
- if (!Number.isNaN(aNum) && !Number.isNaN(bNum) && aNum !== bNum) {
380
- return aNum - bNum;
381
- }
382
- if (Number.isNaN(aNum) && !Number.isNaN(bNum)) {
383
- return 1;
384
- }
385
- if (!Number.isNaN(aNum) && Number.isNaN(bNum)) {
386
- return -1;
387
- }
388
- return aShort.localeCompare(bShort, void 0, {
389
- numeric: true,
390
- sensitivity: "base"
391
- });
392
- });
393
- const parentStationIds = new Set(stops.map((stop) => stop.parent_station));
394
- const parentStationStops = getStops(
395
- { stop_id: Array.from(parentStationIds) },
396
- ["stop_id", "stop_name", "stop_code", "parent_station"]
397
- );
398
- stops.push(
399
- ...parentStationStops.map((stop) => ({
400
- ...stop,
401
- is_parent_station: true
402
- }))
403
- );
404
- const sortedStops = sortBy(uniqBy(stops, "stop_id"), "stop_name");
405
- return {
406
- routes: arrayOfArrays(removeNulls(sortedRoutes)),
407
- stops: arrayOfArrays(removeNulls(sortedStops))
408
- };
409
- }
410
- function removeNulls(data) {
411
- if (Array.isArray(data)) {
412
- return data.map(removeNulls).filter((item) => item !== null && item !== void 0);
413
- } else if (data !== null && typeof data === "object" && Object.getPrototypeOf(data) === Object.prototype) {
414
- return Object.entries(data).reduce(
415
- (acc, [key, value]) => {
416
- const cleanedValue = removeNulls(value);
417
- if (cleanedValue !== null && cleanedValue !== void 0) {
418
- acc[key] = cleanedValue;
419
- }
420
- return acc;
421
- },
422
- {}
423
- );
424
- } else {
425
- return data;
426
- }
427
- }
428
- function arrayOfArrays(array) {
429
- if (array.length === 0) {
430
- return { fields: [], rows: [] };
431
- }
432
- const fields = Array.from(
433
- array.reduce((fieldSet, item) => {
434
- Object.keys(item ?? {}).forEach((key) => fieldSet.add(key));
435
- return fieldSet;
436
- }, /* @__PURE__ */ new Set())
437
- );
438
- return {
439
- fields,
440
- rows: array.map((item) => fields.map((field) => item?.[field] ?? null))
441
- };
442
- }
443
- function formatWhereClause(key, value) {
444
- if (Array.isArray(value)) {
445
- let whereClause = `${sqlString.escapeId(key)} IN (${value.filter((v) => v !== null).map((v) => sqlString.escape(v)).join(", ")})`;
446
- if (value.includes(null)) {
447
- whereClause = `(${whereClause} OR ${sqlString.escapeId(key)} IS NULL)`;
448
- }
449
- return whereClause;
450
- }
451
- if (value === null) {
452
- return `${sqlString.escapeId(key)} IS NULL`;
453
- }
454
- return `${sqlString.escapeId(key)} = ${sqlString.escape(value)}`;
455
- }
456
- function formatWhereClauses(query) {
457
- if (Object.keys(query).length === 0) {
458
- return "";
459
- }
460
- const whereClauses = Object.entries(query).map(
461
- ([key, value]) => formatWhereClause(key, value)
462
- );
463
- return `WHERE ${whereClauses.join(" AND ")}`;
464
- }
465
-
466
- // src/app/index.ts
467
- var argv = yargs(hideBin(process.argv)).option("c", {
468
- alias: "configPath",
469
- describe: "Path to config file",
470
- default: "./config.json",
471
- type: "string"
12
+ //#region src/app/index.ts
13
+ const argv = yargs(hideBin(process.argv)).option("c", {
14
+ alias: "configPath",
15
+ describe: "Path to config file",
16
+ default: "./config.json",
17
+ type: "string"
472
18
  }).parseSync();
473
- var app = express();
474
- var configPath = argv.configPath || join3(process.cwd(), "config.json");
475
- var selectedConfig = JSON.parse(readFileSync(configPath, "utf8"));
476
- var config = setDefaultConfig(selectedConfig);
19
+ const app = express();
20
+ const configPath = argv.configPath || join(process.cwd(), "config.json");
21
+ const config = setDefaultConfig(JSON.parse(readFileSync(configPath, "utf8")));
477
22
  config.noHead = false;
478
23
  config.assetPath = "/";
479
24
  config.logFunction = console.log;
480
25
  try {
481
- openDb2(config);
482
- const gtfsPath = config.agency.gtfs_static_path;
483
- const gtfsUrl = config.agency.gtfs_static_url;
484
- if (!gtfsPath && !gtfsUrl) {
485
- throw new Error(
486
- "Missing GTFS source. Set `agency.gtfs_static_path` or `agency.gtfs_static_url` in config.json."
487
- );
488
- }
489
- const agencyImportConfig = gtfsPath ? { path: gtfsPath } : { url: gtfsUrl };
490
- const gtfsImportConfig = {
491
- ...clone(omit(config, "agency")),
492
- agencies: [agencyImportConfig]
493
- };
494
- await importGtfs(gtfsImportConfig);
26
+ openDb(config);
27
+ const gtfsPath = config.agency.gtfs_static_path;
28
+ const gtfsUrl = config.agency.gtfs_static_url;
29
+ if (!gtfsPath && !gtfsUrl) throw new Error("Missing GTFS source. Set `agency.gtfs_static_path` or `agency.gtfs_static_url` in config.json.");
30
+ const agencyImportConfig = {
31
+ exclude: config.agency.exclude,
32
+ ...gtfsPath ? { path: gtfsPath } : { url: gtfsUrl }
33
+ };
34
+ await importGtfs({
35
+ ...clone(omit(config, "agency")),
36
+ agencies: [agencyImportConfig]
37
+ });
495
38
  } catch (error) {
496
- console.error(
497
- `Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists and run gtfs-to-html to import GTFS before running this app.`
498
- );
499
- throw error;
39
+ console.error(`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists and run gtfs-to-html to import GTFS before running this app.`);
40
+ throw error;
500
41
  }
501
42
  app.set("views", getPathToViewsFolder(config));
502
43
  app.set("view engine", "pug");
503
44
  app.use((req, res, next) => {
504
- console.log(`${req.method} ${req.url}`);
505
- next();
45
+ console.log(`${req.method} ${req.url}`);
46
+ next();
506
47
  });
507
- var staticAssetPath = config.templatePath === void 0 ? getPathToViewsFolder(config) : untildify2(config.templatePath);
48
+ const staticAssetPath = config.templatePath === void 0 ? getPathToViewsFolder(config) : untildify(config.templatePath);
508
49
  app.use(express.static(staticAssetPath));
509
- var frontendLibraryPaths = [
510
- { route: "/js", package: "pbf", subPath: "dist" },
511
- { route: "/js", package: "gtfs-realtime-pbf-js-module", subPath: "" },
512
- { route: "/js", package: "accessible-autocomplete", subPath: "" },
513
- { route: "/css", package: "accessible-autocomplete", subPath: "" }
514
- ];
515
- var resolvePackagePath = (packageName, subPath) => {
516
- const packagePath = dirname2(fileURLToPath2(import.meta.resolve(packageName)));
517
- return subPath ? join3(packagePath, subPath) : packagePath;
518
- };
519
- for (const { route, package: pkg, subPath } of frontendLibraryPaths) {
520
- app.use(route, express.static(resolvePackagePath(pkg, subPath)));
521
- }
50
+ const browserAssetsPath = join(dirname(fileURLToPath(import.meta.url)), "../browser");
51
+ app.use("/js", express.static(browserAssetsPath));
52
+ app.use("/css", express.static(browserAssetsPath));
522
53
  app.get("/", async (request, response, next) => {
523
- try {
524
- const html = await generateTransitDeparturesWidgetHtml(config);
525
- response.send(html);
526
- } catch (error) {
527
- next(error);
528
- }
54
+ try {
55
+ const html = await generateTransitDeparturesWidgetHtml(config);
56
+ response.send(html);
57
+ } catch (error) {
58
+ next(error);
59
+ }
529
60
  });
530
61
  app.get("/data/routes.json", async (request, response, next) => {
531
- try {
532
- const { routes } = await generateTransitDeparturesWidgetJson(config);
533
- response.json(routes);
534
- } catch (error) {
535
- next(error);
536
- }
62
+ try {
63
+ const { routes } = await generateTransitDeparturesWidgetJson(config);
64
+ response.json(routes);
65
+ } catch (error) {
66
+ next(error);
67
+ }
537
68
  });
538
69
  app.get("/data/stops.json", async (request, response, next) => {
539
- try {
540
- const { stops } = await generateTransitDeparturesWidgetJson(config);
541
- response.json(stops);
542
- } catch (error) {
543
- next(error);
544
- }
70
+ try {
71
+ const { stops } = await generateTransitDeparturesWidgetJson(config);
72
+ response.json(stops);
73
+ } catch (error) {
74
+ next(error);
75
+ }
545
76
  });
546
77
  app.use((req, res) => {
547
- res.status(404).send("Not Found");
78
+ res.status(404).send("Not Found");
548
79
  });
549
- app.use(
550
- (err, req, res, next) => {
551
- console.error(err.stack);
552
- res.status(500).send("Something broke!");
553
- }
554
- );
555
- var startServer = async (port2) => {
556
- try {
557
- await new Promise((resolve2, reject) => {
558
- const server = app.listen(port2).once("listening", () => {
559
- console.log(`Express server listening on port ${port2}`);
560
- resolve2();
561
- }).once("error", (err) => {
562
- if (err.code === "EADDRINUSE") {
563
- console.log(`Port ${port2} is in use, trying ${port2 + 1}`);
564
- server.close();
565
- resolve2(startServer(port2 + 1));
566
- } else {
567
- reject(err);
568
- }
569
- });
570
- });
571
- } catch (err) {
572
- console.error("Failed to start server:", err);
573
- process.exit(1);
574
- }
80
+ app.use((err, req, res, next) => {
81
+ console.error(err.stack);
82
+ res.status(500).send("Something broke!");
83
+ });
84
+ const startServer = async (port) => {
85
+ try {
86
+ await new Promise((resolve, reject) => {
87
+ const server = app.listen(port).once("listening", () => {
88
+ console.log(`Express server listening on port ${port}`);
89
+ resolve();
90
+ }).once("error", (err) => {
91
+ if (err.code === "EADDRINUSE") {
92
+ console.log(`Port ${port} is in use, trying ${port + 1}`);
93
+ server.close();
94
+ resolve(startServer(port + 1));
95
+ } else reject(err);
96
+ });
97
+ });
98
+ } catch (err) {
99
+ console.error("Failed to start server:", err);
100
+ process.exit(1);
101
+ }
575
102
  };
576
- var port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3e3;
577
- startServer(port);
103
+ startServer(process.env.PORT ? parseInt(process.env.PORT, 10) : 3e3);
104
+
105
+ //#endregion
106
+ export { };
578
107
  //# sourceMappingURL=index.js.map