tmux-weblink 0.3.0

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.
Files changed (75) hide show
  1. package/README.md +70 -0
  2. package/dist/assets/addon-fit-D5N335P2.js +16 -0
  3. package/dist/assets/terminal-client.js +4 -0
  4. package/dist/assets/xterm-NI46XXQY.js +51 -0
  5. package/dist/assets/xterm.css +285 -0
  6. package/dist/browser/terminal-client.js +4 -0
  7. package/dist/frontend.js +1 -0
  8. package/dist/index.js +12 -0
  9. package/dist/lib/agent-detect.js +3 -0
  10. package/dist/lib/agents-watch.js +2 -0
  11. package/dist/lib/atomicWrite.js +1 -0
  12. package/dist/lib/auditLog.js +1 -0
  13. package/dist/lib/auth.js +2 -0
  14. package/dist/lib/cli.js +32 -0
  15. package/dist/lib/commandbar.js +555 -0
  16. package/dist/lib/db.js +1 -0
  17. package/dist/lib/drawer-resize.js +166 -0
  18. package/dist/lib/drawer-script.js +8 -0
  19. package/dist/lib/ext-loader.js +1 -0
  20. package/dist/lib/html.js +1 -0
  21. package/dist/lib/icons.js +1 -0
  22. package/dist/lib/image-upload.js +1 -0
  23. package/dist/lib/load-env.js +6 -0
  24. package/dist/lib/mobile-toolbar.js +313 -0
  25. package/dist/lib/notes-db.js +18 -0
  26. package/dist/lib/notes-drawer.js +210 -0
  27. package/dist/lib/notes-utils.js +15 -0
  28. package/dist/lib/pages/agents-index.js +105 -0
  29. package/dist/lib/pages/history-index.js +85 -0
  30. package/dist/lib/pages/landing.js +78 -0
  31. package/dist/lib/pages/login.js +191 -0
  32. package/dist/lib/pages/notes-index.js +65 -0
  33. package/dist/lib/pages/notes-page.js +158 -0
  34. package/dist/lib/pages/quick-commands.js +361 -0
  35. package/dist/lib/pages/schedule-index.js +392 -0
  36. package/dist/lib/pages/settings.js +206 -0
  37. package/dist/lib/pages/terminal.js +364 -0
  38. package/dist/lib/pinned-views.js +1 -0
  39. package/dist/lib/plugins.js +3 -0
  40. package/dist/lib/quick-commands.js +1 -0
  41. package/dist/lib/rateLimiter.js +2 -0
  42. package/dist/lib/schedule-delay.js +9 -0
  43. package/dist/lib/scheduler-drawer.js +379 -0
  44. package/dist/lib/scheduler.js +1 -0
  45. package/dist/lib/security-config.js +2 -0
  46. package/dist/lib/session-access.js +1 -0
  47. package/dist/lib/session-windows.js +1 -0
  48. package/dist/lib/sessions-drawer.js +634 -0
  49. package/dist/lib/sessions-sidebar.js +1 -0
  50. package/dist/lib/settings.js +2 -0
  51. package/dist/lib/setup-features.js +1 -0
  52. package/dist/lib/setup-prompts.js +3 -0
  53. package/dist/lib/shared-layout.js +412 -0
  54. package/dist/lib/state-paths.js +1 -0
  55. package/dist/lib/terminal-config.js +1 -0
  56. package/dist/lib/theme-store.js +2 -0
  57. package/dist/lib/theme.js +28 -0
  58. package/dist/lib/themes/dark-cove.js +1 -0
  59. package/dist/lib/themes/ghostty.js +1 -0
  60. package/dist/lib/themes/index.js +1 -0
  61. package/dist/lib/themes/types.js +0 -0
  62. package/dist/lib/themes/vscode.js +1 -0
  63. package/dist/lib/themes/warm-clay.js +1 -0
  64. package/dist/lib/tmux-capture.js +5 -0
  65. package/dist/lib/tmux-control.js +2 -0
  66. package/dist/lib/tmux-panes.js +2 -0
  67. package/dist/lib/tmux-windows.js +4 -0
  68. package/dist/lib/watched-panes.js +1 -0
  69. package/dist/lib/window-history.js +1 -0
  70. package/dist/lib/window-labels.js +1 -0
  71. package/dist/lib/windows-drawer.js +364 -0
  72. package/dist/lib/ws-message.js +1 -0
  73. package/dist/sessions.js +2 -0
  74. package/package.json +62 -0
  75. package/scripts/fix-pty-perms.mjs +16 -0
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # tmux-weblink
2
+
3
+ Access your tmux sessions from the browser. A lightweight web server that lists running tmux sessions and lets you attach through a full terminal in your browser — with built-in notes, a scheduler, and sidebar extensions.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g tmux-weblink
9
+ ```
10
+
11
+ Or run directly with npx:
12
+
13
+ ```bash
14
+ npx tmux-weblink
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Interactive setup (command bar, agents page)
21
+ tmux-weblink setup
22
+
23
+ # Start on default port 3000
24
+ tmux-weblink
25
+
26
+ # Custom port
27
+ PORT=8080 tmux-weblink
28
+
29
+ # Use the default xterm.js renderer
30
+ tmux-weblink
31
+
32
+ # Optional: use ghostty-web for terminal rendering
33
+ tmux-weblink --ghostty
34
+
35
+ # Equivalent environment override
36
+ TMUX_WEB_TERMINAL_RENDERER=ghostty tmux-weblink
37
+
38
+ # Optional: tail-first buffer loading (see docs/architecture.md)
39
+ TMUX_WEB_INITIAL_LINES=1000 TMUX_WEB_HISTORY_CHUNK=500 tmux-weblink
40
+ ```
41
+
42
+ Then open `http://localhost:3000` in your browser. You'll see a list of active tmux sessions — click one to attach.
43
+
44
+ ## Documentation
45
+
46
+ - [Documentation hub](docs/index.md)
47
+ - [Notes](docs/notes.md) — per-session Markdown scratchpad
48
+ - [Scheduler](docs/scheduler.md) — delayed `send-keys` tasks
49
+ - **Windows drawer** — switch tmux windows from the terminal header (mobile-friendly tab picker)
50
+ - [Extensions](docs/extensions.md) — install, configure, and build sidebar plugins
51
+ - [Architecture](docs/architecture.md) — how the server, terminal, and extensions connect
52
+
53
+ ## Prerequisites
54
+
55
+ - **Node.js** >= 22
56
+ - **tmux** installed and available in your PATH
57
+ - Writable `~/.tmux-web/` and `~/.config/tmux-web/` (see [docs](docs/index.md) for dev-mode paths)
58
+
59
+ ## Credits
60
+
61
+ This project is built on top of ideas and code from:
62
+
63
+ - [tmux-web](https://github.com/ashutoshpw/tmux-web) by [@ashutoshpw](https://github.com/ashutoshpw)
64
+ - [persalink](https://github.com/brobata/persalink) by [@brobata](https://github.com/brobata)
65
+
66
+ It is a continuation and re-packaging of those experiments, focused on making a single-person, browser-first tmux companion that is easy to install and run.
67
+
68
+ ## License
69
+
70
+ MIT
@@ -0,0 +1,16 @@
1
+ var p=2,c=1,d=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let i=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(i._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core._renderService.dimensions;if(e.css.cell.width===0||e.css.cell.height===0)return;let i=this._terminal.options.scrollback===0?0:this._terminal.options.overviewRuler?.width||14,s=window.getComputedStyle(this._terminal.element.parentElement),l=parseInt(s.getPropertyValue("height")),o=Math.max(0,parseInt(s.getPropertyValue("width"))),t=window.getComputedStyle(this._terminal.element),r={top:parseInt(t.getPropertyValue("padding-top")),bottom:parseInt(t.getPropertyValue("padding-bottom")),right:parseInt(t.getPropertyValue("padding-right")),left:parseInt(t.getPropertyValue("padding-left"))},a=r.top+r.bottom,n=r.right+r.left,h=l-a,m=o-n-i;return{cols:Math.max(p,Math.floor(m/e.css.cell.width)),rows:Math.max(c,Math.floor(h/e.css.cell.height))}}};/*! Bundled license information:
2
+
3
+ @xterm/addon-fit/lib/addon-fit.mjs:
4
+ (**
5
+ * Copyright (c) 2014-2024 The xterm.js authors. All rights reserved.
6
+ * @license MIT
7
+ *
8
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
9
+ * @license MIT
10
+ *
11
+ * Originally forked from (with the author's permission):
12
+ * Fabrice Bellard's javascript vt100 for jslinux:
13
+ * http://bellard.org/jslinux/
14
+ * Copyright (c) 2011 Fabrice Bellard
15
+ *)
16
+ */export{d as FitAddon};
@@ -0,0 +1,4 @@
1
+ var O="https://esm.sh/ghostty-web@0.4.0",y;function U(){return y||(document.querySelector("link[data-tmux-web-xterm-css]")?y=Promise.resolve():(y=new Promise(t=>{let e=document.createElement("link");e.rel="stylesheet",e.href="/assets/xterm.css",e.setAttribute("data-tmux-web-xterm-css",""),e.addEventListener("load",()=>t(),{once:!0}),e.addEventListener("error",()=>t(),{once:!0}),document.head.appendChild(e)}),y))}var J=class j{terminal;fitAddon;container;constructor(e,n,r){this.container=e,this.terminal=n,this.fitAddon=r,this.terminal.loadAddon(this.fitAddon),this.terminal.open(e)}static async create(e,n,r){let[{Terminal:o},{FitAddon:h}]=await Promise.all([import("./xterm-NI46XXQY.js"),import("./addon-fit-D5N335P2.js"),U()]),g=new o({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:r});return new j(e,g,new h)}get cols(){return this.terminal.cols}get rows(){return this.terminal.rows}write(e){return new Promise(n=>this.terminal.write(e,n))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom()}scrollToLine(e){this.terminal.scrollToLine(Math.max(0,e))}isNearScrollbackTop(){return this.terminal.buffer.active.viewportY<=1}viewportY(){return this.terminal.buffer.active.viewportY}baseY(){return this.terminal.buffer.active.baseY}fit(){let e=V(this.container);return e.width<=0||e.height<=0?!1:(this.fitAddon.fit(),!0)}focus(){this.terminal.focus()}pasteText(e){this.terminal.paste(e)}input(e){this.terminal.input(e,!1)}onData(e){this.terminal.onData(e),this.terminal.onBinary(e)}onResize(e){this.terminal.onResize(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||this.container.contains(e))}},G=class q{terminal;container;colsValue=80;rowsValue=24;charW=0;charH=0;resizeCallbacks=[];constructor(e,n){this.container=e,this.terminal=n,this.terminal.open(e)}static async create(e,n,r){let o=await import(O);await o.init();let h=new o.Terminal({fontSize:14,fontFamily:"'JetBrains Mono', 'SF Mono', 'Menlo', monospace",cursorBlink:!0,cursorStyle:"bar",scrollback:n,convertEol:!1,theme:r});return new q(e,h)}get cols(){return this.colsValue}get rows(){return this.rowsValue}write(e){return new Promise(n=>this.terminal.write(e,n))}reset(){this.terminal.reset()}scrollToBottom(){this.terminal.scrollToBottom?.()}scrollToLine(e){this.terminal.scrollToLine?.(Math.max(0,e))}isNearScrollbackTop(){let e=this.terminal.buffer?.active;return e?e.viewportY>=e.baseY:!1}viewportY(){return this.terminal.buffer?.active?.viewportY??0}baseY(){return this.terminal.buffer?.active?.baseY??0}fit(){let e=V(this.container);if(e.width<=0||e.height<=0)return!1;this.updateCellMetrics(!this.charW||!this.charH);let n=Math.floor(e.width/this.charW),r=Math.floor(e.height/this.charH);if(n<10||r<5)return!1;if(n!==this.colsValue||r!==this.rowsValue){this.colsValue=n,this.rowsValue=r,this.terminal.resize(n,r);for(let o of this.resizeCallbacks)o({cols:n,rows:r})}return!0}focus(){(this.terminal.textarea||this.container.querySelector("textarea")||this.container)?.focus?.()}pasteText(e){let n=this.terminal.getMode?.(2004)??!1;this.input(n?"\x1B[200~"+e+"\x1B[201~":e)}input(e){this.terminal.input?.(e,!1)}onData(e){this.terminal.onData(n=>e(n))}onResize(e){this.resizeCallbacks.push(e)}onScroll(e){this.terminal.onScroll(e)}attachCustomKeyEventHandler(e){this.terminal.attachCustomKeyEventHandler(e)}isFocused(){let e=document.activeElement;return!!e&&(e===this.container||e===this.terminal.textarea||this.container.contains(e))}updateCellMetrics(e=!1){let n=this.container.querySelector("canvas");if(n instanceof HTMLElement&&n.offsetWidth>0&&n.offsetHeight>0&&this.colsValue>0&&this.rowsValue>0){let r=n.offsetWidth/this.colsValue,o=n.offsetHeight/this.rowsValue;(e||!this.charW||!this.charH)&&(this.charW=r,this.charH=o)}(!this.charW||!this.charH)&&(this.charW=9,this.charH=18)}},A=window.__TMUX_WEB_TERMINAL__;if(!A)throw new Error("missing tmux-web terminal config");var u=A,W=document.getElementById("terminal-container");if(!W)throw new Error("missing terminal container");var i=W;function Q(){let t=document.createElement("div");t.textContent="ghostty-web unavailable \u2014 using xterm.js",t.style.cssText='position:fixed;bottom:12px;right:12px;z-index:2000;background:rgba(0,0,0,0.85);color:#fbbf24;font:12px/1.4 "JetBrains Mono",monospace;padding:8px 12px;border:1px solid rgba(251,191,36,0.4);border-radius:6px;',document.body.appendChild(t),setTimeout(()=>t.remove(),6e3)}async function Z(){if(u.renderer==="ghostty")try{return await G.create(i,u.scrollback,u.theme)}catch(t){console.error("[tmux-web] ghostty-web failed to load; falling back to xterm.js:",t),Q()}return J.create(i,u.scrollback,u.theme)}var a=await Z(),c,b=0,Y,s=null,C=0,d="connecting",x=0,E=!1,T=[],m="";function $(){return T.join("")+m}async function ee(t,e=0){let n=t?a.viewportY():0,r=t?a.baseY():0,o=$();if(a.reset(),!o){t||a.scrollToBottom();return}await a.write(o),t?a.scrollToLine(r+n+e):a.scrollToBottom()}function te(t){let e;try{e=JSON.parse(t)}catch{d==="live"&&(m+=t,a.write(t));return}if(e.type==="auth.required"){let n=localStorage.getItem("tmux-web-token");n?w({type:"auth.token",token:n}):location.href="/login?returnTo="+encodeURIComponent(location.pathname+location.search);return}if(e.type==="auth.ok"){e.token&&localStorage.setItem("tmux-web-token",e.token),S(!0),f=1e3,p(),w({type:"resize",cols:a.cols,rows:a.rows}),l();return}if(e.type==="auth.failed"){if(S(!1),e.permanentLock||e.retryAfterMs&&e.retryAfterMs>6e4){localStorage.removeItem("tmux-web-token"),location.href="/login?error="+encodeURIComponent(e.message);return}let n=document.createElement("div");n.textContent="Auth failed: "+e.message,n.style.cssText='position:fixed;top:12px;right:12px;z-index:2000;background:rgba(0,0,0,0.85);color:#f87171;font:12px/1.4 "JetBrains Mono",monospace;padding:8px 12px;border:1px solid rgba(248,113,113,0.4);border-radius:6px;',document.body.appendChild(n),setTimeout(()=>n.remove(),4e3);return}if(e.type==="snapshot"&&typeof e.data=="string"){T=[e.data],m="",x=typeof e.lines=="number"?e.lines:u.terminal.initialLines,d="live",a.reset(),a.write(e.data).then(()=>a.scrollToBottom());return}if(e.type==="window_changed"&&typeof e.activeIndex=="number"){let n=new URL(location.href);n.searchParams.get("window")!==String(e.activeIndex)&&(n.searchParams.set("window",String(e.activeIndex)),history.replaceState(history.state,"",n)),window.dispatchEvent(new CustomEvent("tmux:windows",{detail:e.windows}));return}if(e.type==="history"&&typeof e.data=="string"){E=!1,e.lines>0&&e.data&&(T.unshift(e.data),x+=e.lines,ee(!0,e.lines));return}if(e.type==="data"&&typeof e.data=="string"){if(d==="connecting"){d="live",m=e.data,a.write(e.data);return}d==="live"&&(m+=e.data,a.write(e.data))}}function V(t){let e=t.getBoundingClientRect(),n=window.visualViewport;return n?{width:Math.min(e.width,n.width),height:Math.max(0,Math.min(e.height,n.height-Math.max(0,e.top)))}:e}function p(){return a.fit()}function B(){i.classList.remove("terminal-pending")}function l(){b&&cancelAnimationFrame(b),Y&&clearTimeout(Y),p(),b=requestAnimationFrame(()=>{b=0,p()&&B()}),Y=setTimeout(()=>{p()&&B()},120)}function H(){l(),setTimeout(l,50),setTimeout(l,150),setTimeout(l,300)}var F=document.getElementById("status-dot"),k=document.getElementById("status-text");function S(t){F&&(F.className="dot"+(t?" connected":"")),k&&(k.textContent=t?"connected":"reconnecting")}var ne=location.protocol==="https:"?"wss:":"ws:",re=ne+"//"+location.host+"/ws/"+encodeURIComponent(u.sessionName),ae="/api/session/"+encodeURIComponent(u.sessionName)+"/upload",f=1e3,ie=/^((?!chrome|android|crios|fxios|edgios).)*safari/i.test(navigator.userAgent);function w(t){c?.readyState===WebSocket.OPEN&&c.send(JSON.stringify(t))}function R(){let t=re,e=localStorage.getItem("tmux-web-token");e&&(t+=(t.includes("?")?"&":"?")+"token="+encodeURIComponent(e)),c=new WebSocket(t),c.onopen=()=>{d="connecting",x=0,E=!1,T=[],m="",a.reset(),f=1e3},c.onmessage=n=>{typeof n.data=="string"&&te(n.data)},c.onclose=()=>{S(!1),d="connecting",setTimeout(()=>{f=Math.min(f*2,1e4),R()},f)},c.onerror=()=>c?.close()}function L(t){w({type:"input",data:t})}function oe(t){L(t)}function X(t){return t.split(`\r
2
+ `).join(`
3
+ `).split(`
4
+ `).join("\r")}function K(t){return typeof t=="string"&&t.startsWith("image/")}function N(t){return t?.files?.length?t.files[0]??null:null}function se(t){if(!t?.items)return null;for(let e=0;e<t.items.length;e++){let n=t.items[e];if(n?.kind==="file"&&K(n.type))return n.getAsFile()}return null}function M(t){t&&k?k.textContent=t:S(c?.readyState===WebSocket.OPEN)}async function le(t){let e=new FormData,n=t instanceof File&&t.name?t.name:"upload";e.append("file",t,n);let r=localStorage.getItem("tmux-web-token"),o={};r&&(o.Authorization="Bearer "+r);let h=await fetch(ae,{method:"POST",body:e,headers:o});if(!h.ok){let I="upload failed";try{let z=await h.json();z.error&&(I=z.error)}catch{}throw new Error(I)}let g=await h.json();if(!g.path)throw new Error("no path in response");return g.path}async function P(t){try{M("uploading...");let e=await le(t);oe(e),M(null)}catch(e){console.warn("image upload:",e),M("upload failed"),setTimeout(()=>M(null),2e3)}}a.onData(t=>L(t)),a.onResize(({cols:t,rows:e})=>w({type:"resize",cols:t,rows:e})),window.tmuxWeb={sendInput:L,focusTerminal:_},a.onScroll(()=>{d!=="live"||E||!a.isNearScrollbackTop()||(E=!0,w({type:"load_history",before:x}))}),a.attachCustomKeyEventHandler(t=>t.type!=="keydown"?!0:(t.ctrlKey||t.metaKey)&&t.code==="KeyV"?(t.preventDefault(),(async()=>{try{if(navigator.clipboard?.read){let e=await navigator.clipboard.read();for(let n of e)for(let r of n.types)if(K(r)){let o=await n.getType(r);await P(o);return}}}catch{}try{let e=await navigator.clipboard?.readText();e&&a.pasteText(X(e))}catch{}})(),!1):!0);var D=0;async function ce(t){let e=se(t.clipboardData);if(e){t.preventDefault(),t.stopPropagation();let o=Date.now();if(o-D<50)return;D=o,await P(e);return}let n=t.clipboardData?.getData("text/plain");if(!n)return;t.preventDefault(),t.stopPropagation();let r=Date.now();r-D<50||(D=r,a.pasteText(X(n)))}i.addEventListener("paste",ce);var v=0;i.addEventListener("dragenter",t=>{t.preventDefault(),v++,N(t.dataTransfer)&&i.classList.add("terminal-drag-over")}),i.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy")}),i.addEventListener("dragleave",t=>{t.preventDefault(),v--,v<=0&&(v=0,i.classList.remove("terminal-drag-over"))}),i.addEventListener("drop",async t=>{t.preventDefault(),v=0,i.classList.remove("terminal-drag-over");let e=N(t.dataTransfer);e&&await P(e)}),document.addEventListener("keydown",t=>{!ie||t.key!=="Escape"||t.defaultPrevented||t.repeat||t.metaKey||t.ctrlKey||t.altKey||a.isFocused()&&(t.preventDefault(),t.stopPropagation(),L("\x1B"))},!0);function ue(t,e,n){(i.querySelector(".xterm-screen")??i).dispatchEvent(new WheelEvent("wheel",{deltaY:t,deltaMode:WheelEvent.DOM_DELTA_PIXEL,clientX:e,clientY:n,bubbles:!0,cancelable:!0}))}function _(){a.focus(),H()}i.addEventListener("touchstart",t=>{if(t.touches.length!==1){s=null;return}let e=t.touches[0];e&&(s={startX:e.clientX,startY:e.clientY,lastX:e.clientX,lastY:e.clientY,scrolling:!1},t.stopPropagation())},{passive:!0,capture:!0}),i.addEventListener("touchmove",t=>{if(!s||t.touches.length!==1)return;let e=t.touches[0];if(!e)return;let n=e.clientY-s.startY,r=e.clientX-s.startX;if(!s.scrolling){if(Math.abs(n)<8||Math.abs(n)<Math.abs(r))return;s.scrolling=!0,C=Date.now()+500}t.preventDefault(),t.stopPropagation(),ue(-(e.clientY-s.lastY),e.clientX,e.clientY),s.lastX=e.clientX,s.lastY=e.clientY},{passive:!1,capture:!0}),i.addEventListener("touchend",t=>{if(!s)return;let e=s.scrolling;s=null,t.stopPropagation(),e?(C=Date.now()+500,t.preventDefault()):_()},{passive:!1,capture:!0}),i.addEventListener("touchcancel",t=>{s=null,t.stopPropagation()},{passive:!0,capture:!0}),i.addEventListener("pointerup",t=>{t.pointerType==="touch"&&Date.now()<C&&(t.preventDefault(),t.stopPropagation())},!0),window.addEventListener("resize",l),window.visualViewport?.addEventListener("resize",l),window.visualViewport?.addEventListener("scroll",l),new ResizeObserver(l).observe(i),document.fonts?.ready.then(()=>{l(),setTimeout(l,50),setTimeout(l,200)}),i.addEventListener("focusin",H,!0),requestAnimationFrame(()=>{p()&&B(),R(),l()});