chore: upload sw script from runner iframe
All checks were successful
Docs / build (push) Successful in 2m11s

hopefully this should fix firefox 🙏
This commit is contained in:
alina 🌸 2025-01-21 07:02:42 +03:00
parent c2107bf01d
commit 04947eb8c9
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
5 changed files with 40 additions and 19 deletions

View file

@ -1,15 +1,23 @@
import type { DropdownMenuTriggerProps } from '@kobalte/core/dropdown-menu' import type { DropdownMenuTriggerProps } from '@kobalte/core/dropdown-menu'
import type { mtcute } from 'mtcute-repl-worker/client'
import type { CustomTypeScriptWorker } from '../editor/utils/custom-worker.ts' import type { CustomTypeScriptWorker } from '../editor/utils/custom-worker.ts'
import { timers } from '@fuman/utils' import { timers } from '@fuman/utils'
import { persistentAtom } from '@nanostores/persistent' import { persistentAtom } from '@nanostores/persistent'
import { LucideCheck, LucidePlay, LucidePlug, LucideRefreshCw, LucideSkull, LucideUnplug } from 'lucide-solid' import { LucideCheck, LucidePlay, LucidePlug, LucideRefreshCw, LucideSkull, LucideUnplug } from 'lucide-solid'
import { languages, Uri } from 'monaco-editor/esm/vs/editor/editor.api.js' import { languages, Uri } from 'monaco-editor/esm/vs/editor/editor.api.js'
import { type mtcute, workerInvoke } from 'mtcute-repl-worker/client'
import { nanoid } from 'nanoid'
import { createEffect, createSignal, on, onCleanup, onMount } from 'solid-js' import { createEffect, createSignal, on, onCleanup, onMount } from 'solid-js'
import { Dynamic } from 'solid-js/web' import { Dynamic } from 'solid-js/web'
import { Button } from '../../lib/components/ui/button.tsx' import { Button } from '../../lib/components/ui/button.tsx'
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuGroupLabel, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '../../lib/components/ui/dropdown-menu.tsx' import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuGroupLabel,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '../../lib/components/ui/dropdown-menu.tsx'
import { cn } from '../../lib/utils.ts' import { cn } from '../../lib/utils.ts'
import { $activeAccountId } from '../../store/accounts.ts' import { $activeAccountId } from '../../store/accounts.ts'
import { $tabs } from '../../store/tabs.ts' import { $tabs } from '../../store/tabs.ts'
@ -41,7 +49,6 @@ export function Runner(props: { isResizing: boolean }) {
const enableUpdates = useStore($enableUpdates) const enableUpdates = useStore($enableUpdates)
const enableVerbose = useStore($enableVerbose) const enableVerbose = useStore($enableVerbose)
let currentScriptId: string | undefined
let deadTimer: timers.Timer | undefined let deadTimer: timers.Timer | undefined
let inactivityTimer: timers.Timer | undefined let inactivityTimer: timers.Timer | undefined
let iframeContainerRef!: HTMLIFrameElement let iframeContainerRef!: HTMLIFrameElement
@ -102,8 +109,6 @@ export function Runner(props: { isResizing: boolean }) {
} }
case 'SCRIPT_END': { case 'SCRIPT_END': {
setRunning(false) setRunning(false)
workerInvoke('sw', 'forgetScript', { name: currentScriptId! })
currentScriptId = undefined
rescheduleInactivityTimer() rescheduleInactivityTimer()
break break
} }
@ -180,12 +185,9 @@ export function Runner(props: { isResizing: boolean }) {
} }
} }
currentScriptId = nanoid()
await workerInvoke('sw', 'uploadScript', { name: currentScriptId, files })
runnerIframe()!.contentWindow!.postMessage({ runnerIframe()!.contentWindow!.postMessage({
event: 'RUN', event: 'RUN',
scriptId: currentScriptId, files,
exports, exports,
}, '*') }, '*')
setRunning(true) setRunning(true)
@ -328,7 +330,7 @@ export function Runner(props: { isResizing: boolean }) {
</DropdownMenu> </DropdownMenu>
</div> </div>
</div> </div>
<div class="bg-border h-px shrink-0" /> <div class="h-px shrink-0 bg-border" />
<Devtools <Devtools
class={cn('size-full grow-0', props.isResizing && 'pointer-events-none')} class={cn('size-full grow-0', props.isResizing && 'pointer-events-none')}
iframeRef={setDevtoolsIframe} iframeRef={setDevtoolsIframe}

View file

@ -19,6 +19,9 @@ await build({
format: 'esm', format: 'esm',
outfile: 'src/sw/iframe/script-bundled.js', outfile: 'src/sw/iframe/script-bundled.js',
define: defines, define: defines,
external: ['@mtcute/web'], external: [
'@mtcute/web',
'./sw.ts',
],
minify: true, minify: true,
}) })

View file

@ -12,7 +12,10 @@ let nextId = 0
const pending = new Map<number, Deferred<any>>() const pending = new Map<number, Deferred<any>>()
export async function swInvokeMethod(request: SwMessage) { export async function swInvokeMethod(request: SwMessage) {
const sw = await getServiceWorker() return swInvokeMethodInner(request, await getServiceWorker())
}
export async function swInvokeMethodInner(request: SwMessage, sw: ServiceWorker) {
if (!registered) { if (!registered) {
navigator.serviceWorker.addEventListener('message', (e) => { navigator.serviceWorker.addEventListener('message', (e) => {
const { id, result, error } = (e as MessageEvent).data const { id, result, error } = (e as MessageEvent).data

View file

@ -1,4 +1,7 @@
import { asNonNull } from '@fuman/utils'
import { Long, TelegramClient } from '@mtcute/web' import { Long, TelegramClient } from '@mtcute/web'
import { nanoid } from 'nanoid'
import { swInvokeMethodInner } from '../client.ts'
type ConnectionState = import('@mtcute/web').ConnectionState type ConnectionState = import('@mtcute/web').ConnectionState
type TelegramClientOptions = import('@mtcute/web').TelegramClientOptions type TelegramClientOptions = import('@mtcute/web').TelegramClientOptions
@ -31,6 +34,7 @@ chobitsu.setOnMessage((message: string) => {
let lastAccountId: string | undefined let lastAccountId: string | undefined
let lastConnectionState: ConnectionState | undefined let lastConnectionState: ConnectionState | undefined
let currentScriptId: string | undefined
let logUpdates = false let logUpdates = false
let verboseLogs = false let verboseLogs = false
@ -70,7 +74,7 @@ function initClient(accountId: string, verbose: boolean) {
}) })
} }
window.addEventListener('message', ({ data }) => { window.addEventListener('message', async ({ data }) => {
if (data.event === 'INIT') { if (data.event === 'INIT') {
sendToDevtools({ sendToDevtools({
method: 'Page.frameNavigated', method: 'Page.frameNavigated',
@ -102,9 +106,12 @@ window.addEventListener('message', ({ data }) => {
window.parent.postMessage({ event: 'PING' }, HOST_ORIGIN) window.parent.postMessage({ event: 'PING' }, HOST_ORIGIN)
}, 500) }, 500)
} else if (data.event === 'RUN') { } else if (data.event === 'RUN') {
currentScriptId = nanoid()
await swInvokeMethodInner({ event: 'UPLOAD_SCRIPT', name: currentScriptId, files: data.files }, asNonNull(navigator.serviceWorker.controller))
const el = document.createElement('script') const el = document.createElement('script')
el.type = 'module' el.type = 'module'
let script = `import * as result from "/sw/runtime/script/${data.scriptId}/main.js";` let script = `import * as result from "/sw/runtime/script/${currentScriptId}/main.js";`
for (const exportName of data.exports ?? []) { for (const exportName of data.exports ?? []) {
script += `window.${exportName} = result.${exportName};` script += `window.${exportName} = result.${exportName};`
} }
@ -114,9 +121,11 @@ window.addEventListener('message', ({ data }) => {
script += 'console.log("[mtcute-repl] Script ended");' script += 'console.log("[mtcute-repl] Script ended");'
} }
script += 'window.__handleScriptEnd();' script += 'window.__handleScriptEnd();'
el.textContent = script el.textContent = script
el.addEventListener('error', e => window.__handleScriptEnd(e.error)) el.addEventListener('error', e => window.__handleScriptEnd(e.error))
window.__currentScript = el window.__currentScript = el
document.body.appendChild(el) document.body.appendChild(el)
} else if (data.event === 'FROM_DEVTOOLS') { } else if (data.event === 'FROM_DEVTOOLS') {
chobitsu.sendRawMessage(data.value) chobitsu.sendRawMessage(data.value)
@ -152,6 +161,10 @@ window.addEventListener('message', ({ data }) => {
window.__handleScriptEnd = (error) => { window.__handleScriptEnd = (error) => {
if (!window.__currentScript) return if (!window.__currentScript) return
if (currentScriptId) {
swInvokeMethodInner({ event: 'FORGET_SCRIPT', name: currentScriptId }, asNonNull(navigator.serviceWorker.controller))
.catch(console.error)
}
window.parent.postMessage({ event: 'SCRIPT_END', error }, HOST_ORIGIN) window.parent.postMessage({ event: 'SCRIPT_END', error }, HOST_ORIGIN)
window.__currentScript.remove() window.__currentScript.remove()
window.__currentScript = undefined window.__currentScript = undefined

View file

@ -59,19 +59,19 @@ export type SwMessage =
| { event: 'CLEAR_AVATAR_CACHE', accountId: string } | { event: 'CLEAR_AVATAR_CACHE', accountId: string }
| { event: 'CLEAR_CACHE' } | { event: 'CLEAR_CACHE' }
function handleMessage(msg: SwMessage) { async function handleMessage(msg: SwMessage) {
switch (msg.event) { switch (msg.event) {
case 'UPLOAD_SCRIPT': { case 'UPLOAD_SCRIPT': {
uploadScript(msg.name, msg.files) await uploadScript(msg.name, msg.files)
break break
} }
case 'FORGET_SCRIPT': { case 'FORGET_SCRIPT': {
forgetScript(msg.name) await forgetScript(msg.name)
break break
} }
case 'CLEAR_CACHE': { case 'CLEAR_CACHE': {
clearCache() clearCache()
forgetAllScripts() await forgetAllScripts()
break break
} }
case 'CLEAR_AVATAR_CACHE': { case 'CLEAR_AVATAR_CACHE': {