Skip to content

Multi-playing: recoverable loadProfile when the browser blocks it, honest setActiveProfile across tabs - #464

Merged
Delwing merged 2 commits into
masterfrom
claude/fix-issue-453
Oct 8, 2026
Merged

Delwing merged 2 commits into
masterfrom
claude/fix-issue-453

Conversation

@Delwing

@Delwing Delwing commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Addresses #453. This PR doesn't close it; the three remaining gaps are under "Not fixed here" below.

Changes

  • loadProfile(): the browser blocks the new tab on a second call in one alias, and on any call from a trigger, timer or event.
    • In that case it returns nil, msg and leaves an "Open profile " link on its own line in the main console.
    • Clicking the link opens and connects the profile, because the click is the user gesture the browser requires.
    • If the profile is already open by then, or the click is also blocked, the link says so instead of opening a second tab.
  • setActiveProfile(): for a profile open in another tab it now returns false, msg instead of a false true, since a page can't bring another tab to the front.
    • The other tab gets a new attention message over the profiles-presence BroadcastChannel and flashes its title until the user switches to it.
    • sysProfileFocusChangeEvent fires when they do.
    • Calling it for the current tab's own profile still returns true.
  • raiseGlobalEvent(): behaviour is unchanged.
    • There's no avoidable delay: it sends synchronously, and the receiving tab hands the event straight to the Lua runtime.
    • A comment guards against anyone adding a delay later.
    • Tests confirm the event arrives after the call returns and never reaches the sender, matching desktop's postInterHostEvent.
  • Documentation: all three differences from desktop are recorded in e2e/knownDivergences.ts, docs/MUDLET_API.md and luaCompletions.ts.
  • Tests: tests/scripting/multiProfile453.test.ts.

Not fixed here

These remain, and all of them come from running each profile in its own tab:

  • Several alts from one alias: browsers allow one new tab per click or key press, so the second and later alts each need a click on their link.
  • setActiveProfile() across tabs can't actually switch to the other tab.
  • raiseGlobalEvent() replies arrive one task later.

Closing these needs several profiles hosted in one tab, as desktop does. That's an estimated 35–50 file change and is out of scope for this PR.

Testing

  • yarn typecheck passes.
  • yarn test: 3 failures, none caused by this branch:
    • serverEncoding.test.ts (GBK euro sign) also fails on master.
    • added-apis (clipboard) and mapperParity295 fail only in the full parallel run and pass when run alone.
  • Not tried in a real browser with multiple tabs.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Um3ZSHRbGj1Rbf55rAQzdM


Generated by Claude Code

claude added 2 commits October 8, 2026 14:10
Each profile is its own browser tab, and three scripted multi-playing
calls behaved worse than they had to:

1. loadProfile(): a browser opens one new tab per user gesture, so the
   second call in an alias, and any call from a trigger, was refused with
   nothing left for the user to act on. The refusal now also leaves an
   "Open profile <name>" link on its own line in the main console; the
   click is the gesture the call lacked, so one click opens the profile.
   A click that finds the profile already open, or is itself blocked,
   says so instead of opening a duplicate tab.

2. setActiveProfile(): for a profile in another tab it answered true
   without switching. A page cannot bring another tab forward, so it now
   answers false with that reason and asks the target tab (over the
   profiles-presence channel) to request focus and flash its title until
   the user switches to it, when sysProfileFocusChangeEvent fires.

3. raiseGlobalEvent(): other tabs handle the event a task later, where
   desktop runs every host's handlers inline. That is inherent in separate
   tabs, so it is recorded rather than changed.

All three are recorded in e2e/knownDivergences.ts, docs/MUDLET_API.md and
the luaCompletions descriptions; tests/scripting/multiProfile453.test.ts
covers each point.

Fixes #453

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUGrWWjYht6BA7w5asDWRi
Investigated whether the cross-profile delay has an avoidable part: it
doesn't. raise() posts synchronously and the receiving tab dispatches into
Lua straight from the BroadcastChannel message event, so the browser's
cross-tab hop is the only delay. Say so where a later change would add
one, and test that the sender never receives its own global event, as
desktop's postInterHostEvent skips the sending host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUGrWWjYht6BA7w5asDWRi
@Delwing
Delwing merged commit 910ebbf into master Oct 8, 2026
10 checks passed
@Delwing
Delwing deleted the claude/fix-issue-453 branch October 8, 2026 21:49
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.

2 participants