Skip to content

refactor(gui): remove the Services system, flatten into plain singleton modules#3405

Open
jelveh wants to merge 1 commit into
mainfrom
flatten-gui-services
Open

refactor(gui): remove the Services system, flatten into plain singleton modules#3405
jelveh wants to merge 1 commit into
mainfrom
flatten-gui-services

Conversation

@jelveh

@jelveh jelveh commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What

Removes the GUI's mini service framework (src/gui/src/services/) and flattens it into plain ES-module singletons.

The old system had:

  • a Service base class (in definitions.js) with construct/init/__on/context magic
  • a globalThis.services string-keyed registry with a two-phase construct→init lifecycle and an emit/__on_* event bus
  • a frontend↔backend service_script bridge (window.service_script / service_script_api_promise / PuterHomepageService.registerScript) for registering extra services from the backend

Nothing used the extension bridge, and the framework was indirection over what are really just nine long-lived singletons.

Changes

  • Move the nine services to src/gui/src/modules/ as plain classes exporting a singleton: process, exec, ipc, broadcast, theme, debug, locale, anti-csrf. __launch-on-init becomes a plain launch_on_init(gui_params) function (nothing else referenced it). Method bodies are unchanged.
  • Direct imports replace globalThis.services.get(name) at every call site (IPC.js, helpers.js, helpers/launch_app.js, UIDesktop.js, UIWindowThemeDialog.js, UIWindowTaskManager.js, UIWindowNewPassword.js, UIWindowManageSessions.js, and cross-module refs).
  • The single gui:ready event (the only user of the event bus) becomes a direct process_service.on_gui_ready() call from UIDesktop.
  • launch_services() now just calls init() on the four modules that need runtime setup (exec/debug/theme/process), then runs launch_on_init. All singletons are constructed at import time, so the original construct-before-init ordering is preserved.
  • Remove the Service base class from definitions.js.
  • Remove the unused service_script bridge from PuterHomepageService (the window.service_script shim, registerScript, #serviceScripts, and the serviceScriptTags injection point).

No container, no string-keyed registry, no base-class lifecycle, no event emitter, no backend bridge — just singletons wired by import.

Net: +121 / −253 lines across 20 files (renames preserved).

Testing

  • webpack GUI build: clean (only pre-existing asset-size warnings)
  • backend tsc -p tsconfig.build.json: 0 errors
  • HomepageController.test.ts: 8/8 pass (validates the shell HTML still renders after the service_script removal)
  • Booted the app and exercised it in the browser with no console errors:
    • desktop + dashboard render
    • File Manager window opens
    • launching an SDK app (Dev Center) → registered as a process
    • Task Manager shows the correct process tree (Puter/Init, explorer/UI, dev-center/App) — validates process_service init + register + tree

…on modules

The GUI had a mini service framework in src/gui/src/services/: a `Service`
base class (definitions.js) with `construct`/`init`/`__on`/`context` magic, a
`globalThis.services` string-keyed registry with a two-phase construct→init
lifecycle and an `emit`/`__on_*` event bus, plus a frontend↔backend
`service_script` bridge for registering extra services from the backend.

Nothing used the extension bridge, and the framework added indirection over
what are really just nine long-lived singletons. This flattens all of it:

- Move the nine services to src/gui/src/modules/ as plain classes exporting a
  singleton (process, exec, ipc, broadcast, theme, debug, locale, anti-csrf).
  `__launch-on-init` becomes a plain `launch_on_init(gui_params)` function
  since nothing else references it. Method bodies are unchanged.
- Cross-service access is now direct ES-module imports instead of
  `globalThis.services.get(name)`. No base class, no registry, no lifecycle
  phases, no event bus. The single `gui:ready` event becomes a direct
  `process_service.on_gui_ready()` call from UIDesktop.
- launch_services() now just calls init() on the four modules that need
  runtime setup (exec/debug/theme/process), then runs launch_on_init. All
  singletons are constructed at import, so construct-before-init ordering is
  preserved.
- Remove the `Service` base class from definitions.js.
- Remove the unused `service_script` bridge from PuterHomepageService (the
  `window.service_script`/`service_script_api_promise` shim, `registerScript`,
  `#serviceScripts`, and the `serviceScriptTags` injection point).

Verified: webpack GUI build and backend tsc both clean; homepage controller
tests pass; booted the app and exercised the desktop, launching an SDK app
(process registration) and the Task Manager (process tree) with no console
errors.
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 76.06%
🟰 ±0%
16221 / 21324
🔵 Statements 74.32%
⬆️ +0.01%
17264 / 23228
🔵 Functions 72.85%
⬆️ +0.03%
2698 / 3703
🔵 Branches 62.85%
🟰 ±0%
11290 / 17963
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/backend/services/homepage/PuterHomepageService.ts 70.76%
⬆️ +1.20%
60.6%
🟰 ±0%
77.77%
⬆️ +14.14%
73.77%
⬆️ +1.47%
83, 93-103, 123-132, 204, 325-339, 349, 357-365
Generated in workflow #538 for commit bc3f778 by the Vitest Coverage Report Action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant