Frontmatter
| id | 8149 |
| title | Architecture: Migrate from ''main'' destination to explicit Window IDs |
| state | Closed |
| labels | enhancementepicaiarchitecture |
| assignees | tobiu |
| createdAt | Dec 19, 2025, 11:27 PM |
| updatedAt | Dec 21, 2025, 5:04 PM |
| githubUrl | https://github.com/neomjs/neo/issues/8149 |
| author | tobiu |
| commentsCount | 4 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Dec 21, 2025, 5:04 PM |
Architecture: Migrate from 'main' destination to explicit Window IDs

Input from Gemini 2.5 pro:
✦ Progress Update: Phase 1 Complete & Phase 2 In Progress
We have successfully implemented the core architectural changes in commit
80047446741083289a7d1a3a0ec0f76320e9ad58.Completed Items:
- Hybrid Routing Support:
Neo.worker.Base#sendMessagenow acceptswindowId(or port ID) directly as a destination, bypassing the legacy'main'fallback logic.- Manager Routing:
Neo.worker.Managernow treats its ownwindowIdas equivalent to'main', enabling precise targeting.- Auto-Migration for Remote Methods:
RemoteMethodAccessnow automatically promotes the destination from'main'towindowIdif the method payload contains awindowId. It also cleans the payload by removing the redundantwindowIdproperty.- Manual Migration: Critical methods like
App.applyDeltasandregisterApphave been manually updated to use the new routing scheme.Current State: The system is in a "Hybrid" state. New code (and auto-migrated remote calls) uses the strict
windowIdrouting. Legacy code using'main'will continue to work but will now trigger a deprecation warning in the console when running in a SharedWorker environment.Next Steps: Monitor the console for
sendMessage destination "main" is deprecatedwarnings to identify and migrate any remaining edge cases (e.g., third-party addons or manualsendMessagecalls).

Input from Gemini 2.5 pro:
✦ I have completed a comprehensive review and refactoring of
src/main/addon/*.mjsto ensure all remote methods adhere to the required object parameter pattern. This is a critical step in Phase 2 of the migration to support explicit window IDs.Refactoring Summary:
The following methods were updated to accept a single object argument (or destructure from it), ensuring compatibility with the new
windowIdinjection logic:
Cookie.mjs:
getCookie(name)→getCookie({name})getCookies()→getCookies(data)setCookie(value)→setCookie({value})DocumentHead.mjs:
getCanonical()→getCanonical(data)getDescription()→getDescription(data)getTitle()→getTitle(data)HighlightJS.mjs:
switchTheme(theme)→switchTheme({theme})- Updated internal usages of
Stylesheet.createStyleSheetto match its new signature.Markdown.mjs:
markdownToHtml(markdown)→markdownToHtml({markdown})Mwc.mjs:
checkValidity(id)→checkValidity({id})loadButtonModule()→loadButtonModule(data)loadTextFieldModule()→loadTextFieldModule(data)reportValidity(id)→reportValidity({id})Stylesheet.mjs:
createStyleSheet(name, id, href)→createStyleSheet({name, id, href})- Updated all internal calls within
Stylesheet.mjsto use the new object signature.Additional Notes:
- Identified and tracked a technical debt item: #8152 ("Combine DomAccess.addScript and loadScript into a unified API") to resolve the overlap between
addScript(remote) andloadScript(local helper).- Verified that
DomAccess.loadScriptis currently a local helper and does not require remote method refactoring at this stage.

Input from Gemini 2.5 pro:
✦ I have analyzed the request to challenge Phase 3. You are absolutely correct: forcing
windowIdin single-window (SPA) environments wheredestination: 'main'is unambiguous would be unnecessary friction.Revised Phase 3 Strategy:
- SharedWorker Environments: Strict enforcement.
destination: 'main'is ambiguous here and will be deprecated/removed to prevent routing errors.windowIdis mandatory.- Dedicated Worker / SPA Environments: Permissive.
destination: 'main'(or implicit destination) remains supported. Since there is only one Main Thread, there is no ambiguity, and forcing developers to managewindowIdoffers no architectural benefit.Implementation Status: The current codebase already supports this distinction:
Neo.worker.Base#sendMessageonly logs the deprecation warning ifthis.isSharedWorkeris true.Neo.worker.Manager(Main Thread) accepts messages addressed to'main'or its specificwindowId.RemoteMethodAccessdefaults to'main'if nowindowIdis provided, which works seamlessly in SPAs.I will proceed with the understanding that Phase 3 "Removal" applies only to SharedWorker modes. No code changes are required to support this "allowance" as it is the current behavior, but we will ensure no future commits break this compatibility.

Closing as Phase 3 requirements are already met by the current hybrid implementation. Strict enforcement is applied only to SharedWorker environments, while remains supported for standard SPAs.
This epic proposes a fundamental architectural shift to replace the ambiguous
destination: 'main'with explicitwindowIds for all cross-worker communication.The Problem: In a multi-window environment (SharedWorker), "Main" is a relative term. To the App Worker, multiple connected windows are just different clients (ports). Currently, code uses
sendMessage('main', {windowId: '...'}). This relies onNeo.worker.Base#sendMessageinspecting the options to find the correct port, with a dangerous fallback toports[0]if the ID is missing.The Solution: Stop using the generic string
'main'as a destination. Instead,sendMessageshould accept the targetwindowIddirectly as thedestinationargument.Target API:
// Old Neo.currentWorker.sendMessage('main', {windowId: 'uuid-123', action: 'foo'}); // New Neo.currentWorker.sendMessage('uuid-123', {action: 'foo'});Benefits:
sendMessagebecomes a simple lookup:ports[dest]. No complexif/elselogic to check options for IDs.destination: "uuid-123"are instantly clear.Implementation Strategy (Phased):
Phase 1: Hybrid Support (Core Refactoring):
Neo.worker.Base#sendMessageto treat thedestargument as a potentialwindowIdorportId.destmatches a connected port's ID or Window ID, route to it directly.'main'support for backward compatibility.Phase 2: Caller Migration:
RemoteMethodAccessto use theorigin(which should be a window ID) as thedestinationfor replies.App.applyDeltas) to passwindowIdas the first argument.Phase 3: Deprecation & Removal:
destination: 'main'is used in a SharedWorker context.'main'as a destination string entirely.