diff --git a/package-lock.json b/package-lock.json index ea74671..8ba14e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,11 +18,13 @@ "@eslint/js": "^9.2.0", "@rollup/plugin-commonjs": "^26.0.0", "@rollup/plugin-node-resolve": "^15.2.2", + "@rollup/plugin-replace": "^5.0.7", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", "@tsconfig/node20": "^20.1.2", "@types/node": "20.14.13", "@types/ws": "^8.5.10", + "cross-env": "^7.0.3", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.2.0", @@ -486,6 +488,27 @@ } } }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", + "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-terser": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", @@ -562,7 +585,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -576,7 +598,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -590,7 +611,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -604,7 +624,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -618,7 +637,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -632,7 +650,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -646,7 +663,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -660,7 +676,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -674,7 +689,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -688,7 +702,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -702,7 +715,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -716,7 +728,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -730,7 +741,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -744,7 +754,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -758,7 +767,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -772,7 +780,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1477,6 +1484,24 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/package.json b/package.json index 7eefba7..79f8ac7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "scripts": { "build": "rollup -c", - "watch": "rollup -c -w --watch.onEnd=\"streamdeck restart com.neil-enns.trackaudio\"", + "watch": "cross-env NODE_ENV=development rollup -c -w --watch.onEnd=\"streamdeck restart com.neil-enns.trackaudio\"", "pack": "streamdeck pack com.neil-enns.trackaudio.sdPlugin -o .", "link": "streamdeck link com.neil-enns.trackaudio.sdPlugin", "lint": "npm run eslint && npm run markdownlint", @@ -14,11 +14,13 @@ "@eslint/js": "^9.2.0", "@rollup/plugin-commonjs": "^26.0.0", "@rollup/plugin-node-resolve": "^15.2.2", + "@rollup/plugin-replace": "^5.0.7", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", "@tsconfig/node20": "^20.1.2", "@types/node": "20.14.13", "@types/ws": "^8.5.10", + "cross-env": "^7.0.3", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.2.0", diff --git a/rollup.config.mjs b/rollup.config.mjs index 38f1a03..5dcc048 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -5,6 +5,7 @@ import typescript from "@rollup/plugin-typescript"; import path from "node:path"; import url from "node:url"; import json from "@rollup/plugin-json"; +import replace from "@rollup/plugin-replace"; const isWatching = !!process.env.ROLLUP_WATCH; const sdPlugin = "com.neil-enns.trackaudio.sdPlugin"; @@ -24,6 +25,14 @@ const config = { }, }, plugins: [ + replace({ + preventAssignment: true, + sourcemap: true, + values: { + "process.env.NODE_ENV": + JSON.stringify(process.env.NODE_ENV) ?? "production", + }, + }), { name: "watch-externals", buildStart: function () { diff --git a/src/actions/hotline.ts b/src/actions/hotline.ts index 97dfb83..792b867 100644 --- a/src/actions/hotline.ts +++ b/src/actions/hotline.ts @@ -7,6 +7,7 @@ import { WillDisappearEvent, } from "@elgato/streamdeck"; import actionManager from "@managers/action"; +import * as logger from "@utils/logger"; @action({ UUID: "com.neil-enns.trackaudio.hotline" }) /** @@ -24,7 +25,7 @@ export class Hotline extends SingletonAction { ev.action .setTitle(ev.payload.settings.hotlineCallsign) .catch((error: unknown) => { - console.error(error); + logger.error(error); }); } diff --git a/src/managers/action.ts b/src/managers/action.ts index e5a8d38..4718a04 100644 --- a/src/managers/action.ts +++ b/src/managers/action.ts @@ -31,6 +31,7 @@ import debounce from "debounce"; import { EventEmitter } from "events"; import vatsimManager from "./vatsim"; import { PushToTalkSettings } from "@actions/pushToTalk"; +import * as logger from "@utils/logger"; /** * Singleton class that manages StreamDeck actions @@ -707,7 +708,7 @@ class ActionManager extends EventEmitter { public showAlertOnAll() { this.actions.forEach((entry) => { entry.action.showAlert().catch((error: unknown) => { - console.error(error); + logger.error(error); }); }); } diff --git a/src/managers/svg.ts b/src/managers/svg.ts index 0270c85..5355b32 100644 --- a/src/managers/svg.ts +++ b/src/managers/svg.ts @@ -3,6 +3,7 @@ import Handlebars from "handlebars"; import path from "path"; import * as chokidar from "chokidar"; import EventEmitter from "events"; +import * as logger from "@utils/logger"; export type CompiledSvgTemplate = | ReturnType @@ -99,7 +100,7 @@ class SvgTemplateManager extends EventEmitter { return compiledTemplate; } catch (err: unknown) { - console.error(err); + logger.error(err); } return undefined; diff --git a/src/managers/trackAudio.ts b/src/managers/trackAudio.ts index e49d441..a7bfcef 100644 --- a/src/managers/trackAudio.ts +++ b/src/managers/trackAudio.ts @@ -13,6 +13,7 @@ import { } from "@interfaces/messages"; import { EventEmitter } from "events"; import WebSocket from "ws"; +import * as logger from "../utils/logger"; /** * Manages the websocket connection to TrackAudio. @@ -73,7 +74,7 @@ class TrackAudioManager extends EventEmitter { */ public connect(): void { if (this.socket && this.socket.readyState !== WebSocket.CLOSED) { - console.warn("WebSocket is already connected or connecting."); + logger.warn("WebSocket is already connected or connecting."); return; } @@ -86,12 +87,12 @@ class TrackAudioManager extends EventEmitter { this.socket = new WebSocket(this.url); this.socket.on("open", () => { - console.debug("WebSocket connection established."); + logger.debug("WebSocket connection established."); this.emit("connected"); }); this.socket.on("close", () => { - console.debug("WebSocket connection closed"); + logger.debug("WebSocket connection closed"); this._isVoiceConnected = false; this.emit("disconnected"); @@ -100,11 +101,11 @@ class TrackAudioManager extends EventEmitter { this.socket.on("error", (err: Error & { code: string }) => { if (err.code === "ECONNREFUSED") { - console.error( + logger.error( "Unable to connect to TrackAudio, connection refused. TrackAudio probably isn't running." ); } else { - console.error("WebSocket error:", err.message); + logger.error("WebSocket error:", err.message); } this._isVoiceConnected = false; @@ -122,7 +123,7 @@ class TrackAudioManager extends EventEmitter { * @param message The message to process */ private processMessage(message: string): void { - console.debug("Received: %s", message); + logger.debug("Received: %s", message); const data = JSON.parse(message) as IncomingMessage; @@ -193,7 +194,7 @@ class TrackAudioManager extends EventEmitter { } this.reconnectTimer = setTimeout(() => { - console.debug(`Attempting to reconnect...`); + logger.debug(`Attempting to reconnect...`); this.connect(); }, this.reconnectInterval); } diff --git a/src/managers/vatsim.ts b/src/managers/vatsim.ts index 780bb9d..5dadc5b 100644 --- a/src/managers/vatsim.ts +++ b/src/managers/vatsim.ts @@ -2,6 +2,7 @@ import { VatsimData } from "@interfaces/vatsim"; import { handleAsyncException } from "@root/utils/handleAsyncException"; import axios from "axios"; import EventEmitter from "events"; +import * as logger from "@utils/logger"; /** * Singleton class that manages communication with VATSIM. @@ -34,7 +35,7 @@ class VatsimManager extends EventEmitter { this.emit("vatsimDataReceived", data); } catch (error) { - console.error("Error fetching VATSIM data: ", error); + logger.error("Error fetching VATSIM data: ", error); } } diff --git a/src/plugin.ts b/src/plugin.ts index b2ac2fa..ecc2505 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -31,13 +31,14 @@ import { handleTxEnd } from "@eventHandlers/trackAudio/txEnd"; import { handleVoiceConnectedState } from "@eventHandlers/trackAudio/voiceConnectedState"; import { handleVatsimDataReceived } from "@eventHandlers/vatsim/vatsimDataReceived"; import { handleActionAdded } from "@eventHandlers/action/actionAdded"; +import * as logger from "@utils/logger"; // Flag to prevent handling repeated disconnect events let disconnectHandled = false; // Register for uncaught exceptions process.on("uncaughtException", (error) => { - console.error("Uncaught Exception:", error); + logger.error("Uncaught Exception:", error); }); // Register all the event handlers diff --git a/src/utils/handleAsyncException.ts b/src/utils/handleAsyncException.ts index 2a19046..fa994f5 100644 --- a/src/utils/handleAsyncException.ts +++ b/src/utils/handleAsyncException.ts @@ -1,4 +1,6 @@ +import * as logger from "@utils/logger"; + export const handleAsyncException = (preamble: string, error: unknown) => { const err = error as Error; - console.error(`${preamble}${err.message}`); + logger.error(`${preamble}${err.message}`); }; diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 0000000..026ab9e --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,18 @@ +type LogLevel = "log" | "error" | "warn" | "info" | "debug"; +type LogFunction = (...args: unknown[]) => void; + +const isDevelopment: boolean = process.env.NODE_ENV === "development"; + +const createLogger = (method: LogLevel): LogFunction => { + return (...args: unknown[]): void => { + if (isDevelopment && method === "debug") { + console[method](...args); + } + }; +}; + +export const log = createLogger("log"); +export const error = createLogger("error"); +export const warn = createLogger("warn"); +export const info = createLogger("info"); +export const debug = createLogger("debug"); diff --git a/tsconfig.json b/tsconfig.json index fb5d140..5a43191 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "@helpers/*": ["./src/helpers/*"], "@interfaces/*": ["./src/interfaces/*"], "@managers/*": ["./src/managers/*"], - "@root/*": ["./src/*"] + "@root/*": ["./src/*"], + "@utils/*": ["./src/utils/*"], } }, "include": ["src/**/*.ts"],