update to express 5

This commit is contained in:
Matt Walsh
2025-04-02 22:34:59 -05:00
parent bd6c5430c4
commit 130a1bfad3
6 changed files with 970 additions and 970 deletions

View File

@@ -12,9 +12,9 @@ const port = process.env.WS4KP_PORT ?? 8080;
app.set('view engine', 'ejs'); app.set('view engine', 'ejs');
// cors pass-thru to api.weather.gov // cors pass-thru to api.weather.gov
app.get('/stations/*', corsPassThru); app.get('/stations/*station', corsPassThru);
app.get('/Conus/*', radarPassThru); app.get('/Conus/*radar', radarPassThru);
app.get('/products/*', outlookPassThru); app.get('/products/*product', outlookPassThru);
app.get('/playlist.json', playlist); app.get('/playlist.json', playlist);
// version // version
@@ -38,7 +38,7 @@ if (process.env?.DIST === '1') {
// debugging // debugging
app.get('/index.html', index); app.get('/index.html', index);
app.get('/', index); app.get('/', index);
app.get('*', express.static('./server')); app.get('*name', express.static('./server'));
} }
const server = app.listen(port, () => { const server = app.listen(port, () => {

1766
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -49,6 +49,6 @@
}, },
"dependencies": { "dependencies": {
"ejs": "^3.1.5", "ejs": "^3.1.5",
"express": "^4.17.1" "express": "^5.1.0"
} }
} }

View File

@@ -131,7 +131,7 @@ class WeatherDisplay {
// get necessary data for this display // get necessary data for this display
getData(weatherParameters, refresh) { getData(weatherParameters, refresh) {
// refresh doesn't delete existing data, and is resued if the silent refresh fails // refresh doesn't delete existing data, and is reused if the silent refresh fails
if (!refresh) { if (!refresh) {
this.data = undefined; this.data = undefined;
} }

File diff suppressed because one or more lines are too long

View File

@@ -392,12 +392,13 @@ class SystemZone extends Zone {
} }
} }
let dtfCache = {}; const dtfCache = new Map();
function makeDTF(zone) { function makeDTF(zoneName) {
if (!dtfCache[zone]) { let dtf = dtfCache.get(zoneName);
dtfCache[zone] = new Intl.DateTimeFormat("en-US", { if (dtf === undefined) {
dtf = new Intl.DateTimeFormat("en-US", {
hour12: false, hour12: false,
timeZone: zone, timeZone: zoneName,
year: "numeric", year: "numeric",
month: "2-digit", month: "2-digit",
day: "2-digit", day: "2-digit",
@@ -406,8 +407,9 @@ function makeDTF(zone) {
second: "2-digit", second: "2-digit",
era: "short", era: "short",
}); });
dtfCache.set(zoneName, dtf);
} }
return dtfCache[zone]; return dtf;
} }
const typeToPos = { const typeToPos = {
@@ -443,7 +445,7 @@ function partsOffset(dtf, date) {
return filled; return filled;
} }
let ianaZoneCache = {}; const ianaZoneCache = new Map();
/** /**
* A zone identified by an IANA identifier, like America/New_York * A zone identified by an IANA identifier, like America/New_York
* @implements {Zone} * @implements {Zone}
@@ -454,10 +456,11 @@ class IANAZone extends Zone {
* @return {IANAZone} * @return {IANAZone}
*/ */
static create(name) { static create(name) {
if (!ianaZoneCache[name]) { let zone = ianaZoneCache.get(name);
ianaZoneCache[name] = new IANAZone(name); if (zone === undefined) {
ianaZoneCache.set(name, (zone = new IANAZone(name)));
} }
return ianaZoneCache[name]; return zone;
} }
/** /**
@@ -465,8 +468,8 @@ class IANAZone extends Zone {
* @return {void} * @return {void}
*/ */
static resetCache() { static resetCache() {
ianaZoneCache = {}; ianaZoneCache.clear();
dtfCache = {}; dtfCache.clear();
} }
/** /**
@@ -569,6 +572,7 @@ class IANAZone extends Zone {
* @return {number} * @return {number}
*/ */
offset(ts) { offset(ts) {
if (!this.valid) return NaN;
const date = new Date(ts); const date = new Date(ts);
if (isNaN(date)) return NaN; if (isNaN(date)) return NaN;
@@ -634,36 +638,36 @@ function getCachedLF(locString, opts = {}) {
return dtf; return dtf;
} }
let intlDTCache = {}; const intlDTCache = new Map();
function getCachedDTF(locString, opts = {}) { function getCachedDTF(locString, opts = {}) {
const key = JSON.stringify([locString, opts]); const key = JSON.stringify([locString, opts]);
let dtf = intlDTCache[key]; let dtf = intlDTCache.get(key);
if (!dtf) { if (dtf === undefined) {
dtf = new Intl.DateTimeFormat(locString, opts); dtf = new Intl.DateTimeFormat(locString, opts);
intlDTCache[key] = dtf; intlDTCache.set(key, dtf);
} }
return dtf; return dtf;
} }
let intlNumCache = {}; const intlNumCache = new Map();
function getCachedINF(locString, opts = {}) { function getCachedINF(locString, opts = {}) {
const key = JSON.stringify([locString, opts]); const key = JSON.stringify([locString, opts]);
let inf = intlNumCache[key]; let inf = intlNumCache.get(key);
if (!inf) { if (inf === undefined) {
inf = new Intl.NumberFormat(locString, opts); inf = new Intl.NumberFormat(locString, opts);
intlNumCache[key] = inf; intlNumCache.set(key, inf);
} }
return inf; return inf;
} }
let intlRelCache = {}; const intlRelCache = new Map();
function getCachedRTF(locString, opts = {}) { function getCachedRTF(locString, opts = {}) {
const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options
const key = JSON.stringify([locString, cacheKeyOpts]); const key = JSON.stringify([locString, cacheKeyOpts]);
let inf = intlRelCache[key]; let inf = intlRelCache.get(key);
if (!inf) { if (inf === undefined) {
inf = new Intl.RelativeTimeFormat(locString, opts); inf = new Intl.RelativeTimeFormat(locString, opts);
intlRelCache[key] = inf; intlRelCache.set(key, inf);
} }
return inf; return inf;
} }
@@ -678,14 +682,28 @@ function systemLocale() {
} }
} }
let weekInfoCache = {}; const intlResolvedOptionsCache = new Map();
function getCachedIntResolvedOptions(locString) {
let opts = intlResolvedOptionsCache.get(locString);
if (opts === undefined) {
opts = new Intl.DateTimeFormat(locString).resolvedOptions();
intlResolvedOptionsCache.set(locString, opts);
}
return opts;
}
const weekInfoCache = new Map();
function getCachedWeekInfo(locString) { function getCachedWeekInfo(locString) {
let data = weekInfoCache[locString]; let data = weekInfoCache.get(locString);
if (!data) { if (!data) {
const locale = new Intl.Locale(locString); const locale = new Intl.Locale(locString);
// browsers currently implement this as a property, but spec says it should be a getter function // browsers currently implement this as a property, but spec says it should be a getter function
data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo; data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo;
weekInfoCache[locString] = data; // minimalDays was removed from WeekInfo: https://github.com/tc39/proposal-intl-locale-info/issues/86
if (!("minimalDays" in data)) {
data = { ...fallbackWeekSettings, ...data };
}
weekInfoCache.set(locString, data);
} }
return data; return data;
} }
@@ -784,7 +802,7 @@ function supportsFastNumbers(loc) {
loc.numberingSystem === "latn" || loc.numberingSystem === "latn" ||
!loc.locale || !loc.locale ||
loc.locale.startsWith("en") || loc.locale.startsWith("en") ||
new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn" getCachedIntResolvedOptions(loc.locale).numberingSystem === "latn"
); );
} }
} }
@@ -943,7 +961,6 @@ const fallbackWeekSettings = {
/** /**
* @private * @private
*/ */
class Locale { class Locale {
static fromOpts(opts) { static fromOpts(opts) {
return Locale.create( return Locale.create(
@@ -967,9 +984,11 @@ class Locale {
static resetCache() { static resetCache() {
sysLocaleCache = null; sysLocaleCache = null;
intlDTCache = {}; intlDTCache.clear();
intlNumCache = {}; intlNumCache.clear();
intlRelCache = {}; intlRelCache.clear();
intlResolvedOptionsCache.clear();
weekInfoCache.clear();
} }
static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) { static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) {
@@ -1123,7 +1142,7 @@ class Locale {
return ( return (
this.locale === "en" || this.locale === "en" ||
this.locale.toLowerCase() === "en-us" || this.locale.toLowerCase() === "en-us" ||
new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us") getCachedIntResolvedOptions(this.intl).locale.startsWith("en-us")
); );
} }
@@ -1461,22 +1480,26 @@ function parseDigits(str) {
} }
// cache of {numberingSystem: {append: regex}} // cache of {numberingSystem: {append: regex}}
let digitRegexCache = {}; const digitRegexCache = new Map();
function resetDigitRegexCache() { function resetDigitRegexCache() {
digitRegexCache = {}; digitRegexCache.clear();
} }
function digitRegex({ numberingSystem }, append = "") { function digitRegex({ numberingSystem }, append = "") {
const ns = numberingSystem || "latn"; const ns = numberingSystem || "latn";
if (!digitRegexCache[ns]) { let appendCache = digitRegexCache.get(ns);
digitRegexCache[ns] = {}; if (appendCache === undefined) {
appendCache = new Map();
digitRegexCache.set(ns, appendCache);
} }
if (!digitRegexCache[ns][append]) { let regex = appendCache.get(append);
digitRegexCache[ns][append] = new RegExp(`${numberingSystems[ns]}${append}`); if (regex === undefined) {
regex = new RegExp(`${numberingSystems[ns]}${append}`);
appendCache.set(append, regex);
} }
return digitRegexCache[ns][append]; return regex;
} }
let now = () => Date.now(), let now = () => Date.now(),
@@ -4227,6 +4250,14 @@ class Interval {
return this.isValid ? this.e : null; return this.isValid ? this.e : null;
} }
/**
* Returns the last DateTime included in the interval (since end is not part of the interval)
* @type {DateTime}
*/
get lastDateTime() {
return this.isValid ? (this.e ? this.e.minus(1) : null) : null;
}
/** /**
* Returns whether this Interval's end is at least its start, meaning that the Interval isn't 'backwards'. * Returns whether this Interval's end is at least its start, meaning that the Interval isn't 'backwards'.
* @type {boolean} * @type {boolean}
@@ -4491,8 +4522,11 @@ class Interval {
} }
/** /**
* Merge an array of Intervals into a equivalent minimal set of Intervals. * Merge an array of Intervals into an equivalent minimal set of Intervals.
* Combines overlapping and adjacent Intervals. * Combines overlapping and adjacent Intervals.
* The resulting array will contain the Intervals in ascending order, that is, starting with the earliest Interval
* and ending with the latest.
*
* @param {Array} intervals * @param {Array} intervals
* @return {Array} * @return {Array}
*/ */
@@ -5815,15 +5849,27 @@ function normalizeUnitWithLocalWeeks(unit) {
// This is safe for quickDT (used by local() and utc()) because we don't fill in // This is safe for quickDT (used by local() and utc()) because we don't fill in
// higher-order units from tsNow (as we do in fromObject, this requires that // higher-order units from tsNow (as we do in fromObject, this requires that
// offset is calculated from tsNow). // offset is calculated from tsNow).
/**
* @param {Zone} zone
* @return {number}
*/
function guessOffsetForZone(zone) { function guessOffsetForZone(zone) {
if (!zoneOffsetGuessCache[zone]) { if (zoneOffsetTs === undefined) {
if (zoneOffsetTs === undefined) { zoneOffsetTs = Settings.now();
zoneOffsetTs = Settings.now();
}
zoneOffsetGuessCache[zone] = zone.offset(zoneOffsetTs);
} }
return zoneOffsetGuessCache[zone];
// Do not cache anything but IANA zones, because it is not safe to do so.
// Guessing an offset which is not present in the zone can cause wrong results from fixOffset
if (zone.type !== "iana") {
return zone.offset(zoneOffsetTs);
}
const zoneName = zone.name;
let offsetGuess = zoneOffsetGuessCache.get(zoneName);
if (offsetGuess === undefined) {
offsetGuess = zone.offset(zoneOffsetTs);
zoneOffsetGuessCache.set(zoneName, offsetGuess);
}
return offsetGuess;
} }
// this is a dumbed down version of fromObject() that runs about 60% faster // this is a dumbed down version of fromObject() that runs about 60% faster
@@ -5913,7 +5959,7 @@ let zoneOffsetTs;
* This optimizes quickDT via guessOffsetForZone to avoid repeated calls of * This optimizes quickDT via guessOffsetForZone to avoid repeated calls of
* zone.offset(). * zone.offset().
*/ */
let zoneOffsetGuessCache = {}; const zoneOffsetGuessCache = new Map();
/** /**
* A DateTime is an immutable data structure representing a specific date and time and accompanying methods. It contains class and instance methods for creating, parsing, interrogating, transforming, and formatting them. * A DateTime is an immutable data structure representing a specific date and time and accompanying methods. It contains class and instance methods for creating, parsing, interrogating, transforming, and formatting them.
@@ -6478,7 +6524,7 @@ class DateTime {
static resetCache() { static resetCache() {
zoneOffsetTs = undefined; zoneOffsetTs = undefined;
zoneOffsetGuessCache = {}; zoneOffsetGuessCache.clear();
} }
// INFO // INFO
@@ -7247,7 +7293,7 @@ class DateTime {
* @example DateTime.now().toISO() //=> '2017-04-22T20:47:05.335-04:00' * @example DateTime.now().toISO() //=> '2017-04-22T20:47:05.335-04:00'
* @example DateTime.now().toISO({ includeOffset: false }) //=> '2017-04-22T20:47:05.335' * @example DateTime.now().toISO({ includeOffset: false }) //=> '2017-04-22T20:47:05.335'
* @example DateTime.now().toISO({ format: 'basic' }) //=> '20170422T204705.335-0400' * @example DateTime.now().toISO({ format: 'basic' }) //=> '20170422T204705.335-0400'
* @return {string} * @return {string|null}
*/ */
toISO({ toISO({
format = "extended", format = "extended",
@@ -7274,7 +7320,7 @@ class DateTime {
* @param {string} [opts.format='extended'] - choose between the basic and extended format * @param {string} [opts.format='extended'] - choose between the basic and extended format
* @example DateTime.utc(1982, 5, 25).toISODate() //=> '1982-05-25' * @example DateTime.utc(1982, 5, 25).toISODate() //=> '1982-05-25'
* @example DateTime.utc(1982, 5, 25).toISODate({ format: 'basic' }) //=> '19820525' * @example DateTime.utc(1982, 5, 25).toISODate({ format: 'basic' }) //=> '19820525'
* @return {string} * @return {string|null}
*/ */
toISODate({ format = "extended" } = {}) { toISODate({ format = "extended" } = {}) {
if (!this.isValid) { if (!this.isValid) {
@@ -7359,7 +7405,7 @@ class DateTime {
/** /**
* Returns a string representation of this DateTime appropriate for use in SQL Date * Returns a string representation of this DateTime appropriate for use in SQL Date
* @example DateTime.utc(2014, 7, 13).toSQLDate() //=> '2014-07-13' * @example DateTime.utc(2014, 7, 13).toSQLDate() //=> '2014-07-13'
* @return {string} * @return {string|null}
*/ */
toSQLDate() { toSQLDate() {
if (!this.isValid) { if (!this.isValid) {
@@ -7454,7 +7500,7 @@ class DateTime {
} }
/** /**
* Returns the epoch seconds of this DateTime. * Returns the epoch seconds (including milliseconds in the fractional part) of this DateTime.
* @return {number} * @return {number}
*/ */
toSeconds() { toSeconds() {
@@ -7561,7 +7607,7 @@ class DateTime {
/** /**
* Return an Interval spanning between this DateTime and another DateTime * Return an Interval spanning between this DateTime and another DateTime
* @param {DateTime} otherDateTime - the other end point of the Interval * @param {DateTime} otherDateTime - the other end point of the Interval
* @return {Interval} * @return {Interval|DateTime}
*/ */
until(otherDateTime) { until(otherDateTime) {
return this.isValid ? Interval.fromDateTimes(this, otherDateTime) : this; return this.isValid ? Interval.fromDateTimes(this, otherDateTime) : this;
@@ -7979,7 +8025,7 @@ function friendlyDateTime(dateTimeish) {
} }
} }
const VERSION = "3.5.0"; const VERSION = "3.6.1";
export { DateTime, Duration, FixedOffsetZone, IANAZone, Info, Interval, InvalidZone, Settings, SystemZone, VERSION, Zone }; export { DateTime, Duration, FixedOffsetZone, IANAZone, Info, Interval, InvalidZone, Settings, SystemZone, VERSION, Zone };
//# sourceMappingURL=luxon.js.map //# sourceMappingURL=luxon.js.map