diff --git a/package-lock.json b/package-lock.json index bcd172176..c2ff6cd0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5812,16 +5812,16 @@ } }, "node_modules/@microsoft/signalr": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.1.tgz", - "integrity": "sha512-witYtScUxPxl1QA69AsuVIsn54S4Rcfym3c/ON2bsA0ZWHcvskA0dUnOX9JCxOduGMEGwkMprKFfVTxUO/inzQ==", + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-10.0.11.tgz", + "integrity": "sha512-FulOJ2EEtKvLQcswe/U7v8pzyXyk7Jua5xgWJPPwyQU/2Z9ORvKcVjyO75VvLsem+CJ1ORRexJ+7Bz1FCei2aw==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", - "eventsource": "^1.0.7", - "fetch-cookie": "^0.11.0", - "node-fetch": "^2.6.1", - "ws": "^7.4.5" + "eventsource": "^2.0.2", + "fetch-cookie": "^2.0.3", + "node-fetch": "^2.6.7", + "ws": "^7.5.10" } }, "node_modules/@microsoft/signalr/node_modules/ws": { @@ -16256,12 +16256,12 @@ } }, "node_modules/eventsource": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.2.tgz", - "integrity": "sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=12.0.0" } }, "node_modules/execa": { @@ -16761,15 +16761,13 @@ "license": "MIT" }, "node_modules/fetch-cookie": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", - "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.2.0.tgz", + "integrity": "sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==", "license": "Unlicense", "dependencies": { - "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" - }, - "engines": { - "node": ">=8" + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" } }, "node_modules/fflate": { @@ -25325,6 +25323,12 @@ "node": ">= 0.8" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -29143,7 +29147,7 @@ "version": "0.9.10", "license": "MIT", "dependencies": { - "@microsoft/signalr": "6.0.1", + "@microsoft/signalr": "^10.0.11", "@reflex/angular-components": "file:../../../packages/reflex-angular-components", "@reflex/shared-types": "file:../../../packages/reflex-shared-types", "d3": "^7.9.0", diff --git a/package.json b/package.json index 4e1d2141e..6909ce604 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "lint:server": "npm run lint -w tools/ReFlex.TrackingServer/ClientApp", "test:emulator": "npm run test -w tools/emulator", "test:net-with-report": "dotnet coverage collect dotnet test --output test/artifacts/coverage-net/cobertura-coverage.xml --output-format cobertura && dotnet reportgenerator -reports:test/artifacts/coverage-net/cobertura-coverage.xml -targetdir:\"test/artifacts/coverage-net/report\" -reporttypes:Html -assemblyfilters:\"+ReFlex.*;-*.Test\"", - "test:server": "npm run test-ci -w tools/ReFlex.TrackingServer/ClientApp" + "test:server": "npm run test-ci -w tools/ReFlex.TrackingServer/ClientApp", + "update:server:dependencies": "node scripts/update_trackingserver_dependencies.cjs" }, "workspaces": [ "packages/reflex-shared-types", diff --git a/packages/reflex-angular-components/package.json b/packages/reflex-angular-components/package.json index b04d4c231..f32ad4472 100644 --- a/packages/reflex-angular-components/package.json +++ b/packages/reflex-angular-components/package.json @@ -1,6 +1,6 @@ { "name": "@reflex/angular-components", - "version": "1.0.0", + "version": "0.9.10", "description": "Angular Component library for common Components used by the ReFlex Framework", "sideEffects": false, "scripts": { diff --git a/packages/reflex-shared-types/package.json b/packages/reflex-shared-types/package.json index c855deb91..5cab7947f 100644 --- a/packages/reflex-shared-types/package.json +++ b/packages/reflex-shared-types/package.json @@ -1,6 +1,6 @@ { "name": "@reflex/shared-types", - "version": "0.9.8", + "version": "0.9.10", "description": "common types for reuse between typescript projects", "module": "dist/index.js", "types": "dist/index.d.ts", diff --git a/scripts/update_trackingserver_dependencies.cjs b/scripts/update_trackingserver_dependencies.cjs new file mode 100644 index 000000000..343743534 --- /dev/null +++ b/scripts/update_trackingserver_dependencies.cjs @@ -0,0 +1,75 @@ +// Usage: npm run update:server:dependencies +// Requires no npm install. Paths are resolved relative to this script. +// Merge declared dependencies (not devDependencies or installed/lockfile versions). +// App entries override root entries; file: references use the local package version. +// Only the target's dependencies object is replaced; all other bytes are preserved. +const fs = require('node:fs'); +const path = require('node:path'); + +const root = path.resolve(__dirname, '..'); +const app = path.join(root, 'tools/ReFlex.TrackingServer/ClientApp'); +const target = path.join(app, 'src/assets/data/package.json'); +const readJson = (file) => JSON.parse(fs.readFileSync(file, 'utf8')); +const isObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value); + +try { + const dependencies = {}; + for (const directory of [root, app]) { + const source = path.join(directory, 'package.json'); + const entries = readJson(source).dependencies ?? {}; + if (!isObject(entries)) throw new Error(`Invalid dependencies in ${source}`); + for (const [name, specification] of Object.entries(entries)) { + if (typeof specification !== 'string') throw new Error(`Invalid dependency ${name} in ${source}`); + let version = specification; + if (specification.startsWith('file:')) { + const localFile = path.resolve(directory, specification.slice(5), 'package.json'); + const local = readJson(localFile); + if (local.name !== name || typeof local.version !== 'string' || !local.version.trim()) { + throw new Error(`Expected package ${name} with a version in ${localFile}`); + } + version = local.version; + } + dependencies[name] = version; + } + } + + const original = fs.readFileSync(target, 'utf8'); + if (!isObject(readJson(target).dependencies)) throw new Error(`Missing dependencies object in ${target}`); + + // Find the top-level object without reformatting the surrounding JSON. + // Strings are consumed as complete tokens so braces inside strings are ignored. + const tokens = /"(?:\\.|[^"\\])*"|[{}\[\]]/g; + let depth = 0; + let start; + let end; + let keyPosition; + for (const token of original.matchAll(tokens)) { + const value = token[0]; + if (depth === 1 && value.startsWith('"') && JSON.parse(value) === 'dependencies') { + const following = original.slice(token.index + value.length).match(/^\s*:\s*\{/); + if (following) { + start = token.index + value.length + following[0].length - 1; + keyPosition = token.index; + } + } + if (value === '{' || value === '[') depth++; + if (value === '}' || value === ']') depth--; + if (start !== undefined && token.index >= start && depth === 1) { + end = token.index + 1; + break; + } + } + if (end === undefined) throw new Error(`Cannot locate dependencies in ${target}`); + + const indent = original.slice(original.lastIndexOf('\n', keyPosition) + 1, keyPosition).match(/^[\t ]*/)[0]; + const newline = original.includes('\r\n') ? '\r\n' : '\n'; + const sorted = Object.fromEntries(Object.entries(dependencies).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)); + const replacement = JSON.stringify(sorted, null, 2).replace(/\n/g, newline + indent); + const updated = original.slice(0, start) + replacement + original.slice(end); + JSON.parse(updated); + if (updated !== original) fs.writeFileSync(target, updated); + console.log(`Updated ${Object.keys(dependencies).length} dependencies in ${target}`); +} catch (error) { + console.error(`Error: ${error.message}`); + process.exitCode = 1; +} diff --git a/tools/ReFlex.TrackingServer/ClientApp/app.js b/tools/ReFlex.TrackingServer/ClientApp/app.js index f646e634e..9aae3ec44 100644 --- a/tools/ReFlex.TrackingServer/ClientApp/app.js +++ b/tools/ReFlex.TrackingServer/ClientApp/app.js @@ -22,7 +22,8 @@ function initWindow() { autoHideMenuBar: true, frame: false, webPreferences: { - nodeIntegration: true, + nodeIntegration: false, + contextIsolation: true, backgroundThrottling: false } }); diff --git a/tools/ReFlex.TrackingServer/ClientApp/package.json b/tools/ReFlex.TrackingServer/ClientApp/package.json index 1946b0e9f..27dc38a8c 100644 --- a/tools/ReFlex.TrackingServer/ClientApp/package.json +++ b/tools/ReFlex.TrackingServer/ClientApp/package.json @@ -45,7 +45,7 @@ ], "private": true, "dependencies": { - "@microsoft/signalr": "6.0.1", + "@microsoft/signalr": "^10.0.11", "@reflex/angular-components": "file:../../../packages/reflex-angular-components", "@reflex/shared-types": "file:../../../packages/reflex-shared-types", "d3": "^7.9.0", diff --git a/tools/ReFlex.TrackingServer/ClientApp/src/assets/data/package.json b/tools/ReFlex.TrackingServer/ClientApp/src/assets/data/package.json index 147df8ab1..f3d56280e 100644 --- a/tools/ReFlex.TrackingServer/ClientApp/src/assets/data/package.json +++ b/tools/ReFlex.TrackingServer/ClientApp/src/assets/data/package.json @@ -1,87 +1,33 @@ { - "name": "@reflex/trackingserver", - "version": "0.9.9", - "description": "Platform-independent server application using ASP.NET Core as backend and Angular as frontend.", - "main": "app.js", - "repository": { - "type": "git", - "url": "git+https://github.com/visualengineers/reflex.git" - }, - "author": "Mathias Müller", - "license": "MIT", - "keywords": [ - "electron", - "sdk", - "dotnet-core", - "shape-changing-interfaces", - "elastic-displays" - ], - "private": true, + "name": "@reflex/trackingserver", + "version": "0.9.10", + "description": "Platform-independent server application using ASP.NET Core as backend and Angular as frontend.", + "main": "app.js", + "repository": { + "type": "git", + "url": "git+https://github.com/visualengineers/reflex.git" + }, "dependencies": { - "@angular/animations": "19.0.5", - "@angular/common": "19.0.5", - "@angular/compiler": "19.0.5", - "@angular/core": "19.0.5", - "@angular/forms": "19.0.5", - "@angular/platform-browser": "19.0.5", - "@angular/platform-browser-dynamic": "19.0.5", - "@angular/platform-server": "19.0.5", - "@angular/router": "19.0.5", - "@angular/ssr": "19.0.6", - "@microsoft/signalr": "6.0.1", - "@reflex/shared-types": "0.9.8", - "@reflex/angular-components": "0.9.9", + "@angular/animations": "19.1.4", + "@angular/common": "19.1.4", + "@angular/compiler": "19.1.4", + "@angular/core": "19.1.4", + "@angular/forms": "19.1.4", + "@angular/platform-browser": "19.1.4", + "@angular/platform-browser-dynamic": "19.1.4", + "@angular/platform-server": "19.1.4", + "@angular/router": "19.1.4", + "@angular/ssr": "19.2.26", + "@microsoft/signalr": "^10.0.11", + "@reflex/angular-components": "0.9.10", + "@reflex/shared-types": "0.9.10", "angular-plotly.js": "^5.2.2", "d3": "^7.9.0", "file-saver": "^2.0.5", - "happy-dom": "15.11.7", + "happy-dom": "17.4.4", "plotly.js-dist-min": "^2.33.0", "rxjs": "^7.8.1", - "three": "^0.170.0", + "three": "^0.175.0", "zone.js": "^0.15.0" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^19.0.6", - "@angular-eslint/builder": "^19.0.2", - "@angular-eslint/eslint-plugin": "^19.0.2", - "@angular-eslint/eslint-plugin-template": "^19.0.2", - "@angular-eslint/schematics": "^19.0.2", - "@angular-eslint/template-parser": "^19.0.2", - "@angular/cli": "19.0.6", - "@angular/compiler-cli": "19.0.5", - "@types/d3": "^7.4.3", - "@angular/language-service": "19.0.5", - "@gtvmbh/eslint-config": "^1.1.7", - "@stylistic/eslint-plugin-ts": "^2.12.1", - "@types/file-saver": "^2.0.7", - "@types/jasmine": "~5.1.0", - "@types/jasminewd2": "~2.0.8", - "@types/node": "^18.18.0", - "@types/plotly.js-dist-min": "^2.3.4", - "@types/three": "^0.170.0", - "@types/ws": "<8.5.5", - "@types/webxr": "^0.5.20", - "@typescript-eslint/eslint-plugin": "7.18.0", - "@typescript-eslint/parser": "7.18.0", - "electron-builder": "^24.13.3", - "eslint": "^8.45.0", - "eslint-config-angular": "^0.5.0", - "eslint-plugin-angular": "^4.1.0", - "eslint-plugin-jsdoc": "^48.2.6", - "jasmine-core": "~5.5.0", - "jasmine-marbles": "^0.9.2", - "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.4.1", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "^2.1.0", - "karma-junit-reporter": "^2.0.1", - "karma-spec-reporter": "^0.0.36", - "karma-viewport": "^1.0.9", - "ng-packagr": "^19.0.1", - "puppeteer": "^23.11.1", - "tslib": "^2.3.0", - "typescript": "5.6.3" } } diff --git a/tools/ReFlex.TrackingServer/Startup.cs b/tools/ReFlex.TrackingServer/Startup.cs index 392c8522c..230ced3d2 100644 --- a/tools/ReFlex.TrackingServer/Startup.cs +++ b/tools/ReFlex.TrackingServer/Startup.cs @@ -253,7 +253,16 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { try { - var window = await Electron.WindowManager.CreateWindowAsync(); + var window = await Electron.WindowManager.CreateWindowAsync( + new ElectronNET.API.Entities.BrowserWindowOptions + { + WebPreferences = new ElectronNET.API.Entities.WebPreferences + { + NodeIntegration = false, + ContextIsolation = true + } + } + ); window.SetFullScreen(true); window.SetAutoHideMenuBar(true); }