@open-wxa/wxa-runner-core 0.12.3 → 0.12.4

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/index.d.mts CHANGED
@@ -3,7 +3,7 @@ import { ResolvedBaseLib } from '@open-wxa/wxa-runner-extractor';
3
3
  import { D as DeviceProfile, F as ForwardConsole } from './setup--EIOgQvG.mjs';
4
4
  export { A as ApiContext, a as ApiHandler, b as ApiResult, c as AppInfo, M as MockConfig, d as MockRequest, e as MockResponse, f as MockValue, N as NetworkConfig, R as RouteHandler, S as SetupApi, g as SetupConfig, h as SetupContext, i as SetupDefinition } from './setup--EIOgQvG.mjs';
5
5
  import { Request, Response } from 'express';
6
- export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-CoYw0cPm.mjs';
6
+ export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-CEA0oH79.mjs';
7
7
 
8
8
  /**
9
9
  * 样式预处理:project.config.json 的 setting.useCompilerPlugins 开启 less / sass 时,
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { ResolvedBaseLib } from '@open-wxa/wxa-runner-extractor';
3
3
  import { D as DeviceProfile, F as ForwardConsole } from './setup--EIOgQvG.js';
4
4
  export { A as ApiContext, a as ApiHandler, b as ApiResult, c as AppInfo, M as MockConfig, d as MockRequest, e as MockResponse, f as MockValue, N as NetworkConfig, R as RouteHandler, S as SetupApi, g as SetupConfig, h as SetupContext, i as SetupDefinition } from './setup--EIOgQvG.js';
5
5
  import { Request, Response } from 'express';
6
- export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-BfzCTOhg.js';
6
+ export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-CfcEUYpC.js';
7
7
 
8
8
  /**
9
9
  * 样式预处理:project.config.json 的 setting.useCompilerPlugins 开启 less / sass 时,
@@ -45,6 +45,9 @@
45
45
  loaded: (id) => contexts.loaded(id)
46
46
  };
47
47
  }
48
+ function installSingleContextLibLoader(service) {
49
+ service.WeixinJSContext = { loadLibFiles: () => 1 };
50
+ }
48
51
  var JsContexts = class {
49
52
  constructor(main, host2, options) {
50
53
  this.main = main;
@@ -363,6 +366,18 @@
363
366
  }
364
367
  return replaced;
365
368
  }
369
+ var BUILT_IN_SDK_GLOBALS = /* @__PURE__ */ new Set(["__cloudSDKMain__"]);
370
+ function guardSdkGlobals(global, before) {
371
+ const guarded = [];
372
+ for (const key of Object.getOwnPropertyNames(global)) {
373
+ if (before.has(key) || BUILT_IN_SDK_GLOBALS.has(key)) continue;
374
+ const descriptor = Object.getOwnPropertyDescriptor(global, key);
375
+ if (!descriptor?.get || !descriptor.configurable) continue;
376
+ Object.defineProperty(global, key, { get: () => void 0, enumerable: descriptor.enumerable, configurable: true });
377
+ guarded.push(key);
378
+ }
379
+ return guarded;
380
+ }
366
381
 
367
382
  // src/runtime/workers.ts
368
383
  function createWeixinWorker(win, host2) {
@@ -445,7 +460,16 @@
445
460
  }
446
461
  };
447
462
  const businessCodeHere = !subContextId && !script.dataset.appService;
448
- hookRequire(businessCodeHere ? reserveFunctionConstructor() : void 0);
463
+ if (businessCodeHere) {
464
+ const disableFunctionConstructor = reserveFunctionConstructor();
465
+ const globalsBeforeBaseLib = new Set(Object.getOwnPropertyNames(g));
466
+ hookRequire(() => {
467
+ disableFunctionConstructor();
468
+ guardSdkGlobals(g, globalsBeforeBaseLib);
469
+ });
470
+ } else {
471
+ hookRequire();
472
+ }
449
473
  g.createCustomImage = createCustomImage;
450
474
  moveCanvasesIntoPages();
451
475
  } else {
@@ -456,9 +480,7 @@
456
480
  overrideUserAgent();
457
481
  window.addEventListener("error", (event) => host.reportError(kind, webviewId, event.error || event.message));
458
482
  window.addEventListener("unhandledrejection", (event) => host.reportError(kind, webviewId, event.reason));
459
- if (host.forwardConsole) {
460
- hookConsole(host.forwardConsole === "all" ? ["warn", "error"] : ["error"], (level, args) => host.reportConsole(kind, webviewId, level, args));
461
- }
483
+ hookConsole(host.forwardConsole === "all" ? ["warn", "error"] : ["error"], (level, args) => host.reportConsole(kind, webviewId, level, args));
462
484
  if (subContextId) {
463
485
  window.parent.__wxaContexts.prepare(subContextId, window);
464
486
  } else {
@@ -471,6 +493,8 @@
471
493
  appServiceScripts: JSON.parse(script.dataset.appService),
472
494
  hot: script.dataset.hot === "1"
473
495
  });
496
+ } else if (kind === "service") {
497
+ installSingleContextLibLoader(window);
474
498
  }
475
499
  host.registerFrame(kind, window, bridge, webviewId);
476
500
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/runtime/consoleHook.ts","../../src/runtime/syncScript.ts","../../src/runtime/context.ts","../../src/runtime/fileSession.ts","../../src/runtime/networkPanel.ts","../../src/runtime/sdkStubs.ts","../../src/runtime/workers.ts","../../src/runtime/frame.ts"],"sourcesContent":["/**\n * 包装 iframe 里的 console:照常打印,同时交给宿主转发到终端\n *\n * 开发服务器把这个文件列入 frame.js 的 source map 的忽略列表,DevTools 跳过这层包装,\n * 控制台里的来源链接仍指向调用 console 的业务代码\n */\n\nexport type ConsoleLevel = 'warn' | 'error';\n\nexport function hookConsole(levels: ConsoleLevel[], report: (level: ConsoleLevel, args: unknown[]) => void) {\n for (const level of levels) {\n const original = console[level];\n console[level] = function (this: Console, ...args: unknown[]) {\n original.apply(this, args);\n try {\n report(level, args);\n } catch {\n // 转发出错不能影响业务代码\n }\n };\n }\n}\n","/**\n * 同步执行脚本:与开发者工具的 loadLibFiles 一致,同步请求脚本内容,以内联脚本执行\n */\n\n/** @throws 状态码不是 200 */\nexport function readSync(url: string): string {\n const xhr = new XMLHttpRequest();\n xhr.open('GET', url, false);\n xhr.send();\n if (xhr.status !== 200) throw new Error(`[wxa-runner] 加载 ${url} 失败:${xhr.status}`);\n return xhr.responseText;\n}\n\n/** 在 win 里执行完才返回;DevTools 里显示为 url 这个文件 */\nexport function runScript(win: Window, url: string, code: string) {\n const href = new URL(url, location.href).href;\n // 基础库文件同样加入 DevTools 的忽略列表(见 server/ignoreList.ts)\n const sourceMap = url.startsWith('/__baselib__/') ? `\\n//# sourceMappingURL=${href}.map` : '';\n const script = win.document.createElement('script');\n script.text = `${code}\\n//# sourceURL=${href}${sourceMap}`;\n win.document.head.appendChild(script);\n}\n","/**\n * 模拟原生 WeixinJSContext(3.7.1 起的基础库需要)\n *\n * 新版基础库把逻辑层分成主上下文和子上下文:逻辑层 iframe 是主上下文,运行 WAServiceMainContext.js,\n * 持有 WeixinJSBridge;App / Page / wx 和业务代码在子上下文里,子上下文由主上下文通过这个接口创建。\n * 与开发者工具一样,每个子上下文是逻辑层 iframe 里的一个同源 iframe(subcontext.html)。\n *\n * 两边的消息不经过这里:子上下文拿到同一个 WeixinJSContext 对象,主上下文初始化时在上面挂了\n * register / subscribeHandler,双方直接互相调用。\n *\n * 交给基础库的 WeixinJSContext 是一次性的门面:基础库初始化时取走上面的方法、再把它们删掉,\n * 所以这里的逻辑都不经过它。\n */\n\nimport { readSync, runScript } from './syncScript';\nimport type { HostApi } from './types';\n\nconst MAIN_CONTEXT_ID = 1;\n/** 业务代码所在的子上下文 */\nconst APP_CONTEXT_NAME = 'app';\n/** 基础库要执行的业务代码入口,对应构建出的 define 脚本和 bootstrap */\nconst APP_SERVICE_ENTRY = 'app-service.js';\n/** 从基础库开始执行到业务代码执行完的最长时间 */\nconst BOOT_TIMEOUT = 10000;\n\ntype Callback = () => void;\n\nexport interface WeixinJSContextOptions {\n /** 向主上下文派发原生事件(WeixinJSBridge.on) */\n dispatchNative: (event: string, data: unknown) => void;\n /** 业务代码的脚本地址,基础库执行 app-service.js 时按顺序加载 */\n appServiceScripts: string[];\n /** 打开基础库的热更新开关(见 server/html.ts 的 enableHotUpdate) */\n hot: boolean;\n}\n\n/** 在逻辑层主上下文里提供 window.WeixinJSContext,必须在基础库之前调用 */\nexport function installWeixinJSContext(main: Window, host: HostApi, options: WeixinJSContextOptions) {\n const contexts = new JsContexts(main, host, options);\n (main as any).WeixinJSContext = contexts.nativeInterface;\n // subcontext.html 通过 parent.__wxaContexts 回调这两个入口\n (main as any).__wxaContexts = {\n prepare: (id: number, win: Window) => contexts.prepare(id, win),\n loaded: (id: number) => contexts.loaded(id)\n };\n}\n\n/** 主上下文和它创建的子上下文 */\nclass JsContexts {\n private readonly boot: AppBoot;\n private readonly mainContext: JsContext;\n private readonly contexts = new Map<number, JsContext>();\n private nextId = MAIN_CONTEXT_ID + 1;\n\n /** 交给基础库的原生接口。基础库会把方法取下来单独调用,所以都不依赖 this */\n readonly nativeInterface = {\n mainContextId: MAIN_CONTEXT_ID,\n alloc: (name?: string, callback?: Callback) => this.open(name, false).whenReady(callback).id,\n allocEmpty: (name?: string, callback?: Callback) => this.open(name, true).whenReady(callback).id,\n create: (entry: string | undefined, name?: string, callback?: Callback) => {\n const context = this.open(name, false);\n context.whenReady(entry ? () => this.evaluate(context, entry, callback) : callback);\n return context.id;\n },\n evaluateScriptFile: (id: number, file: string, callback?: Callback) =>\n this.withContext(id, context => this.evaluate(context, file, callback)),\n loadJsFiles: (id: number, files: string, callback?: Callback) =>\n this.withContext(id, context => this.evaluateAll(context, JSON.parse(files), callback)),\n /** 基础库自己的文件(如 WARenderContext.js),同步执行 */\n loadLibFiles: (id: number, files: string) =>\n this.withContext(id, context => {\n context.runSync((JSON.parse(files) as string[]).map(file => `/__baselib__/${file}`));\n return 1;\n }),\n destroy: (id: number, callback?: Callback) => this.destroy(id, callback)\n };\n\n constructor(private readonly main: Window, private readonly host: HostApi, private readonly options: WeixinJSContextOptions) {\n this.boot = new AppBoot(host);\n this.mainContext = new JsContext(MAIN_CONTEXT_ID, 'main', main);\n this.contexts.set(MAIN_CONTEXT_ID, this.mainContext);\n }\n\n /** 子上下文页面开始执行,基础库之前:交给它基础库需要的全局变量 */\n prepare(id: number, win: Window) {\n const context = this.contexts.get(id);\n if (!context || context === this.mainContext) throw new Error(`[wxa-runner] 未知的子上下文 ${id}`);\n context.win = win;\n Object.assign(win, { WeixinJSContext: this.nativeInterface, WeixinJSContextId: id, __wxConfig: (this.main as any).__wxConfig });\n if (context.isApp) this.host.registerAppContext(win);\n }\n\n /** 子上下文页面执行完(基础库已初始化) */\n loaded(id: number) {\n const context = this.contexts.get(id);\n if (!context) return;\n context.markReady();\n if (context.isApp) {\n this.boot.reach('entry');\n // 真机上由客户端在主包就绪后派发,基础库收到后才执行业务入口\n this.options.dispatchNative('onSubPackageReady', { moduleName: '__APP__' });\n }\n }\n\n private open(name: string | undefined, empty: boolean): JsContext {\n const context = openSubContext(this.main, this.nextId++, name, empty);\n this.contexts.set(context.id, context);\n if (context.isApp) this.boot.reach('load');\n return context;\n }\n\n /** 原生接口的结果码:1 成功,0 失败 */\n private withContext(id: number, action: (context: JsContext) => number): number {\n const context = this.contexts.get(Number(id));\n if (context) return action(context);\n console.warn(`[wxa-runner] 找不到 JS 上下文 ${id}`);\n return 0;\n }\n\n /** 执行基础库要求的脚本文件:带回调时等上下文加载完再异步执行,否则同步执行 */\n private evaluate(context: JsContext, file: string, done?: Callback): number {\n // 基础库只会要求执行业务代码入口\n if (!context.isApp || file.replace(/^\\/+/, '') !== APP_SERVICE_ENTRY) {\n console.warn(`[wxa-runner] 基础库要求执行未知脚本 ${file}`);\n return 0;\n }\n const urls = this.options.appServiceScripts;\n if (done) {\n context.whenReady(() => {\n this.startApp(context);\n loadScripts(context.win!, urls, () => {\n done();\n this.boot.finish();\n });\n });\n } else {\n this.startApp(context);\n context.runSync(urls);\n this.boot.finish();\n }\n return 1;\n }\n\n private startApp(context: JsContext) {\n this.boot.reach('run');\n // 与旧版基础库一样,必须在业务代码注册 Page / Component 之前打开\n if (this.options.hot) (context.win as any).__virtualDOM__?.enableUpdateWxAppCode?.();\n }\n\n private evaluateAll(context: JsContext, files: string[], done?: Callback): number {\n if (!done) return files.every(file => this.evaluate(context, file) === 1) ? 1 : 0;\n let remaining = files.length;\n if (remaining === 0) done();\n for (const file of files) {\n if (this.evaluate(context, file, () => --remaining === 0 && done()) === 0) return 0;\n }\n return 1;\n }\n\n private destroy(id: number, callback?: Callback) {\n const context = this.contexts.get(Number(id));\n if (!context || context === this.mainContext) return;\n this.contexts.delete(context.id);\n context.destroy();\n if (context.isApp) this.host.registerAppContext(null);\n callback?.();\n }\n}\n\n/** 一个 JS 上下文:主上下文是逻辑层 iframe 本身,子上下文是其中的一个同源 iframe */\nclass JsContext {\n /** 页面加载完之前收到的任务;加载完后为 null */\n private pending: Callback[] | null;\n\n constructor(readonly id: number, readonly name: string, public win: Window | null, private readonly iframe?: HTMLIFrameElement) {\n this.pending = win ? null : [];\n }\n\n get isApp(): boolean {\n return this.name === APP_CONTEXT_NAME;\n }\n\n /** 加载完后执行,已加载完时立即执行 */\n whenReady(task?: Callback): this {\n if (task) {\n if (this.pending) this.pending.push(task);\n else task();\n }\n return this;\n }\n\n markReady() {\n const tasks = this.pending || [];\n this.pending = null;\n tasks.forEach(task => task());\n }\n\n runSync(urls: string[]) {\n if (this.pending) throw new Error(`[wxa-runner] JS 上下文 ${this.id} 尚未加载完,不能同步执行脚本`);\n for (const url of urls) runScript(this.win!, url, readSync(url));\n }\n\n destroy() {\n this.pending = [];\n this.iframe?.remove();\n }\n}\n\nfunction openSubContext(main: Window, id: number, name: string | undefined, empty: boolean): JsContext {\n const iframe = main.document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.src = `/__wxa__/subcontext.html?id=${id}${empty ? '&empty=1' : ''}`;\n // 基础库在逻辑层页面的 <head> 里执行时就会创建子上下文,那时还没有 body\n main.document.documentElement.appendChild(iframe);\n return new JsContext(id, name || `context${id}`, null, iframe);\n}\n\nconst BOOT_STAGES = {\n alloc: `基础库没有创建业务子上下文(名为 ${APP_CONTEXT_NAME} 的子上下文)`,\n load: '业务子上下文没有加载完(WASubContext.js 加载或执行出错)',\n entry: `基础库没有执行业务代码入口 ${APP_SERVICE_ENTRY}`,\n run: '业务代码没有加载完'\n};\n\ntype BootStage = keyof typeof BOOT_STAGES;\n\n/**\n * 业务代码的启动过程,每一步都依赖基础库的内部行为:\n * 创建业务子上下文 → 子上下文加载完 → 派发 onSubPackageReady → 基础库执行业务入口 → 业务代码执行完。\n * 任何一步没发生,宿主都会一直等逻辑层就绪,所以超时后报告停在哪一步,照常结束启动\n */\nclass AppBoot {\n private stage: BootStage = 'alloc';\n private finished = false;\n private readonly timer: ReturnType<typeof setTimeout>;\n\n constructor(private readonly host: HostApi) {\n this.timer = setTimeout(() => {\n this.finish(new Error(`[wxa-runner] 逻辑层 ${BOOT_TIMEOUT}ms 内没有就绪:${BOOT_STAGES[this.stage]}`));\n }, BOOT_TIMEOUT);\n }\n\n reach(stage: BootStage) {\n this.stage = stage;\n }\n\n /** 通知宿主逻辑层就绪,只通知一次;出错时先报告错误 */\n finish(error?: Error) {\n if (this.finished) return;\n this.finished = true;\n clearTimeout(this.timer);\n if (error) {\n console.error(error.message);\n this.host.reportError('service', 0, error);\n }\n this.host.frameLoaded('service', 0);\n }\n}\n\n/** 按顺序加载外部脚本(保留文件名和行号,便于在 DevTools 里调试),全部执行完后回调 */\nfunction loadScripts(win: Window, urls: string[], done: Callback) {\n let remaining = urls.length;\n if (remaining === 0) {\n done();\n return;\n }\n for (const url of urls) {\n const script = win.document.createElement('script');\n script.async = false;\n script.src = url;\n const settle = () => {\n if (--remaining === 0) done();\n };\n script.onload = settle;\n script.onerror = () => {\n console.error(`[wxa-runner] 加载 ${url} 失败`);\n settle();\n };\n win.document.head.appendChild(script);\n }\n}\n","/**\n * 文件会话:开发服务器上每个会话一份用户文件和临时文件(见 DevServer 的 /__wxa__/fs)。\n * 标识和 Storage 一样存在 localStorage:刷新后不变,同一浏览器上下文的页面共用,新的上下文(Playwright 的每个用例)另起一份\n */\nconst KEY = '__wxa_file_session__';\n\nexport function fileSession(): string {\n let session = localStorage.getItem(KEY);\n if (!session) {\n session = crypto.randomUUID();\n localStorage.setItem(KEY, session);\n }\n return session;\n}\n","/**\n * 小程序的请求在浏览器 Network 面板里的样子,宿主、Service Worker 和开发服务器共用\n *\n * 原地址放在路径里:/__wxa__/proxy/https/api.example.com/user/info?id=1。Name 列显示接口名(info?id=1),\n * 按域名、路径过滤也直接可用;放在查询参数里时每一行都是 proxy?url=https%3A%2F%2F…,分不出是哪个接口。\n *\n * - 经开发服务器转发的请求:/__wxa__/proxy/…\n * - 被拦截规则拦下的请求:/__wxa__/mock/…,由 Service Worker 返回规则给出的响应,只用于显示(见 sw.ts)\n */\n\nimport type { MockedResponse } from './host/api/routes';\n\nexport const PROXY_PREFIX = '/__wxa__/proxy/';\nexport const MOCK_PREFIX = '/__wxa__/mock/';\n\n/** 显示被拦截请求的 fetch 带上这个头,Service Worker 凭它向宿主要对应的响应 */\nexport const MOCK_ID_HEADER = 'x-wxa-mock-id';\n\n/** Service Worker 向宿主要响应时发的消息,附带一个 MessagePort,宿主从这个端口回复 MockReply */\nexport interface MockQuery {\n type: 'wxa-mock-response';\n id: string;\n}\n\n/** 请求被取消、拦截规则出错,或宿主已经不认识这个 id 时为 null,Network 面板里显示为失败 */\nexport type MockReply = MockedResponse | null;\n\n/**\n * 原地址在开发服务器上对应的路径,prefix 是 PROXY_PREFIX 或 MOCK_PREFIX。不是 http(s) 地址时返回 null\n *\n * 先按 URL 规范化:路径里的 .. 要在拼接前解析掉,否则浏览器会在代理路径上解析,把域名那一段也吃掉\n */\nexport function toServerPath(prefix: string, url: string): string | null {\n let target: URL;\n try {\n target = new URL(url);\n } catch {\n return null;\n }\n if (target.protocol !== 'http:' && target.protocol !== 'https:') return null;\n return `${prefix}${target.protocol.slice(0, -1)}/${target.host}${target.pathname}${target.search}`;\n}\n\n/**\n * toServerPath 的逆运算,格式不对或还原出的地址不合法时返回 null\n *\n * 只校验不规范化,返回拼出的原样字符串:路径里的 %2F 等编码要原样转发\n */\nexport function fromServerPath(prefix: string, serverPath: string): string | null {\n if (!serverPath.startsWith(prefix)) return null;\n const match = /^(https?)\\/([^/?#]+)(.*)$/.exec(serverPath.slice(prefix.length));\n if (!match) return null;\n const url = `${match[1]}://${match[2]}${match[3]}`;\n try {\n new URL(url);\n return url;\n } catch {\n return null;\n }\n}\n\n/**\n * 用于显示的请求、响应头。浏览器不允许设置的(cookie、set-cookie 等)会被忽略,\n * 名字或值不合法的(如值里有中文)跳过:它们只影响 Network 面板里的显示,小程序拿到的头不受影响。\n * 值为 undefined、null 的和代理一样不发\n */\nexport function toHeaders(header: Record<string, unknown>): Headers {\n const headers = new Headers();\n for (const [name, value] of Object.entries(header)) {\n if (value === undefined || value === null) continue;\n try {\n headers.set(name, String(value));\n } catch {\n // 跳过\n }\n }\n return headers;\n}\n","/**\n * 基础库伴生 SDK 子包能力的占位实现\n *\n * WAService.js 不是自包含的。广告、云开发、米大师支付等能力放在一组伴生文件里\n * (WAAppAd.js / WACloud.js / WAMidasSDK.js 等),真机和开发者工具由原生层调用\n * loadMainContextLibFile 把它们同步加载进同一个上下文,再把导出挂到约定的全局名上\n * (WAAppAd.js → globalThis.AD → 基础库读作 ADSDK)。运行时没有这套加载机制。\n *\n * 缺失不会直接抛到业务代码:基础库把内部异常包成 appServiceSDKScriptError 自己吞掉,\n * 于是 wx.createRewardedVideoAd() 返回 undefined。真正崩的是下一行业务代码\n * ——`ad.onError(...)`,Cannot read properties of undefined。所以占位放在 wx 这一层,\n * 不管基础库内部走的是哪条失败路径(3.7.0 上 createRewardedVideoAd 栽在\n * loadSdkSubPackage,createInterstitialAd 栽在 ADSDK 未定义)都能接住。\n *\n * 不在 ADSDK / __cloudSDKMain__ 这些全局上打桩:基础库 init 时会按子包注册表回写\n * 这些全局,占位会被覆盖掉;而 SkylineGlobal / NativeGlobal / xrFrame 等是基础库会\n * typeof 检测的能力开关,补上反而会让它走进依赖更多的分支,比缺失更糟。\n */\n\nconst UNSUPPORTED = '浏览器运行时不支持广告';\n\ntype Listener = (...args: unknown[]) => void;\n\n/** 没人接的占位调用不该变成 unhandledrejection,但返回的 promise 仍然可以被 catch */\nfunction rejected(reason: unknown): Promise<never> {\n const promise = Promise.reject(reason);\n promise.catch(() => undefined);\n return promise;\n}\n\nclass StubAd {\n private listeners: Record<string, Listener[]> = {};\n\n constructor(private readonly hideable: boolean) {}\n\n load() { return this.fail(); }\n show() { return this.fail(); }\n destroy() { this.listeners = {}; }\n\n onLoad(callback: Listener) { this.add('load', callback); }\n offLoad(callback?: Listener) { this.remove('load', callback); }\n onError(callback: Listener) { this.add('error', callback); }\n offError(callback?: Listener) { this.remove('error', callback); }\n onClose(callback: Listener) { this.add('close', callback); }\n offClose(callback?: Listener) { this.remove('close', callback); }\n\n /** 只有原生模板广告(createCustomAd)有这组接口 */\n hide() { return this.hideable ? Promise.resolve() : undefined; }\n isShow() { return this.hideable ? false : undefined; }\n onHide(callback: Listener) { if (this.hideable) this.add('hide', callback); }\n offHide(callback?: Listener) { if (this.hideable) this.remove('hide', callback); }\n\n private add(event: string, callback: Listener) {\n (this.listeners[event] = this.listeners[event] || []).push(callback);\n }\n\n private remove(event: string, callback?: Listener) {\n if (!this.listeners[event]) return;\n this.listeners[event] = callback ? this.listeners[event].filter(l => l !== callback) : [];\n }\n\n /** 真机上拉取失败也是先回调 onError 再 reject,这里保持一致 */\n private fail() {\n const error = { errCode: 1000, errMsg: UNSUPPORTED };\n queueMicrotask(() => {\n for (const listener of (this.listeners.error || []).slice()) listener({ ...error });\n });\n return rejected(error);\n }\n}\n\n/** 基础库缺少伴生子包时会返回 undefined 的广告接口 */\nexport const UNSUPPORTED_AD_APIS = [\n 'createRewardedVideoAd',\n 'createInterstitialAd',\n 'createCustomAd',\n 'createSkitAd'\n] as const;\n\nexport interface ApiStubOptions {\n /** 默认 console.warn,测试里可以注入收集 */\n warn?: (message: string) => void;\n}\n\n/** 标在占位函数上,重复调用 installApiStubs 时据此跳过 */\nconst STUB = Symbol.for('wxa-runner.apiStub') as unknown as string;\n\n/** 每次 require 都会重装一遍,提示挂在 wx 上,第一次用到广告时出一次 */\nconst WARNED = Symbol.for('wxa-runner.apiStubWarned') as unknown as string;\n\n/**\n * 替换掉基础库里这些返回 undefined 的接口。\n * 幂等:装过的不再重装,可以在每次 require 前安全调用。\n * 返回这次实际替换的名字;wx 上的属性个别基础库版本可能不可配置,那种就跳过。\n */\nexport function installApiStubs(wx: Record<string, any>, options: ApiStubOptions = {}): string[] {\n const warn = options.warn || ((message: string) => console.warn(message));\n const replaced: string[] = [];\n\n for (const name of UNSUPPORTED_AD_APIS) {\n if (wx[name]?.[STUB]) continue;\n\n const stub = () => {\n if (!wx[WARNED]) {\n wx[WARNED] = true;\n warn('[wxa-runner] 广告(WAAppAd.js)在浏览器运行时不可用,广告对象的 load/show 会失败,但不会中断页面');\n }\n return new StubAd(name === 'createCustomAd');\n };\n (stub as any)[STUB] = true;\n\n try {\n Object.defineProperty(wx, name, { value: stub, writable: true, configurable: true, enumerable: true });\n replaced.push(name);\n } catch {\n // 属性不可配置,保持基础库原样(仍会返回 undefined)\n }\n }\n\n return replaced;\n}\n","/**\n * 逻辑层的原生 WeixinWorker:基础库的 wx.createWorker 用它创建 Worker、收发消息,Worker 那一端见 runtime/worker.ts\n *\n * 和开发者工具一样,每个 Worker 是一个浏览器的 Web Worker,加载 /__wxa__/worker.js(server/html.ts 的 workerScript)。\n * create 收到的脚本名总是 workers.js(整个 workers 目录),业务指定的入口随后由基础库发消息让 Worker 去 require。\n * 基础库加载时把全局的 WeixinWorker 换成自己的包装,原始对象留给自己调用;Worker 发来的消息交给包装上的 workerMsgHandler\n */\n\nimport { fileSession } from './fileSession';\nimport type { FromWorkerMessage, HostApi, ToWorkerMessage } from './types';\n\ninterface CreateOptions {\n /** Worker 里允许调用的原生接口 */\n APIList?: string[];\n}\n\n/** 必须在基础库之前调用:基础库加载后会从全局的 __wxConfig 里删掉 workers */\nexport function createWeixinWorker(win: Window, host: HostApi) {\n const g = win as any;\n const configured = !!g.__wxConfig?.workers;\n const workers = new Map<number, Worker>();\n let nextId = 1;\n\n const send = (worker: Worker, message: ToWorkerMessage) => worker.postMessage(message);\n\n const reportError = (id: number, error: { message: string; stack?: string }) => {\n host.reportError('service', 0, error);\n // 基础库收到后交给业务的 worker.onError,没有注册时打印到逻辑层的控制台\n g.WeixinWorker.workerMsgHandler(id, { __cmd__: 'workerUncaughtError', __data__: error });\n };\n\n // Worker 以逻辑层的身份调用宿主:结果先复制到逻辑层,接口的事件也只发给逻辑层。现在能用的都是只有回调的接口,\n // 带事件的(request、connectSocket、音频)建任务要用同步接口,已在 Worker 里直接失败。\n // 支持它们之前先把 Host.invoke 的「执行接口」和「交付结果、派发事件」拆开,让宿主知道调用方是哪个 Worker,不要在这里加 Worker 的特例\n const invoke = (worker: Worker, allowed: Set<string>, { api, args, callbackId }: Extract<FromWorkerMessage, { type: 'invoke' }>) => {\n const reply = (result: unknown) => send(worker, { type: 'callback', callbackId, result });\n if (!allowed.has(api)) reply({ errMsg: `${api}:fail not support` });\n else host.invoke('service', win, api, args, reply);\n };\n\n return {\n /** 返回 Worker 的编号;没有配置 workers 时返回 -1,基础库报告 Worker 不存在 */\n create(_script: string, options: CreateOptions = {}): number {\n if (!configured) return -1;\n const id = nextId++;\n const url = `/__wxa__/worker.js?id=${id}&session=${fileSession()}`;\n const worker = new Worker(url);\n const allowed = new Set(options.APIList || []);\n worker.addEventListener('message', ({ data }: MessageEvent<FromWorkerMessage>) => {\n if (data.type === 'message') g.WeixinWorker.workerMsgHandler(id, data.data);\n else if (data.type === 'invoke') invoke(worker, allowed, data);\n else reportError(id, { message: data.message, stack: data.stack });\n });\n // 冒泡到这里的只有 Worker 基础库加载前的异常(入口或基础库加载失败等),之后的由基础库处理,见 runtime/worker.ts。\n // 入口加载失败时是没有 message 的普通 Event。不取消的话,浏览器会把它当作逻辑层的未捕获异常再报告一次\n worker.addEventListener('error', event => {\n event.preventDefault();\n reportError(id, { message: event.message || `[wxa-runner] Worker 启动失败:加载 ${url} 失败` });\n });\n workers.set(id, worker);\n return id;\n },\n /** 基础库内部的消息(如 setSharedBuffer、readCompressedFile 的结果)不序列化,直接给对象 */\n postMsgToWorker(id: number, message: unknown) {\n const worker = workers.get(id);\n if (worker) send(worker, { type: 'message', data: typeof message === 'string' ? JSON.parse(message) : message });\n },\n terminate(id: number) {\n workers.get(id)?.terminate();\n workers.delete(id);\n }\n };\n}\n","/**\n * 注入到逻辑层/渲染层 iframe 的脚本,必须在基础库之前执行\n *\n * 1. 准备开发者工具会预置的全局变量(基础库依赖它们)\n * 2. 提供 WeixinJSBridge,把调用转发给宿主\n * 3. 渲染层:模拟手机屏幕尺寸,处理鼠标输入(见 installInput)\n *\n * 新版基础库的逻辑层分主上下文和子上下文(见 context.ts)。逻辑层 iframe 是主上下文;\n * 子上下文页面也加载这个脚本(data-context-id),只准备全局变量,桥由主上下文的基础库交给它。\n */\n\nimport { hookConsole } from './consoleHook';\nimport { installWeixinJSContext } from './context';\nimport { fileSession } from './fileSession';\nimport { PROXY_PREFIX, toServerPath } from './networkPanel';\nimport { installApiStubs } from './sdkStubs';\nimport type { FrameBridge, FrameKind, HostApi } from './types';\nimport { createWeixinWorker } from './workers';\n\ntype Listener = (data: unknown, webviewId?: number) => void;\n\nconst script = document.currentScript as HTMLScriptElement;\nconst kind = (script.dataset.kind || 'webview') as FrameKind;\nconst webviewId = Number(script.dataset.webviewId || 0);\nconst subContextId = Number(script.dataset.contextId || 0);\nconst host = ((subContextId ? window.parent.parent : window.parent) as any).__wxaHost as HostApi;\nconst g = window as any;\n\ng.__global = g;\n// 用户目录按浏览器会话隔离(见 fileSession.ts),基础库读 __wxConfig 前换好。子上下文没有自己的 __wxConfig\nif (!subContextId) g.__wxConfig.env.USER_DATA_PATH = `${location.origin}/__wxa__/usr/${fileSession()}`;\n\nif (kind === 'service') {\n Object.assign(g, {\n __wxAppData: {},\n __wxRoute: undefined,\n __wxRouteBegin: undefined,\n __wxAppCode__: {},\n __wxAppCurrentFile__: undefined,\n __vd_version_info__: {},\n global: {},\n __workerVendorCode__: {},\n __workersCode__: {},\n // 创建 Worker 的基础库代码在逻辑层 iframe 里(3.8 起是主上下文),子上下文用不到\n WeixinWorker: subContextId ? {} : createWeixinWorker(window, host),\n $gwx: undefined\n });\n g.__WeixinWorker = g.WeixinWorker;\n // 真机的逻辑层没有 DOM。按全局对象上有没有 MutationObserver 判断是否在浏览器里的库(如 core-js 2 的微任务 polyfill)\n // 看到它就去用 document,而业务代码里的 document 被模块包装屏蔽了(见 AppBuilder 的 MODULE_PARAMS),app.js 执行出错\n delete g.MutationObserver;\n delete g.WebKitMutationObserver;\n // 基础库初始化完成后通过它交出 App/Page/Component/wx/define/require 等全局对象\n g.__passWAServiceGlobal__ = (globals: Record<string, unknown>) => {\n for (const key of Object.keys(globals)) {\n if (key !== 'Protect') g[key] = globals[key];\n }\n };\n // 新版基础库在业务代码所在的子上下文里自己替换 Function;单上下文的基础库(3.7.0 及以前)不替换\n const businessCodeHere = !subContextId && !script.dataset.appService;\n hookRequire(businessCodeHere ? reserveFunctionConstructor() : undefined);\n g.createCustomImage = createCustomImage;\n moveCanvasesIntoPages();\n} else {\n emulateDeviceScreen(host.device);\n installInput();\n runLoadCallbacksEarly();\n}\n\noverrideUserAgent();\n\nwindow.addEventListener('error', event => host.reportError(kind, webviewId, event.error || event.message));\nwindow.addEventListener('unhandledrejection', event => host.reportError(kind, webviewId, event.reason));\n// 生命周期、事件处理函数里的错误被基础库捕获后只用 console.error 打印,转发报错也要包装它\nif (host.forwardConsole) {\n hookConsole(host.forwardConsole === 'all' ? ['warn', 'error'] : ['error'], (level, args) => host.reportConsole(kind, webviewId, level, args));\n}\n\nif (subContextId) {\n (window.parent as any).__wxaContexts.prepare(subContextId, window);\n} else {\n const bridge = createBridge();\n g.WeixinJSBridge = bridge;\n // 基础库会用自己的包装替换 WeixinJSBridge,宿主始终通过这个引用回调\n g.__wxaBridge = bridge;\n if (script.dataset.appService) {\n installWeixinJSContext(window, host, {\n dispatchNative: bridge.__dispatchOn,\n appServiceScripts: JSON.parse(script.dataset.appService),\n hot: script.dataset.hot === '1'\n });\n }\n host.registerFrame(kind, window, bridge, webviewId);\n}\n\n/**\n * 与新版基础库的 hijack 相同:真机上业务代码用不了 Function 构造函数,除 Function('return this') 返回全局对象外,\n * 都返回 undefined、不编译参数。uni-app 的 props: { onBack: { default: Function } } 因此在真机上静默得到 undefined,\n * 不替换的话 Vue 取默认值时会把 props 对象当代码编译,抛出 SyntaxError,组件创建失败。\n *\n * 单上下文的基础库初始化时自己要用 Function,初始化完又把内置对象改成只有基础库能写的属性,到执行业务代码时已经换不掉。\n * 所以在基础库之前把 Function 和 Function.prototype.constructor 占成不可配置的存取器(基础库就不再接管),\n * 返回的函数在执行业务代码前调用,之后取到的都是禁用的版本\n */\nfunction reserveFunctionConstructor(): () => void {\n const native = Function;\n const disabled = function (...args: unknown[]) {\n if (args.length > 0 && args[args.length - 1] === 'return this') return () => g;\n };\n disabled.prototype = native.prototype;\n let current: unknown = native;\n const reserve = (target: object, key: string) => Object.defineProperty(target, key, {\n get: () => current,\n set() {},\n enumerable: false,\n configurable: false\n });\n reserve(g, 'Function');\n reserve(native.prototype, 'constructor');\n return () => {\n current = disabled;\n };\n}\n\n/**\n * 基础库初始化完会把广告等缺伴生子包的接口改成「返回 undefined」的函数,占位只有在\n * 业务代码执行前装才留得住 —— bootstrap 里 require 第一个业务模块就是那个时机。\n *\n * 这里用存取器占住 require 再等基础库赋值,而不是事后包装:基础库交出全局的方式按版本\n * 而异(3.7.0 直接写 globalThis,并不调 __passWAServiceGlobal__),事后包装没有可靠的时机。\n * installApiStubs 幂等,每次 require 都查一遍,不赌某一次调用的先后。\n */\nfunction hookRequire(beforeBusinessCode?: () => void) {\n let real: unknown;\n let businessCodeStarted = false;\n const wrapper = function (this: unknown, ...args: unknown[]) {\n if (g.wx) installApiStubs(g.wx);\n if (!businessCodeStarted) {\n businessCodeStarted = true;\n beforeBusinessCode?.();\n }\n return (real as (...a: unknown[]) => unknown).apply(this, args);\n };\n try {\n Object.defineProperty(g, 'require', {\n configurable: true,\n enumerable: true,\n get: () => (typeof real === 'function' ? wrapper : real),\n set: value => { real = value; }\n });\n } catch {\n // 定义不了就算了,广告接口退回基础库原样(返回 undefined)\n }\n}\n\n/**\n * type=\"2d\" 和 webgl 画布:基础库在 devtools 平台把它们建在逻辑层文档的 body 里,开发者工具把逻辑层透明地叠在页面上显示,\n * 画布于是盖住页面里的所有内容;真机上画布和页面元素一样参与层级。所以业务第一次取上下文时(还没开始画),\n * 请宿主把画布搬进页面里对应的 wx-canvas(见 Host.placeCanvas)。之后基础库删除画布时仍从 body 里删,那时元素已经不在这里了\n */\nfunction moveCanvasesIntoPages() {\n const { getContext } = HTMLCanvasElement.prototype;\n const { removeChild } = Node.prototype;\n // 宿主认不出的(如离屏画布)只试一次\n const tried = new WeakSet<HTMLCanvasElement>();\n\n HTMLCanvasElement.prototype.getContext = function (this: HTMLCanvasElement, ...args: unknown[]) {\n if (this.parentNode === document.body && !tried.has(this)) {\n tried.add(this);\n host.placeCanvas(this, String(args[0]));\n }\n return (getContext as (...a: unknown[]) => unknown).apply(this, args);\n } as typeof getContext;\n\n HTMLBodyElement.prototype.removeChild = function <T extends Node>(this: HTMLBodyElement, child: T): T {\n if (child.parentNode === this || !(child instanceof HTMLCanvasElement)) return removeChild.call(this, child) as T;\n child.remove();\n return child;\n };\n}\n\n/**\n * type=\"2d\" 和 webgl 画布的 createImage,开发者工具提供的原生能力(__global.createCustomImage)。\n * toUrl 把业务设置的 src 转成要加载的地址,代码包里的文件会带上开发者工具的 /__pageframe__/ 前缀;\n * fromUrl 把它还原成业务读 src 时看到的值。\n */\nfunction createCustomImage(toUrl: (src: string) => string, fromUrl: (url: string) => string): HTMLImageElement {\n let url = '';\n return new (class extends Image {\n set src(value: string) {\n url = toUrl(value);\n super.src = loadableImageUrl(url);\n }\n\n get src() {\n return fromUrl(url);\n }\n })();\n}\n\n/**\n * 代码包里的文件由开发服务器在根路径提供。其他域名的图片经代理变成同源:直接加载的话画上去会污染画布,\n * 之后读像素、导出都会失败;加 crossOrigin 又要对方返回 CORS 头,大多数图片服务器不返回。\n * 格式不对的地址原样加载,失败时走 onerror,和原生 Image 一样不在赋值时抛错\n */\nfunction loadableImageUrl(url: string): string {\n if (url.startsWith('/__pageframe__/')) return url.slice('/__pageframe__'.length);\n if (/^https?:\\/\\//i.test(url) && !url.startsWith(location.origin + '/')) return toServerPath(PROXY_PREFIX, url) ?? url;\n return url;\n}\n\nfunction createBridge(): FrameBridge & Record<string, unknown> {\n const onListeners: Record<string, Listener[]> = {};\n const subListeners: Record<string, Listener[]> = {};\n\n const add = (map: Record<string, Listener[]>, event: string, listener: Listener) => {\n (map[event] = map[event] || []).push(listener);\n };\n const remove = (map: Record<string, Listener[]>, event: string, listener?: Listener) => {\n if (!map[event]) return;\n map[event] = listener ? map[event].filter(l => l !== listener) : [];\n };\n const emit = (map: Record<string, Listener[]>, event: string, data: unknown, id?: number) => {\n for (const listener of (map[event] || []).slice()) {\n try {\n listener(data, id);\n } catch (error) {\n console.error(`[wxa-runner] ${event} 处理出错`, error);\n }\n }\n };\n\n return {\n invoke(api: string, args: unknown, callback?: (res: any) => void) {\n host.invoke(kind, window, api, args, callback);\n },\n publish(event: string, data: unknown, webviewIds?: number[]) {\n host.publish(kind, window, event, data, webviewIds);\n },\n subscribe(event: string, listener: Listener) {\n add(subListeners, event, listener);\n },\n on(event: string, listener: Listener) {\n add(onListeners, event, listener);\n },\n addEventListener(event: string, listener: Listener) {\n add(onListeners, event, listener);\n },\n removeEventListener(event: string, listener?: Listener) {\n remove(onListeners, event, listener);\n },\n addSubscribeListener(event: string, listener: Listener) {\n add(subListeners, event, listener);\n },\n removeSubscribeListener(event: string, listener?: Listener) {\n remove(subListeners, event, listener);\n },\n __dispatchOn(event: string, data: unknown, id?: number) {\n emit(onListeners, event, data, id);\n },\n __dispatchSub(event: string, data: unknown, id?: number) {\n emit(subListeners, event, data, id);\n }\n };\n}\n\n/**\n * wcsc 生成的 rpx 换算读取 window.screen.width,桌面浏览器里那是显示器宽度,\n * 这里改成模拟设备的尺寸。\n */\nfunction emulateDeviceScreen(device: HostApi['device']) {\n const values: Record<string, number> = {\n width: device.screenWidth,\n height: device.screenHeight,\n availWidth: device.screenWidth,\n availHeight: device.screenHeight\n };\n for (const key of Object.keys(values)) {\n try {\n Object.defineProperty(window.screen, key, { get: () => values[key], configurable: true });\n } catch {\n // 个别浏览器不允许重定义,退回到真实值\n }\n }\n // 桌面浏览器报告横屏,基础库会因此改用 screen.height 作为设备宽度换算 rpx\n const portrait = {\n type: 'portrait-primary',\n angle: 0,\n onchange: null,\n addEventListener() {},\n removeEventListener() {},\n dispatchEvent: () => false,\n lock: () => Promise.reject(new Error('not supported')),\n unlock() {}\n };\n try {\n Object.defineProperty(window.screen, 'orientation', { get: () => portrait, configurable: true });\n } catch {\n // 同上\n }\n try {\n Object.defineProperty(window, 'devicePixelRatio', { get: () => device.pixelRatio, configurable: true });\n } catch {\n // 同上\n }\n}\n\n/**\n * 基础库在文档没加载完时,把内置组件样式(wx-view 的 display、wx-canvas 的默认尺寸等)推迟到\n * window.onload 再注入。开发者工具在文档加载完后才注入基础库,那边是立即注入;这里基础库随页面\n * 同步加载,首屏渲染早于 onload,canvas 这类挂载时测量尺寸的组件会量到没有样式时的大小。\n * 所以加载完成前赋给 window.onload 的回调改为在当前脚本执行完后立即运行,仍早于首屏渲染。\n * 效果与开发者工具一致:那边每处都直接调用回调,多次赋值各自执行,window.onload 本身始终为空。\n */\nfunction runLoadCallbacksEarly() {\n let owner: object | null = window;\n while (owner && !Object.getOwnPropertyDescriptor(owner, 'onload')) owner = Object.getPrototypeOf(owner);\n const native = owner && Object.getOwnPropertyDescriptor(owner, 'onload');\n if (!native?.get || !native.set) return;\n Object.defineProperty(window, 'onload', {\n configurable: true,\n get: () => native.get!.call(window),\n set(handler: unknown) {\n if (typeof handler === 'function' && document.readyState !== 'complete') {\n queueMicrotask(() => handler.call(window, new Event('load')));\n } else {\n native.set!.call(window, handler);\n }\n }\n });\n}\n\nfunction overrideUserAgent() {\n const ua = `${navigator.userAgent} (iPhone; wxa-runner) MicroMessenger/8.0.50 miniProgram`;\n try {\n Object.defineProperty(navigator, 'userAgent', { get: () => ua, configurable: true });\n } catch {\n // 只影响基础库对平台的判断,失败可以忽略\n }\n}\n\n/**\n * 鼠标输入 → 触摸事件\n *\n * 模拟的是手机,页面只应收到触摸事件。基础库在部分版本/平台上会自己把鼠标或 pointer 事件\n * 转换为触摸,和这里的转换叠加会导致一次点击触发两次 tap,所以在 window 捕获阶段\n * (先于基础库注册的任何监听)拦下鼠标类事件。不调用 preventDefault,输入框聚焦等默认行为不受影响。\n *\n * 另外,基础库在元素滚动后 50ms 内会把触摸当作滑动、取消 tap。自动化测试常常是\n * 「滚动到元素 → 立刻点击」,而 scroll 事件要到下一帧才派发,所以按下时先等两帧\n * 让挂起的 scroll 事件派发完,刚滚动过的话再顺延到窗口之后。同一次按压的事件按原顺序派发。\n *\n * 按下后移出 TOUCH_SLOP 之前的 mousemove 不转成 touchmove(类似触屏的 touch slop)。swiper 等组件\n * 按第一个 touchmove 的位移判断手势方向,鼠标刚拖动时常先抖出 1px 的竖向位移,直接转发的话横向拖动\n * 会被判成竖向、整次拖动都被忽略。阈值小于基础库取消 tap 的 10px,点击和长按不受影响。\n * 没移出阈值就松手时,先补一个到松手位置的 touchmove,slider 微调、画短笔画这类小幅拖动不会丢。\n */\nfunction installInput() {\n const SCROLL_TAP_GUARD = 80;\n const TOUCH_SLOP = 8;\n let lastScroll = 0;\n let queue: Promise<void> = Promise.resolve();\n let target: EventTarget | null = null;\n let start: { x: number; y: number } | null = null;\n\n document.addEventListener('scroll', () => {\n lastScroll = Date.now();\n }, true);\n\n const nextFrame = () => new Promise<void>(resolve => requestAnimationFrame(() => resolve()));\n const sleep = (ms: number) => new Promise<void>(resolve => setTimeout(resolve, ms));\n\n const fire = (type: 'touchstart' | 'touchmove' | 'touchend', event: MouseEvent, eventTarget: EventTarget) => {\n const point = {\n clientX: event.clientX,\n clientY: event.clientY,\n pageX: event.pageX,\n pageY: event.pageY,\n screenX: event.screenX,\n screenY: event.screenY\n };\n queue = queue.then(async () => {\n if (type === 'touchstart') {\n await nextFrame();\n await nextFrame();\n const wait = lastScroll + SCROLL_TAP_GUARD - Date.now();\n if (wait > 0) await sleep(wait);\n }\n const touch = new Touch({ identifier: 1, target: eventTarget, ...point });\n const active = type === 'touchend' ? [] : [touch];\n eventTarget.dispatchEvent(new TouchEvent(type, {\n bubbles: true,\n cancelable: true,\n composed: true,\n touches: active,\n targetTouches: active,\n changedTouches: [touch]\n }));\n });\n };\n\n window.addEventListener('mousedown', event => {\n event.stopImmediatePropagation();\n if (event.button !== 0 || !event.target) return;\n target = event.target;\n start = { x: event.clientX, y: event.clientY };\n fire('touchstart', event, target);\n }, true);\n window.addEventListener('mousemove', event => {\n event.stopImmediatePropagation();\n if (!target) return;\n if (start) {\n if (Math.hypot(event.clientX - start.x, event.clientY - start.y) < TOUCH_SLOP) return;\n start = null;\n }\n fire('touchmove', event, target);\n }, true);\n window.addEventListener('mouseup', event => {\n event.stopImmediatePropagation();\n if (!target) return;\n if (start && (event.clientX !== start.x || event.clientY !== start.y)) {\n fire('touchmove', event, target);\n // movable-view 等组件在下一帧才应用位移,同一帧里就收到 touchend 的话这段位移会被丢掉\n queue = queue.then(nextFrame);\n }\n fire('touchend', event, target);\n target = null;\n }, true);\n for (const type of ['pointerdown', 'pointermove', 'pointerup', 'pointercancel']) {\n window.addEventListener(type, event => {\n if ((event as PointerEvent).pointerType !== 'touch') event.stopImmediatePropagation();\n }, true);\n }\n}\n"],"mappings":"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","names":["script","host","script","host","g"]}
1
+ {"version":3,"sources":["../../src/runtime/consoleHook.ts","../../src/runtime/syncScript.ts","../../src/runtime/context.ts","../../src/runtime/fileSession.ts","../../src/runtime/networkPanel.ts","../../src/runtime/sdkStubs.ts","../../src/runtime/workers.ts","../../src/runtime/frame.ts"],"sourcesContent":["/**\n * 包装 iframe 里的 console:照常打印,同时交给宿主转发到终端\n *\n * 开发服务器把这个文件列入 frame.js 的 source map 的忽略列表,DevTools 跳过这层包装,\n * 控制台里的来源链接仍指向调用 console 的业务代码\n */\n\nexport type ConsoleLevel = 'warn' | 'error';\n\nexport function hookConsole(levels: ConsoleLevel[], report: (level: ConsoleLevel, args: unknown[]) => void) {\n for (const level of levels) {\n const original = console[level];\n console[level] = function (this: Console, ...args: unknown[]) {\n original.apply(this, args);\n try {\n report(level, args);\n } catch {\n // 转发出错不能影响业务代码\n }\n };\n }\n}\n","/**\n * 同步执行脚本:与开发者工具的 loadLibFiles 一致,同步请求脚本内容,以内联脚本执行\n */\n\n/** @throws 状态码不是 200 */\nexport function readSync(url: string): string {\n const xhr = new XMLHttpRequest();\n xhr.open('GET', url, false);\n xhr.send();\n if (xhr.status !== 200) throw new Error(`[wxa-runner] 加载 ${url} 失败:${xhr.status}`);\n return xhr.responseText;\n}\n\n/** 在 win 里执行完才返回;DevTools 里显示为 url 这个文件 */\nexport function runScript(win: Window, url: string, code: string) {\n const href = new URL(url, location.href).href;\n // 基础库文件同样加入 DevTools 的忽略列表(见 server/ignoreList.ts)\n const sourceMap = url.startsWith('/__baselib__/') ? `\\n//# sourceMappingURL=${href}.map` : '';\n const script = win.document.createElement('script');\n script.text = `${code}\\n//# sourceURL=${href}${sourceMap}`;\n win.document.head.appendChild(script);\n}\n","/**\n * 模拟原生 WeixinJSContext(3.7.1 起的基础库需要)\n *\n * 新版基础库把逻辑层分成主上下文和子上下文:逻辑层 iframe 是主上下文,运行 WAServiceMainContext.js,\n * 持有 WeixinJSBridge;App / Page / wx 和业务代码在子上下文里,子上下文由主上下文通过这个接口创建。\n * 与开发者工具一样,每个子上下文是逻辑层 iframe 里的一个同源 iframe(subcontext.html)。\n *\n * 两边的消息不经过这里:子上下文拿到同一个 WeixinJSContext 对象,主上下文初始化时在上面挂了\n * register / subscribeHandler,双方直接互相调用。\n *\n * 交给基础库的 WeixinJSContext 是一次性的门面:基础库初始化时取走上面的方法、再把它们删掉,\n * 所以这里的逻辑都不经过它。\n */\n\nimport { readSync, runScript } from './syncScript';\nimport type { HostApi } from './types';\n\nconst MAIN_CONTEXT_ID = 1;\n/** 业务代码所在的子上下文 */\nconst APP_CONTEXT_NAME = 'app';\n/** 基础库要执行的业务代码入口,对应构建出的 define 脚本和 bootstrap */\nconst APP_SERVICE_ENTRY = 'app-service.js';\n/** 从基础库开始执行到业务代码执行完的最长时间 */\nconst BOOT_TIMEOUT = 10000;\n\ntype Callback = () => void;\n\nexport interface WeixinJSContextOptions {\n /** 向主上下文派发原生事件(WeixinJSBridge.on) */\n dispatchNative: (event: string, data: unknown) => void;\n /** 业务代码的脚本地址,基础库执行 app-service.js 时按顺序加载 */\n appServiceScripts: string[];\n /** 打开基础库的热更新开关(见 server/html.ts 的 enableHotUpdate) */\n hot: boolean;\n}\n\n/** 在逻辑层主上下文里提供 window.WeixinJSContext,必须在基础库之前调用 */\nexport function installWeixinJSContext(main: Window, host: HostApi, options: WeixinJSContextOptions) {\n const contexts = new JsContexts(main, host, options);\n (main as any).WeixinJSContext = contexts.nativeInterface;\n // subcontext.html 通过 parent.__wxaContexts 回调这两个入口\n (main as any).__wxaContexts = {\n prepare: (id: number, win: Window) => contexts.prepare(id, win),\n loaded: (id: number) => contexts.loaded(id)\n };\n}\n\n/**\n * 单上下文的基础库(3.7.0 及以前)也读 WeixinJSContext,只用它的 loadLibFiles 加载广告、云开发等伴生 SDK\n * (WAAppAd.js、WACloud.js)。没有这个接口时,基础库认为自己在「真机调试 1.0」里,业务代码一读到这些能力\n * 就抛 Fatal: unexpected loadSdkSubPackage case;Taro 等框架启动时遍历全局对象,也会读到。\n *\n * 只报告加载成功、不执行文件:基础库在 devtools 平台上把 SDK 依赖的 getXGlobalVar 挂在内部对象上,SDK 文件\n * 在这里拿不到,执行了也只是各自报 t is not a function;返回失败则报一串 WAFiles … is not exist。报告成功后\n * 基础库退回自带的部分:wx.cloud 的接口本体在 WAService.js 里,调用经 operateWXData 明确失败(见 host/api/misc.ts);\n * 其余 SDK 的全局由 sdkStubs 的 guardSdkGlobals 当作不存在,广告接口由 installApiStubs 接住。\n * 必须在基础库之前调用,基础库初始化时取走它再删掉\n */\nexport function installSingleContextLibLoader(service: Window) {\n (service as any).WeixinJSContext = { loadLibFiles: () => 1 };\n}\n\n/** 主上下文和它创建的子上下文 */\nclass JsContexts {\n private readonly boot: AppBoot;\n private readonly mainContext: JsContext;\n private readonly contexts = new Map<number, JsContext>();\n private nextId = MAIN_CONTEXT_ID + 1;\n\n /** 交给基础库的原生接口。基础库会把方法取下来单独调用,所以都不依赖 this */\n readonly nativeInterface = {\n mainContextId: MAIN_CONTEXT_ID,\n alloc: (name?: string, callback?: Callback) => this.open(name, false).whenReady(callback).id,\n allocEmpty: (name?: string, callback?: Callback) => this.open(name, true).whenReady(callback).id,\n create: (entry: string | undefined, name?: string, callback?: Callback) => {\n const context = this.open(name, false);\n context.whenReady(entry ? () => this.evaluate(context, entry, callback) : callback);\n return context.id;\n },\n evaluateScriptFile: (id: number, file: string, callback?: Callback) =>\n this.withContext(id, context => this.evaluate(context, file, callback)),\n loadJsFiles: (id: number, files: string, callback?: Callback) =>\n this.withContext(id, context => this.evaluateAll(context, JSON.parse(files), callback)),\n /** 基础库自己的文件(如 WARenderContext.js),同步执行 */\n loadLibFiles: (id: number, files: string) =>\n this.withContext(id, context => {\n context.runSync((JSON.parse(files) as string[]).map(file => `/__baselib__/${file}`));\n return 1;\n }),\n destroy: (id: number, callback?: Callback) => this.destroy(id, callback)\n };\n\n constructor(private readonly main: Window, private readonly host: HostApi, private readonly options: WeixinJSContextOptions) {\n this.boot = new AppBoot(host);\n this.mainContext = new JsContext(MAIN_CONTEXT_ID, 'main', main);\n this.contexts.set(MAIN_CONTEXT_ID, this.mainContext);\n }\n\n /** 子上下文页面开始执行,基础库之前:交给它基础库需要的全局变量 */\n prepare(id: number, win: Window) {\n const context = this.contexts.get(id);\n if (!context || context === this.mainContext) throw new Error(`[wxa-runner] 未知的子上下文 ${id}`);\n context.win = win;\n Object.assign(win, { WeixinJSContext: this.nativeInterface, WeixinJSContextId: id, __wxConfig: (this.main as any).__wxConfig });\n if (context.isApp) this.host.registerAppContext(win);\n }\n\n /** 子上下文页面执行完(基础库已初始化) */\n loaded(id: number) {\n const context = this.contexts.get(id);\n if (!context) return;\n context.markReady();\n if (context.isApp) {\n this.boot.reach('entry');\n // 真机上由客户端在主包就绪后派发,基础库收到后才执行业务入口\n this.options.dispatchNative('onSubPackageReady', { moduleName: '__APP__' });\n }\n }\n\n private open(name: string | undefined, empty: boolean): JsContext {\n const context = openSubContext(this.main, this.nextId++, name, empty);\n this.contexts.set(context.id, context);\n if (context.isApp) this.boot.reach('load');\n return context;\n }\n\n /** 原生接口的结果码:1 成功,0 失败 */\n private withContext(id: number, action: (context: JsContext) => number): number {\n const context = this.contexts.get(Number(id));\n if (context) return action(context);\n console.warn(`[wxa-runner] 找不到 JS 上下文 ${id}`);\n return 0;\n }\n\n /** 执行基础库要求的脚本文件:带回调时等上下文加载完再异步执行,否则同步执行 */\n private evaluate(context: JsContext, file: string, done?: Callback): number {\n // 基础库只会要求执行业务代码入口\n if (!context.isApp || file.replace(/^\\/+/, '') !== APP_SERVICE_ENTRY) {\n console.warn(`[wxa-runner] 基础库要求执行未知脚本 ${file}`);\n return 0;\n }\n const urls = this.options.appServiceScripts;\n if (done) {\n context.whenReady(() => {\n this.startApp(context);\n loadScripts(context.win!, urls, () => {\n done();\n this.boot.finish();\n });\n });\n } else {\n this.startApp(context);\n context.runSync(urls);\n this.boot.finish();\n }\n return 1;\n }\n\n private startApp(context: JsContext) {\n this.boot.reach('run');\n // 与旧版基础库一样,必须在业务代码注册 Page / Component 之前打开\n if (this.options.hot) (context.win as any).__virtualDOM__?.enableUpdateWxAppCode?.();\n }\n\n private evaluateAll(context: JsContext, files: string[], done?: Callback): number {\n if (!done) return files.every(file => this.evaluate(context, file) === 1) ? 1 : 0;\n let remaining = files.length;\n if (remaining === 0) done();\n for (const file of files) {\n if (this.evaluate(context, file, () => --remaining === 0 && done()) === 0) return 0;\n }\n return 1;\n }\n\n private destroy(id: number, callback?: Callback) {\n const context = this.contexts.get(Number(id));\n if (!context || context === this.mainContext) return;\n this.contexts.delete(context.id);\n context.destroy();\n if (context.isApp) this.host.registerAppContext(null);\n callback?.();\n }\n}\n\n/** 一个 JS 上下文:主上下文是逻辑层 iframe 本身,子上下文是其中的一个同源 iframe */\nclass JsContext {\n /** 页面加载完之前收到的任务;加载完后为 null */\n private pending: Callback[] | null;\n\n constructor(readonly id: number, readonly name: string, public win: Window | null, private readonly iframe?: HTMLIFrameElement) {\n this.pending = win ? null : [];\n }\n\n get isApp(): boolean {\n return this.name === APP_CONTEXT_NAME;\n }\n\n /** 加载完后执行,已加载完时立即执行 */\n whenReady(task?: Callback): this {\n if (task) {\n if (this.pending) this.pending.push(task);\n else task();\n }\n return this;\n }\n\n markReady() {\n const tasks = this.pending || [];\n this.pending = null;\n tasks.forEach(task => task());\n }\n\n runSync(urls: string[]) {\n if (this.pending) throw new Error(`[wxa-runner] JS 上下文 ${this.id} 尚未加载完,不能同步执行脚本`);\n for (const url of urls) runScript(this.win!, url, readSync(url));\n }\n\n destroy() {\n this.pending = [];\n this.iframe?.remove();\n }\n}\n\nfunction openSubContext(main: Window, id: number, name: string | undefined, empty: boolean): JsContext {\n const iframe = main.document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.src = `/__wxa__/subcontext.html?id=${id}${empty ? '&empty=1' : ''}`;\n // 基础库在逻辑层页面的 <head> 里执行时就会创建子上下文,那时还没有 body\n main.document.documentElement.appendChild(iframe);\n return new JsContext(id, name || `context${id}`, null, iframe);\n}\n\nconst BOOT_STAGES = {\n alloc: `基础库没有创建业务子上下文(名为 ${APP_CONTEXT_NAME} 的子上下文)`,\n load: '业务子上下文没有加载完(WASubContext.js 加载或执行出错)',\n entry: `基础库没有执行业务代码入口 ${APP_SERVICE_ENTRY}`,\n run: '业务代码没有加载完'\n};\n\ntype BootStage = keyof typeof BOOT_STAGES;\n\n/**\n * 业务代码的启动过程,每一步都依赖基础库的内部行为:\n * 创建业务子上下文 → 子上下文加载完 → 派发 onSubPackageReady → 基础库执行业务入口 → 业务代码执行完。\n * 任何一步没发生,宿主都会一直等逻辑层就绪,所以超时后报告停在哪一步,照常结束启动\n */\nclass AppBoot {\n private stage: BootStage = 'alloc';\n private finished = false;\n private readonly timer: ReturnType<typeof setTimeout>;\n\n constructor(private readonly host: HostApi) {\n this.timer = setTimeout(() => {\n this.finish(new Error(`[wxa-runner] 逻辑层 ${BOOT_TIMEOUT}ms 内没有就绪:${BOOT_STAGES[this.stage]}`));\n }, BOOT_TIMEOUT);\n }\n\n reach(stage: BootStage) {\n this.stage = stage;\n }\n\n /** 通知宿主逻辑层就绪,只通知一次;出错时先报告错误 */\n finish(error?: Error) {\n if (this.finished) return;\n this.finished = true;\n clearTimeout(this.timer);\n if (error) {\n console.error(error.message);\n this.host.reportError('service', 0, error);\n }\n this.host.frameLoaded('service', 0);\n }\n}\n\n/** 按顺序加载外部脚本(保留文件名和行号,便于在 DevTools 里调试),全部执行完后回调 */\nfunction loadScripts(win: Window, urls: string[], done: Callback) {\n let remaining = urls.length;\n if (remaining === 0) {\n done();\n return;\n }\n for (const url of urls) {\n const script = win.document.createElement('script');\n script.async = false;\n script.src = url;\n const settle = () => {\n if (--remaining === 0) done();\n };\n script.onload = settle;\n script.onerror = () => {\n console.error(`[wxa-runner] 加载 ${url} 失败`);\n settle();\n };\n win.document.head.appendChild(script);\n }\n}\n","/**\n * 文件会话:开发服务器上每个会话一份用户文件和临时文件(见 DevServer 的 /__wxa__/fs)。\n * 标识和 Storage 一样存在 localStorage:刷新后不变,同一浏览器上下文的页面共用,新的上下文(Playwright 的每个用例)另起一份\n */\nconst KEY = '__wxa_file_session__';\n\nexport function fileSession(): string {\n let session = localStorage.getItem(KEY);\n if (!session) {\n session = crypto.randomUUID();\n localStorage.setItem(KEY, session);\n }\n return session;\n}\n","/**\n * 小程序的请求在浏览器 Network 面板里的样子,宿主、Service Worker 和开发服务器共用\n *\n * 原地址放在路径里:/__wxa__/proxy/https/api.example.com/user/info?id=1。Name 列显示接口名(info?id=1),\n * 按域名、路径过滤也直接可用;放在查询参数里时每一行都是 proxy?url=https%3A%2F%2F…,分不出是哪个接口。\n *\n * - 经开发服务器转发的请求:/__wxa__/proxy/…\n * - 被拦截规则拦下的请求:/__wxa__/mock/…,由 Service Worker 返回规则给出的响应,只用于显示(见 sw.ts)\n */\n\nimport type { MockedResponse } from './host/api/routes';\n\nexport const PROXY_PREFIX = '/__wxa__/proxy/';\nexport const MOCK_PREFIX = '/__wxa__/mock/';\n\n/** 显示被拦截请求的 fetch 带上这个头,Service Worker 凭它向宿主要对应的响应 */\nexport const MOCK_ID_HEADER = 'x-wxa-mock-id';\n\n/** Service Worker 向宿主要响应时发的消息,附带一个 MessagePort,宿主从这个端口回复 MockReply */\nexport interface MockQuery {\n type: 'wxa-mock-response';\n id: string;\n}\n\n/** 请求被取消、拦截规则出错,或宿主已经不认识这个 id 时为 null,Network 面板里显示为失败 */\nexport type MockReply = MockedResponse | null;\n\n/**\n * 原地址在开发服务器上对应的路径,prefix 是 PROXY_PREFIX 或 MOCK_PREFIX。不是 http(s) 地址时返回 null\n *\n * 先按 URL 规范化:路径里的 .. 要在拼接前解析掉,否则浏览器会在代理路径上解析,把域名那一段也吃掉\n */\nexport function toServerPath(prefix: string, url: string): string | null {\n let target: URL;\n try {\n target = new URL(url);\n } catch {\n return null;\n }\n if (target.protocol !== 'http:' && target.protocol !== 'https:') return null;\n return `${prefix}${target.protocol.slice(0, -1)}/${target.host}${target.pathname}${target.search}`;\n}\n\n/**\n * toServerPath 的逆运算,格式不对或还原出的地址不合法时返回 null\n *\n * 只校验不规范化,返回拼出的原样字符串:路径里的 %2F 等编码要原样转发\n */\nexport function fromServerPath(prefix: string, serverPath: string): string | null {\n if (!serverPath.startsWith(prefix)) return null;\n const match = /^(https?)\\/([^/?#]+)(.*)$/.exec(serverPath.slice(prefix.length));\n if (!match) return null;\n const url = `${match[1]}://${match[2]}${match[3]}`;\n try {\n new URL(url);\n return url;\n } catch {\n return null;\n }\n}\n\n/**\n * 用于显示的请求、响应头。浏览器不允许设置的(cookie、set-cookie 等)会被忽略,\n * 名字或值不合法的(如值里有中文)跳过:它们只影响 Network 面板里的显示,小程序拿到的头不受影响。\n * 值为 undefined、null 的和代理一样不发\n */\nexport function toHeaders(header: Record<string, unknown>): Headers {\n const headers = new Headers();\n for (const [name, value] of Object.entries(header)) {\n if (value === undefined || value === null) continue;\n try {\n headers.set(name, String(value));\n } catch {\n // 跳过\n }\n }\n return headers;\n}\n","/**\n * 基础库伴生 SDK 子包能力的占位实现\n *\n * WAService.js 不是自包含的。广告、云开发、米大师支付等能力放在一组伴生文件里\n * (WAAppAd.js / WACloud.js / WAMidasSDK.js 等),真机和开发者工具由原生层调用\n * loadMainContextLibFile 把它们同步加载进同一个上下文,再把导出挂到约定的全局名上\n * (WAAppAd.js → globalThis.AD → 基础库读作 ADSDK)。运行时没有这套加载机制。\n *\n * 缺失不会直接抛到业务代码:基础库把内部异常包成 appServiceSDKScriptError 自己吞掉,\n * 于是 wx.createRewardedVideoAd() 返回 undefined。真正崩的是下一行业务代码\n * ——`ad.onError(...)`,Cannot read properties of undefined。所以占位放在 wx 这一层,\n * 不管基础库内部走的是哪条失败路径(3.7.0 上 createRewardedVideoAd 栽在\n * loadSdkSubPackage,createInterstitialAd 栽在 ADSDK 未定义)都能接住。\n *\n * 不在 ADSDK / __cloudSDKMain__ 这些全局上打桩:基础库 init 时会按子包注册表回写\n * 这些全局,占位会被覆盖掉;而 SkylineGlobal / NativeGlobal / xrFrame 等是基础库会\n * typeof 检测的能力开关,补上反而会让它走进依赖更多的分支,比缺失更糟。\n */\n\nconst UNSUPPORTED = '浏览器运行时不支持广告';\n\ntype Listener = (...args: unknown[]) => void;\n\n/** 没人接的占位调用不该变成 unhandledrejection,但返回的 promise 仍然可以被 catch */\nfunction rejected(reason: unknown): Promise<never> {\n const promise = Promise.reject(reason);\n promise.catch(() => undefined);\n return promise;\n}\n\nclass StubAd {\n private listeners: Record<string, Listener[]> = {};\n\n constructor(private readonly hideable: boolean) {}\n\n load() { return this.fail(); }\n show() { return this.fail(); }\n destroy() { this.listeners = {}; }\n\n onLoad(callback: Listener) { this.add('load', callback); }\n offLoad(callback?: Listener) { this.remove('load', callback); }\n onError(callback: Listener) { this.add('error', callback); }\n offError(callback?: Listener) { this.remove('error', callback); }\n onClose(callback: Listener) { this.add('close', callback); }\n offClose(callback?: Listener) { this.remove('close', callback); }\n\n /** 只有原生模板广告(createCustomAd)有这组接口 */\n hide() { return this.hideable ? Promise.resolve() : undefined; }\n isShow() { return this.hideable ? false : undefined; }\n onHide(callback: Listener) { if (this.hideable) this.add('hide', callback); }\n offHide(callback?: Listener) { if (this.hideable) this.remove('hide', callback); }\n\n private add(event: string, callback: Listener) {\n (this.listeners[event] = this.listeners[event] || []).push(callback);\n }\n\n private remove(event: string, callback?: Listener) {\n if (!this.listeners[event]) return;\n this.listeners[event] = callback ? this.listeners[event].filter(l => l !== callback) : [];\n }\n\n /** 真机上拉取失败也是先回调 onError 再 reject,这里保持一致 */\n private fail() {\n const error = { errCode: 1000, errMsg: UNSUPPORTED };\n queueMicrotask(() => {\n for (const listener of (this.listeners.error || []).slice()) listener({ ...error });\n });\n return rejected(error);\n }\n}\n\n/** 基础库缺少伴生子包时会返回 undefined 的广告接口 */\nexport const UNSUPPORTED_AD_APIS = [\n 'createRewardedVideoAd',\n 'createInterstitialAd',\n 'createCustomAd',\n 'createSkitAd'\n] as const;\n\nexport interface ApiStubOptions {\n /** 默认 console.warn,测试里可以注入收集 */\n warn?: (message: string) => void;\n}\n\n/** 标在占位函数上,重复调用 installApiStubs 时据此跳过 */\nconst STUB = Symbol.for('wxa-runner.apiStub') as unknown as string;\n\n/** 每次 require 都会重装一遍,提示挂在 wx 上,第一次用到广告时出一次 */\nconst WARNED = Symbol.for('wxa-runner.apiStubWarned') as unknown as string;\n\n/**\n * 替换掉基础库里这些返回 undefined 的接口。\n * 幂等:装过的不再重装,可以在每次 require 前安全调用。\n * 返回这次实际替换的名字;wx 上的属性个别基础库版本可能不可配置,那种就跳过。\n */\nexport function installApiStubs(wx: Record<string, any>, options: ApiStubOptions = {}): string[] {\n const warn = options.warn || ((message: string) => console.warn(message));\n const replaced: string[] = [];\n\n for (const name of UNSUPPORTED_AD_APIS) {\n if (wx[name]?.[STUB]) continue;\n\n const stub = () => {\n if (!wx[WARNED]) {\n wx[WARNED] = true;\n warn('[wxa-runner] 广告(WAAppAd.js)在浏览器运行时不可用,广告对象的 load/show 会失败,但不会中断页面');\n }\n return new StubAd(name === 'createCustomAd');\n };\n (stub as any)[STUB] = true;\n\n try {\n Object.defineProperty(wx, name, { value: stub, writable: true, configurable: true, enumerable: true });\n replaced.push(name);\n } catch {\n // 属性不可配置,保持基础库原样(仍会返回 undefined)\n }\n }\n\n return replaced;\n}\n\n/** 单上下文里唯一要照常读取的伴生 SDK 全局:云开发的接口本体在 WAService.js 里,wx.cloud 就是经它取到的 */\nconst BUILT_IN_SDK_GLOBALS = new Set(['__cloudSDKMain__']);\n\n/**\n * 单上下文的基础库(3.7.0 及以前)把伴生 SDK 挂成全局对象上的懒加载存取器(ADSDK、MidasSDK、__sclEngine__ 等),\n * 第一次读时才加载。这种上下文里它们加载不了(见 context.ts 的 installSingleContextLibLoader),读一次的后果是:\n * - 有的存取器直接抛 TypeError(往 undefined 上写 inject)。业务代码一般不直接读它们,但 Taro 等框架启动时\n * 把全局对象上的属性逐个拷到自己的 window 上,一读就中断 app.js\n * - 不抛错的,基础库也会把这个 SDK 标成已注入,之后自己去用它。如 2.32.3 首屏渲染时调 ADSDK.getPreloadAdUnitIds(),\n * 页面渲染不出来\n *\n * 所以在业务代码执行前,把基础库加上的、可重新定义的存取器换成返回 undefined,不触发加载,等同这个 SDK 不存在。\n * 只看基础库加上的(不在 before 里),不按名字列:各版本的伴生 SDK 不一样。读取不提示,真用到广告时由\n * installApiStubs 的占位提示;基础库之后回写这些全局不受影响。\n *\n * @param before 基础库执行前全局对象上已有的属性名\n * @returns 换掉了的属性名\n */\nexport function guardSdkGlobals(global: object, before: ReadonlySet<string>): string[] {\n const guarded: string[] = [];\n for (const key of Object.getOwnPropertyNames(global)) {\n if (before.has(key) || BUILT_IN_SDK_GLOBALS.has(key)) continue;\n const descriptor = Object.getOwnPropertyDescriptor(global, key);\n if (!descriptor?.get || !descriptor.configurable) continue;\n Object.defineProperty(global, key, { get: () => undefined, enumerable: descriptor.enumerable, configurable: true });\n guarded.push(key);\n }\n return guarded;\n}\n","/**\n * 逻辑层的原生 WeixinWorker:基础库的 wx.createWorker 用它创建 Worker、收发消息,Worker 那一端见 runtime/worker.ts\n *\n * 和开发者工具一样,每个 Worker 是一个浏览器的 Web Worker,加载 /__wxa__/worker.js(server/html.ts 的 workerScript)。\n * create 收到的脚本名总是 workers.js(整个 workers 目录),业务指定的入口随后由基础库发消息让 Worker 去 require。\n * 基础库加载时把全局的 WeixinWorker 换成自己的包装,原始对象留给自己调用;Worker 发来的消息交给包装上的 workerMsgHandler\n */\n\nimport { fileSession } from './fileSession';\nimport type { FromWorkerMessage, HostApi, ToWorkerMessage } from './types';\n\ninterface CreateOptions {\n /** Worker 里允许调用的原生接口 */\n APIList?: string[];\n}\n\n/** 必须在基础库之前调用:基础库加载后会从全局的 __wxConfig 里删掉 workers */\nexport function createWeixinWorker(win: Window, host: HostApi) {\n const g = win as any;\n const configured = !!g.__wxConfig?.workers;\n const workers = new Map<number, Worker>();\n let nextId = 1;\n\n const send = (worker: Worker, message: ToWorkerMessage) => worker.postMessage(message);\n\n const reportError = (id: number, error: { message: string; stack?: string }) => {\n host.reportError('service', 0, error);\n // 基础库收到后交给业务的 worker.onError,没有注册时打印到逻辑层的控制台\n g.WeixinWorker.workerMsgHandler(id, { __cmd__: 'workerUncaughtError', __data__: error });\n };\n\n // Worker 以逻辑层的身份调用宿主:结果先复制到逻辑层,接口的事件也只发给逻辑层。现在能用的都是只有回调的接口,\n // 带事件的(request、connectSocket、音频)建任务要用同步接口,已在 Worker 里直接失败。\n // 支持它们之前先把 Host.invoke 的「执行接口」和「交付结果、派发事件」拆开,让宿主知道调用方是哪个 Worker,不要在这里加 Worker 的特例\n const invoke = (worker: Worker, allowed: Set<string>, { api, args, callbackId }: Extract<FromWorkerMessage, { type: 'invoke' }>) => {\n const reply = (result: unknown) => send(worker, { type: 'callback', callbackId, result });\n if (!allowed.has(api)) reply({ errMsg: `${api}:fail not support` });\n else host.invoke('service', win, api, args, reply);\n };\n\n return {\n /** 返回 Worker 的编号;没有配置 workers 时返回 -1,基础库报告 Worker 不存在 */\n create(_script: string, options: CreateOptions = {}): number {\n if (!configured) return -1;\n const id = nextId++;\n const url = `/__wxa__/worker.js?id=${id}&session=${fileSession()}`;\n const worker = new Worker(url);\n const allowed = new Set(options.APIList || []);\n worker.addEventListener('message', ({ data }: MessageEvent<FromWorkerMessage>) => {\n if (data.type === 'message') g.WeixinWorker.workerMsgHandler(id, data.data);\n else if (data.type === 'invoke') invoke(worker, allowed, data);\n else reportError(id, { message: data.message, stack: data.stack });\n });\n // 冒泡到这里的只有 Worker 基础库加载前的异常(入口或基础库加载失败等),之后的由基础库处理,见 runtime/worker.ts。\n // 入口加载失败时是没有 message 的普通 Event。不取消的话,浏览器会把它当作逻辑层的未捕获异常再报告一次\n worker.addEventListener('error', event => {\n event.preventDefault();\n reportError(id, { message: event.message || `[wxa-runner] Worker 启动失败:加载 ${url} 失败` });\n });\n workers.set(id, worker);\n return id;\n },\n /** 基础库内部的消息(如 setSharedBuffer、readCompressedFile 的结果)不序列化,直接给对象 */\n postMsgToWorker(id: number, message: unknown) {\n const worker = workers.get(id);\n if (worker) send(worker, { type: 'message', data: typeof message === 'string' ? JSON.parse(message) : message });\n },\n terminate(id: number) {\n workers.get(id)?.terminate();\n workers.delete(id);\n }\n };\n}\n","/**\n * 注入到逻辑层/渲染层 iframe 的脚本,必须在基础库之前执行\n *\n * 1. 准备开发者工具会预置的全局变量(基础库依赖它们)\n * 2. 提供 WeixinJSBridge,把调用转发给宿主\n * 3. 渲染层:模拟手机屏幕尺寸,处理鼠标输入(见 installInput)\n *\n * 新版基础库的逻辑层分主上下文和子上下文(见 context.ts)。逻辑层 iframe 是主上下文;\n * 子上下文页面也加载这个脚本(data-context-id),只准备全局变量,桥由主上下文的基础库交给它。\n */\n\nimport { hookConsole } from './consoleHook';\nimport { installSingleContextLibLoader, installWeixinJSContext } from './context';\nimport { fileSession } from './fileSession';\nimport { PROXY_PREFIX, toServerPath } from './networkPanel';\nimport { guardSdkGlobals, installApiStubs } from './sdkStubs';\nimport type { FrameBridge, FrameKind, HostApi } from './types';\nimport { createWeixinWorker } from './workers';\n\ntype Listener = (data: unknown, webviewId?: number) => void;\n\nconst script = document.currentScript as HTMLScriptElement;\nconst kind = (script.dataset.kind || 'webview') as FrameKind;\nconst webviewId = Number(script.dataset.webviewId || 0);\nconst subContextId = Number(script.dataset.contextId || 0);\nconst host = ((subContextId ? window.parent.parent : window.parent) as any).__wxaHost as HostApi;\nconst g = window as any;\n\ng.__global = g;\n// 用户目录按浏览器会话隔离(见 fileSession.ts),基础库读 __wxConfig 前换好。子上下文没有自己的 __wxConfig\nif (!subContextId) g.__wxConfig.env.USER_DATA_PATH = `${location.origin}/__wxa__/usr/${fileSession()}`;\n\nif (kind === 'service') {\n Object.assign(g, {\n __wxAppData: {},\n __wxRoute: undefined,\n __wxRouteBegin: undefined,\n __wxAppCode__: {},\n __wxAppCurrentFile__: undefined,\n __vd_version_info__: {},\n global: {},\n __workerVendorCode__: {},\n __workersCode__: {},\n // 创建 Worker 的基础库代码在逻辑层 iframe 里(3.8 起是主上下文),子上下文用不到\n WeixinWorker: subContextId ? {} : createWeixinWorker(window, host),\n $gwx: undefined\n });\n g.__WeixinWorker = g.WeixinWorker;\n // 真机的逻辑层没有 DOM。按全局对象上有没有 MutationObserver 判断是否在浏览器里的库(如 core-js 2 的微任务 polyfill)\n // 看到它就去用 document,而业务代码里的 document 被模块包装屏蔽了(见 AppBuilder 的 MODULE_PARAMS),app.js 执行出错\n delete g.MutationObserver;\n delete g.WebKitMutationObserver;\n // 基础库初始化完成后通过它交出 App/Page/Component/wx/define/require 等全局对象\n g.__passWAServiceGlobal__ = (globals: Record<string, unknown>) => {\n for (const key of Object.keys(globals)) {\n if (key !== 'Protect') g[key] = globals[key];\n }\n };\n // 单上下文的基础库(3.7.0 及以前):业务代码和基础库在同一个全局对象里。新版基础库在业务代码所在的子上下文里\n // 自己替换 Function,伴生 SDK 也能正常加载,这两件事都不用管\n const businessCodeHere = !subContextId && !script.dataset.appService;\n if (businessCodeHere) {\n const disableFunctionConstructor = reserveFunctionConstructor();\n const globalsBeforeBaseLib = new Set(Object.getOwnPropertyNames(g));\n hookRequire(() => {\n disableFunctionConstructor();\n guardSdkGlobals(g, globalsBeforeBaseLib);\n });\n } else {\n hookRequire();\n }\n g.createCustomImage = createCustomImage;\n moveCanvasesIntoPages();\n} else {\n emulateDeviceScreen(host.device);\n installInput();\n runLoadCallbacksEarly();\n}\n\noverrideUserAgent();\n\nwindow.addEventListener('error', event => host.reportError(kind, webviewId, event.error || event.message));\nwindow.addEventListener('unhandledrejection', event => host.reportError(kind, webviewId, event.reason));\n// 生命周期、事件处理函数、wx API 回调里的错误被基础库捕获后只用 console.error 打印,记入 errors() 也要包装它\nhookConsole(host.forwardConsole === 'all' ? ['warn', 'error'] : ['error'], (level, args) => host.reportConsole(kind, webviewId, level, args));\n\nif (subContextId) {\n (window.parent as any).__wxaContexts.prepare(subContextId, window);\n} else {\n const bridge = createBridge();\n g.WeixinJSBridge = bridge;\n // 基础库会用自己的包装替换 WeixinJSBridge,宿主始终通过这个引用回调\n g.__wxaBridge = bridge;\n if (script.dataset.appService) {\n installWeixinJSContext(window, host, {\n dispatchNative: bridge.__dispatchOn,\n appServiceScripts: JSON.parse(script.dataset.appService),\n hot: script.dataset.hot === '1'\n });\n } else if (kind === 'service') {\n installSingleContextLibLoader(window);\n }\n host.registerFrame(kind, window, bridge, webviewId);\n}\n\n/**\n * 与新版基础库的 hijack 相同:真机上业务代码用不了 Function 构造函数,除 Function('return this') 返回全局对象外,\n * 都返回 undefined、不编译参数。uni-app 的 props: { onBack: { default: Function } } 因此在真机上静默得到 undefined,\n * 不替换的话 Vue 取默认值时会把 props 对象当代码编译,抛出 SyntaxError,组件创建失败。\n *\n * 单上下文的基础库初始化时自己要用 Function,初始化完又把内置对象改成只有基础库能写的属性,到执行业务代码时已经换不掉。\n * 所以在基础库之前把 Function 和 Function.prototype.constructor 占成不可配置的存取器(基础库就不再接管),\n * 返回的函数在执行业务代码前调用,之后取到的都是禁用的版本\n */\nfunction reserveFunctionConstructor(): () => void {\n const native = Function;\n const disabled = function (...args: unknown[]) {\n if (args.length > 0 && args[args.length - 1] === 'return this') return () => g;\n };\n disabled.prototype = native.prototype;\n let current: unknown = native;\n const reserve = (target: object, key: string) => Object.defineProperty(target, key, {\n get: () => current,\n set() {},\n enumerable: false,\n configurable: false\n });\n reserve(g, 'Function');\n reserve(native.prototype, 'constructor');\n return () => {\n current = disabled;\n };\n}\n\n/**\n * 基础库初始化完会把广告等缺伴生子包的接口改成「返回 undefined」的函数,占位只有在\n * 业务代码执行前装才留得住 —— bootstrap 里 require 第一个业务模块就是那个时机。\n *\n * 这里用存取器占住 require 再等基础库赋值,而不是事后包装:基础库交出全局的方式按版本\n * 而异(3.7.0 直接写 globalThis,并不调 __passWAServiceGlobal__),事后包装没有可靠的时机。\n * installApiStubs 幂等,每次 require 都查一遍,不赌某一次调用的先后。\n */\nfunction hookRequire(beforeBusinessCode?: () => void) {\n let real: unknown;\n let businessCodeStarted = false;\n const wrapper = function (this: unknown, ...args: unknown[]) {\n if (g.wx) installApiStubs(g.wx);\n if (!businessCodeStarted) {\n businessCodeStarted = true;\n beforeBusinessCode?.();\n }\n return (real as (...a: unknown[]) => unknown).apply(this, args);\n };\n try {\n Object.defineProperty(g, 'require', {\n configurable: true,\n enumerable: true,\n get: () => (typeof real === 'function' ? wrapper : real),\n set: value => { real = value; }\n });\n } catch {\n // 定义不了就算了,广告接口退回基础库原样(返回 undefined)\n }\n}\n\n/**\n * type=\"2d\" 和 webgl 画布:基础库在 devtools 平台把它们建在逻辑层文档的 body 里,开发者工具把逻辑层透明地叠在页面上显示,\n * 画布于是盖住页面里的所有内容;真机上画布和页面元素一样参与层级。所以业务第一次取上下文时(还没开始画),\n * 请宿主把画布搬进页面里对应的 wx-canvas(见 Host.placeCanvas)。之后基础库删除画布时仍从 body 里删,那时元素已经不在这里了\n */\nfunction moveCanvasesIntoPages() {\n const { getContext } = HTMLCanvasElement.prototype;\n const { removeChild } = Node.prototype;\n // 宿主认不出的(如离屏画布)只试一次\n const tried = new WeakSet<HTMLCanvasElement>();\n\n HTMLCanvasElement.prototype.getContext = function (this: HTMLCanvasElement, ...args: unknown[]) {\n if (this.parentNode === document.body && !tried.has(this)) {\n tried.add(this);\n host.placeCanvas(this, String(args[0]));\n }\n return (getContext as (...a: unknown[]) => unknown).apply(this, args);\n } as typeof getContext;\n\n HTMLBodyElement.prototype.removeChild = function <T extends Node>(this: HTMLBodyElement, child: T): T {\n if (child.parentNode === this || !(child instanceof HTMLCanvasElement)) return removeChild.call(this, child) as T;\n child.remove();\n return child;\n };\n}\n\n/**\n * type=\"2d\" 和 webgl 画布的 createImage,开发者工具提供的原生能力(__global.createCustomImage)。\n * toUrl 把业务设置的 src 转成要加载的地址,代码包里的文件会带上开发者工具的 /__pageframe__/ 前缀;\n * fromUrl 把它还原成业务读 src 时看到的值。\n */\nfunction createCustomImage(toUrl: (src: string) => string, fromUrl: (url: string) => string): HTMLImageElement {\n let url = '';\n return new (class extends Image {\n set src(value: string) {\n url = toUrl(value);\n super.src = loadableImageUrl(url);\n }\n\n get src() {\n return fromUrl(url);\n }\n })();\n}\n\n/**\n * 代码包里的文件由开发服务器在根路径提供。其他域名的图片经代理变成同源:直接加载的话画上去会污染画布,\n * 之后读像素、导出都会失败;加 crossOrigin 又要对方返回 CORS 头,大多数图片服务器不返回。\n * 格式不对的地址原样加载,失败时走 onerror,和原生 Image 一样不在赋值时抛错\n */\nfunction loadableImageUrl(url: string): string {\n if (url.startsWith('/__pageframe__/')) return url.slice('/__pageframe__'.length);\n if (/^https?:\\/\\//i.test(url) && !url.startsWith(location.origin + '/')) return toServerPath(PROXY_PREFIX, url) ?? url;\n return url;\n}\n\nfunction createBridge(): FrameBridge & Record<string, unknown> {\n const onListeners: Record<string, Listener[]> = {};\n const subListeners: Record<string, Listener[]> = {};\n\n const add = (map: Record<string, Listener[]>, event: string, listener: Listener) => {\n (map[event] = map[event] || []).push(listener);\n };\n const remove = (map: Record<string, Listener[]>, event: string, listener?: Listener) => {\n if (!map[event]) return;\n map[event] = listener ? map[event].filter(l => l !== listener) : [];\n };\n const emit = (map: Record<string, Listener[]>, event: string, data: unknown, id?: number) => {\n for (const listener of (map[event] || []).slice()) {\n try {\n listener(data, id);\n } catch (error) {\n console.error(`[wxa-runner] ${event} 处理出错`, error);\n }\n }\n };\n\n return {\n invoke(api: string, args: unknown, callback?: (res: any) => void) {\n host.invoke(kind, window, api, args, callback);\n },\n publish(event: string, data: unknown, webviewIds?: number[]) {\n host.publish(kind, window, event, data, webviewIds);\n },\n subscribe(event: string, listener: Listener) {\n add(subListeners, event, listener);\n },\n on(event: string, listener: Listener) {\n add(onListeners, event, listener);\n },\n addEventListener(event: string, listener: Listener) {\n add(onListeners, event, listener);\n },\n removeEventListener(event: string, listener?: Listener) {\n remove(onListeners, event, listener);\n },\n addSubscribeListener(event: string, listener: Listener) {\n add(subListeners, event, listener);\n },\n removeSubscribeListener(event: string, listener?: Listener) {\n remove(subListeners, event, listener);\n },\n __dispatchOn(event: string, data: unknown, id?: number) {\n emit(onListeners, event, data, id);\n },\n __dispatchSub(event: string, data: unknown, id?: number) {\n emit(subListeners, event, data, id);\n }\n };\n}\n\n/**\n * wcsc 生成的 rpx 换算读取 window.screen.width,桌面浏览器里那是显示器宽度,\n * 这里改成模拟设备的尺寸。\n */\nfunction emulateDeviceScreen(device: HostApi['device']) {\n const values: Record<string, number> = {\n width: device.screenWidth,\n height: device.screenHeight,\n availWidth: device.screenWidth,\n availHeight: device.screenHeight\n };\n for (const key of Object.keys(values)) {\n try {\n Object.defineProperty(window.screen, key, { get: () => values[key], configurable: true });\n } catch {\n // 个别浏览器不允许重定义,退回到真实值\n }\n }\n // 桌面浏览器报告横屏,基础库会因此改用 screen.height 作为设备宽度换算 rpx\n const portrait = {\n type: 'portrait-primary',\n angle: 0,\n onchange: null,\n addEventListener() {},\n removeEventListener() {},\n dispatchEvent: () => false,\n lock: () => Promise.reject(new Error('not supported')),\n unlock() {}\n };\n try {\n Object.defineProperty(window.screen, 'orientation', { get: () => portrait, configurable: true });\n } catch {\n // 同上\n }\n try {\n Object.defineProperty(window, 'devicePixelRatio', { get: () => device.pixelRatio, configurable: true });\n } catch {\n // 同上\n }\n}\n\n/**\n * 基础库在文档没加载完时,把内置组件样式(wx-view 的 display、wx-canvas 的默认尺寸等)推迟到\n * window.onload 再注入。开发者工具在文档加载完后才注入基础库,那边是立即注入;这里基础库随页面\n * 同步加载,首屏渲染早于 onload,canvas 这类挂载时测量尺寸的组件会量到没有样式时的大小。\n * 所以加载完成前赋给 window.onload 的回调改为在当前脚本执行完后立即运行,仍早于首屏渲染。\n * 效果与开发者工具一致:那边每处都直接调用回调,多次赋值各自执行,window.onload 本身始终为空。\n */\nfunction runLoadCallbacksEarly() {\n let owner: object | null = window;\n while (owner && !Object.getOwnPropertyDescriptor(owner, 'onload')) owner = Object.getPrototypeOf(owner);\n const native = owner && Object.getOwnPropertyDescriptor(owner, 'onload');\n if (!native?.get || !native.set) return;\n Object.defineProperty(window, 'onload', {\n configurable: true,\n get: () => native.get!.call(window),\n set(handler: unknown) {\n if (typeof handler === 'function' && document.readyState !== 'complete') {\n queueMicrotask(() => handler.call(window, new Event('load')));\n } else {\n native.set!.call(window, handler);\n }\n }\n });\n}\n\nfunction overrideUserAgent() {\n const ua = `${navigator.userAgent} (iPhone; wxa-runner) MicroMessenger/8.0.50 miniProgram`;\n try {\n Object.defineProperty(navigator, 'userAgent', { get: () => ua, configurable: true });\n } catch {\n // 只影响基础库对平台的判断,失败可以忽略\n }\n}\n\n/**\n * 鼠标输入 → 触摸事件\n *\n * 模拟的是手机,页面只应收到触摸事件。基础库在部分版本/平台上会自己把鼠标或 pointer 事件\n * 转换为触摸,和这里的转换叠加会导致一次点击触发两次 tap,所以在 window 捕获阶段\n * (先于基础库注册的任何监听)拦下鼠标类事件。不调用 preventDefault,输入框聚焦等默认行为不受影响。\n *\n * 另外,基础库在元素滚动后 50ms 内会把触摸当作滑动、取消 tap。自动化测试常常是\n * 「滚动到元素 → 立刻点击」,而 scroll 事件要到下一帧才派发,所以按下时先等两帧\n * 让挂起的 scroll 事件派发完,刚滚动过的话再顺延到窗口之后。同一次按压的事件按原顺序派发。\n *\n * 按下后移出 TOUCH_SLOP 之前的 mousemove 不转成 touchmove(类似触屏的 touch slop)。swiper 等组件\n * 按第一个 touchmove 的位移判断手势方向,鼠标刚拖动时常先抖出 1px 的竖向位移,直接转发的话横向拖动\n * 会被判成竖向、整次拖动都被忽略。阈值小于基础库取消 tap 的 10px,点击和长按不受影响。\n * 没移出阈值就松手时,先补一个到松手位置的 touchmove,slider 微调、画短笔画这类小幅拖动不会丢。\n */\nfunction installInput() {\n const SCROLL_TAP_GUARD = 80;\n const TOUCH_SLOP = 8;\n let lastScroll = 0;\n let queue: Promise<void> = Promise.resolve();\n let target: EventTarget | null = null;\n let start: { x: number; y: number } | null = null;\n\n document.addEventListener('scroll', () => {\n lastScroll = Date.now();\n }, true);\n\n const nextFrame = () => new Promise<void>(resolve => requestAnimationFrame(() => resolve()));\n const sleep = (ms: number) => new Promise<void>(resolve => setTimeout(resolve, ms));\n\n const fire = (type: 'touchstart' | 'touchmove' | 'touchend', event: MouseEvent, eventTarget: EventTarget) => {\n const point = {\n clientX: event.clientX,\n clientY: event.clientY,\n pageX: event.pageX,\n pageY: event.pageY,\n screenX: event.screenX,\n screenY: event.screenY\n };\n queue = queue.then(async () => {\n if (type === 'touchstart') {\n await nextFrame();\n await nextFrame();\n const wait = lastScroll + SCROLL_TAP_GUARD - Date.now();\n if (wait > 0) await sleep(wait);\n }\n const touch = new Touch({ identifier: 1, target: eventTarget, ...point });\n const active = type === 'touchend' ? [] : [touch];\n eventTarget.dispatchEvent(new TouchEvent(type, {\n bubbles: true,\n cancelable: true,\n composed: true,\n touches: active,\n targetTouches: active,\n changedTouches: [touch]\n }));\n });\n };\n\n window.addEventListener('mousedown', event => {\n event.stopImmediatePropagation();\n if (event.button !== 0 || !event.target) return;\n target = event.target;\n start = { x: event.clientX, y: event.clientY };\n fire('touchstart', event, target);\n }, true);\n window.addEventListener('mousemove', event => {\n event.stopImmediatePropagation();\n if (!target) return;\n if (start) {\n if (Math.hypot(event.clientX - start.x, event.clientY - start.y) < TOUCH_SLOP) return;\n start = null;\n }\n fire('touchmove', event, target);\n }, true);\n window.addEventListener('mouseup', event => {\n event.stopImmediatePropagation();\n if (!target) return;\n if (start && (event.clientX !== start.x || event.clientY !== start.y)) {\n fire('touchmove', event, target);\n // movable-view 等组件在下一帧才应用位移,同一帧里就收到 touchend 的话这段位移会被丢掉\n queue = queue.then(nextFrame);\n }\n fire('touchend', event, target);\n target = null;\n }, true);\n for (const type of ['pointerdown', 'pointermove', 'pointerup', 'pointercancel']) {\n window.addEventListener(type, event => {\n if ((event as PointerEvent).pointerType !== 'touch') event.stopImmediatePropagation();\n }, true);\n }\n}\n"],"mappings":"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","names":["script","host","script","host","g"]}
@@ -1,11 +1,52 @@
1
1
  "use strict";
2
2
  (() => {
3
- // src/runtime/host/ConsoleForwarder.ts
3
+ // src/runtime/host/frameErrors.ts
4
4
  var DEDUPE_MS = 1e3;
5
+ var MINI_PROGRAM_ERROR = /^(\(in promise\) )?MiniProgramError\n/;
6
+ var STACK_FRAME = /^\s*at /;
7
+ function isErrorLike(value) {
8
+ return typeof value === "object" && value !== null && typeof value.message === "string";
9
+ }
10
+ function caughtError(value) {
11
+ if (isErrorLike(value) && MINI_PROGRAM_ERROR.test(value.message)) {
12
+ const ownStack = typeof value.stack === "string" && /^[^\n]*MiniProgramError\n/.test(value.stack);
13
+ return { message: value.message.replace(MINI_PROGRAM_ERROR, ""), stack: ownStack ? void 0 : value.stack };
14
+ }
15
+ if (typeof value === "string" && MINI_PROGRAM_ERROR.test(value)) {
16
+ const text = value.replace(MINI_PROGRAM_ERROR, "");
17
+ const firstFrame2 = text.search(/^\s*at /m);
18
+ const head = (firstFrame2 < 0 ? text : text.slice(0, firstFrame2)).replace(/\n$/, "");
19
+ const message = /^([\s\S]*)\n[^\n]*?: \1$/.exec(head)?.[1] ?? head;
20
+ return { message, stack: firstFrame2 < 0 ? void 0 : text.slice(firstFrame2) };
21
+ }
22
+ return null;
23
+ }
24
+ var RecentErrors = class {
25
+ constructor() {
26
+ this.recent = /* @__PURE__ */ new Map();
27
+ }
28
+ /**
29
+ * 比较栈里的各帧而不是整个栈:基础库打印成字符串时,栈开头的 `TypeError: …` 那行拆不出来。
30
+ * 不同位置抛出的同名错误帧不同,各记各的
31
+ */
32
+ isRepeated(kind, webviewId, message, stack) {
33
+ const frames = (stack || "").split("\n").filter((line) => STACK_FRAME.test(line)).map((line) => line.trim()).join("\n");
34
+ const key = `${kind}:${webviewId}:${message}
35
+ ${frames}`;
36
+ const now = Date.now();
37
+ for (const [recent, time] of this.recent) {
38
+ if (now - time >= DEDUPE_MS) this.recent.delete(recent);
39
+ }
40
+ if (this.recent.has(key)) return true;
41
+ this.recent.set(key, now);
42
+ return false;
43
+ }
44
+ };
45
+
46
+ // src/runtime/host/ConsoleForwarder.ts
5
47
  var MAX_ARG_LENGTH = 1e3;
6
48
  var MAX_TEXT_LENGTH = 8e3;
7
49
  var LAYERS = { service: "\u903B\u8F91\u5C42", webview: "\u6E32\u67D3\u5C42" };
8
- var MINI_PROGRAM_ERROR = /^(\(in promise\) )?MiniProgramError\n/;
9
50
  var MODULE_URL = /\bhttps?:\/\/[^/\s]+\/__wxa__\/module\/([^?\s)]+?)(?:\?[^:\s)]*)?:(\d+):(\d+)/;
10
51
  var ConsoleForwarder = class {
11
52
  /**
@@ -17,13 +58,11 @@
17
58
  this.send = send;
18
59
  this.pageOf = pageOf;
19
60
  this.hintsOf = hintsOf;
20
- this.recentErrors = /* @__PURE__ */ new Map();
21
61
  }
22
- /** 运行时错误:全局 error、未处理的 Promise 拒绝、基础库捕获的业务代码错误 */
62
+ /** 运行时错误:全局 error、未处理的 Promise 拒绝、基础库捕获的业务代码错误。两路报来的同一个错误由宿主去重(见 frameErrors.ts) */
23
63
  error(kind, webviewId, message, stack) {
64
+ if (!this.mode) return;
24
65
  const frames = businessFrames(stack);
25
- if (!this.mode || this.isRepeated(`${kind}:${webviewId}:${message}
26
- ${frames}`)) return;
27
66
  const hints = this.hintsOf(kind).map((hint) => `
28
67
  \u63D0\u793A\uFF1A${hint}`).join("");
29
68
  this.post("error", `${this.origin(kind, webviewId)}\u62A5\u9519\uFF1A${message}${frames ? `
@@ -33,14 +72,9 @@ ${frames}` : ""}${hints}`);
33
72
  warn(text) {
34
73
  if (this.mode) this.post("warn", text);
35
74
  }
36
- /** iframe 里的 console.warn / console.error;基础库捕获业务代码错误后打印的 console.error 按报错转发 */
75
+ /** iframe 里的 console.warn / console.error;基础库捕获业务代码错误后打印的不经过这里,按报错转发 */
37
76
  console(kind, webviewId, level, args) {
38
- const thrown = level === "error" ? miniProgramError(args[0]) : null;
39
- if (thrown) {
40
- this.error(kind, webviewId, thrown.message, thrown.stack);
41
- } else if (this.mode === "all") {
42
- this.post(level, `${this.origin(kind, webviewId)} console.${level}\uFF1A${args.map(formatArg).join(" ")}`);
43
- }
77
+ if (this.mode === "all") this.post(level, `${this.origin(kind, webviewId)} console.${level}\uFF1A${args.map(formatArg).join(" ")}`);
44
78
  }
45
79
  post(level, text) {
46
80
  this.send({ type: "console", level, text: text.length > MAX_TEXT_LENGTH ? `${text.slice(0, MAX_TEXT_LENGTH)}\u2026` : text });
@@ -49,33 +83,7 @@ ${frames}` : ""}${hints}`);
49
83
  const page = this.pageOf(kind, webviewId);
50
84
  return page ? `${LAYERS[kind]}\uFF08${page}\uFF09` : LAYERS[kind];
51
85
  }
52
- /** @param key 来源、错误信息和业务代码的帧:两路报来的同一个错误相同,不同位置抛出的同名错误不同 */
53
- isRepeated(key) {
54
- const now = Date.now();
55
- for (const [recent, time] of this.recentErrors) {
56
- if (now - time >= DEDUPE_MS) this.recentErrors.delete(recent);
57
- }
58
- if (this.recentErrors.has(key)) return true;
59
- this.recentErrors.set(key, now);
60
- return false;
61
- }
62
86
  };
63
- function isErrorLike(value) {
64
- return typeof value === "object" && value !== null && typeof value.message === "string";
65
- }
66
- function miniProgramError(value) {
67
- if (isErrorLike(value) && MINI_PROGRAM_ERROR.test(value.message)) {
68
- return { message: value.message.replace(MINI_PROGRAM_ERROR, ""), stack: value.stack };
69
- }
70
- if (typeof value === "string" && MINI_PROGRAM_ERROR.test(value)) {
71
- const text = value.replace(MINI_PROGRAM_ERROR, "");
72
- const firstFrame2 = text.search(/^\s*at /m);
73
- const head = (firstFrame2 < 0 ? text : text.slice(0, firstFrame2)).replace(/\n$/, "");
74
- const message = /^([\s\S]*)\n[^\n]*?: \1$/.exec(head)?.[1] ?? head;
75
- return { message, stack: firstFrame2 < 0 ? void 0 : text.slice(firstFrame2) };
76
- }
77
- return null;
78
- }
79
87
  function businessFrames(stack) {
80
88
  return (stack || "").split("\n").filter((line) => /^\s*at /.test(line) && MODULE_URL.test(line)).map((line) => ` ${line.trim().replace(MODULE_URL, "$1:$2:$3")}`).join("\n");
81
89
  }
@@ -106,7 +114,6 @@ ${frames}` : "");
106
114
  "systemLog",
107
115
  "traceEvent",
108
116
  "getPermissionBytes",
109
- "getABTestConfig",
110
117
  "initRenderDone",
111
118
  "saveInitialRenderingCache",
112
119
  "setKeyValue",
@@ -627,6 +634,7 @@ ${frames}` : "");
627
634
 
628
635
  // src/runtime/host/api/misc.ts
629
636
  var SERVICE_MARKET = "webapi_servicemarket_jsapi_comm";
637
+ var CLOUD = "qbase_commapi";
630
638
  function createMiscApis(appid, options) {
631
639
  const viaDevtools = async (api, url, json) => {
632
640
  try {
@@ -636,6 +644,14 @@ ${frames}` : "");
636
644
  throw error;
637
645
  }
638
646
  };
647
+ let cloudWarned = false;
648
+ const cloudUnavailable = (api, operation) => {
649
+ if (!cloudWarned) {
650
+ cloudWarned = true;
651
+ console.warn("[wxa-runner] \u4E91\u5F00\u53D1\uFF08wx.cloud\uFF09\u5728\u6D4F\u89C8\u5668\u8FD0\u884C\u65F6\u4E0D\u53EF\u7528\uFF0C\u8C03\u7528\u4F1A\u5931\u8D25");
652
+ }
653
+ return fail(api, `wxa-runner \u4E0D\u652F\u6301\u4E91\u5F00\u53D1\uFF08${operation ?? "unknown"}\uFF09`);
654
+ };
639
655
  return {
640
656
  // canvas 导出图片、拍照、录像的结果都经过这里
641
657
  base64ToTempFilePath: async (args) => {
@@ -652,11 +668,14 @@ ${frames}` : "");
652
668
  (error) => serviceMarketFail(error.message)
653
669
  );
654
670
  }
671
+ if (args.data?.api_name === CLOUD) return cloudUnavailable(api, args.data.data?.qbase_api_name);
655
672
  if (args.data?.api_name === "webapi_getwxanetwork") return bizDomainUnavailable(api);
656
673
  if (args.data?.api_name === "webapi_getwxauserprivacyauthinfo") return ok(api, { data: { data: JSON.stringify(PRIVACY_AUTH_INFO) } });
657
- return ok(api);
674
+ return ok(api, { data: {} });
658
675
  },
659
676
  getAppContact: (args, { api }) => args.keyPath === "WxaAppInfo.Network.BizDomain" ? bizDomainUnavailable(api) : ok(api),
677
+ // 基础库内部的实验开关。不在实验里时原生返回空字符串;没有 testConfig 时 3.3.4 读它的 length 报错
678
+ getABTestConfig: (_args, { api }) => ok(api, { testConfig: "" }),
660
679
  // 插件:基础库启动时校验插件、取插件信息,插件里的网络请求要等拿到这两样才发出。插件代码也只在 --devtools-login 时下载
661
680
  ...options?.devtoolsLogin ? {
662
681
  verifyPlugin: (async (args, { api }) => ok(api, await viaDevtools(api, "/__wxa__/api/verify-plugin", { data: args.data }))),
@@ -2760,6 +2779,7 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
2760
2779
  constructor(info, root, sendReport = () => void 0) {
2761
2780
  this.info = info;
2762
2781
  this.errors = [];
2782
+ this.recentErrors = new RecentErrors();
2763
2783
  /** 小程序发出的 wx.request */
2764
2784
  this.requests = new RequestLog();
2765
2785
  this.api = new ApiRegistry((context) => this.reportUnimplemented(context));
@@ -2917,14 +2937,20 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
2917
2937
  message: err ? err.message : String(error),
2918
2938
  stack: typeof err?.stack === "string" ? err.stack : void 0
2919
2939
  };
2920
- this.errors.push(report);
2921
- this.forwarder.error(kind, webviewId, report.message, report.stack);
2940
+ this.recordError(report);
2922
2941
  }
2923
2942
  get forwardConsole() {
2924
2943
  return this.forwarder.mode;
2925
2944
  }
2926
2945
  reportConsole(kind, webviewId, level, args) {
2927
- this.forwarder.console(kind, webviewId, level, args);
2946
+ const caught = level === "error" ? caughtError(args[0]) : null;
2947
+ if (caught) this.recordError({ kind, webviewId, ...caught });
2948
+ else this.forwarder.console(kind, webviewId, level, args);
2949
+ }
2950
+ recordError(report) {
2951
+ if (this.recentErrors.isRepeated(report.kind, report.webviewId, report.message, report.stack)) return;
2952
+ this.errors.push(report);
2953
+ this.forwarder.error(report.kind, report.webviewId, report.message, report.stack);
2928
2954
  }
2929
2955
  /**
2930
2956
  * 只记录逻辑层的公开 wx API 和 FileSystemManager 方法,每个原生接口一次。