@dimina-kit/devtools 0.4.0-dev.20260716214527 → 0.4.0-dev.20260718085557
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.
- package/dist/main/app/app.js +6 -1
- package/dist/main/index.bundle.js +7658 -7306
- package/dist/main/services/cdp-session/index.d.ts +87 -0
- package/dist/main/services/cdp-session/index.js +173 -0
- package/dist/main/services/elements-forward/index.d.ts +132 -15
- package/dist/main/services/elements-forward/index.js +162 -229
- package/dist/main/services/network-forward/body-cache.d.ts +70 -0
- package/dist/main/services/network-forward/body-cache.js +175 -0
- package/dist/main/services/network-forward/frontend-dispatch.d.ts +27 -0
- package/dist/main/services/network-forward/frontend-dispatch.js +42 -0
- package/dist/main/services/network-forward/index.d.ts +80 -9
- package/dist/main/services/network-forward/index.js +419 -149
- package/dist/main/services/render-inspect/index.d.ts +10 -0
- package/dist/main/services/render-inspect/index.js +17 -98
- package/dist/main/services/safe-area/index.d.ts +4 -1
- package/dist/main/services/safe-area/index.js +62 -34
- package/dist/main/services/simulator-appdata/index.d.ts +6 -0
- package/dist/main/services/simulator-appdata/index.js +20 -1
- package/dist/main/services/simulator-storage/index.d.ts +22 -4
- package/dist/main/services/simulator-storage/index.js +51 -64
- package/dist/main/services/views/native-simulator-devtools-host.js +12 -1
- package/dist/main/services/views/native-simulator-view.js +6 -0
- package/dist/main/services/views/view-manager.d.ts +9 -0
- package/dist/main/services/views/view-manager.js +1 -1
- package/dist/main/services/workbench-context.d.ts +9 -0
- package/dist/main/services/workbench-context.js +3 -0
- package/dist/main/utils/ipc-registry.d.ts +2 -1
- package/dist/main/utils/ipc-registry.js +30 -10
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs.map +2 -2
- package/dist/renderer/assets/index-U9F8MrtV.js +49 -0
- package/dist/renderer/assets/{input-7P0WbXyg.js → input-c2OcrrZy.js} +2 -2
- package/dist/renderer/assets/ipc-transport-Blac3sOj.css +1 -0
- package/dist/renderer/assets/{ipc-transport-DTEmLpxx.js → ipc-transport-CuDJ07aE.js} +2 -2
- package/dist/renderer/assets/{popover-DsOcyIS6.js → popover-kv2qspWz.js} +2 -2
- package/dist/renderer/assets/{select-Bzbhbg9Z.js → select-DKqzMtTh.js} +2 -2
- package/dist/renderer/assets/{settings-api-B1wVFAPB.js → settings-api-qpXKDRXt.js} +2 -2
- package/dist/renderer/assets/{settings-CR1TyBWu.js → settings-dJNKTGr8.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-CFbToT4Q.js → workbenchSettings-DQ_VP5-W.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +5 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/service-host/appdata-set-data.cjs +39 -0
- package/dist/service-host/preload.cjs +21 -0
- package/dist/shared/ipc-channels.d.ts +9 -0
- package/dist/shared/ipc-channels.js +11 -0
- package/package.json +5 -5
- package/dist/renderer/assets/index-CZd3LyY8.js +0 -49
- package/dist/renderer/assets/ipc-transport-BGtDnv6p.css +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/preload/shared/expose.ts", "../../../src/preload/shared/page-iframe.ts", "../../../../inspect/dist/sid-registry.js", "../../../../inspect/dist/appdata-accumulator.js", "../../../src/preload/runtime/bridge.ts", "../../../src/preload/runtime/custom-apis.ts", "../../../src/shared/ipc-channels.ts", "../../../src/preload/runtime/temp-files.ts", "../../../src/simulator/temp-files.ts", "../../../src/preload/runtime/host.ts", "../../../src/preload/instrumentation/console.ts", "../../../src/preload/instrumentation/app-data.ts", "../../../src/shared/request-core.ts", "../../../src/preload/shared/api-compat.ts", "../../../src/preload/runtime/native-host.ts", "../../../src/shared/bridge-channels.ts", "../../../src/preload/windows/simulator.ts"],
|
|
4
|
-
"sourcesContent": ["import { contextBridge } from 'electron'\n\n/**\n * Expose `value` on the renderer's main world under `key`.\n *\n * Uses Electron's `contextBridge` only when `contextIsolation` is enabled\n * (the path that reaches the renderer's `window` through the isolated world).\n * When context isolation is OFF \u2014 e.g. the simulator/render-host/service-host\n * frames \u2014 `contextBridge.exposeInMainWorld` would always throw, so we skip it\n * entirely and assign `value` directly onto the preload realm's `window`.\n *\n * `process.contextIsolated` is Electron's renderer-side boolean for the current\n * frame: `true` when context isolation is on, `false` when it's off. (It is\n * `undefined` only in the main process, which never runs this preload helper.)\n *\n * Returns a disposer. It can only undo the direct-assignment path (a\n * `contextBridge` binding cannot be un-exposed); on the contextBridge path\n * the disposer is a no-op. The disposer never clobbers a `window[key]` that\n * something else has since reassigned.\n */\nexport function exposeOnMainWorld(key: string, value: unknown): () => void {\n let assignedToWindow = false\n\n if (process.contextIsolated) {\n // Isolated world (main / settings / view-manager host windows): the only\n // way to reach the renderer's `window` is via contextBridge. Keep the\n // defensive fallback + warn for the genuinely-unexpected failure case.\n try {\n contextBridge.exposeInMainWorld(key, value)\n }\n catch (err) {\n console.warn('[devtools/expose] contextBridge.exposeInMainWorld failed, falling back to direct window assignment:', err)\n ;(window as unknown as Record<string, unknown>)[key] = value\n assignedToWindow = true\n }\n }\n else {\n // Context isolation off (simulator <webview>, render-host, service-host):\n // contextBridge is unusable here and would always throw, so assign the\n // preload realm's `window` directly without the noisy failed attempt.\n ;(window as unknown as Record<string, unknown>)[key] = value\n assignedToWindow = true\n }\n\n return () => {\n if (!assignedToWindow) return\n const w = window as unknown as Record<string, unknown>\n if (w[key] === value) delete w[key]\n }\n}\n", "/** Locate the active page's webview iframe \u2014 the last one in the simulator stack. */\nexport function getActivePageIframe(): HTMLIFrameElement | null {\n const iframes = document.querySelectorAll<HTMLIFrameElement>('.dimina-native-webview__window')\n return iframes.length > 0 ? iframes[iframes.length - 1]! : null\n}\n", "// Stable-id registry for WXML nodes, shared by every extractor that walks a\n// render-layer document (host iframe extractors, injected guest inspectors,\n// browser preview bridges). It is dependency-free so injected bundles stay\n// small and don't drag in host-specific machinery.\n// \u5408\u6210 sid \u6CE8\u518C\u8868\uFF1A\u7528 WeakMap \u628A\u5143\u7D20 \u2194 sid \u53CC\u5411\u7ED1\u5B9A\uFF0C\u907F\u514D\u5728\u6E90 DOM \u4E0A\u5199\n// `data-*` \u5C5E\u6027\uFF08\u63D0\u53D6\u672C\u5E94\u53EA\u8BFB\uFF0C\u4E14\u5C5E\u6027\u5F62\u5F0F\u4F1A\u6C61\u67D3\u7528\u6237\u7684\u5FEB\u7167/\u9009\u62E9\u5668\uFF09\u3002\n// elBySyntheticSid \u4E3A\u53CD\u5411\u67E5\u627E\u7528 WeakRef\uFF0C\u5143\u7D20\u88AB GC \u540E\u4E0B\u6B21 lookup \u81EA\u52A8\u6E05\u7406\u3002\nexport const SYNTHETIC_SID_PREFIX = 'devtools-';\nconst syntheticSidByEl = new WeakMap();\nconst elBySyntheticSid = new Map();\nlet nextSyntheticSid = 1;\nexport function registerSyntheticSid(el) {\n const existing = syntheticSidByEl.get(el);\n if (existing)\n return existing;\n const synthetic = `${SYNTHETIC_SID_PREFIX}${nextSyntheticSid++}`;\n syntheticSidByEl.set(el, synthetic);\n elBySyntheticSid.set(synthetic, new WeakRef(el));\n return synthetic;\n}\nexport function findElementBySid(doc, sid) {\n if (sid.startsWith(SYNTHETIC_SID_PREFIX)) {\n const ref = elBySyntheticSid.get(sid);\n if (!ref)\n return null;\n const el = ref.deref();\n if (!el || !el.isConnected) {\n elBySyntheticSid.delete(sid);\n return null;\n }\n if (el.ownerDocument !== doc)\n return null;\n return el;\n }\n return doc.querySelector(`[data-sid=\"${escapeForAttrSelector(sid)}\"]`);\n}\n// `CSS.escape` only exists in real browser realms (jsdom has no `window.CSS`).\n// Inside a double-quoted attribute selector, escaping backslashes and quotes\n// is sufficient, so fall back to that when the host lacks the API.\nfunction escapeForAttrSelector(value) {\n const impl = globalThis.CSS?.escape;\n if (impl)\n return impl(value);\n return value.replace(/[\\\\\"]/g, '\\\\$&');\n}\n", "/**\n * Framework-agnostic AppData accumulator.\n *\n * The dimina runtime emits two service\u2192render messages relevant to the AppData\n * panel, identical in shape on BOTH container paths:\n * \u2022 update batches `{type:'ub', body:{bridgeId, updates:[{moduleId,data}]}}`\n * \u2014 each `data` is a partial setData patch.\n * \u2022 instance init: `type === 'page_*'`, body `{bridgeId, path, data}` with the\n * COMPLETE initial state.\n *\n * Hosts differ only in where they tap that stream \u2014 an Electron preload\n * sniffing Worker `message` events, a main-process service\u2192render forward, or\n * a same-origin web workbench observing the pageFrame's Worker. Every tap\n * feeds this one accumulator so the decode/merge/page-only/init-gate policy\n * can't drift between hosts.\n */\n/** Parse a service/worker message payload; a non-string is passed through as-is. */\nfunction parseMessagePayload(message) {\n if (typeof message !== 'string')\n return message;\n try {\n return JSON.parse(message);\n }\n catch {\n return null;\n }\n}\n/**\n * Decode a `ub` (update batch) body into patch entries, PAGE modules only \u2014\n * component-module updates are dropped (see `decodeWorkerMessage`).\n */\nfunction decodeUpdateBatchBody(rawBody) {\n const body = rawBody;\n if (!body || typeof body !== 'object')\n return null;\n if (typeof body.bridgeId !== 'string' || !Array.isArray(body.updates))\n return null;\n const out = [];\n for (const u of body.updates) {\n if (!u || typeof u.moduleId !== 'string')\n continue;\n if (!u.moduleId.startsWith('page_'))\n continue;\n out.push({ mode: 'patch', bridgeId: body.bridgeId, moduleId: u.moduleId, data: u.data });\n }\n return out.length > 0 ? out : null;\n}\n/** Decode a `page_*` instance-init body into its single init entry. */\nfunction decodePageInitBody(moduleId, rawBody) {\n const body = rawBody;\n if (!body || typeof body !== 'object')\n return null;\n if (typeof body.bridgeId !== 'string' || typeof body.path !== 'string')\n return null;\n if (!body.data || typeof body.data !== 'object')\n return null;\n return [{\n mode: 'init',\n bridgeId: body.bridgeId,\n moduleId,\n componentPath: body.path,\n data: body.data,\n }];\n}\n/**\n * Decode a service\u2192render message into AppData entries, or null when it is not\n * AppData-relevant. Policy: surface PAGE entries only \u2014 component entries are\n * dropped (they sometimes flow on a bridge id distinct from their owning page's\n * and never receive pageUnload, which would manifest as ghost tabs).\n */\nexport function decodeWorkerMessage(message) {\n const payload = parseMessagePayload(message);\n if (!payload || typeof payload !== 'object')\n return null;\n const record = payload;\n if (record.type === 'ub')\n return decodeUpdateBatchBody(record.body);\n if (typeof record.type === 'string' && record.type.startsWith('page_')) {\n return decodePageInitBody(record.type, record.body);\n }\n return null;\n}\n/** main\u2192worker direction: container signals page teardown so cache can evict. */\nexport function decodeOutgoingMessage(message) {\n const payload = parseMessagePayload(message);\n if (!payload || typeof payload !== 'object')\n return null;\n const r = payload;\n if (typeof r.type !== 'string')\n return null;\n return {\n type: r.type,\n bridgeId: typeof r.body?.bridgeId === 'string' ? r.body.bridgeId : undefined,\n };\n}\n/** Convert a decoded entry to the normalized accumulator input. */\nexport function decodedToInput(entry) {\n const input = {\n bridgeId: entry.bridgeId,\n moduleId: entry.moduleId,\n data: entry.data,\n mode: entry.mode,\n };\n if (entry.mode === 'init')\n input.componentPath = entry.componentPath;\n return input;\n}\n/**\n * Cumulative per-(bridgeId, moduleId) setData state. Pure data structure \u2014 no\n * Worker / IPC / DOM. Callers own transport (publish/emit) and the automation\n * mirror.\n */\nexport class AppDataAccumulator {\n cache = new Map();\n // Bridges in insertion order \u2014 drives the `bridges` array (stable tab order).\n bridgeOrder = [];\n // Page path per bridge: set from `page_*` init's body.path (the page route).\n bridgePagePath = new Map();\n recordBridge(bridgeId) {\n if (!this.bridgeOrder.includes(bridgeId))\n this.bridgeOrder.push(bridgeId);\n }\n /**\n * Apply one entry. Returns true if it was accepted (a mutation worth\n * republishing), false if dropped (missing ids, or the init-gate).\n */\n apply(input) {\n if (!input.bridgeId || !input.moduleId)\n return false;\n // Drop ub patches whose bridge has never been initialised. dimina\n // dispatches pageUnload \u2192 onUnload, whose setData produces a late `ub`\n // arriving AFTER clearBridge; without this gate it would resurrect the\n // unloaded bridge as a ghost tab.\n if (input.mode !== 'init' && !this.bridgePagePath.has(input.bridgeId))\n return false;\n const key = `${input.bridgeId}/${input.moduleId}`;\n const prev = this.cache.get(key);\n const incoming = input.data && typeof input.data === 'object'\n ? input.data\n : {};\n // init = full-state replace; patch = merge into previous (setData semantics)\n const merged = input.mode === 'init'\n ? { ...incoming }\n : { ...(prev?.data ?? {}), ...incoming };\n const componentPath = input.componentPath ?? prev?.componentPath;\n const next = componentPath !== undefined\n ? { componentPath, data: merged }\n : { data: merged };\n this.cache.set(key, next);\n this.recordBridge(input.bridgeId);\n if (input.mode === 'init' && input.moduleId.startsWith('page_') && input.componentPath) {\n this.bridgePagePath.set(input.bridgeId, input.componentPath);\n }\n return true;\n }\n /** Evict every entry for a bridge (page teardown). */\n clearBridge(bridgeId) {\n const prefix = `${bridgeId}/`;\n for (const key of [...this.cache.keys()]) {\n if (key.startsWith(prefix))\n this.cache.delete(key);\n }\n const idx = this.bridgeOrder.indexOf(bridgeId);\n if (idx >= 0)\n this.bridgeOrder.splice(idx, 1);\n this.bridgePagePath.delete(bridgeId);\n }\n /** The full cumulative snapshot for the panel. */\n snapshot() {\n const bridges = [];\n for (const id of this.bridgeOrder) {\n bridges.push({ id, pagePath: this.bridgePagePath.get(id) ?? null });\n }\n const entries = {};\n for (const [key, entry] of this.cache) {\n const slash = key.indexOf('/');\n if (slash < 0)\n continue;\n const bridgeId = key.slice(0, slash);\n const moduleId = key.slice(slash + 1);\n if (!entries[bridgeId])\n entries[bridgeId] = {};\n const displayKey = entry.componentPath ?? moduleId;\n entries[bridgeId][displayKey] = entry.data;\n }\n return { bridges, entries };\n }\n /**\n * The current reactive page state for a bridge: shallow-merge of `entry.data`\n * across every cache entry whose key starts with `${bridgeId}/`, in insertion\n * order (later entries win on key conflicts). `{}` when no entries match\n * (unknown bridge / after clearBridge). Pure, no side effects.\n */\n pageData(bridgeId) {\n const merged = {};\n for (const [key, entry] of this.cache) {\n const slash = key.indexOf('/');\n if (slash < 0)\n continue;\n if (key.slice(0, slash) !== bridgeId)\n continue;\n Object.assign(merged, entry.data);\n }\n return merged;\n }\n /** Flat `key \u2192 data` map for the `__simulatorData.getAppdata()` mirror. */\n flat() {\n const data = {};\n for (const [key, entry] of this.cache)\n data[key] = entry.data;\n return data;\n }\n clear() {\n this.cache.clear();\n this.bridgeOrder.length = 0;\n this.bridgePagePath.clear();\n }\n}\n", "import type { ElementInspection } from '../../shared/ipc-channels.js'\nimport { exposeOnMainWorld } from '../shared/expose.js'\nimport { getActivePageIframe } from '../shared/page-iframe.js'\nimport { findElementBySid, type WxmlNode } from '@dimina-kit/inspect'\n\n// Re-export so existing importers (wxml.ts, shared/types.ts, renderer panels)\n// keep their `from '../runtime/bridge.js'` path while the registry lives in the\n// dependency-free shared module.\nexport type { WxmlNode } from '@dimina-kit/inspect'\nexport { registerSyntheticSid } from '@dimina-kit/inspect'\n\nexport interface Snapshot<T> {\n gen: number\n ready: boolean\n data: T\n}\n\nexport interface StorageSnapshot extends Snapshot<Record<string, string>> {\n namespace: string | null\n}\n\ntype RefreshTarget = 'wxml' | 'appdata' | 'storage'\n\ninterface SimulatorBridgeState {\n appdata: Snapshot<Record<string, unknown>>\n storage: StorageSnapshot\n wxml: Snapshot<WxmlNode | WxmlNode[] | null>\n refreshHandler: ((type: RefreshTarget) => void) | null\n}\n\nconst state: SimulatorBridgeState = {\n appdata: { gen: 0, ready: true, data: {} },\n storage: { gen: 0, ready: false, namespace: null, data: {} },\n wxml: { gen: 0, ready: false, data: null },\n refreshHandler: null,\n}\n\nlet highlightOverlay: HTMLDivElement | null = null\nlet exposedApi: Record<string, unknown> | null = null\n\nfunction clone<T>(value: T): T {\n try {\n return JSON.parse(JSON.stringify(value)) as T\n } catch {\n return value\n }\n}\n\nfunction ensureOverlay(doc: Document): HTMLDivElement {\n if (highlightOverlay && highlightOverlay.ownerDocument === doc) return highlightOverlay\n highlightOverlay = doc.createElement('div')\n highlightOverlay.id = '__simulator-highlight'\n highlightOverlay.style.cssText =\n 'position:fixed;pointer-events:none;z-index:999999;' +\n 'border:2px solid #1a73e8;background:rgba(26,115,232,0.12);' +\n 'transition:all 0.1s ease;display:none;border-radius:2px;box-sizing:border-box;'\n doc.body.appendChild(highlightOverlay)\n return highlightOverlay\n}\n\nfunction highlightElement(sid: string): ElementInspection | null {\n if (!sid) return null\n const iframe = getActivePageIframe()\n if (!iframe?.contentDocument) return null\n const doc = iframe.contentDocument\n const el = findElementBySid(doc, sid)\n if (!el) return null\n const rect = el.getBoundingClientRect()\n const overlay = ensureOverlay(doc)\n overlay.style.left = `${rect.left}px`\n overlay.style.top = `${rect.top}px`\n overlay.style.width = `${rect.width}px`\n overlay.style.height = `${rect.height}px`\n overlay.style.display = 'block'\n const style = el.ownerDocument.defaultView?.getComputedStyle(el)\n if (!style) return null\n return {\n sid,\n rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },\n style: {\n display: style.display,\n position: style.position,\n boxSizing: style.boxSizing,\n margin: style.margin,\n padding: style.padding,\n color: style.color,\n backgroundColor: style.backgroundColor,\n fontSize: style.fontSize,\n },\n }\n}\n\nfunction unhighlightElement(): void {\n if (highlightOverlay) highlightOverlay.style.display = 'none'\n}\n\nexport { highlightElement, unhighlightElement }\n\nfunction buildApi(): Record<string, unknown> {\n return {\n getAppdata: () => clone(state.appdata.data),\n getAppdataSnapshot: () => clone(state.appdata),\n getAppdataGen: () => state.appdata.gen,\n getStorageSnapshot: () => clone(state.storage),\n getStorageGen: () => state.storage.gen,\n getWxml: () => clone(state.wxml.data),\n getWxmlSnapshot: () => clone(state.wxml),\n getWxmlGen: () => state.wxml.gen,\n refresh: (type: RefreshTarget) => state.refreshHandler?.(type),\n highlightElement,\n unhighlightElement,\n }\n}\n\nexport const simulatorBridge = state\n\nexport function setRefreshHandler(handler: ((type: RefreshTarget) => void) | null): void {\n state.refreshHandler = handler\n}\n\nexport function setAppDataSnapshot(data: Record<string, unknown>): void {\n state.appdata = {\n gen: state.appdata.gen + 1,\n ready: true,\n data: clone(data),\n }\n}\n\nexport function clearAppDataSnapshot(): void {\n state.appdata = {\n gen: state.appdata.gen + 1,\n ready: true,\n data: {},\n }\n}\n\nexport function setStorageSnapshot(namespace: string | null, data: Record<string, string>): void {\n state.storage = {\n gen: state.storage.gen + 1,\n ready: namespace !== null,\n namespace,\n data: clone(data),\n }\n}\n\nexport function clearStorageSnapshot(): void {\n state.storage = {\n gen: state.storage.gen + 1,\n ready: false,\n namespace: null,\n data: {},\n }\n}\n\nexport function setWxmlSnapshot(data: WxmlNode | WxmlNode[] | null, ready = true): void {\n state.wxml = {\n gen: state.wxml.gen + 1,\n ready,\n data: clone(data),\n }\n}\n\nexport function clearWxmlSnapshot(): void {\n state.wxml = {\n gen: state.wxml.gen + 1,\n ready: false,\n data: null,\n }\n}\n\nexport function resetBridgeState(): void {\n clearAppDataSnapshot()\n clearStorageSnapshot()\n clearWxmlSnapshot()\n unhighlightElement()\n state.refreshHandler = null\n}\n\nexport function installSimulatorBridge(): () => void {\n if (!exposedApi) {\n exposedApi = buildApi()\n }\n const dispose = exposeOnMainWorld('__simulatorData', exposedApi)\n return () => {\n resetBridgeState()\n dispose()\n }\n}\n", "import { ipcRenderer, type IpcRendererEvent } from 'electron'\nimport { SimulatorCustomApiBridgeChannel } from '../../shared/ipc-channels.js'\nimport { exposeOnMainWorld } from '../shared/expose.js'\n\nexport interface DiminaCustomApisBridge {\n list(): Promise<string[]>\n invoke(name: string, params: unknown): Promise<unknown>\n}\n\ntype BridgeRequest =\n | { id: number; op: 'list' }\n | { id: number; op: 'invoke'; name: string; params: unknown }\n\ntype BridgeResponse =\n | { id: number; result: unknown }\n | { id: number; error: string }\n\ninterface Pending {\n resolve: (value: unknown) => void\n reject: (reason: Error) => void\n}\n\n/**\n * Re-send interval and ceiling for `list()` (see `listWithRetry`).\n *\n * `ipcRenderer.send` is fire-and-forget \u2014 a request sent before the main-side\n * `ipcMain.on` listener is live (e.g. across a relaunch / re-attach cycle) is\n * lost, and the bridge call would otherwise hang until `custom-api-boot.ts`'s\n * 3s deadlock-breaker.\n *\n * `list` is an idempotent read, so it is safe to re-send until a response\n * arrives. The retry resolves quickly in practice; the ceiling only bounds the\n * leak if the listener never answers, and is kept below `custom-api-boot.ts`'s\n * `CUSTOM_API_LIST_TIMEOUT_MS` so the retry exhausts before \u2014 not after \u2014 that\n * outer timeout would fire.\n */\nconst LIST_RETRY_INTERVAL_MS = 150\nconst LIST_RETRY_CEILING_MS = 2500\n\n// native-host is the sole runtime: the simulator is a top-level\n// WebContentsView with no embedder to `sendToHost`, so it `ipcRenderer.send`s\n// the request straight to a `ctx.simulatorApis`-backed `ipcMain.on` listener\n// bound to this exact simWc (see view-manager `attachNativeCustomApiBridge`),\n// which posts the result back via `simWc.send`. Responses land on the\n// `ipcRenderer.on(Response)` handler and are correlated to requests by id, so\n// concurrent invokes do not tangle.\nfunction buildBridge(): DiminaCustomApisBridge {\n let nextId = 1\n const pending = new Map<number, Pending>()\n\n const sendRequest = (req: BridgeRequest): void => {\n ipcRenderer.send(SimulatorCustomApiBridgeChannel.Request, req)\n }\n\n ipcRenderer.on(SimulatorCustomApiBridgeChannel.Response, (_event: IpcRendererEvent, payload: BridgeResponse) => {\n const entry = pending.get(payload.id)\n if (!entry) return\n pending.delete(payload.id)\n if ('error' in payload) {\n entry.reject(new Error(payload.error))\n } else {\n entry.resolve(payload.result)\n }\n })\n\n const send = <T>(req: BridgeRequest): Promise<T> => {\n return new Promise<T>((resolve, reject) => {\n pending.set(req.id, {\n resolve: (value) => resolve(value as T),\n reject,\n })\n sendRequest(req)\n })\n }\n\n /**\n * `list()` with re-send, to survive the embedder proxy attaching after the\n * first request (see `LIST_RETRY_INTERVAL_MS`). Each attempt uses a fresh id\n * and its own `pending` entry; whichever response lands first settles the\n * call. Stale entries for the other attempts are dropped so a late duplicate\n * response cannot resolve nothing \u2014 or, worse, leak.\n */\n const listWithRetry = (): Promise<string[]> => {\n return new Promise<string[]>((resolve, reject) => {\n const attemptIds = new Set<number>()\n // Boxed so `cleanup` (defined before the timers are created) can clear\n // them; the box itself is `const`, only its fields are assigned later.\n const state: {\n settled: boolean\n retryTimer?: ReturnType<typeof setInterval>\n ceilingTimer?: ReturnType<typeof setTimeout>\n } = { settled: false }\n\n const cleanup = (): void => {\n state.settled = true\n if (state.retryTimer) clearInterval(state.retryTimer)\n if (state.ceilingTimer) clearTimeout(state.ceilingTimer)\n for (const id of attemptIds) pending.delete(id)\n attemptIds.clear()\n }\n\n const attempt = (): void => {\n if (state.settled) return\n const id = nextId++\n attemptIds.add(id)\n pending.set(id, {\n resolve: (value) => {\n if (state.settled) return\n cleanup()\n resolve(value as string[])\n },\n reject: (reason) => {\n if (state.settled) return\n cleanup()\n reject(reason)\n },\n })\n sendRequest({ id, op: 'list' })\n }\n\n state.retryTimer = setInterval(attempt, LIST_RETRY_INTERVAL_MS)\n state.ceilingTimer = setTimeout(() => {\n if (state.settled) return\n cleanup()\n reject(new Error('custom-apis bridge list() got no response from the host renderer'))\n }, LIST_RETRY_CEILING_MS)\n attempt()\n })\n }\n\n return {\n list: listWithRetry,\n invoke: (name, params) => send<unknown>({ id: nextId++, op: 'invoke', name, params }),\n }\n}\n\nexport function installCustomApisBridge(): () => void {\n const bridge = buildBridge()\n return exposeOnMainWorld('__diminaCustomApis', bridge)\n}\n", "/**\n * Centralised IPC channel name constants for dimina-devtools.\n *\n * Every raw channel string used across main, renderer, preload and e2e code\n * should reference one of these constants so that renaming a channel only\n * requires a single edit.\n */\n\n// \u2500\u2500 Simulator (preload \u2192 host / renderer \u2194 main) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const SimulatorChannel = {\n // Ask main to create the simulator as a top-level WebContentsView (so nested\n // render-host <webview>s can attach). Native-host is the sole runtime.\n AttachNative: 'simulator:attach-native',\n // Renderer pushes the selected device's LOGICAL metrics (screen size,\n // pixelRatio, statusBarHeight, \u2026) when the device dropdown changes. Main\n // maps it to a HostEnvSnapshot and live-updates the running service-host\n // window \u2014 the authoritative `wx.getSystemInfoSync()` source \u2014 so the\n // mini-app sees the selected device without a relaunch.\n SetDeviceInfo: 'simulator:set-device-info',\n // Ask main to soft-reload the LIVE simulator WCV after a watcher rebuild:\n // main forwards a SIMULATOR_EVENTS.RELAUNCH into the shell (which boots a\n // new app session and swaps when ready) instead of destroying the view.\n // Resolves false when there is no live+ready shell \u2014 the renderer then falls\n // back to the hard AttachNative rebuild.\n SoftReload: 'simulator:soft-reload',\n Detach: 'simulator:detach',\n Console: 'simulator:console',\n // Main \u2192 renderer push of the visible top-of-stack page route whenever the\n // mini-app navigates (navigateTo / switchTab / back). Payload: the page path\n // string (same bare format as `getCurrentPagePath`), or '' when unknown.\n CurrentPage: 'simulator:current-page',\n} as const\n\n/** iPhone bezel cutout family driving the device-shell notch visual. */\nexport type NotchType = 'none' | 'notch' | 'dynamic-island'\n\n/** Per-device safe-area insets in CSS px (portrait). */\nexport interface SafeAreaInsets {\n top: number\n right: number\n bottom: number\n left: number\n}\n\n/**\n * Logical device metrics pushed by the renderer device dropdown under\n * native-host (`SimulatorChannel.SetDeviceInfo`). Mirrors a row of the renderer\n * `DEVICES` table; main maps it onto a `HostEnvSnapshot` for the service-host\n * window so `wx.getSystemInfoSync()` reflects the selected device, relays it to\n * the simulator WCV (DeviceShell: bezel size + status bar + notch), and drives\n * the CSS `env(safe-area-inset-*)` override on render-host guests.\n */\nexport interface NativeDeviceInfo {\n brand: string\n model: string\n system: string\n platform: string\n pixelRatio: number\n screenWidth: number\n screenHeight: number\n statusBarHeight: number\n notchType: NotchType\n safeAreaInsets: SafeAreaInsets\n}\n\n// \u2500\u2500 Service host (main \u2192 hidden service-host window) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const ServiceHostChannel = {\n /**\n * NATIVE-HOST ONLY. Live-update the service-host window's host-env snapshot\n * (device metrics) so subsequent `wx.getSystemInfoSync()` reflects a device\n * change without a relaunch. The service-host preload mutates\n * `__diminaSpawnContext.hostEnvSnapshot` in place (see `service-host/preload.cjs`).\n */\n HostEnvUpdate: 'service-host:host-env:update',\n} as const\n\n// \u2500\u2500 Custom simulator APIs (downstream-registered, main-process handlers) \u2500\u2500\n// invoke: forwards an API call to the registry; result/reject propagates.\n//\n// This is an ipcMain.handle channel invoked by the **main-window renderer**\n// only (trusted host). The simulator guest never reaches it directly \u2014 it\n// reaches the host via the bridge channels below, so the sender-policy can keep\n// the simulator off the IPC white-list.\nexport const SimulatorCustomApiChannel = {\n Invoke: 'simulator:custom-apis:invoke',\n} as const\n\n// \u2500\u2500 Custom APIs bridge (simulator \u2192 host) \u2500\u2500\n// payload = { id, op: 'list' } | { id, op: 'invoke', name, params } for Request,\n// { id, result } | { id, error } for Response. Transport (in\n// `src/preload/runtime/custom-apis.ts`): native-host \u2014 the simulator is a\n// top-level WebContentsView (no embedder), so Request goes via\n// `ipcRenderer.send` \u2192 `ipcMain.on` dispatcher bound to that simWc (view-manager\n// `attachNativeCustomApiBridge`) \u2192 Response via `simWc.send`. (The old\n// renderer-proxied `<webview>` transport, `ipcRenderer.sendToHost` \u2192\n// `<webview>.send`, no longer exists \u2014 native-host is the sole runtime.)\n//\n// Request/response are correlated by `id` so multiple concurrent invokes can\n// be in flight at once.\nexport const SimulatorCustomApiBridgeChannel = {\n Request: 'simulator:custom-apis:bridge-request',\n Response: 'simulator:custom-apis:bridge-response',\n} as const\n\n// \u2500\u2500 Storage (CDP-backed; main process attaches the debugger to the\n// simulator guest and forwards DOMStorage events to the renderer) \u2500\u2500\nexport const SimulatorStorageChannel = {\n GetSnapshot: 'simulator:storage:snapshot',\n GetActivePrefix: 'simulator:storage:activePrefix',\n Set: 'simulator:storage:set',\n Remove: 'simulator:storage:remove',\n Clear: 'simulator:storage:clear',\n ClearAll: 'simulator:storage:clearAll',\n Event: 'simulator:storage:event',\n} as const\n\n// The storage wire-format shapes are owned by the shared inspect package\n// (any host's transport carries the same StorageItem/StorageEvent/\n// StorageWriteResult); this channel file re-exports them so IPC consumers\n// keep a single import point.\nexport type { StorageEvent, StorageItem, StorageWriteResult } from '@dimina-kit/inspect'\n\n/**\n * A storage mutation reported by the service-host's SYNC wx storage APIs\n * (`setStorageSync`/`removeStorageSync`/`clearStorageSync`). Those run inside the\n * service-host window and write `localStorage` directly, so \u2014 unlike the async\n * path (`runtimeInvoke`) and the panel's own writes \u2014 they never pass through\n * main and would otherwise leave the Storage panel stale until a manual reload.\n * The service-host posts this over `DiminaServiceBridge` as a `storageChanged`\n * container message; bridge-router hands it to `onServiceStorageChanged`, which\n * pushes the matching `StorageEvent` to the panel. `key` carries the full\n * `${appId}_` prefix (same wire shape as the CDP / async paths).\n */\nexport type SyncStorageChange =\n | { op: 'set'; key: string; value: string }\n | { op: 'remove'; key: string }\n | { op: 'clear' }\n\n// \u2500\u2500 Element inspection (CDP-backed; WXML tree nodes map to real DOM by sid) \u2500\u2500\nexport const SimulatorElementChannel = {\n Inspect: 'simulator:element:inspect',\n Clear: 'simulator:element:clear',\n} as const\n\n// \u2500\u2500 WXML tree (native-host: main pulls the tree from the active render-host\n// <webview> guest via render-inspect, and pushes/answers here \u2014 mirroring the\n// Storage panel's main\u2192renderer contract so the renderer panel is unchanged) \u2500\u2500\nexport const SimulatorWxmlChannel = {\n GetSnapshot: 'simulator:wxml:snapshot',\n Event: 'simulator:wxml:event',\n // renderer\u2192main: whether the WXML panel is currently visible/active. Main\n // only installs the render-guest DOM MutationObserver + pushes live tree\n // updates while active, so an unseen panel never drives a full Vue-tree walk.\n SetActive: 'simulator:wxml:setActive',\n} as const\n\n// \u2500\u2500 AppData (native-host: main taps the service\u2192render setData stream in\n// bridge-router and pushes the cumulative snapshot here \u2014 the service logic runs\n// in the hidden service-host window, not a Worker in the simulator guest) \u2500\u2500\nexport const SimulatorAppDataChannel = {\n GetSnapshot: 'simulator:appdata:snapshot',\n Event: 'simulator:appdata:event',\n} as const\n\n// The element-inspection payload shape is owned by the shared inspect\n// package (it is produced inside render-layer documents by any host); this\n// channel file re-exports it so IPC consumers keep a single import point.\nexport type { ElementInspection } from '@dimina-kit/inspect'\n\n// \u2500\u2500 Workbench settings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const WorkbenchSettingsChannel = {\n Get: 'workbenchSettings:get',\n Save: 'workbenchSettings:save',\n SetTheme: 'workbenchSettings:setTheme',\n GetCdpStatus: 'workbenchSettings:getCdpStatus',\n GetMcpStatus: 'workbenchSettings:getMcpStatus',\n Init: 'workbenchSettings:init',\n // Main \u2192 renderer push: the active color scheme flipped (OS change or in-app\n // SetTheme). Payload is `isDark: boolean`. The app's CSS reacts to\n // `prefers-color-scheme` automatically; this exists for the few JS consumers\n // (Monaco's theme) that can't observe that media change \u2014 Electron does NOT\n // dispatch the renderer's `matchMedia('(prefers-color-scheme)')` change event\n // for programmatic `nativeTheme.themeSource` assignments.\n ThemeChanged: 'workbenchSettings:themeChanged',\n} as const\n\n// \u2500\u2500 Project session \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const ProjectChannel = {\n Open: 'project:open',\n Close: 'project:close',\n GetPages: 'project:getPages',\n GetCompileConfig: 'project:getCompileConfig',\n SaveCompileConfig: 'project:saveCompileConfig',\n Status: 'project:status',\n // Main \u2192 renderer push of per-line dmcc compile logs (devkit `onLog`).\n // Dedicated channel: `project:status` keeps its one-event-per-payload\n // contract (compileEvents), this one carries the line stream (compileLogs).\n CompileLog: 'project:compileLog',\n CaptureThumbnail: 'project:captureThumbnail',\n GetThumbnail: 'project:getThumbnail',\n} as const\n\n// \u2500\u2500 Session runtime status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Main \u2192 renderer push of the post-compile SESSION lifecycle (spawn \u2192 running\n// \u2192 crash/timeout), distinct from `ProjectChannel.Status` which only tracks\n// compile outcomes. Compile succeeding tells the renderer nothing about\n// whether the simulator actually booted \u2014 this channel closes that gap.\n\nexport const SessionChannel = {\n RuntimeStatus: 'session:runtimeStatus',\n} as const\n\n// \u2500\u2500 Project file system (sandboxed to active project root) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Read/write access to the active project's files, used by the in-renderer\n// Monaco editor. Every path is verified against the active project root in\n// the main process (see `services/project-fs`). Replaces the OpenSumi\n// editor's `editor:fs:*` bridge \u2014 same sandbox, callable from the main\n// renderer instead of a separate WebContentsView.\n\nexport const ProjectFsChannel = {\n GetRoot: 'project:fs:getRoot',\n ReadFile: 'project:fs:readFile',\n WriteFile: 'project:fs:writeFile',\n /**\n * Synchronous (blocking) write, used ONLY by the editor's `beforeunload`\n * flush: a hard window/app close tears the renderer down before an async\n * `WriteFile` IPC can round-trip, so the last in-debounce-window edit would\n * be lost. `sendSync` blocks page teardown until the bytes hit disk. Runs the\n * SAME sandbox as `WriteFile` (see project-fs `writeFileSync`).\n */\n WriteFileSync: 'project:fs:writeFileSync',\n ListFiles: 'project:fs:listFiles',\n} as const\n\n// \u2500\u2500 Editor (main \u2192 renderer) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Drives the in-renderer Monaco editor from the main process. Used by the\n// \"click a console file link \u2192 open the file at line:col\" pipeline: the\n// embedded DevTools front-end routes a source-link click through an open-\n// resource handler \u2192 Electron `devtools-open-url` on the service host \u2192 main\n// maps the resource URL to a project-relative path \u2192 this event opens it in\n// Monaco. Payload: `EditorOpenFilePayload`.\n\nexport const EditorChannel = {\n /** main \u2192 renderer: open `path` (project-relative POSIX) at `line`/`column`. */\n OpenFile: 'editor:openFile',\n} as const\n\n/** Payload for `editor:openFile`. `line`/`column` are 1-based for Monaco. */\nexport interface EditorOpenFilePayload {\n /** Project-relative POSIX path (the same key Monaco opens files by). */\n path: string\n /** 1-based line to reveal; omitted/<=0 means open without moving the cursor. */\n line?: number\n /** 1-based column to reveal; defaults to 1 when a line is given. */\n column?: number\n}\n\n// \u2500\u2500 Project list / workspace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const ProjectsChannel = {\n List: 'projects:list',\n Add: 'projects:add',\n Remove: 'projects:remove',\n /** Merged + sanitized template catalog for the create-project dialog. */\n ListTemplates: 'projects:listTemplates',\n /** Host-supplied create-project dialog hook (returns input or null). */\n OpenCreateDialog: 'projects:openCreateDialog',\n /** Server-side scaffold + register (delegates to create-project-service). */\n Create: 'projects:create',\n /** Default values used to pre-fill the create-project dialog (baseDir). */\n GetCreateDefaults: 'projects:getCreateDefaults',\n} as const\n\n/** Renderer-facing payload for `projects:getCreateDefaults`. */\nexport interface ProjectCreateDefaults {\n /** Absolute directory used as the parent for new projects. */\n baseDir: string\n}\n\n// \u2500\u2500 Dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const DialogChannel = {\n OpenDirectory: 'dialog:openDirectory',\n} as const\n\n// \u2500\u2500 Embedded views (renderer \u2192 main) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// The main window's React layout owns the *positions* of the editor +\n// simulator-DevTools WebContentsView overlays \u2014 each visible placeholder\n// `<div>` measures its client rect via ResizeObserver and pushes the\n// rectangle to the main process. The view manager caches the latest\n// payload per kind and applies it to the overlay; no payload means the\n// overlay is hidden.\n//\n// Payload (after schema validation): `{ x, y, width, height }` in CSS\n// pixels relative to the window's content area (origin = top-left,\n// not including the OS chrome).\nexport const ViewChannel = {\n /**\n * Reverse size-advertiser: the host-toolbar WCV's OWN renderer advertises its\n * intrinsic content height so main reserves exactly that much. Payload\n * `{ axis: 'block', extent }`. fire-and-forget (send), NOT invoke.\n */\n HostToolbarAdvertiseHeight: 'view:host-toolbar:advertise-height',\n /**\n * main \u2192 host-toolbar WCV renderer: per-load MessagePort handshake for the\n * gated narrow channel. On every toolbar `did-finish-load` main creates a\n * `MessageChannelMain` and transfers port2 here\n * (`wc.postMessage(HostToolbarPort, null, [port2])`); the session-resident\n * toolbar runtime preload receives it via `event.ports[0]` and bridges it to\n * the page as `window.diminaHostToolbar`. Envelope both directions:\n * `{ channel: string, payload: unknown }`.\n */\n HostToolbarPort: 'view:host-toolbar:port',\n /**\n * main \u2192 main-window renderer: push the reserved host-toolbar height so the\n * renderer placeholder div resizes (closing the dynamic-height loop).\n */\n HostToolbarHeightChanged: 'view:host-toolbar:height-changed',\n /**\n * main \u2190 main-window renderer (invoke): pull the last NOTIFIED toolbar\n * height retained in main. Mount-time replay companion to\n * `HostToolbarHeightChanged`: the push listener mounts with the project\n * view and the toolbar's size-advertiser deduplicates (never re-reports),\n * so a height pushed while no project view was mounted would otherwise be\n * lost forever (cold start on the project list races it; close-project \u2192\n * reopen hits it deterministically). No payload; resolves a number.\n */\n HostToolbarGetHeight: 'view:host-toolbar:get-height',\n /**\n * Renderer \u2192 main: the window-level placement snapshot (one monotonic epoch\n * per commit tick, one generation per renderer lifetime) that drives the view\n * reconciler. The single source of truth for every managed native view's\n * bounds/visibility/z-order \u2014 supersedes the per-view bounds channels above.\n * invoke.\n */\n PlacementSnapshot: 'view:placement-snapshot',\n} as const\n\nexport interface ViewBounds {\n x: number\n y: number\n width: number\n height: number\n}\n\n// \u2500\u2500 Popover \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const PopoverChannel = {\n Show: 'popover:show',\n Hide: 'popover:hide',\n Relaunch: 'popover:relaunch',\n Closed: 'popover:closed',\n Init: 'popover:init',\n} as const\n\n// \u2500\u2500 Window \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const WindowChannel = {\n NavigateBack: 'window:navigateBack',\n // Renderer \u2192 main: the renderer's current top-level screen ('project' when\n // inside a project screen, 'list' on the project list / landing). The\n // renderer pushes this on every screen change, including the moment it enters\n // a project \u2014 BEFORE the open resolves \u2014 so a FAILED open (no session) still\n // leaves main's mirror = 'project'. The window-close decision reads it so\n // closing a stuck/failed project returns to the list instead of quitting.\n ScreenState: 'window:screenState',\n} as const\n\n// \u2500\u2500 App \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const AppChannel = {\n GetBranding: 'app:getBranding',\n} as const\n\n// \u2500\u2500 miniappSnapshot (unified panel snapshot framework) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Two generic channels shared by every snapshot source (AppData, WXML, \u2026).\n// Adding a new panel needs no new channel.\n// Push: preload \u2192 renderer (`sendToHost`), payload: SnapshotEnvelope\n// Pull: renderer \u2192 preload (`webview.send`), payload: { id }\n\nexport const MiniappSnapshotChannel = {\n Push: 'miniapp-snapshot:push',\n Pull: 'miniapp-snapshot:pull',\n} as const\n\n// \u2500\u2500 Automation (WebSocket server) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const AutomationChannel = {\n GetPort: 'automation:port',\n} as const\n\n// \u2500\u2500 Embedded settings overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const SettingsChannel = {\n SetVisible: 'settings:setVisible',\n ConfigChanged: 'settings:configChanged',\n ProjectSettingsChanged: 'settings:projectSettingsChanged',\n Init: 'settings:init',\n} as const\n\n// \u2500\u2500 Updates (UpdateManager) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// String values are FROZEN: shipped builds key off them. Add new entries\n// here, never rename existing ones.\nexport const UpdateChannel = {\n Check: 'updates:check',\n Download: 'updates:download',\n Install: 'updates:install',\n DownloadProgress: 'updates:downloadProgress',\n Available: 'updates:available',\n} as const\n", "/**\n * Preload-side bridge that mirrors the simulator's renderer-side temp-file\n * registry into the main-process store via IPC. The main process serves the\n * resulting `difile://devtools/{uuid}` URLs over a protocol handler bound to\n * the simulator session.\n */\n\nimport { ipcRenderer } from 'electron'\nimport { setTempFileSink } from '../../simulator/temp-files.js'\n\nexport function installTempFileBridge(): void {\n\tsetTempFileSink({\n\t\twrite(path, blob) {\n\t\t\tblob\n\t\t\t\t.arrayBuffer()\n\t\t\t\t.then((bytes) => {\n\t\t\t\t\tipcRenderer.send('simulator:temp-file:write', {\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tmime: blob.type,\n\t\t\t\t\t\tbytes,\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t\t.catch(() => {\n\t\t\t\t\t// best effort: blob read failures cannot be surfaced through the\n\t\t\t\t\t// sink contract (`write` is sync void), so we swallow them.\n\t\t\t\t})\n\t\t},\n\t\trevoke(path) {\n\t\t\tipcRenderer.send('simulator:temp-file:revoke', { path })\n\t\t},\n\t\trevokeAll() {\n\t\t\tipcRenderer.send('simulator:temp-file:revoke-all')\n\t\t},\n\t})\n}\n", "/**\n * Devtools simulator temp-file registry.\n *\n * The simulator hands `chooseImage` / `chooseMedia` / `chooseVideo` /\n * `compressImage` etc. results back to mini-program code as paths. Historically\n * those paths were `blob:` URLs allocated via `URL.createObjectURL`, but the\n * blob: scheme is local-to-the-renderer and cannot be served back into the\n * webview's `persist:simulator` session through a `protocol.handle`. We switched\n * to a custom `difile://_tmp/{uuid}` scheme so the main process can\n * register a single `difile://` protocol handler and stream the bytes for any\n * path, regardless of which renderer originally produced it.\n *\n * To keep the renderer-side cache and the main-process byte store in sync,\n * `setTempFileSink` lets the preload bridge inject a sink that mirrors every\n * `write` / `revoke` / `revokeAll` over IPC. Tests inject a stub sink.\n */\n\nexport interface TempFileSink {\n\twrite(path: string, blob: Blob): void\n\trevoke(path: string): void\n\trevokeAll(): void\n}\n\nconst tempFiles = new Map<string, Blob>()\nlet activeSink: TempFileSink | null = null\n\nexport function setTempFileSink(sink: TempFileSink | null): void {\n\tactiveSink = sink\n}\n\nfunction cryptoRandomId(): string {\n\tconst c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n\tif (c && typeof c.randomUUID === 'function') return c.randomUUID()\n\treturn `${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nexport function createTempFilePath(blob: Blob): string {\n\tconst path = `difile://_tmp/${cryptoRandomId()}`\n\ttempFiles.set(path, blob)\n\tactiveSink?.write(path, blob)\n\treturn path\n}\n\nexport function registerTempFilePath(path: string, blob: Blob): void {\n\ttempFiles.set(path, blob)\n\tactiveSink?.write(path, blob)\n}\n\nexport function revokeTempFilePath(path: string): void {\n\ttempFiles.delete(path)\n\tactiveSink?.revoke(path)\n}\n\nexport function revokeAllTempFilePaths(): void {\n\ttempFiles.clear()\n\tactiveSink?.revokeAll()\n}\n\nexport async function resolveTempFilePath(path: string): Promise<Blob> {\n\tconst cached = tempFiles.get(path)\n\tif (cached) return cached\n\n\tconst response = await fetch(path)\n\tif (!response.ok) {\n\t\tthrow new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${path}`)\n\t}\n\tconst blob = await response.blob()\n\t// Cache the freshly fetched blob in-memory so subsequent reads are local.\n\t// We bypass `registerTempFilePath` deliberately: this is a renderer-only\n\t// cache fill, the main-process store already has the bytes (otherwise the\n\t// fetch would not have returned them), so triggering sink.write would\n\t// produce a redundant IPC.\n\ttempFiles.set(path, blob)\n\treturn blob\n}\n\nexport function getTempFileName(path: string, blob: Blob, fallback = 'file'): string {\n\tconst named = blob as Blob & { name?: unknown }\n\tif (typeof named.name === 'string' && named.name.trim()) {\n\t\treturn named.name\n\t}\n\n\ttry {\n\t\tconst url = new URL(path, window.location.href)\n\t\tconst segment = url.pathname.split('/').filter(Boolean).pop()\n\t\tif (segment) return decodeURIComponent(segment)\n\t} catch {\n\t\t// Fall through to the caller-provided fallback.\n\t}\n\n\treturn fallback\n}\n", "import { ipcRenderer, type IpcRendererEvent } from 'electron'\n\nexport function sendToHost(channel: string, data: unknown): void {\n ipcRenderer.sendToHost(channel, data)\n}\n\nexport function onHostMessage(\n channel: string,\n handler: (...args: unknown[]) => void,\n): () => void {\n let active = true\n const wrapped = (_event: IpcRendererEvent, ...args: unknown[]) => {\n if (!active) return\n handler(...args)\n }\n ipcRenderer.on(channel, wrapped)\n return () => {\n active = false\n ipcRenderer.removeListener(channel, wrapped)\n }\n}\n\nexport function safeSerialize(val: unknown): unknown {\n if (val === null || val === undefined) return val\n if (typeof val === 'function') return `[Function: ${(val as { name?: string }).name || 'anonymous'}]`\n if (typeof val !== 'object') return val\n if (val instanceof Error) return { __isError: true, message: val.message, stack: val.stack }\n try {\n return structuredClone(val)\n } catch {\n // expected: some objects (e.g. DOM nodes, proxies) cannot be structuredCloned\n }\n try {\n return JSON.parse(JSON.stringify(val))\n } catch {\n // expected: circular references or non-serializable values\n }\n return String(val)\n}\n", "import { SimulatorChannel } from '../../shared/ipc-channels.js'\nimport { sendToHost, safeSerialize } from '../runtime/host.js'\n\ntype ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug'\n\nexport function installConsoleInstrumentation(): () => void {\n const consoleRef = console as unknown as Record<string, (...args: unknown[]) => void>\n const originals = new Map<ConsoleLevel, (...args: unknown[]) => void>()\n const levels: ConsoleLevel[] = ['log', 'warn', 'error', 'info', 'debug']\n\n for (const level of levels) {\n const original = consoleRef[level]?.bind(console)\n if (!original) continue\n originals.set(level, original)\n consoleRef[level] = (...args: unknown[]) => {\n original(...args)\n sendToHost(SimulatorChannel.Console, {\n source: 'container',\n level,\n args: args.map(safeSerialize),\n ts: Date.now(),\n })\n }\n }\n\n const handleError = (event: ErrorEvent) => {\n sendToHost(SimulatorChannel.Console, {\n source: 'container',\n level: 'error',\n args: [{\n message: event.message,\n source: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n stack: event.error?.stack,\n }],\n ts: Date.now(),\n })\n }\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n sendToHost(SimulatorChannel.Console, {\n source: 'container',\n level: 'error',\n args: [{ message: 'Unhandled Promise Rejection', reason: String(event.reason) }],\n ts: Date.now(),\n })\n }\n\n window.addEventListener('error', handleError)\n window.addEventListener('unhandledrejection', handleRejection)\n\n return () => {\n for (const [level, original] of originals) {\n consoleRef[level] = original\n }\n window.removeEventListener('error', handleError)\n window.removeEventListener('unhandledrejection', handleRejection)\n }\n}\n", "import {\n clearAppDataSnapshot,\n setAppDataSnapshot,\n} from '../runtime/bridge.js'\nimport type { MiniappSnapshotSource } from '../miniapp-snapshot/types.js'\nimport {\n AppDataAccumulator,\n decodeOutgoingMessage,\n decodeWorkerMessage,\n type AppDataInput,\n type AppDataSnapshot,\n} from '@dimina-kit/inspect'\n\n// Window augmentation is in ../types.ts\n\n// Re-exported so existing importers (use-panel-data, types) keep their\n// `from '.../app-data'` path while the cumulative logic lives in the shared,\n// framework-agnostic accumulator reused by the native-host main service.\nexport type { AppDataSnapshot } from '@dimina-kit/inspect'\n\n/**\n * The AppData snapshot data source.\n *\n * Under native-host (the sole runtime) this is registered in the simulator top\n * frame purely for its `start()` side effects \u2014 it installs\n * `window.__simulatorHook.appData` and mirrors the flat cache into the\n * `window.__simulatorData.getAppdata()` automation surface still read by\n * automation `getData` (handlers/page.ts), the MCP context overview\n * (mcp/tools/context-tools.ts) and the e2e automator. Its iframe/Worker-based\n * snapshot publishing is inert there (no mini-app Worker runs in the top frame).\n *\n * Instruments `window.Worker` (incoming `message` decoding + outgoing\n * `postMessage` interception) and installs `window.__simulatorHook.appData`,\n * feeding the shared `AppDataAccumulator`. Every accepted mutation \u2014 an\n * `ub`/`page_*` worker message, or a `pageUnload` evicting a bridge \u2014 calls\n * `emit()` so the `miniappSnapshot` host republishes. The source itself never\n * touches IPC: the host owns push, pull and the install-time publish.\n *\n * It keeps the `__simulatorData.getAppdata()` automation surface working by\n * mirroring the flat cache into the simulator bridge via `setAppDataSnapshot`\n * / `clearAppDataSnapshot`.\n *\n * Under native-host this source is replaced by the main-process\n * simulator-appdata service, which feeds the SAME accumulator from the\n * service\u2192render message stream \u2014 see shared/appdata-accumulator.ts.\n */\nexport function createAppDataSource(): MiniappSnapshotSource<AppDataSnapshot> {\n const accumulator = new AppDataAccumulator()\n\n let emit: (() => void) | null = null\n let installed = false\n let originalHook: Window['__simulatorHook']\n let originalDescriptor: PropertyDescriptor | undefined\n let OriginalWorker: typeof Worker | undefined\n\n // Mirror the flat cache into the `__simulatorData.getAppdata()` automation\n // surface so MCP / e2e reads keep working after the snapshot migration.\n function publishSnapshot(): void {\n setAppDataSnapshot(accumulator.flat())\n }\n\n function clearBridge(bridgeId: string): void {\n accumulator.clearBridge(bridgeId)\n publishSnapshot()\n // The eviction is a cache mutation \u2014 notify the host so the renderer can\n // drop the evicted bridge's tab immediately.\n emit?.()\n }\n\n function applyAppData(body: unknown): void {\n if (!accumulator.apply(body as AppDataInput)) return\n publishSnapshot()\n emit?.()\n }\n\n function instrumentPostMessage(worker: Worker): void {\n const orig = worker.postMessage.bind(worker) as (msg: unknown, ...rest: unknown[]) => void\n worker.postMessage = function (msg: unknown, ...rest: unknown[]) {\n const decoded = decodeOutgoingMessage(msg)\n if (decoded?.type === 'pageUnload' && decoded.bridgeId) {\n clearBridge(decoded.bridgeId)\n }\n return orig(msg, ...rest)\n } as Worker['postMessage']\n }\n\n function createInstrumentedWorker(Original: typeof Worker): typeof Worker {\n function InstrumentedWorker(\n this: unknown,\n scriptURL: string | URL,\n options?: WorkerOptions\n ): Worker {\n const resolvedScriptURL = scriptURL instanceof URL\n ? scriptURL\n : new URL(scriptURL, window.location.href)\n const worker = Reflect.construct(\n Original,\n [resolvedScriptURL, options],\n new.target ?? InstrumentedWorker\n ) as Worker\n\n instrumentPostMessage(worker)\n\n worker.addEventListener('message', (event: MessageEvent) => {\n const entries = decodeWorkerMessage(event.data)\n if (!entries) return\n for (const entry of entries) {\n const hookBody: AppDataInput = {\n bridgeId: entry.bridgeId,\n moduleId: entry.moduleId,\n data: entry.data,\n mode: entry.mode,\n }\n if (entry.mode === 'init') hookBody.componentPath = entry.componentPath\n window.__simulatorHook?.appData(hookBody)\n }\n })\n\n return worker\n }\n\n Object.setPrototypeOf(InstrumentedWorker, Original)\n Object.defineProperty(InstrumentedWorker, 'prototype', {\n value: Original.prototype,\n })\n\n return InstrumentedWorker as unknown as typeof Worker\n }\n\n return {\n id: 'appdata',\n snapshot: () => accumulator.snapshot(),\n start(onChange) {\n if (installed) return\n installed = true\n emit = onChange\n originalHook = window.__simulatorHook\n originalDescriptor = Object.getOwnPropertyDescriptor(window, 'Worker')\n OriginalWorker = window.Worker\n\n window.__simulatorHook = {\n appData: (body: unknown) => applyAppData(body),\n }\n\n Object.defineProperty(window, 'Worker', {\n configurable: true,\n writable: true,\n value: createInstrumentedWorker(OriginalWorker),\n })\n },\n dispose() {\n if (!installed) return\n installed = false\n if (originalDescriptor) {\n Object.defineProperty(window, 'Worker', originalDescriptor)\n } else if (OriginalWorker) {\n window.Worker = OriginalWorker\n }\n if (originalHook) {\n window.__simulatorHook = originalHook\n } else {\n delete window.__simulatorHook\n }\n originalDescriptor = undefined\n OriginalWorker = undefined\n originalHook = undefined\n accumulator.clear()\n clearAppDataSnapshot()\n emit = null\n },\n }\n}\n", "/**\n * Single authoritative implementation of wx.request network semantics, shared\n * by every request surface (simulator `directRequest`, preload api-compat\n * `wx.request` shim). Keeping the semantics in one module is what prevents the\n * surfaces from drifting apart on the core contract.\n *\n * The contract (official wx.request semantics):\n * - success vs fail is decided ONLY by whether a server response was\n * received. Any HTTP response \u2014 200, 401, 500 \u2014 resolves via `success`\n * with `{ data, statusCode, header, errMsg: 'request:ok' }`; callers\n * branch on `statusCode` (e.g. 401 \u2192 re-login).\n * - `fail` fires only for network-layer failures and always carries a\n * non-empty errMsg: 'request:fail timeout' (deadline hit),\n * 'request:fail abort' (caller aborted), 'request:fail <reason>' (DNS/\n * connection/protocol errors).\n * - `timeout` defaults to 60000ms (the wx default) when omitted or\n * non-positive \u2014 a request never hangs indefinitely.\n * - `dataType` (default 'json') controls body decoding: 'json' attempts\n * JSON.parse with raw-text fallback; anything else keeps raw text.\n * `responseType: 'arraybuffer'` (or the legacy `dataType: 'arraybuffer'`\n * spelling) yields an ArrayBuffer instead.\n * - Outgoing headers merge case-insensitively via `Headers` so a caller's\n * `content-type` in any casing wins exactly once; the `application/json`\n * default applies only when the caller supplied none. Plain-object merges\n * would keep both casings as distinct keys and comma-join them on the wire.\n * - GET/HEAD serialize object `data` into URL query params (no body);\n * other methods send string data verbatim, form-encode objects under\n * application/x-www-form-urlencoded, and JSON-encode otherwise.\n * - `complete` fires exactly once, after success or fail, with that same\n * result object.\n *\n * Not provided: `cookies` on the success result \u2014 fetch() cannot read\n * Set-Cookie response headers, so surfacing a fabricated list would lie.\n */\n\nexport interface RequestSuccessResult {\n data: unknown\n statusCode: number\n header: Record<string, string>\n errMsg: 'request:ok'\n}\n\nexport interface RequestFailResult {\n errMsg: string\n errno?: number\n}\n\nexport interface RequestHandle {\n abort(): void\n}\n\nexport interface RequestCoreOptions {\n url: string\n data?: unknown\n header?: Record<string, string>\n timeout?: number\n method?: string\n dataType?: string\n responseType?: string\n}\n\nexport interface RequestCoreCallbacks {\n success?: (res: RequestSuccessResult) => void\n fail?: (err: RequestFailResult) => void\n complete?: (res: RequestSuccessResult | RequestFailResult) => void\n}\n\n/**\n * The wx.request default timeout budget. Exported as the single source of\n * truth for every layer that reasons about a request's time budget \u2014 the\n * bridge-router watchdog (apiCallWatchdogMs in simulator-api-metadata.ts)\n * derives its window from this so the two cannot drift apart.\n */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n\n/**\n * Largest delay setTimeout honours (2^31-1 ms). Anything above overflows the\n * signed-32-bit timer register and fires ~immediately (~1ms) instead of late \u2014\n * so an oversized caller timeout must be rejected, never passed through.\n */\nexport const MAX_TIMEOUT_MS = 2_147_483_647\n\n/**\n * Resolve a caller-supplied wx timeout into a usable budget: a finite positive\n * number within setTimeout's range is honoured; anything else (absent, 0,\n * negative, NaN, Infinity, overflowing) falls back to the wx default. Shared\n * by performRequest and the bridge-router watchdog (apiCallWatchdogMs) so the\n * two layers can never disagree on what a valid timeout is.\n */\nexport function resolveTimeoutBudgetMs(timeout: unknown): number {\n const t = Number(timeout)\n return Number.isFinite(t) && t > 0 && t <= MAX_TIMEOUT_MS ? t : DEFAULT_REQUEST_TIMEOUT_MS\n}\n\nfunction buildHeaders(header: Record<string, string> | undefined): Headers {\n const headers = new Headers()\n for (const [key, value] of Object.entries(header ?? {})) {\n if (value != null) headers.set(key, String(value))\n }\n if (!headers.has('content-type')) headers.set('content-type', 'application/json')\n return headers\n}\n\nfunction appendQueryParams(url: string, data: Record<string, unknown>): string {\n // Resolve against the current document when available so page-relative URLs\n // keep working in the render-window shim.\n const base = typeof location !== 'undefined' ? location.href : undefined\n const resolved = new URL(url, base)\n for (const [key, value] of Object.entries(data)) {\n resolved.searchParams.append(key, String(value))\n }\n return resolved.toString()\n}\n\nfunction encodeBody(data: unknown, contentType: string): BodyInit {\n if (typeof data === 'string') return data\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const form = new URLSearchParams()\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n form.append(key, String(value))\n }\n return form.toString()\n }\n return JSON.stringify(data)\n}\n\nasync function decodeResponseData(\n response: Response,\n dataType: string,\n responseType: string,\n): Promise<unknown> {\n if (responseType === 'arraybuffer' || dataType === 'arraybuffer') {\n return response.arrayBuffer()\n }\n const text = await response.text()\n if (dataType !== 'json') return text\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n\nexport function performRequest(\n opts: RequestCoreOptions,\n callbacks: RequestCoreCallbacks,\n): RequestHandle {\n const method = (opts.method || 'GET').toUpperCase()\n const canHaveBody = method !== 'GET' && method !== 'HEAD'\n const headers = buildHeaders(opts.header)\n\n let url = opts.url\n const init: RequestInit = { method, headers }\n\n if (!canHaveBody) {\n if (opts.data && typeof opts.data === 'object') {\n url = appendQueryParams(url, opts.data as Record<string, unknown>)\n }\n } else if (opts.data != null) {\n init.body = encodeBody(opts.data, headers.get('content-type') ?? '')\n }\n\n const controller = new AbortController()\n init.signal = controller.signal\n\n // First verdict wins: a timeout/abort settles the call even though the fetch\n // promise is still pending, and the fetch's own late resolution/AbortError\n // rejection must not fire a second callback round.\n let settled = false\n\n function settleSuccess(res: RequestSuccessResult): void {\n if (settled) return\n settled = true\n clearTimeout(timer)\n callbacks.success?.(res)\n callbacks.complete?.(res)\n }\n\n function settleFail(err: RequestFailResult): void {\n if (settled) return\n settled = true\n clearTimeout(timer)\n callbacks.fail?.(err)\n callbacks.complete?.(err)\n }\n\n const timeoutMs = resolveTimeoutBudgetMs(opts.timeout)\n const timer = setTimeout(() => {\n settleFail({ errMsg: 'request:fail timeout' })\n controller.abort()\n }, timeoutMs)\n\n const dataType = opts.dataType ?? 'json'\n const responseType = opts.responseType ?? 'text'\n\n fetch(url, init)\n .then(async (response) => {\n const header: Record<string, string> = {}\n response.headers.forEach((value, key) => {\n header[key] = value\n })\n const data = await decodeResponseData(response, dataType, responseType)\n settleSuccess({ data, statusCode: response.status, header, errMsg: 'request:ok' })\n })\n .catch((error: unknown) => {\n const reason = error instanceof Error ? error.message : String(error)\n settleFail({ errMsg: `request:fail ${reason || 'network error'}` })\n })\n\n return {\n abort() {\n settleFail({ errMsg: 'request:fail abort' })\n controller.abort()\n },\n }\n}\n", "import { performRequest } from '../../shared/request-core.js'\n\ntype Callback<T = unknown> = ((payload: T) => void) | undefined\n\nfunction call<T>(fn: Callback<T>, payload: T): void {\n try {\n fn?.(payload)\n } catch {\n // Ignore callback errors in compat shims.\n }\n}\n\nfunction buildWindowInfo() {\n const width = window.innerWidth || document.documentElement.clientWidth || 375\n const height = window.innerHeight || document.documentElement.clientHeight || 812\n const pixelRatio = window.devicePixelRatio || 2\n const statusBarHeight = 0\n return {\n pixelRatio,\n screenWidth: width,\n screenHeight: height,\n windowWidth: width,\n windowHeight: height,\n statusBarHeight,\n safeArea: {\n width,\n height,\n top: statusBarHeight,\n bottom: height,\n left: 0,\n right: width,\n },\n }\n}\n\nfunction makeStorageKey(key: string): string {\n return `dimina:${key}`\n}\n\nfunction ensureWxApi(wx: Record<string, unknown>): void {\n if (typeof wx.canIUse !== 'function') {\n wx.canIUse = (_schema: unknown) => true\n }\n\n if (typeof wx.getWindowInfo !== 'function') {\n wx.getWindowInfo = (opts: { success?: Callback<unknown>; complete?: Callback<void> } = {}) => {\n const info = buildWindowInfo()\n call(opts.success, info)\n call(opts.complete, undefined)\n return info\n }\n }\n\n if (typeof wx.getSystemSetting !== 'function') {\n wx.getSystemSetting = (opts: { success?: Callback<unknown>; complete?: Callback<void> } = {}) => {\n const info = {\n bluetoothEnabled: false,\n locationEnabled: true,\n wifiEnabled: true,\n deviceOrientation: 'portrait',\n }\n call(opts.success, info)\n call(opts.complete, undefined)\n return info\n }\n }\n\n if (typeof wx.getSystemInfoSync !== 'function') {\n wx.getSystemInfoSync = () => ({\n brand: 'simulator',\n model: 'web',\n platform: 'simulator',\n system: 'web',\n language: 'zh_CN',\n SDKVersion: '3.0.0',\n ...buildWindowInfo(),\n })\n }\n\n if (typeof wx.setStorageSync !== 'function') {\n wx.setStorageSync = (key: string, data: unknown) => {\n const value = typeof data === 'string' ? data : JSON.stringify(data)\n localStorage.setItem(makeStorageKey(String(key)), value)\n }\n }\n\n if (typeof wx.getStorageSync !== 'function') {\n wx.getStorageSync = (key: string) => {\n const raw = localStorage.getItem(makeStorageKey(String(key)))\n if (raw == null) return ''\n try {\n return JSON.parse(raw)\n } catch {\n return raw\n }\n }\n }\n\n if (typeof wx.removeStorageSync !== 'function') {\n wx.removeStorageSync = (key: string) => {\n localStorage.removeItem(makeStorageKey(String(key)))\n }\n }\n\n if (typeof wx.clearStorageSync !== 'function') {\n wx.clearStorageSync = () => {\n const prefix = 'dimina:'\n const keys: string[] = []\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i)\n if (key?.startsWith(prefix)) keys.push(key)\n }\n keys.forEach((key) => localStorage.removeItem(key))\n }\n }\n\n if (typeof wx.getStorageInfoSync !== 'function') {\n wx.getStorageInfoSync = () => {\n const prefix = 'dimina:'\n const keys: string[] = []\n let currentSize = 0\n for (let i = 0; i < localStorage.length; i++) {\n const fullKey = localStorage.key(i)\n if (!fullKey?.startsWith(prefix)) continue\n keys.push(fullKey.slice(prefix.length))\n currentSize += (localStorage.getItem(fullKey) || '').length * 2\n }\n return { keys, currentSize, limitSize: 10 * 1024 * 1024 }\n }\n }\n\n if (typeof wx.request !== 'function') {\n // Delegates to the shared wx.request core (shared/request-core.ts) \u2014 the\n // single owner of success/fail semantics, header dedup, timeout default,\n // and body encoding. This shim only adapts the wx.request option bag onto\n // the core's callbacks.\n wx.request = (opts: {\n url: string\n data?: unknown\n header?: Record<string, string>\n timeout?: number\n method?: string\n dataType?: string\n responseType?: string\n success?: Callback<unknown>\n fail?: Callback<unknown>\n complete?: Callback<unknown>\n }) =>\n performRequest(\n {\n url: opts.url,\n data: opts.data,\n header: opts.header,\n timeout: opts.timeout,\n method: opts.method,\n dataType: opts.dataType,\n responseType: opts.responseType,\n },\n {\n success: (res) => call(opts.success, res),\n fail: (err) => call(opts.fail, err),\n complete: (res) => call(opts.complete, res),\n },\n )\n }\n}\n\nexport function setupApiCompatHook(): void {\n const apply = () => {\n const target = window as unknown as { wx?: Record<string, unknown> }\n if (!target.wx || typeof target.wx !== 'object') {\n target.wx = {}\n }\n const wx = target.wx\n ensureWxApi(wx)\n return true\n }\n\n if (apply()) return\n\n const timer = window.setInterval(() => {\n if (apply()) window.clearInterval(timer)\n }, 200)\n}\n", "import { ipcRenderer } from 'electron'\nimport { BRIDGE_CHANNELS as C } from '../../shared/bridge-channels.js'\nimport type { NativeDeviceInfo } from '../../shared/ipc-channels.js'\n// (extension required: preload tsconfig is moduleResolution node16)\nimport type {\n ActivePagePayload,\n ApiResponsePayload,\n DisposePayload,\n NativeHostConfig,\n NavCallbackPayload,\n PageClosePayload,\n PageLifecyclePayload,\n PageOpenRequest,\n PageOpenResult,\n PageStackPayload,\n SpawnRequest,\n SpawnResult,\n} from '../../shared/bridge-channels.js'\nimport { exposeOnMainWorld } from '../shared/expose.js'\n\nexport interface RenderHostUrlOptions {\n bridgeId: string\n appId: string\n pagePath: string\n /** Whether this page is a tabBar page. Surfaced on the URL so main can pick\n * the bottom safe-area policy at `did-attach-webview` (services/safe-area). */\n isTab?: boolean\n}\n\nexport interface DiminaNativeHostBridge {\n enabled: boolean\n spawn(opts: SpawnRequest): Promise<SpawnResult>\n dispose(bridgeId: string): void\n openPage(opts: PageOpenRequest): Promise<PageOpenResult>\n closePage(bridgeId: string): void\n notifyLifecycle(payload: PageLifecyclePayload): void\n notifyNavCallback(payload: NavCallbackPayload): void\n notifyApiResponse(payload: ApiResponsePayload): void\n /** Tell main which page is the visible top-of-stack (for panel/automation targeting). */\n notifyActivePage(payload: ActivePagePayload): void\n /** Tell main the full ordered page stack (for automation's App.getPageStack). */\n notifyPageStack(payload: PageStackPayload): void\n createRenderHostUrl(opts: RenderHostUrlOptions): string\n renderPreloadUrl: string\n /**\n * The selected device at bridge-install time, if the renderer already pushed\n * it (it does \u2014 SetDeviceInfo precedes AttachNative). DeviceShell reads this\n * as its initial device; live changes arrive via the DEVICE_CHANGE event.\n */\n device?: NativeDeviceInfo\n /**\n * Subscribe to a main\u2192simulator event channel (SIMULATOR_EVENTS). Returns an\n * unsubscribe fn. The simulator renderer (DeviceShell) runs in the webview\n * main world with `nodeIntegration:false`, so it cannot `import 'electron'`;\n * this bridge owns the `ipcRenderer` plumbing on its behalf.\n */\n onSimulatorEvent<T = unknown>(channel: string, listener: (payload: T) => void): () => void\n}\n\n/**\n * Ask the main process (synchronously, at install time) whether native-host is\n * on and, if so, for the render-host file:// URLs. The simulator webview's\n * preload can't read the launch `process.env`, and \u2014 crucially \u2014 can't use\n * `node:path`/`node:url` to compute paths (the guest preload has no Node\n * builtins), so the main process (which has both) supplies everything here.\n */\nfunction queryNativeHostConfig(): NativeHostConfig | null {\n try {\n const res = ipcRenderer.sendSync(C.NATIVE_HOST_ENABLED) as NativeHostConfig | undefined\n return res && res.enabled ? res : null\n } catch {\n return null\n }\n}\n\nfunction buildBridge(cfg: NativeHostConfig): DiminaNativeHostBridge {\n return {\n enabled: true,\n spawn(opts) {\n return ipcRenderer.invoke(C.SPAWN, opts) as Promise<SpawnResult>\n },\n dispose(bridgeId) {\n const payload: DisposePayload = { bridgeId }\n ipcRenderer.send(C.DISPOSE, payload)\n },\n openPage(opts) {\n return ipcRenderer.invoke(C.PAGE_OPEN, opts) as Promise<PageOpenResult>\n },\n closePage(bridgeId) {\n const payload: PageClosePayload = { bridgeId }\n ipcRenderer.send(C.PAGE_CLOSE, payload)\n },\n notifyLifecycle(payload) {\n ipcRenderer.send(C.PAGE_LIFECYCLE, payload)\n },\n notifyNavCallback(payload) {\n ipcRenderer.send(C.NAV_CALLBACK, payload)\n },\n notifyApiResponse(payload) {\n ipcRenderer.send(C.API_RESPONSE, payload)\n },\n notifyActivePage(payload) {\n ipcRenderer.send(C.ACTIVE_PAGE, payload)\n },\n notifyPageStack(payload) {\n ipcRenderer.send(C.PAGE_STACK, payload)\n },\n createRenderHostUrl(opts) {\n // `URL` + `URLSearchParams` are web globals \u2014 no node:url needed.\n const url = new URL(cfg.renderHostHtmlUrl)\n url.searchParams.set('bridgeId', opts.bridgeId)\n url.searchParams.set('appId', opts.appId)\n url.searchParams.set('pagePath', opts.pagePath)\n if (opts.isTab) url.searchParams.set('isTab', '1')\n return url.toString()\n },\n renderPreloadUrl: cfg.renderPreloadUrl,\n device: cfg.device,\n onSimulatorEvent(channel, listener) {\n const wrapped = (_event: unknown, payload: unknown): void => {\n ;(listener as (p: unknown) => void)(payload)\n }\n ipcRenderer.on(channel, wrapped)\n return () => ipcRenderer.removeListener(channel, wrapped)\n },\n }\n}\n\n/**\n * Install the native-host bridge on the simulator main world when native-host\n * mode is on. Self-gating: a no-op disposer is returned when it's off, so the\n * caller can install unconditionally.\n */\nexport function installNativeHostBridge(): () => void {\n const cfg = queryNativeHostConfig()\n if (!cfg) return () => {}\n return exposeOnMainWorld('__diminaNativeHost', buildBridge(cfg))\n}\n", "import type { NativeDeviceInfo } from './ipc-channels.js'\n\nexport const BRIDGE_CHANNELS = {\n SPAWN: 'dmb:spawn',\n DISPOSE: 'dmb:dispose',\n PAGE_OPEN: 'dmb:page:open',\n PAGE_CLOSE: 'dmb:page:close',\n PAGE_LIFECYCLE: 'dmb:page:lifecycle',\n NAV_CALLBACK: 'dmb:nav:callback',\n SERVICE_INVOKE: 'dmb:service:invoke',\n SERVICE_PUBLISH: 'dmb:service:publish',\n RENDER_INVOKE: 'dmb:render:invoke',\n RENDER_PUBLISH: 'dmb:render:publish',\n TO_SERVICE: 'dmb:to-service',\n TO_RENDER: 'dmb:to-render',\n SIMULATOR_API: 'dmb:simulator-api',\n /** simulator \u2192 main: ack of an API_CALL request (carries success/fail args). */\n API_RESPONSE: 'dmb:api:response',\n /**\n * simulator webview preload \u2192 main (sendSync): \"is native-host mode on?\".\n * The guest preload can't read the launch `process.env`, so it asks main\n * (which can) at install time. Reply is `e.returnValue = boolean`.\n */\n NATIVE_HOST_ENABLED: 'dmb:native-host-enabled',\n /**\n * simulator (DeviceShell) \u2192 main: the visible top-of-stack page bridgeId.\n * Main has no z-order concept \u2014 the active page lives only in DeviceShell's\n * ShellState \u2014 so devtools panels / automation that must target \"the current\n * page's render webContents\" resolve it through this signal. Fire-and-forget.\n */\n ACTIVE_PAGE: 'dmb:active-page',\n /**\n * simulator (DeviceShell) \u2192 main: the FULL ordered page stack (bottom\u2192top)\n * whenever it changes. Main has no stack of its own (it only learns the\n * active bridgeId via ACTIVE_PAGE), so automation's `App.getPageStack` needs\n * this to report multi-page stacks. Fire-and-forget.\n */\n PAGE_STACK: 'dmb:page-stack',\n} as const\n\nexport const SIMULATOR_EVENTS = {\n DOM_READY: 'simulator:dom-ready',\n NAV_BAR: 'simulator:navigation-bar',\n NAV_ACTION: 'simulator:nav-action',\n TAB_ACTION: 'simulator:tab-action',\n /** main \u2192 simulator: invoke a wx.* API on the simulator-resident MiniApp. */\n API_CALL: 'simulator:api-call',\n /**\n * main \u2192 simulator: the renderer toolbar picked a different device. Carries a\n * NativeDeviceInfo; DeviceShell resizes the bezel + re-renders status bar /\n * notch. The race-free INITIAL device rides NativeHostConfig.device (read\n * synchronously at preload bridge-install); this event covers live changes.\n */\n DEVICE_CHANGE: 'simulator:device-change',\n /**\n * main \u2192 simulator: a watcher rebuild finished; boot a NEW app session for\n * the carried url ({@link RelaunchPayload}) IN PLACE, keeping the live\n * DeviceShell painted, and swap once the new session's root page reports\n * DOM_READY (ready-then-swap soft reload). Main sends this only when the\n * shell is live+ready; otherwise the renderer falls back to the hard\n * attachNativeSimulator rebuild.\n */\n RELAUNCH: 'simulator:relaunch',\n} as const\n\n/**\n * `simulator:relaunch` payload. `url` is a full simulator URL (same format as\n * the simulator page's own location / AttachNative), carrying the appId and\n * the page route the new session must boot at.\n */\nexport interface RelaunchPayload {\n url: string\n}\n\nexport const CHANNELS = BRIDGE_CHANNELS\n\n/**\n * Reply to a `NATIVE_HOST_ENABLED` sendSync. Main supplies the render-host\n * file:// URLs (computed with node:path/url, which the simulator webview's\n * preload lacks) so the preload can build the native-host bridge.\n */\nexport interface NativeHostConfig {\n enabled: boolean\n renderHostHtmlUrl: string\n renderPreloadUrl: string\n /**\n * The currently-selected device, if the renderer already pushed it before the\n * simulator WCV's preload installed (it does \u2014 SetDeviceInfo precedes\n * AttachNative). DeviceShell reads this as its initial device so it never\n * mounts with the wrong bezel size while waiting for the first DEVICE_CHANGE.\n * Absent only on the pre-spawn default path.\n */\n device?: NativeDeviceInfo\n}\n\nexport type BridgeChannel = typeof BRIDGE_CHANNELS[keyof typeof BRIDGE_CHANNELS]\n\nexport type BridgeTarget = 'service' | 'render' | 'container'\n\nexport type BridgeMessageType =\n | 'loadResource'\n | 'serviceResourceLoaded'\n | 'renderResourceLoaded'\n | 'resourceLoaded'\n | 'firstRender'\n | 'appShow'\n | 'appHide'\n | 'stackShow'\n | 'stackHide'\n | 'pageShow'\n | 'pageHide'\n | 'pageReady'\n | 'pageUnload'\n | 'pageScroll'\n | 'pageResize'\n | 'pageRouteDone'\n | 'mC'\n | 'mR'\n | 'mU'\n | 't'\n | 'u'\n | 'ub'\n | 'triggerCallback'\n | 'invokeAPI'\n | 'h5SdkAction'\n | 'componentError'\n | 'domReady'\n | 'print'\n | 'renderHostReady'\n | 'serviceHostError'\n | string\n\nexport interface MessageEnvelope<TBody extends Record<string, unknown> = Record<string, unknown>> {\n type: BridgeMessageType\n target: BridgeTarget\n body: TBody\n}\n\nexport interface HostEnvSnapshot {\n brand: string\n model: string\n platform: string\n system: string\n version: string\n SDKVersion: string\n pixelRatio: number\n screenWidth: number\n screenHeight: number\n windowWidth: number\n windowHeight: number\n statusBarHeight: number\n language: string\n theme: string\n [key: string]: unknown\n}\n\n/**\n * Map the renderer's logical device metrics onto the subset of a\n * HostEnvSnapshot the service-host window's `getSystemInfoSync` consumes.\n * `windowHeight` excludes the status bar (the page area); `windowWidth` has no\n * horizontal chrome. Zoom is intentionally absent \u2014 it is a display scale, not\n * a logical-size change.\n *\n * Single source of truth for the device\u2192host-env mapping, shared by the live\n * `SetDeviceInfo` IPC path (main/ipc/simulator.ts) and the per-spawn host-env\n * seeding (main/ipc/bridge-router.ts). Keeping them identical guarantees a\n * service-host RESPAWN after a device change reports the same dims the live\n * update pushed \u2014 otherwise a respawn would silently revert to the boot device.\n */\nexport function deviceInfoToHostEnv(d: NativeDeviceInfo): Partial<HostEnvSnapshot> {\n return {\n brand: d.brand,\n model: d.model,\n system: d.system,\n platform: d.platform,\n pixelRatio: d.pixelRatio,\n screenWidth: d.screenWidth,\n screenHeight: d.screenHeight,\n windowWidth: d.screenWidth,\n windowHeight: Math.max(0, d.screenHeight - d.statusBarHeight),\n statusBarHeight: d.statusBarHeight,\n }\n}\n\n/**\n * Subset of WeChat page `window` config plus tabBar list, parsed from\n * `app-config.json` (`{app:{window,tabBar,pages,entryPagePath}, modules:{[pagePath]:{window}}}`).\n * Mirrors mergePageConfig in dimina-fe: page-level keys override app-level.\n */\nexport interface PageWindowConfig {\n navigationBarTitleText?: string\n navigationBarBackgroundColor?: string\n navigationBarTextStyle?: 'black' | 'white'\n navigationStyle?: 'default' | 'custom'\n homeButton?: boolean\n backgroundColor?: string\n backgroundTextStyle?: 'dark' | 'light'\n enablePullDownRefresh?: boolean\n disableScroll?: boolean\n [key: string]: unknown\n}\n\nexport interface TabBarItem {\n pagePath: string\n text?: string\n iconPath?: string\n selectedIconPath?: string\n}\n\nexport interface TabBarConfig {\n color?: string\n selectedColor?: string\n backgroundColor?: string\n borderStyle?: 'black' | 'white'\n position?: 'bottom' | 'top'\n custom?: boolean\n list: TabBarItem[]\n}\n\nexport interface AppManifest {\n entryPagePath: string\n pages: string[]\n tabBar?: TabBarConfig\n /**\n * Provenance of this manifest: `'app-config'` when built from a real\n * compiled `app-config.json` (its `pages` list is authoritative, so mount\n * gates can validate membership against it); `'fallback'` when\n * app-config.json was unreachable and the manifest is a single-page stand-in\n * built from the spawn request. Mount gates only enforce against\n * `'app-config'` \u2014 a `'fallback'` manifest has no compiled truth to check\n * membership against, so it must let every page/nav target through.\n */\n source: 'app-config' | 'fallback'\n}\n\nexport interface SpawnRequest {\n simulatorWcId?: number\n appId: string\n bridgeId?: string\n pagePath?: string\n scene?: number\n query?: Record<string, unknown>\n apiNamespaces?: string[]\n hostEnvSnapshot?: Partial<HostEnvSnapshot>\n pkgRoot?: string\n root?: string\n /**\n * Base URL of the dev server that serves the compiled mini-app, i.e. the\n * SAME origin the simulator page was loaded from (`http://localhost:<port>/`).\n * The dev server statically serves `<appId>/<root>/\u2026` (app-config.json,\n * logic.js, page bundles, styles) \u2014 exactly what the default dimina-fe\n * `<webview>` fetches. The native-host render + service hosts source every\n * resource from here, so we don't need a second resource server or a local\n * compiled-output path. Trailing slash expected.\n */\n resourceBaseUrl?: string\n}\n\nexport interface SpawnResult {\n appSessionId: string\n bridgeId: string\n /** The pagePath originally requested (unchanged even when a fallback applied \u2014 see `resolvedPagePath`). */\n pagePath: string\n /**\n * The pagePath the root PageSession was ACTUALLY spawned with. Equal to\n * `pagePath` unless `pageFallbackApplied` is true, in which case the request\n * was absent from `manifest.pages` and this is `manifest.entryPagePath`\n * (or `manifest.pages[0]` when even that isn't a member). Callers that cache\n * \"the current page\" (e.g. `SimulatorMiniApp`) must reconcile against this,\n * not the original request.\n */\n resolvedPagePath: string\n /** Whether `resolvedPagePath` differs from the request because it was absent from the compiled manifest. Always false for a `'fallback'` manifest (nothing to validate against). */\n pageFallbackApplied: boolean\n serviceWcId: number\n resourceBaseUrl: string\n manifest: AppManifest\n rootWindowConfig: PageWindowConfig\n}\n\nexport interface PageOpenRequest {\n appSessionId: string\n pagePath: string\n query?: Record<string, unknown>\n bridgeId?: string\n}\n\nexport interface PageOpenResult {\n bridgeId: string\n pagePath: string\n windowConfig: PageWindowConfig\n isTab: boolean\n}\n\nexport interface PageClosePayload {\n bridgeId: string\n}\n\nexport interface DisposePayload {\n /** AppSession root bridgeId (legacy) or any page bridgeId. */\n bridgeId: string\n}\n\nexport type PageLifecycleEvent =\n | 'pageShow'\n | 'pageHide'\n | 'pageUnload'\n | 'stackShow'\n | 'stackHide'\n | 'appShow'\n | 'appHide'\n\nexport interface PageLifecyclePayload {\n appSessionId: string\n bridgeId: string\n event: PageLifecycleEvent\n}\n\n/**\n * Sent by simulator after a routing action (navigateTo etc.) completes so the\n * main process can call sendCallback() against the original service-issued\n * success/fail/complete ids.\n */\nexport interface NavCallbackPayload {\n appSessionId: string\n ok: boolean\n errMsg: string\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n\nexport interface ServiceInvokePayload {\n bridgeId: string\n msg: MessageEnvelope\n}\n\nexport interface ServicePublishPayload {\n bridgeId: string\n targetBridgeId?: string\n msg: MessageEnvelope\n}\n\n/**\n * `dmb:active-page` \u2014 simulator (DeviceShell) \u2192 main. Records which page is the\n * visible top-of-stack so main-side services (WXML/element-inspect, automation)\n * can resolve \"the active page's render webContents\" by bridgeId.\n */\nexport interface ActivePagePayload {\n appSessionId: string\n bridgeId: string\n}\n\n/**\n * `dmb:page-stack` \u2014 simulator (DeviceShell) \u2192 main. The full ordered page\n * stack (bottom\u2192top) so `App.getPageStack` can report multi-page stacks.\n */\nexport interface PageStackEntry {\n pagePath: string\n query: Record<string, unknown>\n}\n\nexport interface PageStackPayload {\n appSessionId: string\n stack: PageStackEntry[]\n}\n\nexport interface RenderInvokePayload {\n bridgeId: string\n msg: MessageEnvelope\n}\n\nexport interface RenderPublishPayload {\n bridgeId: string\n msg: MessageEnvelope\n}\n\nexport interface ToServicePayload {\n msg: MessageEnvelope\n}\n\nexport interface ToRenderPayload {\n msg: MessageEnvelope\n}\n\nexport interface SimulatorApiInvokePayload {\n bridgeId: string\n name: string\n params: unknown\n}\n\n/**\n * `simulator:nav-action` \u2014 main \u2192 simulator window, carries router/tabBar\n * intentions. Simulator owns the visual stack state and decides whether to\n * push/pop webviews; it then calls back PAGE_LIFECYCLE + NAV_CALLBACK.\n */\nexport interface NavActionPayload {\n appSessionId: string\n bridgeId: string\n name: 'navigateTo' | 'navigateBack' | 'redirectTo' | 'reLaunch' | 'switchTab'\n params: Record<string, unknown>\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n\n/**\n * `simulator:api-call` \u2014 main \u2192 simulator. Fallback path used when an\n * invokeAPI name is not registered in the main-process `ctx.simulatorApis`\n * registry: the simulator-resident MiniApp owns the wx.* handler (it can\n * read DOM, open file pickers, etc.), so we forward the call there and wait\n * for an `API_RESPONSE` ack.\n */\nexport interface ApiCallPayload {\n appSessionId: string\n bridgeId: string\n requestId: string\n name: string\n params: Record<string, unknown>\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n\n/**\n * `dmb:api:response` \u2014 simulator \u2192 main. Ack for an `API_CALL`. Main looks\n * up `requestId` in its pending map and fires the original service-side\n * success/fail/complete callbacks accordingly.\n */\nexport interface ApiResponsePayload {\n appSessionId: string\n requestId: string\n ok: boolean\n /** Argument the simulator-side success/fail callback was invoked with. */\n result?: unknown\n errMsg?: string\n /**\n * Persistent-subscription marker (`keep: true` APIs, e.g.\n * `audioListen`). When set, this response is one of potentially many\n * fires of the same subscription: main re-fires the service-side success\n * callback but keeps the pendingApiCall alive (does not delete it or fire\n * `complete`) so subsequent fires of the same `requestId` are delivered.\n * Cleanup happens on page/app teardown instead.\n */\n keep?: boolean\n}\n\n/**\n * `simulator:tab-action` \u2014 main \u2192 simulator window, carries dynamic TabBar\n * API calls. Simulator updates TabBar React state and acknowledges via\n * NAV_CALLBACK so the service-side wx.* callback fires.\n */\nexport interface TabActionPayload {\n appSessionId: string\n bridgeId: string\n name:\n | 'setTabBarStyle'\n | 'setTabBarItem'\n | 'showTabBar'\n | 'hideTabBar'\n | 'setTabBarBadge'\n | 'removeTabBarBadge'\n | 'showTabBarRedDot'\n | 'hideTabBarRedDot'\n params: Record<string, unknown>\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n", "// Default preload script for the simulator <webview>.\n// Composes all built-in instrumentation. For custom preloads, import individual\n// functions from '@dimina-kit/devtools/preload' and assemble your own.\n//\n// This file is bundled into a single JS file via build:preload (esbuild)\n// because webview sandbox cannot resolve require() for separate modules.\nimport { installSimulatorBridge } from '../runtime/bridge.js'\nimport { installCustomApisBridge } from '../runtime/custom-apis.js'\nimport { installTempFileBridge } from '../runtime/temp-files.js'\nimport { installConsoleInstrumentation } from '../instrumentation/console.js'\nimport { createAppDataSource } from '../instrumentation/app-data.js'\nimport { setupApiCompatHook } from '../shared/api-compat.js'\nimport { installNativeHostBridge } from '../runtime/native-host.js'\n\n// Note: storage panel data is sourced from the main process via the CDP\n// DOMStorage domain (src/main/services/simulator-storage). No preload-side\n// localStorage hook is required.\n\n// This bundle is assigned to the native-host simulator WebContentsView only, so\n// it always runs in the actual simulator document (`simulator.html`) \u2014 never a\n// per-page render-host (`pageFrame.html`) or service-host (`service.html`)\n// frame, which carry their own dedicated preloads.\nsetupApiCompatHook()\ninstallSimulatorBridge()\ninstallCustomApisBridge()\ninstallTempFileBridge()\ninstallConsoleInstrumentation()\n\n// Native-host render path: self-gating bridge that exposes\n// `window.__diminaNativeHost` so simulator/main.tsx boots the DeviceShell +\n// SimulatorMiniApp pipeline.\ninstallNativeHostBridge()\n\n// AppData instrumentation source. We call its `start()` DIRECTLY (not wrapped\n// in a MiniappSnapshotHost) purely for the automation-surface side effects: it\n// installs `window.__simulatorHook.appData` and mirrors the flat cache into the\n// `window.__simulatorData.getAppdata()` surface \u2014 both still read in the\n// simulator (top) frame by automation `getData` (handlers/page.ts), the MCP\n// context overview (mcp/tools/context-tools.ts) and the e2e automator helper.\n//\n// We do NOT wrap it in a host: the host's `miniapp-snapshot:push/pull` IPC has\n// no consumer under native-host (the renderer reads panel WXML/AppData from\n// main via SimulatorWxmlChannel / SimulatorAppDataChannel), so install()'s\n// publish would only ever fire into the void. We also do NOT register\n// `createWxmlSource` \u2014 under native-host the page DOM lives in child\n// render-host <webview> guests, so a top-frame DOM observer would only publish\n// null. (`createWxmlSource` / `createMiniappSnapshotHost` stay exported from\n// `@dimina-kit/devtools/preload` for external/composed preloads.)\ncreateAppDataSource().start(() => {})\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { contextBridge } from 'electron'\n\n/**\n * Expose `value` on the renderer's main world under `key`.\n *\n * Uses Electron's `contextBridge` only when `contextIsolation` is enabled\n * (the path that reaches the renderer's `window` through the isolated world).\n * When context isolation is OFF \u2014 e.g. the simulator/render-host/service-host\n * frames \u2014 `contextBridge.exposeInMainWorld` would always throw, so we skip it\n * entirely and assign `value` directly onto the preload realm's `window`.\n *\n * `process.contextIsolated` is Electron's renderer-side boolean for the current\n * frame: `true` when context isolation is on, `false` when it's off. (It is\n * `undefined` only in the main process, which never runs this preload helper.)\n *\n * Returns a disposer. It can only undo the direct-assignment path (a\n * `contextBridge` binding cannot be un-exposed); on the contextBridge path\n * the disposer is a no-op. The disposer never clobbers a `window[key]` that\n * something else has since reassigned.\n */\nexport function exposeOnMainWorld(key: string, value: unknown): () => void {\n let assignedToWindow = false\n\n if (process.contextIsolated) {\n // Isolated world (main / settings / view-manager host windows): the only\n // way to reach the renderer's `window` is via contextBridge. Keep the\n // defensive fallback + warn for the genuinely-unexpected failure case.\n try {\n contextBridge.exposeInMainWorld(key, value)\n }\n catch (err) {\n console.warn('[devtools/expose] contextBridge.exposeInMainWorld failed, falling back to direct window assignment:', err)\n ;(window as unknown as Record<string, unknown>)[key] = value\n assignedToWindow = true\n }\n }\n else {\n // Context isolation off (simulator <webview>, render-host, service-host):\n // contextBridge is unusable here and would always throw, so assign the\n // preload realm's `window` directly without the noisy failed attempt.\n ;(window as unknown as Record<string, unknown>)[key] = value\n assignedToWindow = true\n }\n\n return () => {\n if (!assignedToWindow) return\n const w = window as unknown as Record<string, unknown>\n if (w[key] === value) delete w[key]\n }\n}\n", "/** Locate the active page's webview iframe \u2014 the last one in the simulator stack. */\nexport function getActivePageIframe(): HTMLIFrameElement | null {\n const iframes = document.querySelectorAll<HTMLIFrameElement>('.dimina-native-webview__window')\n return iframes.length > 0 ? iframes[iframes.length - 1]! : null\n}\n", "// Stable-id registry for WXML nodes, shared by every extractor that walks a\n// render-layer document (host iframe extractors, injected guest inspectors,\n// browser preview bridges). It is dependency-free so injected bundles stay\n// small and don't drag in host-specific machinery.\n// \u5408\u6210 sid \u6CE8\u518C\u8868\uFF1A\u7528 WeakMap \u628A\u5143\u7D20 \u2194 sid \u53CC\u5411\u7ED1\u5B9A\uFF0C\u907F\u514D\u5728\u6E90 DOM \u4E0A\u5199\n// `data-*` \u5C5E\u6027\uFF08\u63D0\u53D6\u672C\u5E94\u53EA\u8BFB\uFF0C\u4E14\u5C5E\u6027\u5F62\u5F0F\u4F1A\u6C61\u67D3\u7528\u6237\u7684\u5FEB\u7167/\u9009\u62E9\u5668\uFF09\u3002\n// elBySyntheticSid \u4E3A\u53CD\u5411\u67E5\u627E\u7528 WeakRef\uFF0C\u5143\u7D20\u88AB GC \u540E\u4E0B\u6B21 lookup \u81EA\u52A8\u6E05\u7406\u3002\nexport const SYNTHETIC_SID_PREFIX = 'devtools-';\nconst syntheticSidByEl = new WeakMap();\nconst elBySyntheticSid = new Map();\nlet nextSyntheticSid = 1;\nexport function registerSyntheticSid(el) {\n const existing = syntheticSidByEl.get(el);\n if (existing)\n return existing;\n const synthetic = `${SYNTHETIC_SID_PREFIX}${nextSyntheticSid++}`;\n syntheticSidByEl.set(el, synthetic);\n elBySyntheticSid.set(synthetic, new WeakRef(el));\n return synthetic;\n}\nexport function findElementBySid(doc, sid) {\n if (sid.startsWith(SYNTHETIC_SID_PREFIX)) {\n const ref = elBySyntheticSid.get(sid);\n if (!ref)\n return null;\n const el = ref.deref();\n if (!el || !el.isConnected) {\n elBySyntheticSid.delete(sid);\n return null;\n }\n if (el.ownerDocument !== doc)\n return null;\n return el;\n }\n return doc.querySelector(`[data-sid=\"${escapeForAttrSelector(sid)}\"]`);\n}\n// `CSS.escape` only exists in real browser realms (jsdom has no `window.CSS`).\n// Inside a double-quoted attribute selector, escaping backslashes and quotes\n// is sufficient, so fall back to that when the host lacks the API.\nfunction escapeForAttrSelector(value) {\n const impl = globalThis.CSS?.escape;\n if (impl)\n return impl(value);\n return value.replace(/[\\\\\"]/g, '\\\\$&');\n}\n", "/**\n * Framework-agnostic AppData accumulator.\n *\n * The dimina runtime emits two service\u2192render messages relevant to the AppData\n * panel, identical in shape on BOTH container paths:\n * \u2022 update batches `{type:'ub', body:{bridgeId, updates:[{moduleId,data}]}}`\n * \u2014 each `data` is a partial setData patch.\n * \u2022 instance init: `type === 'page_*'`, body `{bridgeId, path, data}` with the\n * COMPLETE initial state.\n *\n * Hosts differ only in where they tap that stream \u2014 an Electron preload\n * sniffing Worker `message` events, a main-process service\u2192render forward, or\n * a same-origin web workbench observing the pageFrame's Worker. Every tap\n * feeds this one accumulator so the decode/merge/page-only/init-gate policy\n * can't drift between hosts.\n */\n/** Parse a service/worker message payload; a non-string is passed through as-is. */\nfunction parseMessagePayload(message) {\n if (typeof message !== 'string')\n return message;\n try {\n return JSON.parse(message);\n }\n catch {\n return null;\n }\n}\n/**\n * Decode a `ub` (update batch) body into patch entries, PAGE modules only \u2014\n * component-module updates are dropped (see `decodeWorkerMessage`).\n */\nfunction decodeUpdateBatchBody(rawBody) {\n const body = rawBody;\n if (!body || typeof body !== 'object')\n return null;\n if (typeof body.bridgeId !== 'string' || !Array.isArray(body.updates))\n return null;\n const out = [];\n for (const u of body.updates) {\n if (!u || typeof u.moduleId !== 'string')\n continue;\n if (!u.moduleId.startsWith('page_'))\n continue;\n out.push({ mode: 'patch', bridgeId: body.bridgeId, moduleId: u.moduleId, data: u.data });\n }\n return out.length > 0 ? out : null;\n}\n/** Decode a `page_*` instance-init body into its single init entry. */\nfunction decodePageInitBody(moduleId, rawBody) {\n const body = rawBody;\n if (!body || typeof body !== 'object')\n return null;\n if (typeof body.bridgeId !== 'string' || typeof body.path !== 'string')\n return null;\n if (!body.data || typeof body.data !== 'object')\n return null;\n return [{\n mode: 'init',\n bridgeId: body.bridgeId,\n moduleId,\n componentPath: body.path,\n data: body.data,\n }];\n}\n/**\n * Decode a service\u2192render message into AppData entries, or null when it is not\n * AppData-relevant. Policy: surface PAGE entries only \u2014 component entries are\n * dropped (they sometimes flow on a bridge id distinct from their owning page's\n * and never receive pageUnload, which would manifest as ghost tabs).\n */\nexport function decodeWorkerMessage(message) {\n const payload = parseMessagePayload(message);\n if (!payload || typeof payload !== 'object')\n return null;\n const record = payload;\n if (record.type === 'ub')\n return decodeUpdateBatchBody(record.body);\n if (typeof record.type === 'string' && record.type.startsWith('page_')) {\n return decodePageInitBody(record.type, record.body);\n }\n return null;\n}\n/** main\u2192worker direction: container signals page teardown so cache can evict. */\nexport function decodeOutgoingMessage(message) {\n const payload = parseMessagePayload(message);\n if (!payload || typeof payload !== 'object')\n return null;\n const r = payload;\n if (typeof r.type !== 'string')\n return null;\n return {\n type: r.type,\n bridgeId: typeof r.body?.bridgeId === 'string' ? r.body.bridgeId : undefined,\n };\n}\n/** Convert a decoded entry to the normalized accumulator input. */\nexport function decodedToInput(entry) {\n const input = {\n bridgeId: entry.bridgeId,\n moduleId: entry.moduleId,\n data: entry.data,\n mode: entry.mode,\n };\n if (entry.mode === 'init')\n input.componentPath = entry.componentPath;\n return input;\n}\n/**\n * Cumulative per-(bridgeId, moduleId) setData state. Pure data structure \u2014 no\n * Worker / IPC / DOM. Callers own transport (publish/emit) and the automation\n * mirror.\n */\nexport class AppDataAccumulator {\n cache = new Map();\n // Bridges in insertion order \u2014 drives the `bridges` array (stable tab order).\n bridgeOrder = [];\n // Page path per bridge: set from `page_*` init's body.path (the page route).\n bridgePagePath = new Map();\n recordBridge(bridgeId) {\n if (!this.bridgeOrder.includes(bridgeId))\n this.bridgeOrder.push(bridgeId);\n }\n /**\n * Apply one entry. Returns true if it was accepted (a mutation worth\n * republishing), false if dropped (missing ids, or the init-gate).\n */\n apply(input) {\n if (!input.bridgeId || !input.moduleId)\n return false;\n // Drop ub patches whose bridge has never been initialised. dimina\n // dispatches pageUnload \u2192 onUnload, whose setData produces a late `ub`\n // arriving AFTER clearBridge; without this gate it would resurrect the\n // unloaded bridge as a ghost tab.\n if (input.mode !== 'init' && !this.bridgePagePath.has(input.bridgeId))\n return false;\n const key = `${input.bridgeId}/${input.moduleId}`;\n const prev = this.cache.get(key);\n const incoming = input.data && typeof input.data === 'object'\n ? input.data\n : {};\n // init = full-state replace; patch = merge into previous (setData semantics)\n const merged = input.mode === 'init'\n ? { ...incoming }\n : { ...(prev?.data ?? {}), ...incoming };\n const componentPath = input.componentPath ?? prev?.componentPath;\n const next = componentPath !== undefined\n ? { componentPath, data: merged }\n : { data: merged };\n this.cache.set(key, next);\n this.recordBridge(input.bridgeId);\n if (input.mode === 'init' && input.moduleId.startsWith('page_') && input.componentPath) {\n this.bridgePagePath.set(input.bridgeId, input.componentPath);\n }\n return true;\n }\n /** Evict every entry for a bridge (page teardown). */\n clearBridge(bridgeId) {\n const prefix = `${bridgeId}/`;\n for (const key of [...this.cache.keys()]) {\n if (key.startsWith(prefix))\n this.cache.delete(key);\n }\n const idx = this.bridgeOrder.indexOf(bridgeId);\n if (idx >= 0)\n this.bridgeOrder.splice(idx, 1);\n this.bridgePagePath.delete(bridgeId);\n }\n /** The full cumulative snapshot for the panel. */\n snapshot() {\n const bridges = [];\n for (const id of this.bridgeOrder) {\n bridges.push({ id, pagePath: this.bridgePagePath.get(id) ?? null });\n }\n const entries = {};\n for (const [key, entry] of this.cache) {\n const slash = key.indexOf('/');\n if (slash < 0)\n continue;\n const bridgeId = key.slice(0, slash);\n const moduleId = key.slice(slash + 1);\n if (!entries[bridgeId])\n entries[bridgeId] = {};\n const displayKey = entry.componentPath ?? moduleId;\n entries[bridgeId][displayKey] = entry.data;\n }\n return { bridges, entries };\n }\n /**\n * The current reactive page state for a bridge: shallow-merge of `entry.data`\n * across every cache entry whose key starts with `${bridgeId}/`, in insertion\n * order (later entries win on key conflicts). `{}` when no entries match\n * (unknown bridge / after clearBridge). Pure, no side effects.\n */\n pageData(bridgeId) {\n const merged = {};\n for (const [key, entry] of this.cache) {\n const slash = key.indexOf('/');\n if (slash < 0)\n continue;\n if (key.slice(0, slash) !== bridgeId)\n continue;\n Object.assign(merged, entry.data);\n }\n return merged;\n }\n /** Flat `key \u2192 data` map for the `__simulatorData.getAppdata()` mirror. */\n flat() {\n const data = {};\n for (const [key, entry] of this.cache)\n data[key] = entry.data;\n return data;\n }\n clear() {\n this.cache.clear();\n this.bridgeOrder.length = 0;\n this.bridgePagePath.clear();\n }\n}\n", "import type { ElementInspection } from '../../shared/ipc-channels.js'\nimport { exposeOnMainWorld } from '../shared/expose.js'\nimport { getActivePageIframe } from '../shared/page-iframe.js'\nimport { findElementBySid, type WxmlNode } from '@dimina-kit/inspect'\n\n// Re-export so existing importers (wxml.ts, shared/types.ts, renderer panels)\n// keep their `from '../runtime/bridge.js'` path while the registry lives in the\n// dependency-free shared module.\nexport type { WxmlNode } from '@dimina-kit/inspect'\nexport { registerSyntheticSid } from '@dimina-kit/inspect'\n\nexport interface Snapshot<T> {\n gen: number\n ready: boolean\n data: T\n}\n\nexport interface StorageSnapshot extends Snapshot<Record<string, string>> {\n namespace: string | null\n}\n\ntype RefreshTarget = 'wxml' | 'appdata' | 'storage'\n\ninterface SimulatorBridgeState {\n appdata: Snapshot<Record<string, unknown>>\n storage: StorageSnapshot\n wxml: Snapshot<WxmlNode | WxmlNode[] | null>\n refreshHandler: ((type: RefreshTarget) => void) | null\n}\n\nconst state: SimulatorBridgeState = {\n appdata: { gen: 0, ready: true, data: {} },\n storage: { gen: 0, ready: false, namespace: null, data: {} },\n wxml: { gen: 0, ready: false, data: null },\n refreshHandler: null,\n}\n\nlet highlightOverlay: HTMLDivElement | null = null\nlet exposedApi: Record<string, unknown> | null = null\n\nfunction clone<T>(value: T): T {\n try {\n return JSON.parse(JSON.stringify(value)) as T\n } catch {\n return value\n }\n}\n\nfunction ensureOverlay(doc: Document): HTMLDivElement {\n if (highlightOverlay && highlightOverlay.ownerDocument === doc) return highlightOverlay\n highlightOverlay = doc.createElement('div')\n highlightOverlay.id = '__simulator-highlight'\n highlightOverlay.style.cssText =\n 'position:fixed;pointer-events:none;z-index:999999;' +\n 'border:2px solid #1a73e8;background:rgba(26,115,232,0.12);' +\n 'transition:all 0.1s ease;display:none;border-radius:2px;box-sizing:border-box;'\n doc.body.appendChild(highlightOverlay)\n return highlightOverlay\n}\n\nfunction highlightElement(sid: string): ElementInspection | null {\n if (!sid) return null\n const iframe = getActivePageIframe()\n if (!iframe?.contentDocument) return null\n const doc = iframe.contentDocument\n const el = findElementBySid(doc, sid)\n if (!el) return null\n const rect = el.getBoundingClientRect()\n const overlay = ensureOverlay(doc)\n overlay.style.left = `${rect.left}px`\n overlay.style.top = `${rect.top}px`\n overlay.style.width = `${rect.width}px`\n overlay.style.height = `${rect.height}px`\n overlay.style.display = 'block'\n const style = el.ownerDocument.defaultView?.getComputedStyle(el)\n if (!style) return null\n return {\n sid,\n rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },\n style: {\n display: style.display,\n position: style.position,\n boxSizing: style.boxSizing,\n margin: style.margin,\n padding: style.padding,\n color: style.color,\n backgroundColor: style.backgroundColor,\n fontSize: style.fontSize,\n },\n }\n}\n\nfunction unhighlightElement(): void {\n if (highlightOverlay) highlightOverlay.style.display = 'none'\n}\n\nexport { highlightElement, unhighlightElement }\n\nfunction buildApi(): Record<string, unknown> {\n return {\n getAppdata: () => clone(state.appdata.data),\n getAppdataSnapshot: () => clone(state.appdata),\n getAppdataGen: () => state.appdata.gen,\n getStorageSnapshot: () => clone(state.storage),\n getStorageGen: () => state.storage.gen,\n getWxml: () => clone(state.wxml.data),\n getWxmlSnapshot: () => clone(state.wxml),\n getWxmlGen: () => state.wxml.gen,\n refresh: (type: RefreshTarget) => state.refreshHandler?.(type),\n highlightElement,\n unhighlightElement,\n }\n}\n\nexport const simulatorBridge = state\n\nexport function setRefreshHandler(handler: ((type: RefreshTarget) => void) | null): void {\n state.refreshHandler = handler\n}\n\nexport function setAppDataSnapshot(data: Record<string, unknown>): void {\n state.appdata = {\n gen: state.appdata.gen + 1,\n ready: true,\n data: clone(data),\n }\n}\n\nexport function clearAppDataSnapshot(): void {\n state.appdata = {\n gen: state.appdata.gen + 1,\n ready: true,\n data: {},\n }\n}\n\nexport function setStorageSnapshot(namespace: string | null, data: Record<string, string>): void {\n state.storage = {\n gen: state.storage.gen + 1,\n ready: namespace !== null,\n namespace,\n data: clone(data),\n }\n}\n\nexport function clearStorageSnapshot(): void {\n state.storage = {\n gen: state.storage.gen + 1,\n ready: false,\n namespace: null,\n data: {},\n }\n}\n\nexport function setWxmlSnapshot(data: WxmlNode | WxmlNode[] | null, ready = true): void {\n state.wxml = {\n gen: state.wxml.gen + 1,\n ready,\n data: clone(data),\n }\n}\n\nexport function clearWxmlSnapshot(): void {\n state.wxml = {\n gen: state.wxml.gen + 1,\n ready: false,\n data: null,\n }\n}\n\nexport function resetBridgeState(): void {\n clearAppDataSnapshot()\n clearStorageSnapshot()\n clearWxmlSnapshot()\n unhighlightElement()\n state.refreshHandler = null\n}\n\nexport function installSimulatorBridge(): () => void {\n if (!exposedApi) {\n exposedApi = buildApi()\n }\n const dispose = exposeOnMainWorld('__simulatorData', exposedApi)\n return () => {\n resetBridgeState()\n dispose()\n }\n}\n", "import { ipcRenderer, type IpcRendererEvent } from 'electron'\nimport { SimulatorCustomApiBridgeChannel } from '../../shared/ipc-channels.js'\nimport { exposeOnMainWorld } from '../shared/expose.js'\n\nexport interface DiminaCustomApisBridge {\n list(): Promise<string[]>\n invoke(name: string, params: unknown): Promise<unknown>\n}\n\ntype BridgeRequest =\n | { id: number; op: 'list' }\n | { id: number; op: 'invoke'; name: string; params: unknown }\n\ntype BridgeResponse =\n | { id: number; result: unknown }\n | { id: number; error: string }\n\ninterface Pending {\n resolve: (value: unknown) => void\n reject: (reason: Error) => void\n}\n\n/**\n * Re-send interval and ceiling for `list()` (see `listWithRetry`).\n *\n * `ipcRenderer.send` is fire-and-forget \u2014 a request sent before the main-side\n * `ipcMain.on` listener is live (e.g. across a relaunch / re-attach cycle) is\n * lost, and the bridge call would otherwise hang until `custom-api-boot.ts`'s\n * 3s deadlock-breaker.\n *\n * `list` is an idempotent read, so it is safe to re-send until a response\n * arrives. The retry resolves quickly in practice; the ceiling only bounds the\n * leak if the listener never answers, and is kept below `custom-api-boot.ts`'s\n * `CUSTOM_API_LIST_TIMEOUT_MS` so the retry exhausts before \u2014 not after \u2014 that\n * outer timeout would fire.\n */\nconst LIST_RETRY_INTERVAL_MS = 150\nconst LIST_RETRY_CEILING_MS = 2500\n\n// native-host is the sole runtime: the simulator is a top-level\n// WebContentsView with no embedder to `sendToHost`, so it `ipcRenderer.send`s\n// the request straight to a `ctx.simulatorApis`-backed `ipcMain.on` listener\n// bound to this exact simWc (see view-manager `attachNativeCustomApiBridge`),\n// which posts the result back via `simWc.send`. Responses land on the\n// `ipcRenderer.on(Response)` handler and are correlated to requests by id, so\n// concurrent invokes do not tangle.\nfunction buildBridge(): DiminaCustomApisBridge {\n let nextId = 1\n const pending = new Map<number, Pending>()\n\n const sendRequest = (req: BridgeRequest): void => {\n ipcRenderer.send(SimulatorCustomApiBridgeChannel.Request, req)\n }\n\n ipcRenderer.on(SimulatorCustomApiBridgeChannel.Response, (_event: IpcRendererEvent, payload: BridgeResponse) => {\n const entry = pending.get(payload.id)\n if (!entry) return\n pending.delete(payload.id)\n if ('error' in payload) {\n entry.reject(new Error(payload.error))\n } else {\n entry.resolve(payload.result)\n }\n })\n\n const send = <T>(req: BridgeRequest): Promise<T> => {\n return new Promise<T>((resolve, reject) => {\n pending.set(req.id, {\n resolve: (value) => resolve(value as T),\n reject,\n })\n sendRequest(req)\n })\n }\n\n /**\n * `list()` with re-send, to survive the embedder proxy attaching after the\n * first request (see `LIST_RETRY_INTERVAL_MS`). Each attempt uses a fresh id\n * and its own `pending` entry; whichever response lands first settles the\n * call. Stale entries for the other attempts are dropped so a late duplicate\n * response cannot resolve nothing \u2014 or, worse, leak.\n */\n const listWithRetry = (): Promise<string[]> => {\n return new Promise<string[]>((resolve, reject) => {\n const attemptIds = new Set<number>()\n // Boxed so `cleanup` (defined before the timers are created) can clear\n // them; the box itself is `const`, only its fields are assigned later.\n const state: {\n settled: boolean\n retryTimer?: ReturnType<typeof setInterval>\n ceilingTimer?: ReturnType<typeof setTimeout>\n } = { settled: false }\n\n const cleanup = (): void => {\n state.settled = true\n if (state.retryTimer) clearInterval(state.retryTimer)\n if (state.ceilingTimer) clearTimeout(state.ceilingTimer)\n for (const id of attemptIds) pending.delete(id)\n attemptIds.clear()\n }\n\n const attempt = (): void => {\n if (state.settled) return\n const id = nextId++\n attemptIds.add(id)\n pending.set(id, {\n resolve: (value) => {\n if (state.settled) return\n cleanup()\n resolve(value as string[])\n },\n reject: (reason) => {\n if (state.settled) return\n cleanup()\n reject(reason)\n },\n })\n sendRequest({ id, op: 'list' })\n }\n\n state.retryTimer = setInterval(attempt, LIST_RETRY_INTERVAL_MS)\n state.ceilingTimer = setTimeout(() => {\n if (state.settled) return\n cleanup()\n reject(new Error('custom-apis bridge list() got no response from the host renderer'))\n }, LIST_RETRY_CEILING_MS)\n attempt()\n })\n }\n\n return {\n list: listWithRetry,\n invoke: (name, params) => send<unknown>({ id: nextId++, op: 'invoke', name, params }),\n }\n}\n\nexport function installCustomApisBridge(): () => void {\n const bridge = buildBridge()\n return exposeOnMainWorld('__diminaCustomApis', bridge)\n}\n", "/**\n * Centralised IPC channel name constants for dimina-devtools.\n *\n * Every raw channel string used across main, renderer, preload and e2e code\n * should reference one of these constants so that renaming a channel only\n * requires a single edit.\n */\n\n// \u2500\u2500 Simulator (preload \u2192 host / renderer \u2194 main) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const SimulatorChannel = {\n // Ask main to create the simulator as a top-level WebContentsView (so nested\n // render-host <webview>s can attach). Native-host is the sole runtime.\n AttachNative: 'simulator:attach-native',\n // Renderer pushes the selected device's LOGICAL metrics (screen size,\n // pixelRatio, statusBarHeight, \u2026) when the device dropdown changes. Main\n // maps it to a HostEnvSnapshot and live-updates the running service-host\n // window \u2014 the authoritative `wx.getSystemInfoSync()` source \u2014 so the\n // mini-app sees the selected device without a relaunch.\n SetDeviceInfo: 'simulator:set-device-info',\n // Ask main to soft-reload the LIVE simulator WCV after a watcher rebuild:\n // main forwards a SIMULATOR_EVENTS.RELAUNCH into the shell (which boots a\n // new app session and swaps when ready) instead of destroying the view.\n // Resolves false when there is no live+ready shell \u2014 the renderer then falls\n // back to the hard AttachNative rebuild.\n SoftReload: 'simulator:soft-reload',\n Detach: 'simulator:detach',\n Console: 'simulator:console',\n // Main \u2192 renderer push of the visible top-of-stack page route whenever the\n // mini-app navigates (navigateTo / switchTab / back). Payload: the page path\n // string (same bare format as `getCurrentPagePath`), or '' when unknown.\n CurrentPage: 'simulator:current-page',\n} as const\n\n/** iPhone bezel cutout family driving the device-shell notch visual. */\nexport type NotchType = 'none' | 'notch' | 'dynamic-island'\n\n/** Per-device safe-area insets in CSS px (portrait). */\nexport interface SafeAreaInsets {\n top: number\n right: number\n bottom: number\n left: number\n}\n\n/**\n * Logical device metrics pushed by the renderer device dropdown under\n * native-host (`SimulatorChannel.SetDeviceInfo`). Mirrors a row of the renderer\n * `DEVICES` table; main maps it onto a `HostEnvSnapshot` for the service-host\n * window so `wx.getSystemInfoSync()` reflects the selected device, relays it to\n * the simulator WCV (DeviceShell: bezel size + status bar + notch), and drives\n * the CSS `env(safe-area-inset-*)` override on render-host guests.\n */\nexport interface NativeDeviceInfo {\n brand: string\n model: string\n system: string\n platform: string\n pixelRatio: number\n screenWidth: number\n screenHeight: number\n statusBarHeight: number\n notchType: NotchType\n safeAreaInsets: SafeAreaInsets\n}\n\n// \u2500\u2500 Service host (main \u2192 hidden service-host window) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const ServiceHostChannel = {\n /**\n * NATIVE-HOST ONLY. Live-update the service-host window's host-env snapshot\n * (device metrics) so subsequent `wx.getSystemInfoSync()` reflects a device\n * change without a relaunch. The service-host preload mutates\n * `__diminaSpawnContext.hostEnvSnapshot` in place (see `service-host/preload.cjs`).\n */\n HostEnvUpdate: 'service-host:host-env:update',\n /**\n * NATIVE-HOST ONLY. Deliver an AppData-panel edit (`{bridgeId, data}`) into\n * the service-host window. The preload resolves the page instance via\n * `getCurrentPages()` and calls `page.setData(data)`, so the resulting `ub`\n * publish flows back through the normal service\u2192render tap \u2014 the panel\n * refreshes from the runtime's own state, not an optimistic local echo.\n */\n AppDataSetData: 'service-host:appdata:set-data',\n} as const\n\n// \u2500\u2500 Custom simulator APIs (downstream-registered, main-process handlers) \u2500\u2500\n// invoke: forwards an API call to the registry; result/reject propagates.\n//\n// This is an ipcMain.handle channel invoked by the **main-window renderer**\n// only (trusted host). The simulator guest never reaches it directly \u2014 it\n// reaches the host via the bridge channels below, so the sender-policy can keep\n// the simulator off the IPC white-list.\nexport const SimulatorCustomApiChannel = {\n Invoke: 'simulator:custom-apis:invoke',\n} as const\n\n// \u2500\u2500 Custom APIs bridge (simulator \u2192 host) \u2500\u2500\n// payload = { id, op: 'list' } | { id, op: 'invoke', name, params } for Request,\n// { id, result } | { id, error } for Response. Transport (in\n// `src/preload/runtime/custom-apis.ts`): native-host \u2014 the simulator is a\n// top-level WebContentsView (no embedder), so Request goes via\n// `ipcRenderer.send` \u2192 `ipcMain.on` dispatcher bound to that simWc (view-manager\n// `attachNativeCustomApiBridge`) \u2192 Response via `simWc.send`. (The old\n// renderer-proxied `<webview>` transport, `ipcRenderer.sendToHost` \u2192\n// `<webview>.send`, no longer exists \u2014 native-host is the sole runtime.)\n//\n// Request/response are correlated by `id` so multiple concurrent invokes can\n// be in flight at once.\nexport const SimulatorCustomApiBridgeChannel = {\n Request: 'simulator:custom-apis:bridge-request',\n Response: 'simulator:custom-apis:bridge-response',\n} as const\n\n// \u2500\u2500 Storage (CDP-backed; main process attaches the debugger to the\n// simulator guest and forwards DOMStorage events to the renderer) \u2500\u2500\nexport const SimulatorStorageChannel = {\n GetSnapshot: 'simulator:storage:snapshot',\n GetActivePrefix: 'simulator:storage:activePrefix',\n Set: 'simulator:storage:set',\n Remove: 'simulator:storage:remove',\n Clear: 'simulator:storage:clear',\n ClearAll: 'simulator:storage:clearAll',\n Event: 'simulator:storage:event',\n} as const\n\n// The storage wire-format shapes are owned by the shared inspect package\n// (any host's transport carries the same StorageItem/StorageEvent/\n// StorageWriteResult); this channel file re-exports them so IPC consumers\n// keep a single import point.\nexport type { StorageEvent, StorageItem, StorageWriteResult } from '@dimina-kit/inspect'\n\n/**\n * A storage mutation reported by the service-host's SYNC wx storage APIs\n * (`setStorageSync`/`removeStorageSync`/`clearStorageSync`). Those run inside the\n * service-host window and write `localStorage` directly, so \u2014 unlike the async\n * path (`runtimeInvoke`) and the panel's own writes \u2014 they never pass through\n * main and would otherwise leave the Storage panel stale until a manual reload.\n * The service-host posts this over `DiminaServiceBridge` as a `storageChanged`\n * container message; bridge-router hands it to `onServiceStorageChanged`, which\n * pushes the matching `StorageEvent` to the panel. `key` carries the full\n * `${appId}_` prefix (same wire shape as the CDP / async paths).\n */\nexport type SyncStorageChange =\n | { op: 'set'; key: string; value: string }\n | { op: 'remove'; key: string }\n | { op: 'clear' }\n\n// \u2500\u2500 Element inspection (CDP-backed; WXML tree nodes map to real DOM by sid) \u2500\u2500\nexport const SimulatorElementChannel = {\n Inspect: 'simulator:element:inspect',\n Clear: 'simulator:element:clear',\n} as const\n\n// \u2500\u2500 WXML tree (native-host: main pulls the tree from the active render-host\n// <webview> guest via render-inspect, and pushes/answers here \u2014 mirroring the\n// Storage panel's main\u2192renderer contract so the renderer panel is unchanged) \u2500\u2500\nexport const SimulatorWxmlChannel = {\n GetSnapshot: 'simulator:wxml:snapshot',\n Event: 'simulator:wxml:event',\n // renderer\u2192main: whether the WXML panel is currently visible/active. Main\n // only installs the render-guest DOM MutationObserver + pushes live tree\n // updates while active, so an unseen panel never drives a full Vue-tree walk.\n SetActive: 'simulator:wxml:setActive',\n} as const\n\n// \u2500\u2500 AppData (native-host: main taps the service\u2192render setData stream in\n// bridge-router and pushes the cumulative snapshot here \u2014 the service logic runs\n// in the hidden service-host window, not a Worker in the simulator guest) \u2500\u2500\nexport const SimulatorAppDataChannel = {\n GetSnapshot: 'simulator:appdata:snapshot',\n Event: 'simulator:appdata:event',\n // renderer \u2192 main invoke: write an AppData-panel edit back into the running\n // page (forwarded to the service host via ServiceHostChannel.AppDataSetData).\n SetData: 'simulator:appdata:set-data',\n} as const\n\n// The element-inspection payload shape is owned by the shared inspect\n// package (it is produced inside render-layer documents by any host); this\n// channel file re-exports it so IPC consumers keep a single import point.\nexport type { ElementInspection } from '@dimina-kit/inspect'\n\n// \u2500\u2500 Workbench settings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const WorkbenchSettingsChannel = {\n Get: 'workbenchSettings:get',\n Save: 'workbenchSettings:save',\n SetTheme: 'workbenchSettings:setTheme',\n GetCdpStatus: 'workbenchSettings:getCdpStatus',\n GetMcpStatus: 'workbenchSettings:getMcpStatus',\n Init: 'workbenchSettings:init',\n // Main \u2192 renderer push: the active color scheme flipped (OS change or in-app\n // SetTheme). Payload is `isDark: boolean`. The app's CSS reacts to\n // `prefers-color-scheme` automatically; this exists for the few JS consumers\n // (Monaco's theme) that can't observe that media change \u2014 Electron does NOT\n // dispatch the renderer's `matchMedia('(prefers-color-scheme)')` change event\n // for programmatic `nativeTheme.themeSource` assignments.\n ThemeChanged: 'workbenchSettings:themeChanged',\n} as const\n\n// \u2500\u2500 Project session \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const ProjectChannel = {\n Open: 'project:open',\n Close: 'project:close',\n GetPages: 'project:getPages',\n GetCompileConfig: 'project:getCompileConfig',\n SaveCompileConfig: 'project:saveCompileConfig',\n Status: 'project:status',\n // Main \u2192 renderer push of per-line dmcc compile logs (devkit `onLog`).\n // Dedicated channel: `project:status` keeps its one-event-per-payload\n // contract (compileEvents), this one carries the line stream (compileLogs).\n CompileLog: 'project:compileLog',\n CaptureThumbnail: 'project:captureThumbnail',\n GetThumbnail: 'project:getThumbnail',\n} as const\n\n// \u2500\u2500 Session runtime status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Main \u2192 renderer push of the post-compile SESSION lifecycle (spawn \u2192 running\n// \u2192 crash/timeout), distinct from `ProjectChannel.Status` which only tracks\n// compile outcomes. Compile succeeding tells the renderer nothing about\n// whether the simulator actually booted \u2014 this channel closes that gap.\n\nexport const SessionChannel = {\n RuntimeStatus: 'session:runtimeStatus',\n} as const\n\n// \u2500\u2500 Project file system (sandboxed to active project root) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Read/write access to the active project's files, used by the in-renderer\n// Monaco editor. Every path is verified against the active project root in\n// the main process (see `services/project-fs`). Replaces the OpenSumi\n// editor's `editor:fs:*` bridge \u2014 same sandbox, callable from the main\n// renderer instead of a separate WebContentsView.\n\nexport const ProjectFsChannel = {\n GetRoot: 'project:fs:getRoot',\n ReadFile: 'project:fs:readFile',\n WriteFile: 'project:fs:writeFile',\n /**\n * Synchronous (blocking) write, used ONLY by the editor's `beforeunload`\n * flush: a hard window/app close tears the renderer down before an async\n * `WriteFile` IPC can round-trip, so the last in-debounce-window edit would\n * be lost. `sendSync` blocks page teardown until the bytes hit disk. Runs the\n * SAME sandbox as `WriteFile` (see project-fs `writeFileSync`).\n */\n WriteFileSync: 'project:fs:writeFileSync',\n ListFiles: 'project:fs:listFiles',\n} as const\n\n// \u2500\u2500 Editor (main \u2192 renderer) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Drives the in-renderer Monaco editor from the main process. Used by the\n// \"click a console file link \u2192 open the file at line:col\" pipeline: the\n// embedded DevTools front-end routes a source-link click through an open-\n// resource handler \u2192 Electron `devtools-open-url` on the service host \u2192 main\n// maps the resource URL to a project-relative path \u2192 this event opens it in\n// Monaco. Payload: `EditorOpenFilePayload`.\n\nexport const EditorChannel = {\n /** main \u2192 renderer: open `path` (project-relative POSIX) at `line`/`column`. */\n OpenFile: 'editor:openFile',\n} as const\n\n/** Payload for `editor:openFile`. `line`/`column` are 1-based for Monaco. */\nexport interface EditorOpenFilePayload {\n /** Project-relative POSIX path (the same key Monaco opens files by). */\n path: string\n /** 1-based line to reveal; omitted/<=0 means open without moving the cursor. */\n line?: number\n /** 1-based column to reveal; defaults to 1 when a line is given. */\n column?: number\n}\n\n// \u2500\u2500 Project list / workspace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const ProjectsChannel = {\n List: 'projects:list',\n Add: 'projects:add',\n Remove: 'projects:remove',\n /** Merged + sanitized template catalog for the create-project dialog. */\n ListTemplates: 'projects:listTemplates',\n /** Host-supplied create-project dialog hook (returns input or null). */\n OpenCreateDialog: 'projects:openCreateDialog',\n /** Server-side scaffold + register (delegates to create-project-service). */\n Create: 'projects:create',\n /** Default values used to pre-fill the create-project dialog (baseDir). */\n GetCreateDefaults: 'projects:getCreateDefaults',\n} as const\n\n/** Renderer-facing payload for `projects:getCreateDefaults`. */\nexport interface ProjectCreateDefaults {\n /** Absolute directory used as the parent for new projects. */\n baseDir: string\n}\n\n// \u2500\u2500 Dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const DialogChannel = {\n OpenDirectory: 'dialog:openDirectory',\n} as const\n\n// \u2500\u2500 Embedded views (renderer \u2192 main) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// The main window's React layout owns the *positions* of the editor +\n// simulator-DevTools WebContentsView overlays \u2014 each visible placeholder\n// `<div>` measures its client rect via ResizeObserver and pushes the\n// rectangle to the main process. The view manager caches the latest\n// payload per kind and applies it to the overlay; no payload means the\n// overlay is hidden.\n//\n// Payload (after schema validation): `{ x, y, width, height }` in CSS\n// pixels relative to the window's content area (origin = top-left,\n// not including the OS chrome).\nexport const ViewChannel = {\n /**\n * Reverse size-advertiser: the host-toolbar WCV's OWN renderer advertises its\n * intrinsic content height so main reserves exactly that much. Payload\n * `{ axis: 'block', extent }`. fire-and-forget (send), NOT invoke.\n */\n HostToolbarAdvertiseHeight: 'view:host-toolbar:advertise-height',\n /**\n * main \u2192 host-toolbar WCV renderer: per-load MessagePort handshake for the\n * gated narrow channel. On every toolbar `did-finish-load` main creates a\n * `MessageChannelMain` and transfers port2 here\n * (`wc.postMessage(HostToolbarPort, null, [port2])`); the session-resident\n * toolbar runtime preload receives it via `event.ports[0]` and bridges it to\n * the page as `window.diminaHostToolbar`. Envelope both directions:\n * `{ channel: string, payload: unknown }`.\n */\n HostToolbarPort: 'view:host-toolbar:port',\n /**\n * main \u2192 main-window renderer: push the reserved host-toolbar height so the\n * renderer placeholder div resizes (closing the dynamic-height loop).\n */\n HostToolbarHeightChanged: 'view:host-toolbar:height-changed',\n /**\n * main \u2190 main-window renderer (invoke): pull the last NOTIFIED toolbar\n * height retained in main. Mount-time replay companion to\n * `HostToolbarHeightChanged`: the push listener mounts with the project\n * view and the toolbar's size-advertiser deduplicates (never re-reports),\n * so a height pushed while no project view was mounted would otherwise be\n * lost forever (cold start on the project list races it; close-project \u2192\n * reopen hits it deterministically). No payload; resolves a number.\n */\n HostToolbarGetHeight: 'view:host-toolbar:get-height',\n /**\n * Renderer \u2192 main: the window-level placement snapshot (one monotonic epoch\n * per commit tick, one generation per renderer lifetime) that drives the view\n * reconciler. The single source of truth for every managed native view's\n * bounds/visibility/z-order \u2014 supersedes the per-view bounds channels above.\n * invoke.\n */\n PlacementSnapshot: 'view:placement-snapshot',\n} as const\n\nexport interface ViewBounds {\n x: number\n y: number\n width: number\n height: number\n}\n\n// \u2500\u2500 Popover \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const PopoverChannel = {\n Show: 'popover:show',\n Hide: 'popover:hide',\n Relaunch: 'popover:relaunch',\n Closed: 'popover:closed',\n Init: 'popover:init',\n} as const\n\n// \u2500\u2500 Window \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const WindowChannel = {\n NavigateBack: 'window:navigateBack',\n // Renderer \u2192 main: the renderer's current top-level screen ('project' when\n // inside a project screen, 'list' on the project list / landing). The\n // renderer pushes this on every screen change, including the moment it enters\n // a project \u2014 BEFORE the open resolves \u2014 so a FAILED open (no session) still\n // leaves main's mirror = 'project'. The window-close decision reads it so\n // closing a stuck/failed project returns to the list instead of quitting.\n ScreenState: 'window:screenState',\n} as const\n\n// \u2500\u2500 App \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const AppChannel = {\n GetBranding: 'app:getBranding',\n} as const\n\n// \u2500\u2500 miniappSnapshot (unified panel snapshot framework) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Two generic channels shared by every snapshot source (AppData, WXML, \u2026).\n// Adding a new panel needs no new channel.\n// Push: preload \u2192 renderer (`sendToHost`), payload: SnapshotEnvelope\n// Pull: renderer \u2192 preload (`webview.send`), payload: { id }\n\nexport const MiniappSnapshotChannel = {\n Push: 'miniapp-snapshot:push',\n Pull: 'miniapp-snapshot:pull',\n} as const\n\n// \u2500\u2500 Automation (WebSocket server) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const AutomationChannel = {\n GetPort: 'automation:port',\n} as const\n\n// \u2500\u2500 Embedded settings overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const SettingsChannel = {\n SetVisible: 'settings:setVisible',\n ConfigChanged: 'settings:configChanged',\n ProjectSettingsChanged: 'settings:projectSettingsChanged',\n Init: 'settings:init',\n} as const\n\n// \u2500\u2500 Updates (UpdateManager) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// String values are FROZEN: shipped builds key off them. Add new entries\n// here, never rename existing ones.\nexport const UpdateChannel = {\n Check: 'updates:check',\n Download: 'updates:download',\n Install: 'updates:install',\n DownloadProgress: 'updates:downloadProgress',\n Available: 'updates:available',\n} as const\n", "/**\n * Preload-side bridge that mirrors the simulator's renderer-side temp-file\n * registry into the main-process store via IPC. The main process serves the\n * resulting `difile://devtools/{uuid}` URLs over a protocol handler bound to\n * the simulator session.\n */\n\nimport { ipcRenderer } from 'electron'\nimport { setTempFileSink } from '../../simulator/temp-files.js'\n\nexport function installTempFileBridge(): void {\n\tsetTempFileSink({\n\t\twrite(path, blob) {\n\t\t\tblob\n\t\t\t\t.arrayBuffer()\n\t\t\t\t.then((bytes) => {\n\t\t\t\t\tipcRenderer.send('simulator:temp-file:write', {\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tmime: blob.type,\n\t\t\t\t\t\tbytes,\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t\t.catch(() => {\n\t\t\t\t\t// best effort: blob read failures cannot be surfaced through the\n\t\t\t\t\t// sink contract (`write` is sync void), so we swallow them.\n\t\t\t\t})\n\t\t},\n\t\trevoke(path) {\n\t\t\tipcRenderer.send('simulator:temp-file:revoke', { path })\n\t\t},\n\t\trevokeAll() {\n\t\t\tipcRenderer.send('simulator:temp-file:revoke-all')\n\t\t},\n\t})\n}\n", "/**\n * Devtools simulator temp-file registry.\n *\n * The simulator hands `chooseImage` / `chooseMedia` / `chooseVideo` /\n * `compressImage` etc. results back to mini-program code as paths. Historically\n * those paths were `blob:` URLs allocated via `URL.createObjectURL`, but the\n * blob: scheme is local-to-the-renderer and cannot be served back into the\n * webview's `persist:simulator` session through a `protocol.handle`. We switched\n * to a custom `difile://_tmp/{uuid}` scheme so the main process can\n * register a single `difile://` protocol handler and stream the bytes for any\n * path, regardless of which renderer originally produced it.\n *\n * To keep the renderer-side cache and the main-process byte store in sync,\n * `setTempFileSink` lets the preload bridge inject a sink that mirrors every\n * `write` / `revoke` / `revokeAll` over IPC. Tests inject a stub sink.\n */\n\nexport interface TempFileSink {\n\twrite(path: string, blob: Blob): void\n\trevoke(path: string): void\n\trevokeAll(): void\n}\n\nconst tempFiles = new Map<string, Blob>()\nlet activeSink: TempFileSink | null = null\n\nexport function setTempFileSink(sink: TempFileSink | null): void {\n\tactiveSink = sink\n}\n\nfunction cryptoRandomId(): string {\n\tconst c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n\tif (c && typeof c.randomUUID === 'function') return c.randomUUID()\n\treturn `${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nexport function createTempFilePath(blob: Blob): string {\n\tconst path = `difile://_tmp/${cryptoRandomId()}`\n\ttempFiles.set(path, blob)\n\tactiveSink?.write(path, blob)\n\treturn path\n}\n\nexport function registerTempFilePath(path: string, blob: Blob): void {\n\ttempFiles.set(path, blob)\n\tactiveSink?.write(path, blob)\n}\n\nexport function revokeTempFilePath(path: string): void {\n\ttempFiles.delete(path)\n\tactiveSink?.revoke(path)\n}\n\nexport function revokeAllTempFilePaths(): void {\n\ttempFiles.clear()\n\tactiveSink?.revokeAll()\n}\n\nexport async function resolveTempFilePath(path: string): Promise<Blob> {\n\tconst cached = tempFiles.get(path)\n\tif (cached) return cached\n\n\tconst response = await fetch(path)\n\tif (!response.ok) {\n\t\tthrow new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${path}`)\n\t}\n\tconst blob = await response.blob()\n\t// Cache the freshly fetched blob in-memory so subsequent reads are local.\n\t// We bypass `registerTempFilePath` deliberately: this is a renderer-only\n\t// cache fill, the main-process store already has the bytes (otherwise the\n\t// fetch would not have returned them), so triggering sink.write would\n\t// produce a redundant IPC.\n\ttempFiles.set(path, blob)\n\treturn blob\n}\n\nexport function getTempFileName(path: string, blob: Blob, fallback = 'file'): string {\n\tconst named = blob as Blob & { name?: unknown }\n\tif (typeof named.name === 'string' && named.name.trim()) {\n\t\treturn named.name\n\t}\n\n\ttry {\n\t\tconst url = new URL(path, window.location.href)\n\t\tconst segment = url.pathname.split('/').filter(Boolean).pop()\n\t\tif (segment) return decodeURIComponent(segment)\n\t} catch {\n\t\t// Fall through to the caller-provided fallback.\n\t}\n\n\treturn fallback\n}\n", "import { ipcRenderer, type IpcRendererEvent } from 'electron'\n\nexport function sendToHost(channel: string, data: unknown): void {\n ipcRenderer.sendToHost(channel, data)\n}\n\nexport function onHostMessage(\n channel: string,\n handler: (...args: unknown[]) => void,\n): () => void {\n let active = true\n const wrapped = (_event: IpcRendererEvent, ...args: unknown[]) => {\n if (!active) return\n handler(...args)\n }\n ipcRenderer.on(channel, wrapped)\n return () => {\n active = false\n ipcRenderer.removeListener(channel, wrapped)\n }\n}\n\nexport function safeSerialize(val: unknown): unknown {\n if (val === null || val === undefined) return val\n if (typeof val === 'function') return `[Function: ${(val as { name?: string }).name || 'anonymous'}]`\n if (typeof val !== 'object') return val\n if (val instanceof Error) return { __isError: true, message: val.message, stack: val.stack }\n try {\n return structuredClone(val)\n } catch {\n // expected: some objects (e.g. DOM nodes, proxies) cannot be structuredCloned\n }\n try {\n return JSON.parse(JSON.stringify(val))\n } catch {\n // expected: circular references or non-serializable values\n }\n return String(val)\n}\n", "import { SimulatorChannel } from '../../shared/ipc-channels.js'\nimport { sendToHost, safeSerialize } from '../runtime/host.js'\n\ntype ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug'\n\nexport function installConsoleInstrumentation(): () => void {\n const consoleRef = console as unknown as Record<string, (...args: unknown[]) => void>\n const originals = new Map<ConsoleLevel, (...args: unknown[]) => void>()\n const levels: ConsoleLevel[] = ['log', 'warn', 'error', 'info', 'debug']\n\n for (const level of levels) {\n const original = consoleRef[level]?.bind(console)\n if (!original) continue\n originals.set(level, original)\n consoleRef[level] = (...args: unknown[]) => {\n original(...args)\n sendToHost(SimulatorChannel.Console, {\n source: 'container',\n level,\n args: args.map(safeSerialize),\n ts: Date.now(),\n })\n }\n }\n\n const handleError = (event: ErrorEvent) => {\n sendToHost(SimulatorChannel.Console, {\n source: 'container',\n level: 'error',\n args: [{\n message: event.message,\n source: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n stack: event.error?.stack,\n }],\n ts: Date.now(),\n })\n }\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n sendToHost(SimulatorChannel.Console, {\n source: 'container',\n level: 'error',\n args: [{ message: 'Unhandled Promise Rejection', reason: String(event.reason) }],\n ts: Date.now(),\n })\n }\n\n window.addEventListener('error', handleError)\n window.addEventListener('unhandledrejection', handleRejection)\n\n return () => {\n for (const [level, original] of originals) {\n consoleRef[level] = original\n }\n window.removeEventListener('error', handleError)\n window.removeEventListener('unhandledrejection', handleRejection)\n }\n}\n", "import {\n clearAppDataSnapshot,\n setAppDataSnapshot,\n} from '../runtime/bridge.js'\nimport type { MiniappSnapshotSource } from '../miniapp-snapshot/types.js'\nimport {\n AppDataAccumulator,\n decodeOutgoingMessage,\n decodeWorkerMessage,\n type AppDataInput,\n type AppDataSnapshot,\n} from '@dimina-kit/inspect'\n\n// Window augmentation is in ../types.ts\n\n// Re-exported so existing importers (use-panel-data, types) keep their\n// `from '.../app-data'` path while the cumulative logic lives in the shared,\n// framework-agnostic accumulator reused by the native-host main service.\nexport type { AppDataSnapshot } from '@dimina-kit/inspect'\n\n/**\n * The AppData snapshot data source.\n *\n * Under native-host (the sole runtime) this is registered in the simulator top\n * frame purely for its `start()` side effects \u2014 it installs\n * `window.__simulatorHook.appData` and mirrors the flat cache into the\n * `window.__simulatorData.getAppdata()` automation surface still read by\n * automation `getData` (handlers/page.ts), the MCP context overview\n * (mcp/tools/context-tools.ts) and the e2e automator. Its iframe/Worker-based\n * snapshot publishing is inert there (no mini-app Worker runs in the top frame).\n *\n * Instruments `window.Worker` (incoming `message` decoding + outgoing\n * `postMessage` interception) and installs `window.__simulatorHook.appData`,\n * feeding the shared `AppDataAccumulator`. Every accepted mutation \u2014 an\n * `ub`/`page_*` worker message, or a `pageUnload` evicting a bridge \u2014 calls\n * `emit()` so the `miniappSnapshot` host republishes. The source itself never\n * touches IPC: the host owns push, pull and the install-time publish.\n *\n * It keeps the `__simulatorData.getAppdata()` automation surface working by\n * mirroring the flat cache into the simulator bridge via `setAppDataSnapshot`\n * / `clearAppDataSnapshot`.\n *\n * Under native-host this source is replaced by the main-process\n * simulator-appdata service, which feeds the SAME accumulator from the\n * service\u2192render message stream \u2014 see shared/appdata-accumulator.ts.\n */\nexport function createAppDataSource(): MiniappSnapshotSource<AppDataSnapshot> {\n const accumulator = new AppDataAccumulator()\n\n let emit: (() => void) | null = null\n let installed = false\n let originalHook: Window['__simulatorHook']\n let originalDescriptor: PropertyDescriptor | undefined\n let OriginalWorker: typeof Worker | undefined\n\n // Mirror the flat cache into the `__simulatorData.getAppdata()` automation\n // surface so MCP / e2e reads keep working after the snapshot migration.\n function publishSnapshot(): void {\n setAppDataSnapshot(accumulator.flat())\n }\n\n function clearBridge(bridgeId: string): void {\n accumulator.clearBridge(bridgeId)\n publishSnapshot()\n // The eviction is a cache mutation \u2014 notify the host so the renderer can\n // drop the evicted bridge's tab immediately.\n emit?.()\n }\n\n function applyAppData(body: unknown): void {\n if (!accumulator.apply(body as AppDataInput)) return\n publishSnapshot()\n emit?.()\n }\n\n function instrumentPostMessage(worker: Worker): void {\n const orig = worker.postMessage.bind(worker) as (msg: unknown, ...rest: unknown[]) => void\n worker.postMessage = function (msg: unknown, ...rest: unknown[]) {\n const decoded = decodeOutgoingMessage(msg)\n if (decoded?.type === 'pageUnload' && decoded.bridgeId) {\n clearBridge(decoded.bridgeId)\n }\n return orig(msg, ...rest)\n } as Worker['postMessage']\n }\n\n function createInstrumentedWorker(Original: typeof Worker): typeof Worker {\n function InstrumentedWorker(\n this: unknown,\n scriptURL: string | URL,\n options?: WorkerOptions\n ): Worker {\n const resolvedScriptURL = scriptURL instanceof URL\n ? scriptURL\n : new URL(scriptURL, window.location.href)\n const worker = Reflect.construct(\n Original,\n [resolvedScriptURL, options],\n new.target ?? InstrumentedWorker\n ) as Worker\n\n instrumentPostMessage(worker)\n\n worker.addEventListener('message', (event: MessageEvent) => {\n const entries = decodeWorkerMessage(event.data)\n if (!entries) return\n for (const entry of entries) {\n const hookBody: AppDataInput = {\n bridgeId: entry.bridgeId,\n moduleId: entry.moduleId,\n data: entry.data,\n mode: entry.mode,\n }\n if (entry.mode === 'init') hookBody.componentPath = entry.componentPath\n window.__simulatorHook?.appData(hookBody)\n }\n })\n\n return worker\n }\n\n Object.setPrototypeOf(InstrumentedWorker, Original)\n Object.defineProperty(InstrumentedWorker, 'prototype', {\n value: Original.prototype,\n })\n\n return InstrumentedWorker as unknown as typeof Worker\n }\n\n return {\n id: 'appdata',\n snapshot: () => accumulator.snapshot(),\n start(onChange) {\n if (installed) return\n installed = true\n emit = onChange\n originalHook = window.__simulatorHook\n originalDescriptor = Object.getOwnPropertyDescriptor(window, 'Worker')\n OriginalWorker = window.Worker\n\n window.__simulatorHook = {\n appData: (body: unknown) => applyAppData(body),\n }\n\n Object.defineProperty(window, 'Worker', {\n configurable: true,\n writable: true,\n value: createInstrumentedWorker(OriginalWorker),\n })\n },\n dispose() {\n if (!installed) return\n installed = false\n if (originalDescriptor) {\n Object.defineProperty(window, 'Worker', originalDescriptor)\n } else if (OriginalWorker) {\n window.Worker = OriginalWorker\n }\n if (originalHook) {\n window.__simulatorHook = originalHook\n } else {\n delete window.__simulatorHook\n }\n originalDescriptor = undefined\n OriginalWorker = undefined\n originalHook = undefined\n accumulator.clear()\n clearAppDataSnapshot()\n emit = null\n },\n }\n}\n", "/**\n * Single authoritative implementation of wx.request network semantics, shared\n * by every request surface (simulator `directRequest`, preload api-compat\n * `wx.request` shim). Keeping the semantics in one module is what prevents the\n * surfaces from drifting apart on the core contract.\n *\n * The contract (official wx.request semantics):\n * - success vs fail is decided ONLY by whether a server response was\n * received. Any HTTP response \u2014 200, 401, 500 \u2014 resolves via `success`\n * with `{ data, statusCode, header, errMsg: 'request:ok' }`; callers\n * branch on `statusCode` (e.g. 401 \u2192 re-login).\n * - `fail` fires only for network-layer failures and always carries a\n * non-empty errMsg: 'request:fail timeout' (deadline hit),\n * 'request:fail abort' (caller aborted), 'request:fail <reason>' (DNS/\n * connection/protocol errors).\n * - `timeout` defaults to 60000ms (the wx default) when omitted or\n * non-positive \u2014 a request never hangs indefinitely.\n * - `dataType` (default 'json') controls body decoding: 'json' attempts\n * JSON.parse with raw-text fallback; anything else keeps raw text.\n * `responseType: 'arraybuffer'` (or the legacy `dataType: 'arraybuffer'`\n * spelling) yields an ArrayBuffer instead.\n * - Outgoing headers merge case-insensitively via `Headers` so a caller's\n * `content-type` in any casing wins exactly once; the `application/json`\n * default applies only when the caller supplied none. Plain-object merges\n * would keep both casings as distinct keys and comma-join them on the wire.\n * - GET/HEAD serialize object `data` into URL query params (no body);\n * other methods send string data verbatim, form-encode objects under\n * application/x-www-form-urlencoded, and JSON-encode otherwise.\n * - `complete` fires exactly once, after success or fail, with that same\n * result object.\n *\n * Not provided: `cookies` on the success result \u2014 fetch() cannot read\n * Set-Cookie response headers, so surfacing a fabricated list would lie.\n */\n\nexport interface RequestSuccessResult {\n data: unknown\n statusCode: number\n header: Record<string, string>\n errMsg: 'request:ok'\n}\n\nexport interface RequestFailResult {\n errMsg: string\n errno?: number\n}\n\nexport interface RequestHandle {\n abort(): void\n}\n\nexport interface RequestCoreOptions {\n url: string\n data?: unknown\n header?: Record<string, string>\n timeout?: number\n method?: string\n dataType?: string\n responseType?: string\n}\n\nexport interface RequestCoreCallbacks {\n success?: (res: RequestSuccessResult) => void\n fail?: (err: RequestFailResult) => void\n complete?: (res: RequestSuccessResult | RequestFailResult) => void\n}\n\n/**\n * The wx.request default timeout budget. Exported as the single source of\n * truth for every layer that reasons about a request's time budget \u2014 the\n * bridge-router watchdog (apiCallWatchdogMs in simulator-api-metadata.ts)\n * derives its window from this so the two cannot drift apart.\n */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n\n/**\n * Largest delay setTimeout honours (2^31-1 ms). Anything above overflows the\n * signed-32-bit timer register and fires ~immediately (~1ms) instead of late \u2014\n * so an oversized caller timeout must be rejected, never passed through.\n */\nexport const MAX_TIMEOUT_MS = 2_147_483_647\n\n/**\n * Resolve a caller-supplied wx timeout into a usable budget: a finite positive\n * number within setTimeout's range is honoured; anything else (absent, 0,\n * negative, NaN, Infinity, overflowing) falls back to the wx default. Shared\n * by performRequest and the bridge-router watchdog (apiCallWatchdogMs) so the\n * two layers can never disagree on what a valid timeout is.\n */\nexport function resolveTimeoutBudgetMs(timeout: unknown): number {\n const t = Number(timeout)\n return Number.isFinite(t) && t > 0 && t <= MAX_TIMEOUT_MS ? t : DEFAULT_REQUEST_TIMEOUT_MS\n}\n\nfunction buildHeaders(header: Record<string, string> | undefined): Headers {\n const headers = new Headers()\n for (const [key, value] of Object.entries(header ?? {})) {\n if (value != null) headers.set(key, String(value))\n }\n if (!headers.has('content-type')) headers.set('content-type', 'application/json')\n return headers\n}\n\nfunction appendQueryParams(url: string, data: Record<string, unknown>): string {\n // Resolve against the current document when available so page-relative URLs\n // keep working in the render-window shim.\n const base = typeof location !== 'undefined' ? location.href : undefined\n const resolved = new URL(url, base)\n for (const [key, value] of Object.entries(data)) {\n resolved.searchParams.append(key, String(value))\n }\n return resolved.toString()\n}\n\nfunction encodeBody(data: unknown, contentType: string): BodyInit {\n if (typeof data === 'string') return data\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const form = new URLSearchParams()\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n form.append(key, String(value))\n }\n return form.toString()\n }\n return JSON.stringify(data)\n}\n\nasync function decodeResponseData(\n response: Response,\n dataType: string,\n responseType: string,\n): Promise<unknown> {\n if (responseType === 'arraybuffer' || dataType === 'arraybuffer') {\n return response.arrayBuffer()\n }\n const text = await response.text()\n if (dataType !== 'json') return text\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n\nexport function performRequest(\n opts: RequestCoreOptions,\n callbacks: RequestCoreCallbacks,\n): RequestHandle {\n const method = (opts.method || 'GET').toUpperCase()\n const canHaveBody = method !== 'GET' && method !== 'HEAD'\n const headers = buildHeaders(opts.header)\n\n let url = opts.url\n const init: RequestInit = { method, headers }\n\n if (!canHaveBody) {\n if (opts.data && typeof opts.data === 'object') {\n url = appendQueryParams(url, opts.data as Record<string, unknown>)\n }\n } else if (opts.data != null) {\n init.body = encodeBody(opts.data, headers.get('content-type') ?? '')\n }\n\n const controller = new AbortController()\n init.signal = controller.signal\n\n // First verdict wins: a timeout/abort settles the call even though the fetch\n // promise is still pending, and the fetch's own late resolution/AbortError\n // rejection must not fire a second callback round.\n let settled = false\n\n function settleSuccess(res: RequestSuccessResult): void {\n if (settled) return\n settled = true\n clearTimeout(timer)\n callbacks.success?.(res)\n callbacks.complete?.(res)\n }\n\n function settleFail(err: RequestFailResult): void {\n if (settled) return\n settled = true\n clearTimeout(timer)\n callbacks.fail?.(err)\n callbacks.complete?.(err)\n }\n\n const timeoutMs = resolveTimeoutBudgetMs(opts.timeout)\n const timer = setTimeout(() => {\n settleFail({ errMsg: 'request:fail timeout' })\n controller.abort()\n }, timeoutMs)\n\n const dataType = opts.dataType ?? 'json'\n const responseType = opts.responseType ?? 'text'\n\n fetch(url, init)\n .then(async (response) => {\n const header: Record<string, string> = {}\n response.headers.forEach((value, key) => {\n header[key] = value\n })\n const data = await decodeResponseData(response, dataType, responseType)\n settleSuccess({ data, statusCode: response.status, header, errMsg: 'request:ok' })\n })\n .catch((error: unknown) => {\n const reason = error instanceof Error ? error.message : String(error)\n settleFail({ errMsg: `request:fail ${reason || 'network error'}` })\n })\n\n return {\n abort() {\n settleFail({ errMsg: 'request:fail abort' })\n controller.abort()\n },\n }\n}\n", "import { performRequest } from '../../shared/request-core.js'\n\ntype Callback<T = unknown> = ((payload: T) => void) | undefined\n\nfunction call<T>(fn: Callback<T>, payload: T): void {\n try {\n fn?.(payload)\n } catch {\n // Ignore callback errors in compat shims.\n }\n}\n\nfunction buildWindowInfo() {\n const width = window.innerWidth || document.documentElement.clientWidth || 375\n const height = window.innerHeight || document.documentElement.clientHeight || 812\n const pixelRatio = window.devicePixelRatio || 2\n const statusBarHeight = 0\n return {\n pixelRatio,\n screenWidth: width,\n screenHeight: height,\n windowWidth: width,\n windowHeight: height,\n statusBarHeight,\n safeArea: {\n width,\n height,\n top: statusBarHeight,\n bottom: height,\n left: 0,\n right: width,\n },\n }\n}\n\nfunction makeStorageKey(key: string): string {\n return `dimina:${key}`\n}\n\nfunction ensureWxApi(wx: Record<string, unknown>): void {\n if (typeof wx.canIUse !== 'function') {\n wx.canIUse = (_schema: unknown) => true\n }\n\n if (typeof wx.getWindowInfo !== 'function') {\n wx.getWindowInfo = (opts: { success?: Callback<unknown>; complete?: Callback<void> } = {}) => {\n const info = buildWindowInfo()\n call(opts.success, info)\n call(opts.complete, undefined)\n return info\n }\n }\n\n if (typeof wx.getSystemSetting !== 'function') {\n wx.getSystemSetting = (opts: { success?: Callback<unknown>; complete?: Callback<void> } = {}) => {\n const info = {\n bluetoothEnabled: false,\n locationEnabled: true,\n wifiEnabled: true,\n deviceOrientation: 'portrait',\n }\n call(opts.success, info)\n call(opts.complete, undefined)\n return info\n }\n }\n\n if (typeof wx.getSystemInfoSync !== 'function') {\n wx.getSystemInfoSync = () => ({\n brand: 'simulator',\n model: 'web',\n platform: 'simulator',\n system: 'web',\n language: 'zh_CN',\n SDKVersion: '3.0.0',\n ...buildWindowInfo(),\n })\n }\n\n if (typeof wx.setStorageSync !== 'function') {\n wx.setStorageSync = (key: string, data: unknown) => {\n const value = typeof data === 'string' ? data : JSON.stringify(data)\n localStorage.setItem(makeStorageKey(String(key)), value)\n }\n }\n\n if (typeof wx.getStorageSync !== 'function') {\n wx.getStorageSync = (key: string) => {\n const raw = localStorage.getItem(makeStorageKey(String(key)))\n if (raw == null) return ''\n try {\n return JSON.parse(raw)\n } catch {\n return raw\n }\n }\n }\n\n if (typeof wx.removeStorageSync !== 'function') {\n wx.removeStorageSync = (key: string) => {\n localStorage.removeItem(makeStorageKey(String(key)))\n }\n }\n\n if (typeof wx.clearStorageSync !== 'function') {\n wx.clearStorageSync = () => {\n const prefix = 'dimina:'\n const keys: string[] = []\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i)\n if (key?.startsWith(prefix)) keys.push(key)\n }\n keys.forEach((key) => localStorage.removeItem(key))\n }\n }\n\n if (typeof wx.getStorageInfoSync !== 'function') {\n wx.getStorageInfoSync = () => {\n const prefix = 'dimina:'\n const keys: string[] = []\n let currentSize = 0\n for (let i = 0; i < localStorage.length; i++) {\n const fullKey = localStorage.key(i)\n if (!fullKey?.startsWith(prefix)) continue\n keys.push(fullKey.slice(prefix.length))\n currentSize += (localStorage.getItem(fullKey) || '').length * 2\n }\n return { keys, currentSize, limitSize: 10 * 1024 * 1024 }\n }\n }\n\n if (typeof wx.request !== 'function') {\n // Delegates to the shared wx.request core (shared/request-core.ts) \u2014 the\n // single owner of success/fail semantics, header dedup, timeout default,\n // and body encoding. This shim only adapts the wx.request option bag onto\n // the core's callbacks.\n wx.request = (opts: {\n url: string\n data?: unknown\n header?: Record<string, string>\n timeout?: number\n method?: string\n dataType?: string\n responseType?: string\n success?: Callback<unknown>\n fail?: Callback<unknown>\n complete?: Callback<unknown>\n }) =>\n performRequest(\n {\n url: opts.url,\n data: opts.data,\n header: opts.header,\n timeout: opts.timeout,\n method: opts.method,\n dataType: opts.dataType,\n responseType: opts.responseType,\n },\n {\n success: (res) => call(opts.success, res),\n fail: (err) => call(opts.fail, err),\n complete: (res) => call(opts.complete, res),\n },\n )\n }\n}\n\nexport function setupApiCompatHook(): void {\n const apply = () => {\n const target = window as unknown as { wx?: Record<string, unknown> }\n if (!target.wx || typeof target.wx !== 'object') {\n target.wx = {}\n }\n const wx = target.wx\n ensureWxApi(wx)\n return true\n }\n\n if (apply()) return\n\n const timer = window.setInterval(() => {\n if (apply()) window.clearInterval(timer)\n }, 200)\n}\n", "import { ipcRenderer } from 'electron'\nimport { BRIDGE_CHANNELS as C } from '../../shared/bridge-channels.js'\nimport type { NativeDeviceInfo } from '../../shared/ipc-channels.js'\n// (extension required: preload tsconfig is moduleResolution node16)\nimport type {\n ActivePagePayload,\n ApiResponsePayload,\n DisposePayload,\n NativeHostConfig,\n NavCallbackPayload,\n PageClosePayload,\n PageLifecyclePayload,\n PageOpenRequest,\n PageOpenResult,\n PageStackPayload,\n SpawnRequest,\n SpawnResult,\n} from '../../shared/bridge-channels.js'\nimport { exposeOnMainWorld } from '../shared/expose.js'\n\nexport interface RenderHostUrlOptions {\n bridgeId: string\n appId: string\n pagePath: string\n /** Whether this page is a tabBar page. Surfaced on the URL so main can pick\n * the bottom safe-area policy at `did-attach-webview` (services/safe-area). */\n isTab?: boolean\n}\n\nexport interface DiminaNativeHostBridge {\n enabled: boolean\n spawn(opts: SpawnRequest): Promise<SpawnResult>\n dispose(bridgeId: string): void\n openPage(opts: PageOpenRequest): Promise<PageOpenResult>\n closePage(bridgeId: string): void\n notifyLifecycle(payload: PageLifecyclePayload): void\n notifyNavCallback(payload: NavCallbackPayload): void\n notifyApiResponse(payload: ApiResponsePayload): void\n /** Tell main which page is the visible top-of-stack (for panel/automation targeting). */\n notifyActivePage(payload: ActivePagePayload): void\n /** Tell main the full ordered page stack (for automation's App.getPageStack). */\n notifyPageStack(payload: PageStackPayload): void\n createRenderHostUrl(opts: RenderHostUrlOptions): string\n renderPreloadUrl: string\n /**\n * The selected device at bridge-install time, if the renderer already pushed\n * it (it does \u2014 SetDeviceInfo precedes AttachNative). DeviceShell reads this\n * as its initial device; live changes arrive via the DEVICE_CHANGE event.\n */\n device?: NativeDeviceInfo\n /**\n * Subscribe to a main\u2192simulator event channel (SIMULATOR_EVENTS). Returns an\n * unsubscribe fn. The simulator renderer (DeviceShell) runs in the webview\n * main world with `nodeIntegration:false`, so it cannot `import 'electron'`;\n * this bridge owns the `ipcRenderer` plumbing on its behalf.\n */\n onSimulatorEvent<T = unknown>(channel: string, listener: (payload: T) => void): () => void\n}\n\n/**\n * Ask the main process (synchronously, at install time) whether native-host is\n * on and, if so, for the render-host file:// URLs. The simulator webview's\n * preload can't read the launch `process.env`, and \u2014 crucially \u2014 can't use\n * `node:path`/`node:url` to compute paths (the guest preload has no Node\n * builtins), so the main process (which has both) supplies everything here.\n */\nfunction queryNativeHostConfig(): NativeHostConfig | null {\n try {\n const res = ipcRenderer.sendSync(C.NATIVE_HOST_ENABLED) as NativeHostConfig | undefined\n return res && res.enabled ? res : null\n } catch {\n return null\n }\n}\n\nfunction buildBridge(cfg: NativeHostConfig): DiminaNativeHostBridge {\n return {\n enabled: true,\n spawn(opts) {\n return ipcRenderer.invoke(C.SPAWN, opts) as Promise<SpawnResult>\n },\n dispose(bridgeId) {\n const payload: DisposePayload = { bridgeId }\n ipcRenderer.send(C.DISPOSE, payload)\n },\n openPage(opts) {\n return ipcRenderer.invoke(C.PAGE_OPEN, opts) as Promise<PageOpenResult>\n },\n closePage(bridgeId) {\n const payload: PageClosePayload = { bridgeId }\n ipcRenderer.send(C.PAGE_CLOSE, payload)\n },\n notifyLifecycle(payload) {\n ipcRenderer.send(C.PAGE_LIFECYCLE, payload)\n },\n notifyNavCallback(payload) {\n ipcRenderer.send(C.NAV_CALLBACK, payload)\n },\n notifyApiResponse(payload) {\n ipcRenderer.send(C.API_RESPONSE, payload)\n },\n notifyActivePage(payload) {\n ipcRenderer.send(C.ACTIVE_PAGE, payload)\n },\n notifyPageStack(payload) {\n ipcRenderer.send(C.PAGE_STACK, payload)\n },\n createRenderHostUrl(opts) {\n // `URL` + `URLSearchParams` are web globals \u2014 no node:url needed.\n const url = new URL(cfg.renderHostHtmlUrl)\n url.searchParams.set('bridgeId', opts.bridgeId)\n url.searchParams.set('appId', opts.appId)\n url.searchParams.set('pagePath', opts.pagePath)\n if (opts.isTab) url.searchParams.set('isTab', '1')\n return url.toString()\n },\n renderPreloadUrl: cfg.renderPreloadUrl,\n device: cfg.device,\n onSimulatorEvent(channel, listener) {\n const wrapped = (_event: unknown, payload: unknown): void => {\n ;(listener as (p: unknown) => void)(payload)\n }\n ipcRenderer.on(channel, wrapped)\n return () => ipcRenderer.removeListener(channel, wrapped)\n },\n }\n}\n\n/**\n * Install the native-host bridge on the simulator main world when native-host\n * mode is on. Self-gating: a no-op disposer is returned when it's off, so the\n * caller can install unconditionally.\n */\nexport function installNativeHostBridge(): () => void {\n const cfg = queryNativeHostConfig()\n if (!cfg) return () => {}\n return exposeOnMainWorld('__diminaNativeHost', buildBridge(cfg))\n}\n", "import type { NativeDeviceInfo } from './ipc-channels.js'\n\nexport const BRIDGE_CHANNELS = {\n SPAWN: 'dmb:spawn',\n DISPOSE: 'dmb:dispose',\n PAGE_OPEN: 'dmb:page:open',\n PAGE_CLOSE: 'dmb:page:close',\n PAGE_LIFECYCLE: 'dmb:page:lifecycle',\n NAV_CALLBACK: 'dmb:nav:callback',\n SERVICE_INVOKE: 'dmb:service:invoke',\n SERVICE_PUBLISH: 'dmb:service:publish',\n RENDER_INVOKE: 'dmb:render:invoke',\n RENDER_PUBLISH: 'dmb:render:publish',\n TO_SERVICE: 'dmb:to-service',\n TO_RENDER: 'dmb:to-render',\n SIMULATOR_API: 'dmb:simulator-api',\n /** simulator \u2192 main: ack of an API_CALL request (carries success/fail args). */\n API_RESPONSE: 'dmb:api:response',\n /**\n * simulator webview preload \u2192 main (sendSync): \"is native-host mode on?\".\n * The guest preload can't read the launch `process.env`, so it asks main\n * (which can) at install time. Reply is `e.returnValue = boolean`.\n */\n NATIVE_HOST_ENABLED: 'dmb:native-host-enabled',\n /**\n * simulator (DeviceShell) \u2192 main: the visible top-of-stack page bridgeId.\n * Main has no z-order concept \u2014 the active page lives only in DeviceShell's\n * ShellState \u2014 so devtools panels / automation that must target \"the current\n * page's render webContents\" resolve it through this signal. Fire-and-forget.\n */\n ACTIVE_PAGE: 'dmb:active-page',\n /**\n * simulator (DeviceShell) \u2192 main: the FULL ordered page stack (bottom\u2192top)\n * whenever it changes. Main has no stack of its own (it only learns the\n * active bridgeId via ACTIVE_PAGE), so automation's `App.getPageStack` needs\n * this to report multi-page stacks. Fire-and-forget.\n */\n PAGE_STACK: 'dmb:page-stack',\n} as const\n\nexport const SIMULATOR_EVENTS = {\n DOM_READY: 'simulator:dom-ready',\n NAV_BAR: 'simulator:navigation-bar',\n NAV_ACTION: 'simulator:nav-action',\n TAB_ACTION: 'simulator:tab-action',\n /** main \u2192 simulator: invoke a wx.* API on the simulator-resident MiniApp. */\n API_CALL: 'simulator:api-call',\n /**\n * main \u2192 simulator: the renderer toolbar picked a different device. Carries a\n * NativeDeviceInfo; DeviceShell resizes the bezel + re-renders status bar /\n * notch. The race-free INITIAL device rides NativeHostConfig.device (read\n * synchronously at preload bridge-install); this event covers live changes.\n */\n DEVICE_CHANGE: 'simulator:device-change',\n /**\n * main \u2192 simulator: a watcher rebuild finished; boot a NEW app session for\n * the carried url ({@link RelaunchPayload}) IN PLACE, keeping the live\n * DeviceShell painted, and swap once the new session's root page reports\n * DOM_READY (ready-then-swap soft reload). Main sends this only when the\n * shell is live+ready; otherwise the renderer falls back to the hard\n * attachNativeSimulator rebuild.\n */\n RELAUNCH: 'simulator:relaunch',\n} as const\n\n/**\n * `simulator:relaunch` payload. `url` is a full simulator URL (same format as\n * the simulator page's own location / AttachNative), carrying the appId and\n * the page route the new session must boot at.\n */\nexport interface RelaunchPayload {\n url: string\n}\n\nexport const CHANNELS = BRIDGE_CHANNELS\n\n/**\n * Reply to a `NATIVE_HOST_ENABLED` sendSync. Main supplies the render-host\n * file:// URLs (computed with node:path/url, which the simulator webview's\n * preload lacks) so the preload can build the native-host bridge.\n */\nexport interface NativeHostConfig {\n enabled: boolean\n renderHostHtmlUrl: string\n renderPreloadUrl: string\n /**\n * The currently-selected device, if the renderer already pushed it before the\n * simulator WCV's preload installed (it does \u2014 SetDeviceInfo precedes\n * AttachNative). DeviceShell reads this as its initial device so it never\n * mounts with the wrong bezel size while waiting for the first DEVICE_CHANGE.\n * Absent only on the pre-spawn default path.\n */\n device?: NativeDeviceInfo\n}\n\nexport type BridgeChannel = typeof BRIDGE_CHANNELS[keyof typeof BRIDGE_CHANNELS]\n\nexport type BridgeTarget = 'service' | 'render' | 'container'\n\nexport type BridgeMessageType =\n | 'loadResource'\n | 'serviceResourceLoaded'\n | 'renderResourceLoaded'\n | 'resourceLoaded'\n | 'firstRender'\n | 'appShow'\n | 'appHide'\n | 'stackShow'\n | 'stackHide'\n | 'pageShow'\n | 'pageHide'\n | 'pageReady'\n | 'pageUnload'\n | 'pageScroll'\n | 'pageResize'\n | 'pageRouteDone'\n | 'mC'\n | 'mR'\n | 'mU'\n | 't'\n | 'u'\n | 'ub'\n | 'triggerCallback'\n | 'invokeAPI'\n | 'h5SdkAction'\n | 'componentError'\n | 'domReady'\n | 'print'\n | 'renderHostReady'\n | 'serviceHostError'\n | string\n\nexport interface MessageEnvelope<TBody extends Record<string, unknown> = Record<string, unknown>> {\n type: BridgeMessageType\n target: BridgeTarget\n body: TBody\n}\n\nexport interface HostEnvSnapshot {\n brand: string\n model: string\n platform: string\n system: string\n version: string\n SDKVersion: string\n pixelRatio: number\n screenWidth: number\n screenHeight: number\n windowWidth: number\n windowHeight: number\n statusBarHeight: number\n language: string\n theme: string\n [key: string]: unknown\n}\n\n/**\n * Map the renderer's logical device metrics onto the subset of a\n * HostEnvSnapshot the service-host window's `getSystemInfoSync` consumes.\n * `windowHeight` excludes the status bar (the page area); `windowWidth` has no\n * horizontal chrome. Zoom is intentionally absent \u2014 it is a display scale, not\n * a logical-size change.\n *\n * Single source of truth for the device\u2192host-env mapping, shared by the live\n * `SetDeviceInfo` IPC path (main/ipc/simulator.ts) and the per-spawn host-env\n * seeding (main/ipc/bridge-router.ts). Keeping them identical guarantees a\n * service-host RESPAWN after a device change reports the same dims the live\n * update pushed \u2014 otherwise a respawn would silently revert to the boot device.\n */\nexport function deviceInfoToHostEnv(d: NativeDeviceInfo): Partial<HostEnvSnapshot> {\n return {\n brand: d.brand,\n model: d.model,\n system: d.system,\n platform: d.platform,\n pixelRatio: d.pixelRatio,\n screenWidth: d.screenWidth,\n screenHeight: d.screenHeight,\n windowWidth: d.screenWidth,\n windowHeight: Math.max(0, d.screenHeight - d.statusBarHeight),\n statusBarHeight: d.statusBarHeight,\n }\n}\n\n/**\n * Subset of WeChat page `window` config plus tabBar list, parsed from\n * `app-config.json` (`{app:{window,tabBar,pages,entryPagePath}, modules:{[pagePath]:{window}}}`).\n * Mirrors mergePageConfig in dimina-fe: page-level keys override app-level.\n */\nexport interface PageWindowConfig {\n navigationBarTitleText?: string\n navigationBarBackgroundColor?: string\n navigationBarTextStyle?: 'black' | 'white'\n navigationStyle?: 'default' | 'custom'\n homeButton?: boolean\n backgroundColor?: string\n backgroundTextStyle?: 'dark' | 'light'\n enablePullDownRefresh?: boolean\n disableScroll?: boolean\n [key: string]: unknown\n}\n\nexport interface TabBarItem {\n pagePath: string\n text?: string\n iconPath?: string\n selectedIconPath?: string\n}\n\nexport interface TabBarConfig {\n color?: string\n selectedColor?: string\n backgroundColor?: string\n borderStyle?: 'black' | 'white'\n position?: 'bottom' | 'top'\n custom?: boolean\n list: TabBarItem[]\n}\n\nexport interface AppManifest {\n entryPagePath: string\n pages: string[]\n tabBar?: TabBarConfig\n /**\n * Provenance of this manifest: `'app-config'` when built from a real\n * compiled `app-config.json` (its `pages` list is authoritative, so mount\n * gates can validate membership against it); `'fallback'` when\n * app-config.json was unreachable and the manifest is a single-page stand-in\n * built from the spawn request. Mount gates only enforce against\n * `'app-config'` \u2014 a `'fallback'` manifest has no compiled truth to check\n * membership against, so it must let every page/nav target through.\n */\n source: 'app-config' | 'fallback'\n}\n\nexport interface SpawnRequest {\n simulatorWcId?: number\n appId: string\n bridgeId?: string\n pagePath?: string\n scene?: number\n query?: Record<string, unknown>\n apiNamespaces?: string[]\n hostEnvSnapshot?: Partial<HostEnvSnapshot>\n pkgRoot?: string\n root?: string\n /**\n * Base URL of the dev server that serves the compiled mini-app, i.e. the\n * SAME origin the simulator page was loaded from (`http://localhost:<port>/`).\n * The dev server statically serves `<appId>/<root>/\u2026` (app-config.json,\n * logic.js, page bundles, styles) \u2014 exactly what the default dimina-fe\n * `<webview>` fetches. The native-host render + service hosts source every\n * resource from here, so we don't need a second resource server or a local\n * compiled-output path. Trailing slash expected.\n */\n resourceBaseUrl?: string\n}\n\nexport interface SpawnResult {\n appSessionId: string\n bridgeId: string\n /** The pagePath originally requested (unchanged even when a fallback applied \u2014 see `resolvedPagePath`). */\n pagePath: string\n /**\n * The pagePath the root PageSession was ACTUALLY spawned with. Equal to\n * `pagePath` unless `pageFallbackApplied` is true, in which case the request\n * was absent from `manifest.pages` and this is `manifest.entryPagePath`\n * (or `manifest.pages[0]` when even that isn't a member). Callers that cache\n * \"the current page\" (e.g. `SimulatorMiniApp`) must reconcile against this,\n * not the original request.\n */\n resolvedPagePath: string\n /** Whether `resolvedPagePath` differs from the request because it was absent from the compiled manifest. Always false for a `'fallback'` manifest (nothing to validate against). */\n pageFallbackApplied: boolean\n serviceWcId: number\n resourceBaseUrl: string\n manifest: AppManifest\n rootWindowConfig: PageWindowConfig\n}\n\nexport interface PageOpenRequest {\n appSessionId: string\n pagePath: string\n query?: Record<string, unknown>\n bridgeId?: string\n}\n\nexport interface PageOpenResult {\n bridgeId: string\n pagePath: string\n windowConfig: PageWindowConfig\n isTab: boolean\n}\n\nexport interface PageClosePayload {\n bridgeId: string\n}\n\nexport interface DisposePayload {\n /** AppSession root bridgeId (legacy) or any page bridgeId. */\n bridgeId: string\n}\n\nexport type PageLifecycleEvent =\n | 'pageShow'\n | 'pageHide'\n | 'pageUnload'\n | 'stackShow'\n | 'stackHide'\n | 'appShow'\n | 'appHide'\n\nexport interface PageLifecyclePayload {\n appSessionId: string\n bridgeId: string\n event: PageLifecycleEvent\n}\n\n/**\n * Sent by simulator after a routing action (navigateTo etc.) completes so the\n * main process can call sendCallback() against the original service-issued\n * success/fail/complete ids.\n */\nexport interface NavCallbackPayload {\n appSessionId: string\n ok: boolean\n errMsg: string\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n\nexport interface ServiceInvokePayload {\n bridgeId: string\n msg: MessageEnvelope\n}\n\nexport interface ServicePublishPayload {\n bridgeId: string\n targetBridgeId?: string\n msg: MessageEnvelope\n}\n\n/**\n * `dmb:active-page` \u2014 simulator (DeviceShell) \u2192 main. Records which page is the\n * visible top-of-stack so main-side services (WXML/element-inspect, automation)\n * can resolve \"the active page's render webContents\" by bridgeId.\n */\nexport interface ActivePagePayload {\n appSessionId: string\n bridgeId: string\n}\n\n/**\n * `dmb:page-stack` \u2014 simulator (DeviceShell) \u2192 main. The full ordered page\n * stack (bottom\u2192top) so `App.getPageStack` can report multi-page stacks.\n */\nexport interface PageStackEntry {\n pagePath: string\n query: Record<string, unknown>\n}\n\nexport interface PageStackPayload {\n appSessionId: string\n stack: PageStackEntry[]\n}\n\nexport interface RenderInvokePayload {\n bridgeId: string\n msg: MessageEnvelope\n}\n\nexport interface RenderPublishPayload {\n bridgeId: string\n msg: MessageEnvelope\n}\n\nexport interface ToServicePayload {\n msg: MessageEnvelope\n}\n\nexport interface ToRenderPayload {\n msg: MessageEnvelope\n}\n\nexport interface SimulatorApiInvokePayload {\n bridgeId: string\n name: string\n params: unknown\n}\n\n/**\n * `simulator:nav-action` \u2014 main \u2192 simulator window, carries router/tabBar\n * intentions. Simulator owns the visual stack state and decides whether to\n * push/pop webviews; it then calls back PAGE_LIFECYCLE + NAV_CALLBACK.\n */\nexport interface NavActionPayload {\n appSessionId: string\n bridgeId: string\n name: 'navigateTo' | 'navigateBack' | 'redirectTo' | 'reLaunch' | 'switchTab'\n params: Record<string, unknown>\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n\n/**\n * `simulator:api-call` \u2014 main \u2192 simulator. Fallback path used when an\n * invokeAPI name is not registered in the main-process `ctx.simulatorApis`\n * registry: the simulator-resident MiniApp owns the wx.* handler (it can\n * read DOM, open file pickers, etc.), so we forward the call there and wait\n * for an `API_RESPONSE` ack.\n */\nexport interface ApiCallPayload {\n appSessionId: string\n bridgeId: string\n requestId: string\n name: string\n params: Record<string, unknown>\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n\n/**\n * `dmb:api:response` \u2014 simulator \u2192 main. Ack for an `API_CALL`. Main looks\n * up `requestId` in its pending map and fires the original service-side\n * success/fail/complete callbacks accordingly.\n */\nexport interface ApiResponsePayload {\n appSessionId: string\n requestId: string\n ok: boolean\n /** Argument the simulator-side success/fail callback was invoked with. */\n result?: unknown\n errMsg?: string\n /**\n * Persistent-subscription marker (`keep: true` APIs, e.g.\n * `audioListen`). When set, this response is one of potentially many\n * fires of the same subscription: main re-fires the service-side success\n * callback but keeps the pendingApiCall alive (does not delete it or fire\n * `complete`) so subsequent fires of the same `requestId` are delivered.\n * Cleanup happens on page/app teardown instead.\n */\n keep?: boolean\n}\n\n/**\n * `simulator:tab-action` \u2014 main \u2192 simulator window, carries dynamic TabBar\n * API calls. Simulator updates TabBar React state and acknowledges via\n * NAV_CALLBACK so the service-side wx.* callback fires.\n */\nexport interface TabActionPayload {\n appSessionId: string\n bridgeId: string\n name:\n | 'setTabBarStyle'\n | 'setTabBarItem'\n | 'showTabBar'\n | 'hideTabBar'\n | 'setTabBarBadge'\n | 'removeTabBarBadge'\n | 'showTabBarRedDot'\n | 'hideTabBarRedDot'\n params: Record<string, unknown>\n callbacks: { success?: unknown; fail?: unknown; complete?: unknown }\n}\n", "// Default preload script for the simulator <webview>.\n// Composes all built-in instrumentation. For custom preloads, import individual\n// functions from '@dimina-kit/devtools/preload' and assemble your own.\n//\n// This file is bundled into a single JS file via build:preload (esbuild)\n// because webview sandbox cannot resolve require() for separate modules.\nimport { installSimulatorBridge } from '../runtime/bridge.js'\nimport { installCustomApisBridge } from '../runtime/custom-apis.js'\nimport { installTempFileBridge } from '../runtime/temp-files.js'\nimport { installConsoleInstrumentation } from '../instrumentation/console.js'\nimport { createAppDataSource } from '../instrumentation/app-data.js'\nimport { setupApiCompatHook } from '../shared/api-compat.js'\nimport { installNativeHostBridge } from '../runtime/native-host.js'\n\n// Note: storage panel data is sourced from the main process via the CDP\n// DOMStorage domain (src/main/services/simulator-storage). No preload-side\n// localStorage hook is required.\n\n// This bundle is assigned to the native-host simulator WebContentsView only, so\n// it always runs in the actual simulator document (`simulator.html`) \u2014 never a\n// per-page render-host (`pageFrame.html`) or service-host (`service.html`)\n// frame, which carry their own dedicated preloads.\nsetupApiCompatHook()\ninstallSimulatorBridge()\ninstallCustomApisBridge()\ninstallTempFileBridge()\ninstallConsoleInstrumentation()\n\n// Native-host render path: self-gating bridge that exposes\n// `window.__diminaNativeHost` so simulator/main.tsx boots the DeviceShell +\n// SimulatorMiniApp pipeline.\ninstallNativeHostBridge()\n\n// AppData instrumentation source. We call its `start()` DIRECTLY (not wrapped\n// in a MiniappSnapshotHost) purely for the automation-surface side effects: it\n// installs `window.__simulatorHook.appData` and mirrors the flat cache into the\n// `window.__simulatorData.getAppdata()` surface \u2014 both still read in the\n// simulator (top) frame by automation `getData` (handlers/page.ts), the MCP\n// context overview (mcp/tools/context-tools.ts) and the e2e automator helper.\n//\n// We do NOT wrap it in a host: the host's `miniapp-snapshot:push/pull` IPC has\n// no consumer under native-host (the renderer reads panel WXML/AppData from\n// main via SimulatorWxmlChannel / SimulatorAppDataChannel), so install()'s\n// publish would only ever fire into the void. We also do NOT register\n// `createWxmlSource` \u2014 under native-host the page DOM lives in child\n// render-host <webview> guests, so a top-frame DOM observer would only publish\n// null. (`createWxmlSource` / `createMiniappSnapshotHost` stay exported from\n// `@dimina-kit/devtools/preload` for external/composed preloads.)\ncreateAppDataSource().start(() => {})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_electron", "state", "import_electron", "import_electron", "import_electron", "buildBridge"]
|
|
7
7
|
}
|