diff --git a/app/package.json b/app/package.json index aff9980..590fad1 100644 --- a/app/package.json +++ b/app/package.json @@ -92,6 +92,6 @@ "webpack-dev-server": "^5.0.4" }, "peerDependencies": { - "electron": "^29" + "electron": "^39" } } diff --git a/app/src/components/BrowserAuthWrapper.tsx b/app/src/components/BrowserAuthWrapper.tsx index a9e5d90..6c261fa 100644 --- a/app/src/components/BrowserAuthWrapper.tsx +++ b/app/src/components/BrowserAuthWrapper.tsx @@ -6,8 +6,7 @@ interface BrowserAuthWrapperProps { } const isBrowserMode = - typeof window !== 'undefined' && - (typeof process === 'undefined' || process.env?.BROWSER_MODE === 'true') + typeof window !== 'undefined' && (typeof process === 'undefined' || process.env?.BROWSER_MODE === 'true') export function BrowserAuthWrapper(props: BrowserAuthWrapperProps) { const [isAuthenticated, setIsAuthenticated] = React.useState(false) diff --git a/app/src/components/ConnectionSetup/Certificates.tsx b/app/src/components/ConnectionSetup/Certificates.tsx index f72cdeb..9960e06 100644 --- a/app/src/components/ConnectionSetup/Certificates.tsx +++ b/app/src/components/ConnectionSetup/Certificates.tsx @@ -10,9 +10,8 @@ import { ConnectionOptions } from '../../model/ConnectionOptions' import { Theme, withStyles } from '@material-ui/core/styles' // Check if we're in browser mode -const isBrowserMode = - typeof window !== 'undefined' && - (typeof process === 'undefined' || process.env?.BROWSER_MODE === 'true') +const isBrowserMode = + typeof window !== 'undefined' && (typeof process === 'undefined' || process.env?.BROWSER_MODE === 'true') const CertSelector = isBrowserMode ? BrowserCertificateFileSelection : CertificateFileSelection interface Props { diff --git a/backend/src/ConfigStorage.ts b/backend/src/ConfigStorage.ts index d982415..35c85e4 100644 --- a/backend/src/ConfigStorage.ts +++ b/backend/src/ConfigStorage.ts @@ -9,7 +9,7 @@ export default class ConfigStorage { private file: string private database: any private rpc: Rpc - + constructor(file: string, rpc: Rpc) { this.file = file this.rpc = rpc diff --git a/backend/src/Model/Base64Message.ts b/backend/src/Model/Base64Message.ts index 096f555..4b585ee 100644 --- a/backend/src/Model/Base64Message.ts +++ b/backend/src/Model/Base64Message.ts @@ -82,7 +82,7 @@ export class Base64Message { let str: string = '' buf.forEach(element => { - let hex = element.toString(16).toUpperCase() + const hex = element.toString(16).toUpperCase() str += `0x${hex.length < 2 ? '0' + hex : hex} ` }) return str.trimRight() diff --git a/events/EventSystem/IpcMainEventBus.ts b/events/EventSystem/IpcMainEventBus.ts index e2d7f08..7b6cfe0 100644 --- a/events/EventSystem/IpcMainEventBus.ts +++ b/events/EventSystem/IpcMainEventBus.ts @@ -7,7 +7,7 @@ export class IpcMainEventBus implements EventBusInterface { private clients: Map = new Map() // webContentsId -> WebContents private connectionOwners: Map = new Map() // connectionId -> webContentsId private currentClient: WebContents | undefined - + constructor(ipc: IpcMain) { this.ipc = ipc } @@ -16,34 +16,34 @@ export class IpcMainEventBus implements EventBusInterface { this.ipc.on(subscribeEvent.topic, (event: any, arg: any) => { const sender = event.sender as WebContents this.currentClient = sender - + // Track the client (O(1) operation) if (!this.clients.has(sender.id)) { this.clients.set(sender.id, sender) - + // Clean up when window is closed sender.once('destroyed', () => { this.clients.delete(sender.id) - + // Clean up owned connections - for (const [connectionId, webContentsId] of this.connectionOwners.entries()) { + Array.from(this.connectionOwners.entries()).forEach(([connectionId, webContentsId]) => { if (webContentsId === sender.id) { this.connectionOwners.delete(connectionId) } - } + }) }) } - + // Track connection ownership if (subscribeEvent.topic === 'connection/add/mqtt' && arg?.id) { this.connectionOwners.set(arg.id, sender.id) } - + // Remove connection ownership if (subscribeEvent.topic === 'connection/remove' && typeof arg === 'string') { this.connectionOwners.delete(arg) } - + callback(arg) }) } @@ -58,7 +58,7 @@ export class IpcMainEventBus implements EventBusInterface { public emit(event: Event, msg: MessageType) { const topic = event.topic - + // RPC responses go only to the requesting client if (topic.includes('/response/')) { if (this.currentClient && !this.currentClient.isDestroyed()) { @@ -66,18 +66,18 @@ export class IpcMainEventBus implements EventBusInterface { } return } - + // Connection-specific events - optimized with early pattern match if (topic.startsWith('conn/')) { const parts = topic.split('/') let connectionId: string | undefined - + if (parts.length === 2) { connectionId = parts[1] } else if (parts.length === 3 && (parts[1] === 'state' || parts[1] === 'publish')) { connectionId = parts[2] } - + if (connectionId) { const ownerWebContentsId = this.connectionOwners.get(connectionId) if (ownerWebContentsId !== undefined) { @@ -89,7 +89,7 @@ export class IpcMainEventBus implements EventBusInterface { } } } - + // All other events go to all clients this.clients.forEach(client => { if (!client.isDestroyed()) { diff --git a/events/EventSystem/SocketIOServerEventBus.ts b/events/EventSystem/SocketIOServerEventBus.ts index 328ae6f..a139f5f 100644 --- a/events/EventSystem/SocketIOServerEventBus.ts +++ b/events/EventSystem/SocketIOServerEventBus.ts @@ -23,7 +23,7 @@ export class SocketIOServerEventBus implements EventBusInterface { private globalHandlers: Map void> = new Map() // Per-socket subscriptions for cleanup - private socketSubscriptions: Map = new Map() + private socketSubscriptions: Map> = new Map() // Track which socket is currently processing a request private currentSocket: Socket | undefined @@ -73,7 +73,7 @@ export class SocketIOServerEventBus implements EventBusInterface { event, totalClients, totalSubscriptions, - + totalConnections, socketId.substring(0, 8), socketSubs, diff --git a/package.json b/package.json index 7e2bbd7..e2ff84a 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "builder-util-runtime": "^9", "chai": "^4.2.0", "cspell": "^8.6.1", - "electron": "29.2.0", + "electron": "39.2.7", "electron-builder": "^24.13.3", "mocha": "^10.4.0", "mustache": "4", diff --git a/src/server.ts b/src/server.ts index a9b86ba..a9eead6 100644 --- a/src/server.ts +++ b/src/server.ts @@ -73,7 +73,7 @@ async function startServer() { backendRpc.on(makeSaveDialogRpc(), async request => { // In browser mode, file saving is handled client-side via download - return { canceled: true, filePath: undefined } + return { canceled: true, filePath: '' } }) backendRpc.on(getAppVersion, async () => { diff --git a/src/spec/mock-sparkplugb.ts b/src/spec/mock-sparkplugb.ts index def8074..62661f7 100644 --- a/src/spec/mock-sparkplugb.ts +++ b/src/spec/mock-sparkplugb.ts @@ -22,8 +22,8 @@ export interface MockSparkplugClient { stop: () => void } -var sample = (function () { - var config = { +let sample = (function () { + let config = { serverUrl: 'tcp://127.0.0.1:1883', username: '', password: '', @@ -169,12 +169,12 @@ var sample = (function () { // Create node command handler // spell-checker: disable-next-line sparkplugClient.on('ncmd', function (payload: UPayload) { - var timestamp = payload.timestamp, + let timestamp = payload.timestamp, metrics = payload.metrics if (metrics !== undefined && metrics !== null) { - for (var i = 0; i < metrics.length; i++) { - var metric = metrics[i] + for (let i = 0; i < metrics.length; i++) { + let metric = metrics[i] if (metric.name == 'Node Control/Rebirth' && metric.value) { console.log("Received 'Rebirth' command") // Publish Node BIRTH certificate @@ -189,7 +189,7 @@ var sample = (function () { // Create device command handler // spell-checker: disable-next-line sparkplugClient.on('dcmd', function (deviceId: string, payload: UPayload) { - var timestamp = payload.timestamp, + let timestamp = payload.timestamp, metrics = payload.metrics, inboundMetricMap: { [name: string]: any } = {}, outboundMetric: Array = [], @@ -199,8 +199,8 @@ var sample = (function () { // Loop over the metrics and store them in a map if (metrics !== undefined && metrics !== null) { - for (var i = 0; i < metrics.length; i++) { - var metric = metrics[i] + for (let i = 0; i < metrics.length; i++) { + let metric = metrics[i] if (metric.name !== undefined && metric.name !== null) { inboundMetricMap[metric.name] = metric.value } @@ -239,7 +239,7 @@ var sample = (function () { return connected } - return { run: run } + return { run } })() export default sample diff --git a/src/spec/testMcpIntrospection.ts b/src/spec/testMcpIntrospection.ts index befaa27..48a2987 100644 --- a/src/spec/testMcpIntrospection.ts +++ b/src/spec/testMcpIntrospection.ts @@ -35,7 +35,7 @@ async function main() { console.log(`✓ Window ready, title: ${title}`) // Check console logs for remote debugging message - const logs: string[] = [] + const logs: Array = [] page.on('console', msg => { const text = msg.text() logs.push(text) diff --git a/yarn.lock b/yarn.lock index d98b26e..0e8ade0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1500,13 +1500,20 @@ dependencies: undici-types "~7.16.0" -"@types/node@>=13.7.0", "@types/node@^20.9.0": +"@types/node@>=13.7.0": version "20.12.4" resolved "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz" integrity sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw== dependencies: undici-types "~5.26.4" +"@types/node@^22.7.7": + version "22.19.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.3.tgz#8dfde7630d7a8528dc9b34db23d34f764467c02c" + integrity sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA== + dependencies: + undici-types "~6.21.0" + "@types/normalize-package-data@^2.4.3": version "2.4.4" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" @@ -3112,13 +3119,13 @@ electron-updater@^4.6: lodash.isequal "^4.5.0" semver "^7.3.5" -electron@29.2.0: - version "29.2.0" - resolved "https://registry.npmjs.org/electron/-/electron-29.2.0.tgz" - integrity sha512-ALKrCN52RG4g9prx4DriXSPnY5WoiyRUCNp7zEVQuoiNOpHTNqMMpRidQAHzntV4hajF1LMWHVoBkwqIs1jHhg== +electron@39.2.7: + version "39.2.7" + resolved "https://registry.yarnpkg.com/electron/-/electron-39.2.7.tgz#1cf2371304994fe26c564764bd50878fe405fb4b" + integrity sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ== dependencies: "@electron/get" "^2.0.0" - "@types/node" "^20.9.0" + "@types/node" "^22.7.7" extract-zip "^2.0.1" emoji-regex@^8.0.0: @@ -7995,6 +8002,11 @@ undici-types@~5.26.4: resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + undici-types@~7.16.0: version "7.16.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46"