mirror of
https://github.com/MichMich/MagicMirror.git
synced 2026-04-21 21:40:55 +00:00
Fix Node.js v25 logging prefix and modernize logger (#4049)
On Node.js v25, the log prefix in the terminal stopped working - instead of seeing something like: ``` [2026-03-05 23:00:00.000] [LOG] [app] Starting MagicMirror: v2.35.0 ``` the output was: ``` [2026-03-05 23:00:00.000] :pre() Starting MagicMirror: v2.35.0 ``` Reported in #4048. ## Why did it break? The logger used the `console-stamp` package to format log output. One part of that formatting used `styleText("grey", ...)` to color the caller prefix gray. Node.js v25 dropped `"grey"` as a valid color name (only `"gray"` with an "a" is accepted now). This caused `styleText` to throw an error internally - and `console-stamp` silently swallowed that error and fell back to returning its raw `:pre()` format string as the prefix. Not ideal. ## What's in this PR? **1. The actual fix** - `"grey"` → `"gray"`. **2. Cleaner stack trace approach** - the previous code set `Error.prepareStackTrace` *after* creating the `Error`, which is fragile and was starting to behave differently across Node versions. Replaced with straightforward string parsing of `new Error().stack`. **3. Removed the `console-stamp` dependency** - all formatting is now done with plain Node.js built-ins (`node:util` `styleText`). Same visual result, no external dependency. **4. Simplified the module wrapper** - the logger was wrapped in a UMD pattern, which is meant for environments like AMD/RequireJS. MagicMirror only runs in two places: Node.js and the browser. Replaced with a simple check (`typeof module !== "undefined"`), which is much easier to follow.
This commit is contained in:
committed by
GitHub
parent
ab3108fc14
commit
3eb3745dd3
226
js/logger.js
226
js/logger.js
@@ -1,131 +1,115 @@
|
||||
// This logger is very simple, but needs to be extended.
|
||||
(function (root, factory) {
|
||||
if (typeof exports === "object") {
|
||||
// Logger for MagicMirror² — works both in Node.js (CommonJS) and the browser (global).
|
||||
(function () {
|
||||
if (typeof module !== "undefined") {
|
||||
if (process.env.mmTestMode !== "true") {
|
||||
const { styleText } = require("node:util");
|
||||
|
||||
// add timestamps in front of log messages
|
||||
require("console-stamp")(console, {
|
||||
format: ":date(yyyy-mm-dd HH:MM:ss.l) :label(7) :pre() :msg",
|
||||
tokens: {
|
||||
pre: () => {
|
||||
const err = new Error();
|
||||
Error.prepareStackTrace = (_, stack) => stack;
|
||||
const stack = err.stack;
|
||||
Error.prepareStackTrace = undefined;
|
||||
try {
|
||||
for (const line of stack) {
|
||||
const file = line.getFileName();
|
||||
if (file && !file.includes("node:") && !file.includes("js/logger.js") && !file.includes("node_modules")) {
|
||||
const filename = file.replace(/.*\/(.*).js/, "$1");
|
||||
const filepath = file.replace(/.*\/(.*)\/.*.js/, "$1");
|
||||
if (filepath === "js") {
|
||||
return styleText("grey", `[${filename}]`);
|
||||
} else {
|
||||
return styleText("grey", `[${filepath}]`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
return styleText("grey", "[unknown]");
|
||||
}
|
||||
},
|
||||
label: (arg) => {
|
||||
const { method, defaultTokens } = arg;
|
||||
let label = defaultTokens.label(arg);
|
||||
switch (method) {
|
||||
case "error":
|
||||
label = styleText("red", label);
|
||||
break;
|
||||
case "warn":
|
||||
label = styleText("yellow", label);
|
||||
break;
|
||||
case "debug":
|
||||
label = styleText("bgBlue", label);
|
||||
break;
|
||||
case "info":
|
||||
label = styleText("blue", label);
|
||||
break;
|
||||
}
|
||||
return label;
|
||||
},
|
||||
msg: (arg) => {
|
||||
const { method, defaultTokens } = arg;
|
||||
let msg = defaultTokens.msg(arg);
|
||||
switch (method) {
|
||||
case "error":
|
||||
msg = styleText("red", msg);
|
||||
break;
|
||||
case "warn":
|
||||
msg = styleText("yellow", msg);
|
||||
break;
|
||||
case "info":
|
||||
msg = styleText("blue", msg);
|
||||
break;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Node, CommonJS-like
|
||||
module.exports = factory(root.config);
|
||||
} else {
|
||||
// Browser globals (root is window)
|
||||
root.Log = factory(root.config);
|
||||
}
|
||||
}(this, function (config) {
|
||||
let logLevel;
|
||||
let enableLog;
|
||||
if (typeof exports === "object") {
|
||||
// in nodejs and not running in test mode
|
||||
enableLog = process.env.mmTestMode !== "true";
|
||||
} else {
|
||||
// in browser and not running with jsdom
|
||||
enableLog = typeof window === "object" && window.name !== "jsdom";
|
||||
}
|
||||
const LABEL_COLORS = { error: "red", warn: "yellow", debug: "bgBlue", info: "blue" };
|
||||
const MSG_COLORS = { error: "red", warn: "yellow", info: "blue" };
|
||||
|
||||
if (enableLog) {
|
||||
logLevel = {
|
||||
debug: Function.prototype.bind.call(console.debug, console),
|
||||
log: Function.prototype.bind.call(console.log, console),
|
||||
info: Function.prototype.bind.call(console.info, console),
|
||||
warn: Function.prototype.bind.call(console.warn, console),
|
||||
error: Function.prototype.bind.call(console.error, console),
|
||||
group: Function.prototype.bind.call(console.group, console),
|
||||
groupCollapsed: Function.prototype.bind.call(console.groupCollapsed, console),
|
||||
groupEnd: Function.prototype.bind.call(console.groupEnd, console),
|
||||
time: Function.prototype.bind.call(console.time, console),
|
||||
timeEnd: Function.prototype.bind.call(console.timeEnd, console),
|
||||
timeStamp: console.timeStamp ? Function.prototype.bind.call(console.timeStamp, console) : function () {}
|
||||
};
|
||||
const formatTimestamp = () => {
|
||||
const d = new Date();
|
||||
const pad2 = (n) => String(n).padStart(2, "0");
|
||||
const pad3 = (n) => String(n).padStart(3, "0");
|
||||
const date = `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
|
||||
const time = `${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}.${pad3(d.getMilliseconds())}`;
|
||||
return `[${date} ${time}]`;
|
||||
};
|
||||
|
||||
logLevel.setLogLevel = function (newLevel) {
|
||||
if (newLevel) {
|
||||
Object.keys(logLevel).forEach(function (key) {
|
||||
if (!newLevel.includes(key.toLocaleUpperCase())) {
|
||||
logLevel[key] = function () {};
|
||||
const getCallerPrefix = () => {
|
||||
try {
|
||||
const lines = new Error().stack.split("\n");
|
||||
for (const line of lines) {
|
||||
if (line.includes("node:") || line.includes("js/logger.js") || line.includes("node_modules")) continue;
|
||||
const match = line.match(/\((.+?\.js):\d+:\d+\)/) || line.match(/at\s+(.+?\.js):\d+:\d+/);
|
||||
if (match) {
|
||||
const file = match[1];
|
||||
const baseName = file.replace(/.*\/(.*)\.js/, "$1");
|
||||
const parentDir = file.replace(/.*\/(.*)\/.*\.js/, "$1");
|
||||
return styleText("gray", parentDir === "js" ? `[${baseName}]` : `[${parentDir}]`);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) { /* ignore */ }
|
||||
return styleText("gray", "[unknown]");
|
||||
};
|
||||
|
||||
// Patch console methods to prepend timestamp, level label, and caller prefix.
|
||||
for (const method of ["debug", "log", "info", "warn", "error"]) {
|
||||
const original = console[method].bind(console);
|
||||
const labelRaw = `[${method.toUpperCase()}]`.padEnd(7);
|
||||
const label = LABEL_COLORS[method] ? styleText(LABEL_COLORS[method], labelRaw) : labelRaw;
|
||||
console[method] = (...args) => {
|
||||
const prefix = `${formatTimestamp()} ${label} ${getCallerPrefix()}`;
|
||||
const msgColor = MSG_COLORS[method];
|
||||
if (msgColor && args.length > 0 && typeof args[0] === "string") {
|
||||
original(prefix, styleText(msgColor, args[0]), ...args.slice(1));
|
||||
} else {
|
||||
original(prefix, ...args);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
// Node, CommonJS
|
||||
module.exports = makeLogger();
|
||||
} else {
|
||||
logLevel = {
|
||||
debug () {},
|
||||
log () {},
|
||||
info () {},
|
||||
warn () {},
|
||||
error () {},
|
||||
group () {},
|
||||
groupCollapsed () {},
|
||||
groupEnd () {},
|
||||
time () {},
|
||||
timeEnd () {},
|
||||
timeStamp () {}
|
||||
};
|
||||
|
||||
logLevel.setLogLevel = function () {};
|
||||
// Browser globals
|
||||
window.Log = makeLogger();
|
||||
}
|
||||
|
||||
return logLevel;
|
||||
}));
|
||||
/**
|
||||
* Creates the logger object. Logging is disabled when running in test mode
|
||||
* (Node.js) or inside jsdom (browser).
|
||||
* @returns {object} The logger object with log level methods.
|
||||
*/
|
||||
function makeLogger () {
|
||||
const enableLog = typeof module !== "undefined"
|
||||
? process.env.mmTestMode !== "true"
|
||||
: typeof window === "object" && window.name !== "jsdom";
|
||||
|
||||
let logLevel;
|
||||
|
||||
if (enableLog) {
|
||||
logLevel = {
|
||||
debug: Function.prototype.bind.call(console.debug, console),
|
||||
log: Function.prototype.bind.call(console.log, console),
|
||||
info: Function.prototype.bind.call(console.info, console),
|
||||
warn: Function.prototype.bind.call(console.warn, console),
|
||||
error: Function.prototype.bind.call(console.error, console),
|
||||
group: Function.prototype.bind.call(console.group, console),
|
||||
groupCollapsed: Function.prototype.bind.call(console.groupCollapsed, console),
|
||||
groupEnd: Function.prototype.bind.call(console.groupEnd, console),
|
||||
time: Function.prototype.bind.call(console.time, console),
|
||||
timeEnd: Function.prototype.bind.call(console.timeEnd, console),
|
||||
timeStamp: console.timeStamp ? Function.prototype.bind.call(console.timeStamp, console) : function () {}
|
||||
};
|
||||
|
||||
logLevel.setLogLevel = function (newLevel) {
|
||||
if (newLevel) {
|
||||
Object.keys(logLevel).forEach(function (key) {
|
||||
if (!newLevel.includes(key.toLocaleUpperCase())) {
|
||||
logLevel[key] = function () {};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
} else {
|
||||
logLevel = {
|
||||
debug () {},
|
||||
log () {},
|
||||
info () {},
|
||||
warn () {},
|
||||
error () {},
|
||||
group () {},
|
||||
groupCollapsed () {},
|
||||
groupEnd () {},
|
||||
time () {},
|
||||
timeEnd () {},
|
||||
timeStamp () {}
|
||||
};
|
||||
|
||||
logLevel.setLogLevel = function () {};
|
||||
}
|
||||
|
||||
return logLevel;
|
||||
}
|
||||
}());
|
||||
|
||||
55
package-lock.json
generated
55
package-lock.json
generated
@@ -15,7 +15,6 @@
|
||||
"@fortawesome/fontawesome-free": "^7.2.0",
|
||||
"ajv": "^8.18.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"console-stamp": "^3.1.2",
|
||||
"croner": "^10.0.1",
|
||||
"eslint": "^9.39.3",
|
||||
"express": "^5.2.1",
|
||||
@@ -249,6 +248,7 @@
|
||||
"integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@keyv/serialize": "^1.1.1"
|
||||
}
|
||||
@@ -407,6 +407,7 @@
|
||||
"integrity": "sha512-Tdfx4eH2uS+gv9V9NCr3Rz+c7RSS6ntXp3Blliud18ibRUlRxO9dTaOjG4iv4x0nAmMeedP1ORkEpeXSkh2QiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
@@ -488,7 +489,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.19.tgz",
|
||||
"integrity": "sha512-VYHtPnZt/Zd/ATbW3rtexWpBnHUohUrQOHff/2JBhsVgxOrksAxJnLAO43Q1ayLJBJUUwNVo+RU0sx0aaysZfg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@cspell/dict-dart": {
|
||||
"version": "2.3.2",
|
||||
@@ -628,14 +630,16 @@
|
||||
"resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.14.tgz",
|
||||
"integrity": "sha512-2bf7n+kS92g+cMKV0wr9o/Oq9n8JzU7CcrB96gIh2GHgnF+0xDOqO2W/1KeFAqOfqosoOVE48t+4dnEMkkoJ2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@cspell/dict-html-symbol-entities": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.5.tgz",
|
||||
"integrity": "sha512-429alTD4cE0FIwpMucvSN35Ld87HCyuM8mF731KU5Rm4Je2SG6hmVx7nkBsLyrmH3sQukTcr1GaiZsiEg8svPA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@cspell/dict-java": {
|
||||
"version": "5.0.12",
|
||||
@@ -833,7 +837,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz",
|
||||
"integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@cspell/dict-vue": {
|
||||
"version": "3.0.5",
|
||||
@@ -991,6 +996,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
},
|
||||
@@ -1031,6 +1037,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
}
|
||||
@@ -3708,6 +3715,7 @@
|
||||
"integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.0.18",
|
||||
"fflate": "^0.8.2",
|
||||
@@ -3762,6 +3770,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -4344,6 +4353,7 @@
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@@ -4637,19 +4647,6 @@
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/console-stamp": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.1.2.tgz",
|
||||
"integrity": "sha512-ab66x3NxOTxPuq71dI6gXEiw2X6ql4Le5gZz0bm7FW3FSCB00eztra/oQUuCoCGlsyKOxtULnHwphzMrRtzMBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.2",
|
||||
"dateformat": "^4.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
||||
@@ -5064,15 +5061,6 @@
|
||||
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dateformat": {
|
||||
"version": "4.6.3",
|
||||
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz",
|
||||
"integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.15",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.15.tgz",
|
||||
@@ -5703,6 +5691,7 @@
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz",
|
||||
"integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -7557,6 +7546,7 @@
|
||||
"integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@acemir/cssom": "^0.9.31",
|
||||
"@asamuzakjp/dom-selector": "^6.8.1",
|
||||
@@ -7630,7 +7620,6 @@
|
||||
"integrity": "sha512-75EA7EWZExL/j+MDKQrRbdzcRI2HOkRlmUw8fZJc1ioqFEOvBsq7Rt+A6yCxOt9w/TYNpkt52gC6nm/g5tFIng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.5.0",
|
||||
"eslint-visitor-keys": "^5.0.0",
|
||||
@@ -7649,7 +7638,6 @@
|
||||
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
@@ -7962,6 +7950,7 @@
|
||||
"integrity": "sha512-DzzmbqfMW3EzHsunP66x556oZDzjcdjjlL2bHG4PubwnL58ZPAfz07px4GqteZkoCGnBYi779Y2mg7+vgNCwbw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"globby": "16.1.0",
|
||||
"js-yaml": "4.1.1",
|
||||
@@ -9680,6 +9669,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -9722,6 +9712,7 @@
|
||||
"integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@@ -9752,6 +9743,7 @@
|
||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -11010,6 +11002,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@csstools/css-calc": "^3.1.1",
|
||||
"@csstools/css-parser-algorithms": "^4.0.0",
|
||||
@@ -11622,7 +11615,6 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -11692,6 +11684,7 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"napi-postinstall": "^0.3.0"
|
||||
},
|
||||
@@ -11793,6 +11786,7 @@
|
||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -11883,6 +11877,7 @@
|
||||
"integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.0.18",
|
||||
"@vitest/mocker": "4.0.18",
|
||||
|
||||
@@ -92,7 +92,6 @@
|
||||
"@fortawesome/fontawesome-free": "^7.2.0",
|
||||
"ajv": "^8.18.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"console-stamp": "^3.1.2",
|
||||
"croner": "^10.0.1",
|
||||
"eslint": "^9.39.3",
|
||||
"express": "^5.2.1",
|
||||
|
||||
Reference in New Issue
Block a user