dsh-builtin-browser 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -327,8 +327,11 @@ function windowFor(windowId: string | undefined): HostWindow {
327
327
  // regaining focus (alt-tab, click) does not automatically refocus any view
328
328
  // (electron#28163) — the last addChildView keeps the focus. Restore the view
329
329
  // the human was last using (click steering via wireFocusRouting), falling
330
- // back to the visible page view.
330
+ // back to the visible page view. Windows-only: on macOS/Linux the OS routes
331
+ // keyboard input to the clicked view natively, and forcing focus() on window
332
+ // focus fights the platform — it can leave page inputs untypeable (issue #7).
331
333
  w.on('focus', () => {
334
+ if (process.platform !== 'win32') return
332
335
  const last = win.lastFocusedViewId
333
336
  const wc = last === TOOLBAR_FOCUS ? win.toolbarView?.webContents
334
337
  : last !== undefined ? win.views.get(last)?.webContentsView.webContents
@@ -361,8 +364,14 @@ function layoutWindow(win: HostWindow): void {
361
364
  * regaining focus does not refocus any view, electron#28163). Focusing the
362
365
  * clicked view on mousedown makes the toolbar and pages behave like a real
363
366
  * browser: click the URL bar and type, click the page and type/scroll.
367
+ *
368
+ * Windows-only by design (issue #7): macOS/Linux already route keyboard input
369
+ * to the clicked view natively; calling webContents.focus() from inside the
370
+ * mousedown input-event there interferes with native click-to-focus and can
371
+ * leave login/page inputs unable to receive typed characters.
364
372
  */
365
373
  function wireFocusRouting(win: HostWindow, view: WebContentsView, focusKey: string): void {
374
+ if (process.platform !== 'win32') return
366
375
  view.webContents.on('input-event', (_event, input) => {
367
376
  if (input.type !== 'mouseDown') return
368
377
  win.lastFocusedViewId = focusKey
@@ -498,17 +507,36 @@ async function handle(op: string, msg: { id: number; viewId?: string; windowId?:
498
507
  case 'createView': {
499
508
  const viewId = msg.viewId
500
509
  if (viewId === undefined) throw new Error('createView missing viewId')
510
+ // Idempotent against a duplicate createView for the same id (e.g. two
511
+ // concurrent parent-side recoveries after a host death): re-creating
512
+ // would stack a second WebContentsView in the window and leak the
513
+ // first — the duplicate call simply confirms the existing view.
514
+ if (windowOfView(viewId) !== undefined) {
515
+ reply(msg.id, { ok: true })
516
+ return
517
+ }
501
518
  const assignment = assignments.get(viewId)
502
519
  const win = windowFor(assignment?.windowId)
503
520
  const view = new WebContentsView()
504
- // Route popups (window.open / target=_blank) back into THIS view
505
- // instead of letting Electron open untracked native windows that would
506
- // diverge from the session/tab model.
521
+ // Route popups (window.open / target=_blank) into the session/tab
522
+ // model instead of letting Electron open untracked native windows.
507
523
  view.webContents.setWindowOpenHandler(({ url }) => {
508
- // HTTP(S) popups (target=_blank, ads): redirect into this view
509
- // instead of opening an untracked native window.
524
+ // HTTP(S) popups open as a NEW TAB of this view's session: the
525
+ // parent (provider) owns the session model and its newTab action
526
+ // creates the tab in the same window, navigates it, and records it
527
+ // in the session history. Overriding THIS view with loadURL()
528
+ // destroyed the opener page — pages that need their opener context
529
+ // (portal dashboards carrying token/referer to the new window)
530
+ // lost it and the target page then 403'd (issue #8); the tab strip
531
+ // now keeps the original page alive like a real browser.
510
532
  if (/^https?:/i.test(url)) {
511
- void view.webContents.loadURL(url).catch(() => { /* navigation failures surface on the next snapshot */ })
533
+ if (win.windowId !== SHARED_WINDOW_ID) {
534
+ sendUserAction({ type: 'newTab', windowId: win.windowId, url })
535
+ } else {
536
+ // Ungrouped view (no live session to attach a tab to,
537
+ // defensive only): fall back to navigating this view.
538
+ void view.webContents.loadURL(url).catch(() => { /* navigation failures surface on the next snapshot */ })
539
+ }
512
540
  return { action: 'deny' }
513
541
  }
514
542
  // Non-HTTP popups (OAuth redirects, mailto:, custom schemes):