From afea8fe80d77d6a0066d52c90ea667df105d3202 Mon Sep 17 00:00:00 2001 From: KernelDeimos <7225168+KernelDeimos@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:31:02 -0400 Subject: [PATCH] dev: introduce NullDevConsoleService In the prod environment there is no instance of DevConsoleService. If methods are called on the service without a check to see if it exists, this results in "read on undefined" errors that can only be produced in a prod environment. This was the cause of the issue caused by the previous log cleanup PR where it looked like "websockets were broken". The missing undefined check is fixed by #1734, but the change in this commit will catch future cases. Additionally, this change will help with moving away from the dev console. --- src/backend/src/CoreModule.js | 7 +++-- .../src/services/NullDevConsoleService.js | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/backend/src/services/NullDevConsoleService.js diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index b0906b76d..3b84a2a53 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -133,7 +133,6 @@ const install = async ({ context, services, app, useapi, modapi }) => { const { HTTPThumbnailService } = require('./services/thumbnails/HTTPThumbnailService'); const { PureJSThumbnailService } = require('./services/thumbnails/PureJSThumbnailService'); const { NAPIThumbnailService } = require('./services/thumbnails/NAPIThumbnailService'); - const { DevConsoleService } = require('./services/DevConsoleService'); const { RateLimitService } = require('./services/sla/RateLimitService'); const { AuthService } = require('./services/auth/AuthService'); const { PreAuthService } = require("./services/auth/PreAuthService"); @@ -270,8 +269,12 @@ const install = async ({ context, services, app, useapi, modapi }) => { }); services.registerService('__refresh-assocs', RefreshAssociationsService); services.registerService('__prod-debugging', MakeProdDebuggingLessAwfulService); - if ( config.env == 'dev' ) { + if ( config.env == 'dev' && ! config.no_devconsole ) { + const { DevConsoleService } = require('./services/DevConsoleService'); services.registerService('dev-console', DevConsoleService); + } else { + const { NullDevConsoleService } = require('./services/NullDevConsoleService'); + services.registerService('dev-console', NullDevConsoleService); } const { EventService } = require('./services/EventService'); diff --git a/src/backend/src/services/NullDevConsoleService.js b/src/backend/src/services/NullDevConsoleService.js new file mode 100644 index 000000000..fca4ae85d --- /dev/null +++ b/src/backend/src/services/NullDevConsoleService.js @@ -0,0 +1,29 @@ +const BaseService = require("./BaseService"); + +/** + * When DevConsoleService is not enabled, it is a more robust approach + * to replace it with a null implementation rather than not have + * 'dev-console' present in the services registry. This is because any + * errors caused by accessing methods on 'dev-console' without ensuring + * it exists are likely only to be caught in the production environment. + */ +class NullDevConsoleService extends BaseService { + notice ({ colors, title, lines }) { + colors = colors ?? { + bg: '46', + bginv: '36', + }; + + console.log(`\x1B[${colors.bginv}m▐\x1B[0m\x1B[${colors.bg}m ${title} \x1B[0m`); + for ( const line of lines ) { + console.log(`\x1B[${colors.bginv}m▐▌\x1B[0m${line}\x1B[0m`); + } + } + turn_on_the_warning_lights () {} + add_widget () {} + remove_widget () {} +} + +module.exports = { + NullDevConsoleService +};