@open-wxa/wxa-runner-core 0.9.0 → 0.10.1

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/server/DevServer.ts","../src/server/FileStore.ts","../src/project/AppBuilder.ts","../src/project/wxConfig.ts","../src/project/WxmlMirror.ts","../src/project/MiniProgram.ts","../src/runtime/networkPanel.ts","../src/server/plugins.ts","../src/server/wechatDev.ts","../src/server/html.ts","../src/server/ignoreList.ts","../src/server/forwardConsole.ts","../src/server/proxy.ts","../src/server/hmr.ts","../src/server/developerTicket.ts","../src/server/devtoolsLogin.ts","../src/server/setup.ts","../src/server/watcher.ts","../src/server/extensions.ts"],"sourcesContent":["/**\n * wxa-runner-core(Node 端入口)\n *\n * 浏览器端运行时单独打包为 dist/runtime/host.js 与 dist/runtime/frame.js。\n */\n\nexport { DevServer, DEFAULT_DEVICE } from './server/DevServer';\nexport type { DevServerMiddleware, DevServerOptions, WebviewScript } from './server/DevServer';\nexport type { DevServerExtension, ExtensionContext, ExtensionEntry, ExtensionSetup } from './server/extensions';\nexport { AppBuilder } from './project/AppBuilder';\nexport type { AppBuilderOptions, BuildResult } from './project/AppBuilder';\nexport { MiniProgram } from './project/MiniProgram';\nexport type { AppJson, UnitJson } from './project/MiniProgram';\nexport { createWxConfig } from './project/wxConfig';\nexport type { AppInfo, DeviceProfile, ForwardConsole } from './runtime/types';\nexport type { ApiContext, ApiHandler, ApiResult } from './runtime/host/api/registry';\nexport type { FrameError } from './runtime/host/Host';\nexport type { PageSnapshot, RecordedRequest, WxaTestApi } from './runtime/host/testApi';\nexport type {\n MockConfig, MockRequest, MockResponse, MockValue, NetworkConfig, RouteHandler,\n SetupApi, SetupConfig, SetupContext, SetupDefinition\n} from './setup';\n","/**\n * 开发服务器\n *\n * / 宿主页面\n * /__wxa__/app-info.json 构建信息(__wxConfig、页面列表、设备参数、setup)\n * /__wxa__/setup.js 编译后的 setup 文件\n * /__wxa__/appservice.html 逻辑层\n * /__wxa__/webview/<page>.html 渲染层(路径与页面一致,wxml 里的相对资源路径因此能正确解析)\n * /__wxa__/module/<file>.js 单个业务 JS 模块(含 workers 目录下的)\n * /__wxa__/worker.js?id= Worker 的入口\n * /__wxa__/service-templates.js、page-templates.js 两层的模板(热更新时重新下发)\n * /__wxa__/page-styles.js 渲染层的样式(热更新时重新下发)\n * /__baselib__/* 官方基础库\n * /__wxa__/proxy/<协议>/<域名><路径> 网络代理,如 /__wxa__/proxy/https/api.example.com/a?b=1\n * /__wxa__/mock/<协议>/<域名><路径> 被拦截的请求在 Network 面板里的地址,由 Service Worker(runtime/sw.js)返回响应\n * /__wxa__/fs/<会话> 文件系统接口(FileSystemManager),每个浏览器会话一份文件,会话标识见 runtime/fileSession.ts\n * /__wxa__/tmp/<会话> 临时文件:POST ?type=png 保存,返回可直接访问的地址(GET 支持分段请求);对该地址 HEAD 查大小、DELETE 删除\n * /__wxa__/usr/<会话>/<路径> 用户目录(USER_DATA_PATH)下的文件,image 等组件和 uploadFile 按地址读取\n * /__wxa__/region/<kind> 地区选择器用的行政区划数据(districts / streets),取自本机开发者工具\n * /__wxa__/api/* --devtools-login:wx.login 的 code、手机号,服务市场、插件的请求转发,只允许本机访问\n * /__wxa__/ws 文件变化通知:热更新(hot)或整页刷新(reload);开启 forwardConsole 时浏览器从这里发来报错\n * middlewares / 扩展挂载的路径 排在 runner 自己的路由之前\n * 其余路径 小程序目录下的静态资源\n */\n\nimport { randomUUID } from 'crypto';\nimport { FileStore } from './FileStore';\nimport fs from 'fs';\nimport http, { IncomingMessage, ServerResponse } from 'http';\nimport net from 'net';\nimport os from 'os';\nimport path from 'path';\nimport express, { Express, NextFunction, Request, Response } from 'express';\nimport { WebSocket, WebSocketServer } from 'ws';\nimport { readRegionData, resolveBaseLib, ResolvedBaseLib, usesIsolatedContext } from '@open-wxa/wxa-runner-extractor';\nimport { AppBuilder } from '../project/AppBuilder';\nimport { MiniProgram } from '../project/MiniProgram';\nimport { MOCK_PREFIX, PROXY_PREFIX } from '../runtime/networkPanel';\nimport type { AppInfo, DeviceProfile, ForwardConsole } from '../runtime/types';\nimport { appserviceHtml, hostHtml, pluginWebviewHtml, subcontextHtml, webviewHtml, workerScript } from './html';\nimport { ignoreListSourceMap } from './ignoreList';\nimport { ignoreConsoleHook, printBrowserReports } from './forwardConsole';\nimport { handleProxy } from './proxy';\nimport { planHotUpdate } from './hmr';\nimport { developerTicketSource, TicketSource } from './developerTicket';\nimport { AppBuild, findPluginPage, PluginStore } from './plugins';\nimport { devtoolsLoginRouter } from './devtoolsLogin';\nimport { requireUsableTicket, WechatDevClient } from './wechatDev';\nimport { bundleSetup, collectSetupEnv, findSetupFile } from './setup';\nimport { ProjectWatcher, watchProject } from './watcher';\nimport { applyExtensions, DevServerExtension, ExtensionEntry } from './extensions';\n\n/** 注入每个渲染层页面的脚本,src 与 content 二选一 */\nexport type WebviewScript = ({ src: string; content?: never } | { content: string; src?: never }) & {\n /**\n * 'head':在基础库(WAWebview.js)之前执行,用于要赶在基础库之前注册事件监听的脚本,执行时还没有 document.body;\n * 'body'(默认):在 <body> 开头、页面开始渲染之前执行。不能放在 <body> 末尾:基础库渲染时会换掉 body,\n * 之后才解析到的脚本落在脱离文档的旧 body 里,不会执行\n */\n position?: 'head' | 'body';\n};\n\n/** 挂在开发服务器上的中间件:按前缀匹配,handler 收到的 req.url 已去掉 path 这段前缀 */\nexport interface DevServerMiddleware {\n /** 以 / 开头的字面量路径前缀,如 /__tool__;不能是 /,不能含通配符和参数,也不能落在 runner 保留的前缀下(见 RESERVED_PREFIXES) */\n path: string;\n handler: (req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => void) => void;\n}\n\n/** runner 自己使用的路径前缀,中间件不能占用 */\nconst RESERVED_PREFIXES = ['/__wxa__', '/__baselib__', '/__plugin__'];\n\nexport interface DevServerOptions {\n projectPath: string;\n /** 不传时从 3000 起找空闲的端口;指定的端口被占用时启动失败;传 0 使用随机端口 */\n port?: number;\n /** 监听地址,默认 localhost;0.0.0.0 或 :: 时局域网也能访问 */\n host?: string;\n /** 指定基础库版本,默认使用本机已安装的最新兼容版本 */\n baseLibVersion?: string;\n baseLibCacheDir?: string;\n watch?: boolean;\n device?: Partial<DeviceProfile>;\n /**\n * 小程序启动前执行的 setup 文件;默认使用项目目录下的 wxa.setup.ts / .js / .mjs,传 false 不使用\n * 环境变量在构造时读取,只暴露 WXA_ 前缀的变量\n */\n setup?: string | false;\n /** 浏览器端运行时(host.js / frame.js)所在目录,默认取构建产物 */\n runtimeDir?: string;\n /**\n * 借本机微信开发者工具的登录态访问微信后台:真实的 wx.login code 和手机号、服务市场、插件。\n * 要先登录开发者工具,会真实请求微信\n */\n devtoolsLogin?: boolean;\n /** @deprecated 改名为 devtoolsLogin */\n realLogin?: boolean;\n /**\n * 把浏览器里的报错打印到终端:'errors' 转发运行时错误和未实现 API 的提醒,'all' 再加上 console.warn / console.error。\n * 默认不转发;命令行默认 'errors',检测到编程助手时 'all'\n */\n forwardConsole?: ForwardConsole;\n /** 注入每个渲染层页面(含插件页面、跳转后新建的页面)的脚本,供检查器等开发工具使用 */\n webviewScripts?: WebviewScript[];\n /** 挂在开发服务器上的中间件,供开发工具提供自己的页面和接口 */\n middlewares?: DevServerMiddleware[];\n /**\n * wxml 交给 wcc 编译前的转换,file 是相对小程序根目录的路径(如 pages/index/index.wxml)。\n * 不能改变行数,编译错误和热更新才能对应到源文件;相同输入要返回相同输出。源文件不会被修改\n */\n wxmlTransform?: (code: string, file: string) => string;\n /** 开发服务器扩展:把上面几个扩展点打包在一起的开发工具,按顺序合并在直接给出的选项之后,见 extensions.ts */\n extensions?: DevServerExtension[];\n logger?: Pick<Console, 'log' | 'warn' | 'error'>;\n}\n\nexport const DEFAULT_DEVICE: DeviceProfile = {\n model: 'iPhone X',\n screenWidth: 375,\n screenHeight: 812,\n pixelRatio: 3,\n statusBarHeight: 44,\n safeAreaBottom: 34,\n system: 'iOS 16.0',\n platform: 'devtools'\n};\n\nexport class DevServer {\n readonly project: MiniProgram;\n readonly builder: AppBuilder;\n readonly baseLib: ResolvedBaseLib;\n /** 生效的 setup 文件绝对路径,没有时为 null */\n readonly setupFile: string | null;\n /** 扩展提供的页面,按扩展的顺序 */\n readonly extensionEntries: ExtensionEntry[];\n private readonly setupEnv: Record<string, string>;\n private readonly device: DeviceProfile;\n private readonly logger: Pick<Console, 'log' | 'warn' | 'error'>;\n private readonly app: Express;\n private server: http.Server | null = null;\n private sockets: WebSocketServer | null = null;\n private watcher: ProjectWatcher | null = null;\n private address = '';\n private lanAccess = false;\n /** 运行时生成的临时文件(canvas 导出、拍照等),随服务器进程存在 */\n private readonly fileSessions = new Map<string, FileStore>();\n private readonly devtoolsLogin: boolean;\n /** 开启 --devtools-login 时才有 */\n private readonly ticketSource: TicketSource | null;\n private readonly plugins: PluginStore;\n\n /** 选项里直接给出的扩展点与各个扩展合并后的结果 */\n private readonly webviewScripts: WebviewScript[];\n private readonly middlewares: DevServerMiddleware[];\n\n constructor(private readonly options: DevServerOptions) {\n this.logger = options.logger || console;\n this.project = new MiniProgram(path.resolve(options.projectPath));\n const extended = applyExtensions(options, options.extensions ?? [], { projectPath: this.project.projectPath, root: this.project.root });\n extended.middlewares.forEach(({ path: mountPath }) => assertMountPath(mountPath));\n this.webviewScripts = extended.webviewScripts;\n this.middlewares = extended.middlewares;\n this.extensionEntries = extended.entries;\n this.baseLib = resolveBaseLib({ version: options.baseLibVersion, cacheDir: options.baseLibCacheDir });\n if (!this.baseLib.compatible) {\n this.logger.warn(`[wxa-runner] 基础库 ${this.baseLib.version} 高于已验证的版本范围,可能无法正常运行`);\n }\n if (options.realLogin !== undefined && options.devtoolsLogin === undefined) {\n this.logger.warn('[wxa-runner] realLogin(--real-login)已改名为 devtoolsLogin(--devtools-login),旧名以后会移除');\n }\n this.devtoolsLogin = (options.devtoolsLogin ?? options.realLogin) === true;\n this.ticketSource = this.devtoolsLogin ? developerTicketSource(this.project.projectPath, this.logger) : null;\n this.plugins = new PluginStore(this.ticketSource && new WechatDevClient(this.project.appid, this.ticketSource), this.logger);\n this.device = { ...DEFAULT_DEVICE, ...options.device };\n this.builder = new AppBuilder(this.project, { wxmlTransform: extended.wxmlTransform });\n this.setupFile = resolveSetupFile(options.setup, this.project.projectPath);\n this.setupEnv = collectSetupEnv(process.env);\n this.app = this.createApp();\n }\n\n /** 本机访问的地址 */\n get url(): string {\n return this.address;\n }\n\n /** 局域网里其他设备访问的地址,每块网卡一个;只监听本机时为空 */\n get networkUrls(): string[] {\n if (!this.lanAccess) return [];\n const { port } = new URL(this.address);\n return Object.values(os.networkInterfaces())\n .flat()\n .filter(net => net && net.family === 'IPv4' && !net.internal)\n .map(net => `http://${net!.address}:${port}`);\n }\n\n async start(): Promise<string> {\n // 先构建一次:编译错误在终端里立即可见\n try {\n const build = await this.builder.build();\n this.logger.log(`[wxa-runner] 编译完成:${build.pages.length} 个页面,${build.components.length} 个组件,${build.durationMs}ms`);\n } catch (error) {\n this.logger.error(`[wxa-runner] 编译失败:\\n${(error as Error).message}`);\n }\n\n const server = http.createServer(this.app);\n // 浏览器只发来报错,单条用不了 64KB\n this.sockets = new WebSocketServer({ noServer: true, maxPayload: 64 * 1024 });\n this.sockets.on('connection', socket => {\n // 消息超过 maxPayload 等协议错误时 ws 会断开这个连接;没有监听器的 error 事件会让整个进程退出\n socket.on('error', () => undefined);\n if (this.options.forwardConsole) printBrowserReports(socket, this.logger);\n });\n server.on('upgrade', (req, socket, head) => {\n if (req.url?.startsWith('/__wxa__/ws')) {\n this.sockets!.handleUpgrade(req, socket, head, ws => this.sockets!.emit('connection', ws, req));\n } else {\n socket.destroy();\n }\n });\n\n const host = this.options.host || 'localhost';\n const port = await listen(server, this.options.port, host, this.logger);\n this.server = server;\n this.lanAccess = LOCAL_HOST_OF_ANY_ADDRESS.has(host);\n this.address = `http://${LOCAL_HOST_OF_ANY_ADDRESS.get(host) ?? host}:${port}`;\n\n if (this.options.watch !== false) this.startWatching();\n // 启动时先取一次:新版开发者工具要先为项目开启自动化接口,第一次 wx.login 就不用等;不可用时在终端提示原因\n this.ticketSource?.()\n .then(requireUsableTicket)\n .catch(error => this.logger.warn(`[wxa-runner] 开发者工具的登录态暂不可用(--devtools-login):${error.message}`));\n return this.address;\n }\n\n async close() {\n await this.watcher?.close();\n this.sockets?.clients.forEach(client => client.terminate());\n this.sockets?.close();\n const server = this.server;\n this.server = null;\n if (server) {\n // 浏览器和 fetch 的 keep-alive 连接会让 close() 一直等到超时\n server.closeAllConnections();\n await new Promise<void>(resolve => server.close(() => resolve()));\n }\n this.fileSessions.clear();\n this.builder.dispose();\n }\n\n private createApp(): Express {\n const app = express();\n const root = this.project.root;\n const noStore = (res: Response) => res.setHeader('Cache-Control', 'no-store');\n\n for (const { path: mountPath, handler } of this.middlewares) {\n app.use(mountPath, (req, res, next) => handler(req, res, next));\n }\n\n app.get('/', (_req, res) => {\n noStore(res);\n res.type('html').send(hostHtml());\n });\n\n app.get('/favicon.ico', (_req, res) => {\n res.status(204).end();\n });\n\n app.get('/__wxa__/app-info.json', async (_req, res) => {\n noStore(res);\n const base = {\n appid: this.project.appid,\n baseLibVersion: this.baseLib.version,\n device: this.device,\n devtoolsLogin: this.devtoolsLogin,\n forwardConsole: this.options.forwardConsole ?? false\n };\n try {\n // 宿主打开小程序时先取 app-info:这时重新决定用哪些插件,之后的请求都按这个结果\n const build = await this.plugins.refresh(await this.builder.build());\n const info: AppInfo = { ...base, version: build.version, wxConfig: build.wxConfig, pages: build.pages };\n if (this.setupFile) info.setup = await this.setupInfo(this.setupFile);\n res.json(info);\n } catch (error) {\n res.json({ ...base, version: 0, wxConfig: {}, pages: [], buildError: (error as Error).message });\n }\n });\n\n app.get('/__wxa__/setup.js', async (_req, res) => {\n noStore(res);\n if (!this.setupFile) {\n res.status(404).type('text').send('没有 setup 文件');\n return;\n }\n try {\n res.type('js').send(await bundleSetup(this.setupFile));\n } catch (error) {\n res.status(500).type('text').send((error as Error).message);\n }\n });\n\n app.get('/__wxa__/appservice.html', this.withBuild((build, req, res) => {\n const launchPath = String(req.query.path || '').replace(/^\\//, '');\n const launch = build.pages.includes(launchPath)\n ? { path: launchPath, query: Object.fromEntries(new URLSearchParams(String(req.query.query || ''))) }\n : { path: build.pages[0], query: {} };\n res.type('html').send(appserviceHtml(build, launch, { hot: this.hotEnabled, isolated: usesIsolatedContext(this.baseLib.version) }));\n }));\n\n app.get('/__wxa__/subcontext.html', (req, res) => {\n const id = Number(req.query.id);\n if (!Number.isInteger(id) || id <= 0) {\n res.status(400).type('text').send('子上下文 id 无效');\n return;\n }\n res.type('html').send(subcontextHtml(id, req.query.empty === '1'));\n });\n\n app.get(/^\\/__wxa__\\/webview\\/(.+)\\.html$/, this.withBuild((build, req, res, next) => {\n const pagePath = decodeURIComponent(req.params[0]);\n if (!build.pages.includes(pagePath)) return next();\n const pluginPage = findPluginPage(build, pagePath);\n const scripts = this.webviewScripts;\n res.type('html').send(pluginPage\n ? pluginWebviewHtml(build, pluginPage.plugin, pluginPage.innerPath, pagePath, Number(req.query.id), { scripts })\n : webviewHtml(build, pagePath, Number(req.query.id), { hot: this.hotEnabled, scripts }));\n }));\n\n // 插件的逻辑层、渲染层代码\n app.get('/__wxa__/plugin/:provider/:version/:file(appservice.js|pageframe.js)', this.withBuild((build, req, res, next) => {\n const { provider, version, file } = req.params;\n const code = build.plugins.find(plugin => plugin.provider === provider && plugin.version === version)?.files.get(`/${file}`);\n if (!code) return next();\n res.type('js').send(code);\n }));\n // 插件页面里的图片等资源:基础库把插件里的相对路径和 / 开头的路径都改写成站点根下的 /__plugin__/<插件 appid>/…\n app.get(/^\\/__plugin__\\/([^/]+)(\\/.+)$/, this.withBuild((build, req, res, next) => {\n const file = build.plugins.find(plugin => plugin.provider === req.params[0])?.files.get(decodeURIComponent(req.params[1]));\n if (!file) return next();\n res.type(path.extname(req.params[1]) || 'application/octet-stream').send(file);\n }));\n\n app.get(/^\\/__wxa__\\/module\\/(.+\\.js)$/, this.withBuild((build, req, res) => {\n const id = decodeURIComponent(req.params[0]);\n if (!build.modules.includes(id) && !build.workerModules.includes(id)) {\n res.status(404).type('js').send(`console.error(${JSON.stringify(`[wxa-runner] 模块 ${id} 不存在`)})`);\n return;\n }\n res.type('js').send(this.builder.getModuleScript(id));\n }));\n\n app.get('/__wxa__/worker.js', this.withBuild((build, _req, res) => {\n const hasWorker = fs.existsSync(path.join(this.baseLib.dir, 'WAWorker.js'));\n res.type('js').send(workerScript(build, { version: this.baseLib.version, hasWorker }));\n }));\n\n app.get('/__wxa__/service-bootstrap.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.serviceBootstrap);\n }));\n\n app.get('/__wxa__/service-templates.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.serviceTemplates);\n }));\n\n app.get('/__wxa__/page-templates.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.pageTemplates);\n }));\n\n app.get('/__wxa__/page-styles.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.pageStyles);\n }));\n\n app.get('/__wxa__/page-frame.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.pageFrame);\n }));\n\n app.get('/__wxa__/runtime/frame.js.map', (_req, res, next) => {\n const file = path.join(this.runtimeDir(), 'frame.js.map');\n if (!fs.existsSync(file)) return next();\n res.type('json').send(ignoreConsoleHook(fs.readFileSync(file, 'utf8')));\n });\n app.use('/__wxa__/runtime', express.static(this.runtimeDir(), {\n cacheControl: false,\n // Service Worker 默认只能接管自己所在目录下的页面,宿主页面在根路径\n setHeaders: (res, file) => {\n if (path.basename(file) === 'sw.js') res.setHeader('Service-Worker-Allowed', '/');\n }\n }));\n // 基础库脚本加入 DevTools 的忽略列表,原始代码就是脚本本身(换个地址,免得和脚本混为一个文件)\n const sourceMaps = new Map<string, string>();\n app.get(/^\\/__baselib__\\/(.+\\.js)\\.map$/, (req, res, next) => {\n const file = path.resolve(this.baseLib.dir, req.params[0]);\n if (!file.startsWith(this.baseLib.dir + path.sep) || !fs.existsSync(file)) return next();\n if (!sourceMaps.has(file)) sourceMaps.set(file, ignoreListSourceMap(fs.readFileSync(file, 'utf8'), `${path.basename(file)}?original`));\n res.type('json').send(sourceMaps.get(file));\n });\n app.use('/__baselib__', express.static(this.baseLib.dir, {\n maxAge: '1d',\n setHeaders: (res, file) => {\n if (file.endsWith('.js')) res.setHeader('SourceMap', `${path.basename(file)}.map`);\n }\n }));\n // 用 app.use 而不是 app.all('…/*'):后者会先解码路径,见 handleProxy\n app.use(PROXY_PREFIX, express.raw({ type: () => true, limit: '100mb' }), handleProxy);\n // 被拦截的请求本该由 Service Worker 返回响应,到这里说明它没有生效\n app.use(MOCK_PREFIX, (_req, res) => {\n res.status(503).type('text').send('这个请求已被拦截规则拦下,这里只用于在 Network 面板里显示它。'\n + 'Service Worker 没有生效(如 DevTools 勾选了 Bypass for network),看不到拦截规则给出的响应');\n });\n\n // 每个浏览器会话一份 FileStore:刷新复用,不同的浏览器上下文(Playwright 的每个用例)互不可见。\n // 会话标识要拼进文件地址,只接受 fileSession() 生成的格式;不合法时返回 null\n const sessionFiles = (session: string): FileStore | null => {\n if (!/^[a-z0-9-]{1,80}$/i.test(session)) return null;\n let files = this.fileSessions.get(session);\n if (!files) {\n files = new FileStore([`/__wxa__/usr/${session}`, `/__wxa__/tmp/${session}`]);\n this.fileSessions.set(session, files);\n }\n return files;\n };\n app.post('/__wxa__/fs/:session', express.json({ limit: '150mb' }), (req, res) => {\n const files = sessionFiles(req.params.session);\n if (!files) {\n res.status(400).json({ error: `invalid filesystem session ${req.params.session}` });\n return;\n }\n // 文件不存在等是接口的正常失败,照样返回 200,免得每次失败都在浏览器控制台留下一条请求错误(基础库启动时就会探测不存在的文件)\n try {\n res.json({ result: files.execute(req.body.operation, req.body.args || {}) });\n } catch (error) {\n res.json({ error: (error as Error).message });\n }\n });\n\n // 返回完整的 http 地址:image、video 组件只原样使用 http(s) 地址。\n app.post('/__wxa__/tmp/:session', express.raw({ type: () => true, limit: '100mb' }), (req, res) => {\n const type = String(req.query.type || 'png');\n if (!/^[a-z0-9]+$/i.test(type)) {\n res.status(400).type('text').send(`非法的文件类型 ${type}`);\n return;\n }\n const files = sessionFiles(req.params.session);\n if (!files) {\n res.status(400).type('text').send(`非法的会话标识 ${req.params.session}`);\n return;\n }\n const filePath = `/__wxa__/tmp/${req.params.session}/${randomUUID()}.${type}`;\n files.write(filePath, Buffer.isBuffer(req.body) ? req.body : Buffer.alloc(0));\n res.json({ url: `${req.protocol}://${req.get('host')}${filePath}` });\n });\n app.get('/__wxa__/region/:kind', (req, res) => {\n const kind = req.params.kind;\n const data = kind === 'districts' || kind === 'streets' ? readRegionData(kind) : null;\n if (!data) {\n res.status(404).end();\n return;\n }\n res.type('text/plain; charset=utf-8').set('Cache-Control', 'public, max-age=86400').send(data);\n });\n\n app.get<{ kind: string; session: string; 0: string }>('/__wxa__/:kind(usr|tmp)/:session/*', (req, res) => {\n const files = this.fileSessions.get(req.params.session);\n const node = files?.stat(`/__wxa__/${req.params.kind}/${req.params.session}/` + req.params[0]);\n if (!node || node.dir) {\n res.status(404).end();\n return;\n }\n const data = node.data;\n res.type(path.extname(req.params[0]));\n // 每次写入更新版本号,追加和 Range 请求不再对整份文件计算哈希。\n res.setHeader('ETag', `\"${node.etag}\"`);\n // 支持分段请求,video 组件播放临时文件时才能跳转(不支持时浏览器认为视频不能跳转,seek 不起作用)\n res.setHeader('Accept-Ranges', 'bytes');\n const ranges = req.range(data.length);\n if (ranges === -1) {\n res.status(416).setHeader('Content-Range', `bytes */${data.length}`);\n res.end();\n return;\n }\n if (Array.isArray(ranges) && ranges.type === 'bytes' && ranges.length === 1) {\n const { start, end } = ranges[0];\n res.status(206).setHeader('Content-Range', `bytes ${start}-${end}/${data.length}`);\n res.send(data.subarray(start, end + 1));\n return;\n }\n res.send(data);\n });\n app.delete<{ session: string; 0: string }>('/__wxa__/tmp/:session/*', (req, res) => {\n try {\n const files = this.fileSessions.get(req.params.session);\n if (!files) throw new Error('file not exist');\n files.remove(`/__wxa__/tmp/${req.params.session}/` + req.params[0], { dir: false });\n res.status(204).end();\n } catch {\n res.status(404).end();\n }\n });\n\n if (this.ticketSource) app.use('/__wxa__/api', devtoolsLoginRouter(this.project.appid, this.ticketSource));\n\n // 渲染层页面路径下的相对资源(如 ../../images/a.png)\n app.use('/__wxa__/webview', express.static(root));\n app.use(express.static(root));\n\n app.use((error: Error, _req: Request, res: Response, _next: NextFunction) => {\n this.logger.error('[wxa-runner]', error);\n res.status(500).type('text').send(error.message);\n });\n\n return app;\n }\n\n /** 先编译一遍 setup:编译错误随 app-info 交给宿主显示,而不是让浏览器 import 失败 */\n private async setupInfo(file: string): Promise<NonNullable<AppInfo['setup']>> {\n try {\n await bundleSetup(file);\n return { env: this.setupEnv };\n } catch (error) {\n return { env: this.setupEnv, error: (error as Error).message };\n }\n }\n\n /** 构建结果并入这次打开小程序时决定用的插件 */\n private async currentBuild(): Promise<AppBuild> {\n return this.plugins.current(await this.builder.build());\n }\n\n /** 需要构建结果的路由;构建失败时返回错误文本 */\n private withBuild(handler: (build: AppBuild, req: Request, res: Response, next: NextFunction) => void) {\n return async (req: Request, res: Response, next: NextFunction) => {\n res.setHeader('Cache-Control', 'no-store');\n let build: AppBuild;\n try {\n build = await this.currentBuild();\n } catch (error) {\n res.status(500).type('text').send((error as Error).message);\n return;\n }\n try {\n handler(build, req, res, next);\n } catch (error) {\n next(error);\n }\n };\n }\n\n private runtimeDir(): string {\n const candidates = [\n this.options.runtimeDir,\n path.join(__dirname, 'runtime'),\n path.join(__dirname, '../runtime'),\n path.join(__dirname, '../../dist/runtime')\n ].filter((dir): dir is string => !!dir);\n const found = candidates.find(dir => fs.existsSync(path.join(dir, 'host.js')));\n if (!found) {\n throw new Error('找不到浏览器端运行时(host.js),请先执行 pnpm build');\n }\n return found;\n }\n\n /** 只在监听文件变化时打开基础库的热更新开关,跑测试(watch: false)时运行环境与真机一致 */\n private get hotEnabled(): boolean {\n return this.options.watch !== false;\n }\n\n private startWatching() {\n // 上次编译失败时页面上显示着错误,修好后整页刷新才能清掉\n let lastBuildFailed = false;\n\n // 项目目录下的 setup 文件不一定在小程序根目录(miniprogramRoot)里\n const watched = [this.project.root];\n if (this.setupFile && path.relative(this.project.root, this.setupFile).startsWith('..')) watched.push(this.setupFile);\n\n this.watcher = watchProject(this.project.root, watched, async ({ files, structural }) => {\n const reloadOnly = structural || lastBuildFailed;\n this.builder.invalidate(files);\n const label = files.length > 3 ? `${files.slice(0, 3).join(', ')} 等 ${files.length} 个文件` : files.join(', ');\n\n try {\n const build = await this.builder.build();\n lastBuildFailed = false;\n const plan = reloadOnly ? null : planHotUpdate(files, build);\n this.logger.log(`[wxa-runner] ${label} 已更新,重新编译 ${build.durationMs}ms${plan ? ',热更新' : ''}`);\n this.broadcast(plan ? { type: 'hot', version: build.version, ...plan } : { type: 'reload' });\n } catch (error) {\n lastBuildFailed = true;\n const message = (error as Error).message;\n this.logger.error(`[wxa-runner] 编译失败:\\n${message}`);\n this.broadcast({ type: 'error', message });\n }\n });\n }\n\n private broadcast(message: Record<string, unknown>) {\n const data = JSON.stringify(message);\n this.sockets?.clients.forEach(client => {\n if (client.readyState === WebSocket.OPEN) client.send(data);\n });\n }\n}\n\nconst DEFAULT_PORT = 3000;\n/** 监听所有地址时,本机访问用的地址:0.0.0.0 只监听 IPv4,localhost 可能解析到 IPv6 的 ::1 */\nconst LOCAL_HOST_OF_ANY_ADDRESS = new Map([['0.0.0.0', '127.0.0.1'], ['::', 'localhost']]);\n\n/** 开始监听,返回实际的端口。没指定端口时从 3000 起往后找空闲的,换了端口在终端提示 */\nasync function listen(server: http.Server, port: number | undefined, host: string, logger: Pick<Console, 'warn'>): Promise<number> {\n for (let candidate = port ?? DEFAULT_PORT; ; candidate++) {\n // macOS 允许本机地址和所有地址上各有一个进程占着同一端口,两个方向都能绑定成功,打开 localhost 会进到哪边说不准\n const taken = (await takenOnLocalAddresses(candidate)) || !(await bind(server, candidate, host));\n if (!taken) {\n const actual = (server.address() as net.AddressInfo).port;\n if (port === undefined && actual !== DEFAULT_PORT) logger.warn(`[wxa-runner] 端口 ${DEFAULT_PORT} 已被占用,改用 ${actual}`);\n return actual;\n }\n if (port !== undefined) throw new Error(`端口 ${port} 已被占用:先关闭占用它的进程,或用 --port 换一个端口`);\n }\n}\n\n/** 返回 false 表示端口已被占用 */\nfunction bind(server: net.Server, port: number, host: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n const onError = (error: NodeJS.ErrnoException) => (error.code === 'EADDRINUSE' ? resolve(false) : reject(error));\n server.once('error', onError);\n server.listen(port, host, () => {\n server.off('error', onError);\n resolve(true);\n });\n });\n}\n\nasync function takenOnLocalAddresses(port: number): Promise<boolean> {\n for (const address of ['127.0.0.1', '::1', '0.0.0.0', '::']) {\n const probe = net.createServer();\n // 没有这个地址(如关掉了 IPv6)时不算占用\n const free = await bind(probe, port, address).catch(() => true);\n if (!free) return true;\n await new Promise(resolve => probe.close(resolve));\n }\n return false;\n}\n\n/**\n * 中间件路径不能盖住宿主页面,也不能落在 runner 保留的前缀下。\n * Express 把路径当模式匹配(支持 * 和 :参数)且不区分大小写,所以只收字面量路径,按小写比较保留前缀\n */\nfunction assertMountPath(mountPath: string): void {\n const literal = typeof mountPath === 'string' && /^(\\/[\\w.~-]+)+$/.test(mountPath);\n const lower = literal ? mountPath.toLowerCase() : '';\n const reserved = RESERVED_PREFIXES.some(prefix => lower === prefix || lower.startsWith(prefix + '/'));\n if (!literal || reserved) {\n throw new Error(\n `中间件路径 ${String(mountPath)} 不可用:要以 / 开头,只含字母、数字和 _ . ~ -(不支持通配符和参数),不能是 /,` +\n `也不能用 wxa-runner 保留的前缀 ${RESERVED_PREFIXES.join('、')}(不区分大小写)`\n );\n }\n}\n\nfunction resolveSetupFile(option: string | false | undefined, projectPath: string): string | null {\n if (option === false) return null;\n if (!option) return findSetupFile(projectPath);\n const file = path.resolve(option);\n if (!fs.existsSync(file)) throw new Error(`找不到 setup 文件:${file}`);\n return file;\n}\n","/** 开发服务器持有的文件存储;文件 API、下载、上传和资源 URL 共用这些字节。 */\n\nimport { randomUUID } from 'crypto';\n\ninterface FsNode {\n dir: boolean;\n data: Buffer;\n mtime: number;\n etag: string;\n}\n\n/** 基础库会往 http://usr/ 写运行日志;业务代码也可以通过 FileSystemManager 读写 */\nexport class FileStore {\n private readonly etagPrefix = randomUUID();\n private version = 0;\n private nodes = new Map<string, FsNode>([['/', { dir: true, data: Buffer.alloc(0), mtime: Date.now(), etag: '' }]]);\n private readonly roots: string[];\n\n /** @param roots 预先创建的目录(如用户目录)。rmdir 不能删除它们和它们的上级目录:删掉之后再写 USER_DATA_PATH 都会失败 */\n constructor(roots: string[] = []) {\n this.roots = roots.map(root => this.normalize(root));\n for (const root of this.roots) this.mkdir(root, true);\n }\n\n normalize(filePath: string): string {\n const stripped = String(filePath || '').replace(/^[a-z]+:\\/\\/[^/]*/i, '');\n const parts: string[] = [];\n for (const part of stripped.split('/')) {\n if (!part || part === '.') continue;\n if (part === '..') parts.pop();\n else parts.push(part);\n }\n return '/' + parts.join('/');\n }\n\n stat(filePath: string): FsNode | undefined {\n return this.nodes.get(this.normalize(filePath));\n }\n\n mkdir(dirPath: string, recursive = false) {\n const target = this.normalize(dirPath);\n if (this.nodes.has(target)) throw new Error(`file already exists ${dirPath}`);\n const parent = target.slice(0, target.lastIndexOf('/')) || '/';\n if (!this.nodes.get(parent)?.dir) {\n if (!recursive) throw new Error(`no such file or directory ${dirPath}`);\n this.mkdir(parent, true);\n }\n this.nodes.set(target, { dir: true, data: Buffer.alloc(0), mtime: Date.now(), etag: '' });\n }\n\n write(filePath: string, input: string | Uint8Array, append = false) {\n const data = Buffer.from(input);\n const target = this.normalize(filePath);\n const parent = target.slice(0, target.lastIndexOf('/')) || '/';\n if (!this.nodes.get(parent)?.dir) throw new Error(`no such file or directory ${filePath}`);\n const existing = this.nodes.get(target);\n if (existing?.dir) throw new Error(`illegal operation on a directory ${filePath}`);\n const contents = append && existing ? Buffer.concat([existing.data, data]) : data;\n this.nodes.set(target, { dir: false, data: contents, mtime: Date.now(), etag: `${this.etagPrefix}-${++this.version}` });\n }\n\n read(filePath: string): Buffer {\n const node = this.stat(filePath);\n if (!node) throw new Error(`no such file or directory, open ${filePath}`);\n if (node.dir) throw new Error(`illegal operation on a directory ${filePath}`);\n return node.data;\n }\n\n readdir(dirPath: string): string[] {\n const target = this.normalize(dirPath);\n if (!this.nodes.get(target)?.dir) throw new Error(`no such file or directory ${dirPath}`);\n const prefix = target === '/' ? '/' : target + '/';\n return [...this.nodes.keys()]\n .filter(key => key.startsWith(prefix) && key !== target && !key.slice(prefix.length).includes('/'))\n .map(key => key.slice(prefix.length));\n }\n\n remove(filePath: string, options: { dir: boolean; recursive?: boolean }) {\n const target = this.normalize(filePath);\n const node = this.nodes.get(target);\n if (!node) throw new Error(`no such file or directory ${filePath}`);\n if (node.dir !== options.dir) throw new Error(options.dir ? `not a directory ${filePath}` : `operation not permitted ${filePath}`);\n if (node.dir) {\n const children = this.readdir(target);\n if (children.length && !options.recursive) throw new Error(`directory not empty ${filePath}`);\n for (const key of [...this.nodes.keys()]) if (key.startsWith(target + '/')) this.nodes.delete(key);\n }\n this.nodes.delete(target);\n }\n\n execute(operation: string, args: any): Record<string, any> {\n switch (operation) {\n case 'readFile': {\n const data = this.read(args.filePath);\n return args.encoding === undefined ? { data: data.toString('base64'), binary: true } : { data: data.toString(args.encoding) };\n }\n case 'writeFile':\n case 'appendFile': {\n const data = Buffer.from(args.data ?? '', args.binary ? 'base64' : args.encoding || 'utf8');\n this.write(args.filePath, data, operation === 'appendFile');\n return {};\n }\n case 'copyFile':\n this.write(args.destPath, this.read(args.srcPath));\n return {};\n case 'access':\n if (!this.stat(args.path)) throw new Error(`no such file or directory ${args.path}`);\n return {};\n case 'stat': {\n const node = this.stat(args.path);\n if (!node) throw new Error(`no such file or directory ${args.path}`);\n const stats = {\n mode: node.dir ? 0o40755 : 0o100644,\n size: node.data.length,\n lastAccessedTime: Math.floor(node.mtime / 1000),\n lastModifiedTime: Math.floor(node.mtime / 1000)\n };\n return { stats, ...stats };\n }\n case 'getFileInfo':\n return { size: this.read(args.filePath).length };\n case 'mkdir':\n this.mkdir(args.dirPath, !!args.recursive);\n return {};\n case 'readdir':\n return { files: this.readdir(args.dirPath) };\n case 'unlink':\n this.remove(args.filePath, { dir: false });\n return {};\n case 'rmdir': {\n const target = this.normalize(args.dirPath);\n const prefix = target === '/' ? '/' : target + '/';\n if (this.roots.some(root => root === target || root.startsWith(prefix))) {\n throw new Error(`operation not permitted ${args.dirPath}`);\n }\n this.remove(args.dirPath, { dir: true, recursive: !!args.recursive });\n return {};\n }\n default:\n throw new Error(`unsupported filesystem operation ${operation}`);\n }\n }\n}\n","/**\n * 把小程序项目构建成官方基础库能直接加载的形式\n *\n * 逻辑层(appservice):\n * 1. 裁剪版 $gwx(wcc -xc),基础库用它了解组件的节点结构\n * 2. 每个 JS 文件单独一个 define(\"x.js\", fn) 脚本(便于在 DevTools 里按原文件调试)\n * 3. bootstrap:注册 __wxAppCode__ 的 json/wxml(serviceTemplates,热更新时单独下发),\n * require(\"app.js\"),再依次 require 组件和页面\n *\n * 渲染层(page-frame):\n * 1. 完整版 $gwx(wcc -cc)与每个页面/组件的 __wxAppCode__ json / wxml(pageTemplates)\n * 2. wcsc 的公共样式运行时 + app.wxss,与每个页面/组件的 __wxAppCode__ wxss(pageStyles)\n * 两部分在热更新时分别下发\n * 样式和模板里的 env(safe-area-inset-*) 改写成 CSS 变量,见 rewriteSafeAreaInsets\n *\n * Worker:workers 目录下的 JS 不进逻辑层,同样包装成 define 脚本,由 Worker 入口(server/html.ts 的 workerScript)加载\n */\n\nimport { compileWxml, compileWxss, ComponentTags } from '@open-wxa/wxa-runner-compiler';\nimport { transformSync } from 'esbuild';\nimport { AppJson, MiniProgram } from './MiniProgram';\nimport { createWxConfig } from './wxConfig';\nimport { WxmlMirror } from './WxmlMirror';\n\nexport interface BuildResult {\n version: number;\n wxConfig: Record<string, any>;\n /** 所有 JS 模块 id(如 \"pages/index/index.js\"),逻辑层按此顺序加载 define 脚本 */\n modules: string[];\n /** workers 目录下的 JS 模块 id,Worker 按此顺序加载 define 脚本 */\n workerModules: string[];\n /** 逻辑层的 $gwx 与 __wxAppCode__ json/wxml,不含 require */\n serviceTemplates: string;\n serviceBootstrap: string;\n pageFrame: string;\n /** 渲染层的 $gwx 与 __wxAppCode__ json/wxml,不含样式(热更新时单独下发) */\n pageTemplates: string;\n /** 渲染层的样式:公共样式立即注入,页面和组件的样式注册到 __wxAppCode__(热更新时单独下发) */\n pageStyles: string;\n pages: string[];\n components: string[];\n durationMs: number;\n}\n\n/** define 包装函数的参数:屏蔽浏览器全局对象,与开发者工具一致 */\nconst MODULE_PARAMS = [\n 'require', 'module', 'exports', 'window', 'document', 'frames', 'self', 'location', 'navigator',\n 'localStorage', 'history', 'Caches', 'screen', 'alert', 'confirm', 'prompt', 'XMLHttpRequest',\n 'WebSocket', 'Reporter', 'webkit', 'WeixinJSCore'\n].join(', ');\n\n/**\n * import / export 语句:在行首,或者在压缩成一行的代码里紧跟着 ; 或 }。\n * 不匹配 import() 动态导入,也不匹配 importance 这类变量名\n */\nconst ESM_SYNTAX = /(?:^|[;}])\\s*(?:import\\s*[{*'\"]|import\\s+[\\w$]|export\\s*[{*]|export\\s+(?:default|const|let|var|function|class|async)\\b)/m;\n\ntype ChangeKind = 'config' | 'wxml' | 'wxss' | 'js';\n\nexport interface AppBuilderOptions {\n /** wxml 交给 wcc 前的转换,见 DevServerOptions.wxmlTransform */\n wxmlTransform?: (code: string, file: string) => string;\n}\n\nexport class AppBuilder {\n private version = 0;\n /** invalidate 标记过的变化次数;每次构建记下开始时覆盖到第几次 */\n private changes = 0;\n private pending: { covers: number; result: Promise<BuildResult> } | null = null;\n private last: BuildResult | null = null;\n private dirty = new Set<ChangeKind>(['config', 'wxml', 'wxss', 'js']);\n private wxmlCache: { full: string; cut: string } | null = null;\n private wxssCache: { comm: string; pages: Record<string, string> } | null = null;\n\n /** 设置了 wxmlTransform 时才有 */\n private readonly wxmlMirror: WxmlMirror | null;\n\n constructor(readonly project: MiniProgram, options: AppBuilderOptions = {}) {\n this.wxmlMirror = options.wxmlTransform ? new WxmlMirror(options.wxmlTransform) : null;\n }\n\n /** wxmlTransform 的镜像目录;没有设置转换或还没编译过时为 null */\n get wxmlMirrorDir(): string | null {\n return this.wxmlMirror?.directory ?? null;\n }\n\n /** 删除 wxmlTransform 的镜像目录,开发服务器关闭时调用 */\n dispose(): void {\n this.wxmlMirror?.dispose();\n }\n\n /** 根据变化的文件标记需要重新构建的部分;返回 true 表示需要刷新 */\n invalidate(changedFiles: string[] = []): boolean {\n if (changedFiles.length === 0) {\n ['config', 'wxml', 'wxss', 'js'].forEach(kind => this.dirty.add(kind as ChangeKind));\n this.changes++;\n return true;\n }\n\n let relevant = false;\n for (const file of changedFiles) {\n const kind = classifyFile(file);\n if (!kind) continue;\n relevant = true;\n this.dirty.add(kind);\n // json 决定组件关系,wxml/wxss 的编译参数都依赖它\n if (kind === 'config') {\n this.dirty.add('wxml');\n this.dirty.add('wxss');\n }\n }\n if (relevant) this.changes++;\n return relevant;\n }\n\n /**\n * 返回包含调用前所有变化的构建结果。并发调用共享同一次构建;\n * 进行中的构建开始得比最近一次变化早时(可能已读到旧文件),等它结束后再构建一次\n */\n async build(): Promise<BuildResult> {\n const wanted = this.changes;\n for (;;) {\n if (!this.pending && this.dirty.size === 0 && this.last) return this.last;\n if (!this.pending) {\n const result = this.doBuild().finally(() => {\n this.pending = null;\n });\n this.pending = { covers: this.changes, result };\n }\n const { covers, result } = this.pending;\n const built = await result;\n if (covers >= wanted) return built;\n }\n }\n\n /**\n * 单个 JS 模块的 define 包装\n *\n * 包装头和代码第一行写在同一行,行号与源文件一致。使用 import/export 的文件\n * 先转换为 CommonJS(对应开发者工具的「ES6 转 ES5」),并内联 source map。\n */\n getModuleScript(id: string): string {\n let code = this.project.readText(id);\n if (ESM_SYNTAX.test(code)) {\n try {\n code = transformSync(code, {\n format: 'cjs',\n loader: 'js',\n target: 'es2020',\n sourcefile: id,\n sourcemap: 'inline'\n }).code;\n } catch (error) {\n const message = `[wxa-runner] ${id} 转换失败:${(error as Error).message}`;\n return `console.error(${JSON.stringify(message)});\\n`;\n }\n }\n return `define(${JSON.stringify(id)}, function(${MODULE_PARAMS}){${code}\\n});\\n`;\n }\n\n private async doBuild(): Promise<BuildResult> {\n const start = Date.now();\n const dirty = new Set(this.dirty);\n this.dirty.clear();\n\n try {\n const app = this.project.readAppJson();\n const { pages, components } = this.project.collectUnits(app);\n const units = [...components, ...pages];\n const unitJson = new Map(units.map(id => [id, this.project.readUnitJson(id, app)]));\n\n const [wxml, wxss] = await Promise.all([\n dirty.has('wxml') || !this.wxmlCache ? this.compileTemplates(units, unitJson) : this.wxmlCache,\n dirty.has('wxss') || !this.wxssCache ? this.compileStyles(units) : this.wxssCache\n ]);\n this.wxmlCache = wxml;\n this.wxssCache = wxss;\n\n const workersDir = this.project.workersDir(app);\n const inWorkers = (file: string) => workersDir !== null && file.startsWith(workersDir + '/');\n const scripts = this.project.listFiles(['.js']);\n const modules = scripts.filter(file => !inWorkers(file));\n\n const serviceTemplates = this.createTemplates(app, units, unitJson, wxml.cut);\n const pageTemplates = this.createTemplates(app, units, unitJson, wxml.full);\n const pageStyles = createStyles(units, wxss);\n const result: BuildResult = {\n version: ++this.version,\n wxConfig: createWxConfig({\n app,\n pages,\n unitJson,\n appid: this.project.appid,\n subPackages: this.project.subPackages(app)\n }),\n modules,\n workerModules: scripts.filter(inWorkers),\n serviceTemplates,\n serviceBootstrap: this.createServiceBootstrap(serviceTemplates, units, modules),\n pageFrame: `${pageTemplates}\\n${pageStyles}`,\n pageTemplates,\n pageStyles,\n pages,\n components,\n durationMs: Date.now() - start\n };\n this.last = result;\n return result;\n } catch (error) {\n // 构建失败时保留脏标记,下次请求重新尝试\n dirty.forEach(kind => this.dirty.add(kind));\n throw error;\n }\n }\n\n private async compileTemplates(units: string[], unitJson: Map<string, any>) {\n const files = this.project.listFiles(['.wxml', '.wxs']).map(f => './' + f);\n const components: ComponentTags[] = units\n .filter(id => this.project.exists(id + '.wxml'))\n .map(id => {\n const json = unitJson.get(id);\n return { path: id, tags: Object.keys({ ...json.usingComponents, ...json.componentGenerics }) };\n });\n\n const cwd = this.wxmlMirror ? this.wxmlMirror.sync(this.project, files.map(file => file.slice(2))) : this.project.root;\n const [full, cut] = await Promise.all([\n compileWxml({ cwd, files, components, cut: false }),\n compileWxml({ cwd, files, components, cut: true })\n ]);\n // 只有渲染层的完整版带内联 style\n return { full: rewriteSafeAreaInsets(full), cut };\n }\n\n /** 与开发者工具一致,项目里的 wxss 全部交给 wcsc:被 @import 的文件(如 uni-app 的 common/main.wxss)也要在列表里 */\n private async compileStyles(units: string[]) {\n const pageFiles = units.filter(id => this.project.exists(id + '.wxss')).map(id => `./${id}.wxss`);\n const commonFiles = this.project.listFiles(['.wxss']).map(file => `./${file}`).filter(file => !pageFiles.includes(file));\n const { comm, pages } = await compileWxss({ cwd: this.project.root, pageFiles, commonFiles });\n return {\n comm: rewriteSafeAreaInsets(comm),\n pages: Object.fromEntries(Object.entries(pages).map(([file, css]) => [file, rewriteSafeAreaInsets(css)]))\n };\n }\n\n /** $gwx 加上各页面、组件的 json / wxml 注册;逻辑层用裁剪版 $gwx,渲染层用完整版 */\n private createTemplates(app: AppJson, units: string[], unitJson: Map<string, any>, gwx: string): string {\n const lines: string[] = [gwx, `__wxAppCode__[\"app.json\"] = ${toJs(app)};`];\n\n for (const id of units) {\n lines.push(`__wxAppCode__[${toJs(id + '.json')}] = ${toJs(unitJson.get(id))};`);\n if (this.project.exists(id + '.wxml')) {\n lines.push(`__wxAppCode__[${toJs(id + '.wxml')}] = $gwx(${toJs('./' + id + '.wxml')});`);\n }\n }\n return lines.join('\\n');\n }\n\n private createServiceBootstrap(serviceTemplates: string, units: string[], modules: string[]): string {\n const lines: string[] = [serviceTemplates];\n\n if (modules.includes('app.js')) {\n lines.push(requireStatement('app.js', null));\n }\n for (const id of units) {\n if (modules.includes(id + '.js')) lines.push(requireStatement(id + '.js', id));\n }\n return lines.join('\\n');\n }\n}\n\nfunction createStyles(units: string[], wxss: { comm: string; pages: Record<string, string> }): string {\n const lines = [wxss.comm];\n for (const id of units) {\n const css = wxss.pages[id + '.wxss'];\n if (css) lines.push(`__wxAppCode__[${toJs(id + '.wxss')}] = ${css};`);\n }\n return lines.join('\\n');\n}\n\n/** 某个模块执行出错时只影响它自己,其余页面照常注册 */\nfunction requireStatement(file: string, route: string | null): string {\n const routeSetup = route\n ? `__wxRoute = ${toJs(route)}; __wxRouteBegin = true; __wxAppCurrentFile__ = ${toJs(file)};`\n : `__wxAppCurrentFile__ = ${toJs(file)};`;\n return `${routeSetup}\\ntry { require(${toJs(file)}); } catch (error) { console.error(${toJs('[wxa-runner] ' + file + ' 执行出错\\n')}, error); }`;\n}\n\n/**\n * env(safe-area-inset-*) / constant(safe-area-inset-*) → var(--wxa-safe-area-inset-*)\n *\n * 桌面浏览器里这些 env() 恒为 0,而真机上的值取决于页面窗口是否贴着屏幕边缘(tabBar 页面底部为 0),\n * 所以改成变量,由宿主按页面写入(PageView.setSafeAreaInsets)。只替换函数名和参数名,\n * fallback 原样保留——wcsc 会把其中的 rpx 拆成数组片段,不能整体解析。\n */\nexport function rewriteSafeAreaInsets(code: string): string {\n return code.replace(/\\b(?:env|constant)\\(\\s*safe-area-inset-(top|right|bottom|left)\\b/g, 'var(--wxa-safe-area-inset-$1');\n}\n\n/** JSON 序列化并转义 </script> 与行分隔符,结果可安全嵌入脚本 */\nexport function toJs(value: unknown): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n\nfunction classifyFile(file: string): ChangeKind | null {\n if (file.endsWith('.json')) return 'config';\n if (file.endsWith('.wxml') || file.endsWith('.wxs')) return 'wxml';\n if (file.endsWith('.wxss')) return 'wxss';\n if (file.endsWith('.js')) return 'js';\n return null;\n}\n","/**\n * 生成基础库读取的 __wxConfig,字段与开发者工具保持一致\n */\n\nimport { AppJson, UnitJson } from './MiniProgram';\n\nexport const DEFAULT_WINDOW = {\n navigationBarBackgroundColor: '#000000',\n navigationBarTextStyle: 'white',\n navigationBarTitleText: '',\n backgroundColor: '#ffffff',\n backgroundTextStyle: 'dark',\n enablePullDownRefresh: false,\n onReachBottomDistance: 50\n};\n\nexport interface WxConfigInput {\n app: AppJson;\n pages: string[];\n unitJson: Map<string, UnitJson>;\n appid: string;\n subPackages: NonNullable<AppJson['subPackages']>;\n}\n\nexport function createWxConfig(input: WxConfigInput): Record<string, any> {\n const { app, pages, unitJson, appid } = input;\n const entryPage = app.entryPagePath || app.pages[0];\n\n const page: Record<string, any> = {};\n for (const id of pages) {\n const { singlePage, ...window } = unitJson.get(id) || { usingComponents: {} };\n page[id + '.html'] = { window, singlePage, renderer: window.renderer };\n }\n\n const tabBar = app.tabBar\n ? { ...app.tabBar, list: app.tabBar.list.map(item => ({ ...item, pagePath: item.pagePath + '.html' })) }\n : undefined;\n\n return {\n ...app,\n pages: app.pages,\n resizable: !!app.resizable,\n subPackages: input.subPackages.length ? input.subPackages : undefined,\n debug: !!app.debug,\n widgets: app.widgets || [],\n customClose: !!app.customClose,\n workers: app.workers || '',\n cloud: !!app.cloud,\n global: { window: { ...DEFAULT_WINDOW, ...app.window } },\n page,\n networkTimeout: { request: 60000, uploadFile: 60000, connectSocket: 60000, downloadFile: 60000, ...app.networkTimeout },\n ext: app.ext || {},\n extAppid: app.extAppid || '',\n plugins: app.plugins || {},\n mainPlugins: { ...app.plugins },\n useExtendedLib: app.useExtendedLib || {},\n requiredPrivateInfos: app.requiredPrivateInfos || [],\n __warning__: '',\n entryPagePath: entryPage + '.html',\n tabBar,\n isLazyLoad: false,\n lazyCodeLoading: undefined,\n // 以下字段由开发者工具在运行时注入\n appname: appid,\n accountInfo: { appId: appid, icon: '', nickname: appid },\n appLaunchInfo: { scene: 1001, path: entryPage, query: {} },\n envVersion: 'develop',\n platform: 'devtools',\n env: { USER_DATA_PATH: 'http://usr' },\n isPluginMiniProgram: false,\n wxAppInfo: { maxRequestConcurrent: 10, maxUploadConcurrent: 10, maxDownloadConcurrent: 10, maxWebsocketConnect: 5 },\n deviceinfo: {}\n };\n}\n","/**\n * wxmlTransform 的镜像目录\n *\n * wcc 只接收文件路径、自己从磁盘读文件,转换不能只在内存里做:把转换后的 .wxml 和原样的 .wxs\n * 写进临时目录,编译时把 wcc 的工作目录指向这里。相对路径和行号与源文件一致,编译错误照常指向源文件。\n */\n\nimport fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { MiniProgram } from './MiniProgram';\n\nexport class WxmlMirror {\n private dir: string | null = null;\n /** 已写入的文件:源内容(判断要不要重新转换)与写入的内容 */\n private readonly files = new Map<string, string>();\n\n constructor(private readonly transform: (code: string, file: string) => string) {}\n\n /** 镜像目录;还没同步过时为 null */\n get directory(): string | null {\n return this.dir;\n }\n\n /**\n * 让镜像目录与项目里的 wxml / wxs 一致,返回镜像目录。\n * 只重写源内容变化的文件;项目里已删除的文件同时从镜像目录删除,被引用时 wcc 照常报错\n */\n sync(project: MiniProgram, relPaths: string[]): string {\n const dir = (this.dir ??= fs.mkdtempSync(path.join(os.tmpdir(), 'wxa-runner-wxml-')));\n const current = new Set(relPaths);\n for (const rel of [...this.files.keys()]) {\n if (current.has(rel)) continue;\n fs.rmSync(path.join(dir, rel), { force: true });\n this.files.delete(rel);\n }\n for (const rel of relPaths) {\n const source = project.readText(rel);\n if (this.files.get(rel) === source) continue;\n const target = path.join(dir, rel);\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, rel.endsWith('.wxml') ? this.transform(source, rel) : source);\n this.files.set(rel, source);\n }\n return dir;\n }\n\n dispose(): void {\n if (this.dir) fs.rmSync(this.dir, { recursive: true, force: true });\n this.dir = null;\n this.files.clear();\n }\n}\n","/**\n * 小程序项目结构解析\n *\n * 负责读取 app.json / 页面与组件 json,并按开发者工具的规则做预处理:\n * - app.json 的全局 usingComponents 展开到每个页面和组件(miniprogram_npm 内除外)\n * - 每个页面/组件 json 都保证有 usingComponents 字段\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nexport interface AppJson {\n pages: string[];\n entryPagePath?: string;\n window?: Record<string, any>;\n tabBar?: {\n custom?: boolean;\n list: Array<{ pagePath: string; text?: string; iconPath?: string; selectedIconPath?: string }>;\n [key: string]: any;\n };\n subPackages?: Array<{ root: string; pages: string[]; independent?: boolean; [key: string]: any }>;\n subpackages?: AppJson['subPackages'];\n usingComponents?: Record<string, string>;\n /** isSubpackage:Worker 代码作为分包,业务先调 wx.preDownloadSubpackage({ packageType: 'workers' }) 再创建 Worker */\n workers?: string | { path: string; isSubpackage?: boolean };\n [key: string]: any;\n}\n\nexport interface UnitJson {\n usingComponents: Record<string, string>;\n componentGenerics?: Record<string, boolean | { default?: string }>;\n component?: boolean;\n [key: string]: any;\n}\n\nconst IGNORED_DIRS = new Set(['node_modules', '.git', '.idea', '.vscode']);\n// wxa.setup.js 是 wxa-runner 的启动前脚本,不属于小程序\nconst PROJECT_FILES = new Set(['project.config.json', 'project.private.config.json', 'sitemap.json', 'app.json', 'wxa.setup.js']);\n\nexport class MiniProgram {\n /** 小程序代码根目录(已考虑 project.config.json 的 miniprogramRoot) */\n readonly root: string;\n readonly appid: string;\n\n constructor(readonly projectPath: string) {\n const projectConfig = readJsonFile(path.join(projectPath, 'project.config.json')) || {};\n this.root = path.resolve(projectPath, projectConfig.miniprogramRoot || '');\n this.appid = projectConfig.appid || 'touristappid';\n\n if (!fs.existsSync(path.join(this.root, 'app.json'))) {\n throw new Error(`${this.root} 下没有 app.json,不是有效的小程序目录`);\n }\n }\n\n readAppJson(): AppJson {\n const app = readJsonFile(path.join(this.root, 'app.json'));\n if (!app || !Array.isArray(app.pages) || app.pages.length === 0) {\n throw new Error('app.json 缺少 pages 配置');\n }\n return app;\n }\n\n subPackages(app: AppJson) {\n return app.subPackages || app.subpackages || [];\n }\n\n /** Worker 代码所在目录,不带首尾的 /;没有配置 workers 时为 null */\n workersDir(app: AppJson): string | null {\n const dir = typeof app.workers === 'string' ? app.workers : app.workers?.path;\n return dir ? path.posix.normalize(dir).replace(/^\\/+|\\/+$/g, '') : null;\n }\n\n /** 主包页面 + 分包页面(带 root 前缀) */\n allPages(app: AppJson): string[] {\n const pages = [...app.pages];\n for (const pkg of this.subPackages(app)) {\n for (const page of pkg.pages) {\n const full = path.posix.join(pkg.root, page);\n if (!pages.includes(full)) pages.push(full);\n }\n }\n return pages;\n }\n\n /**\n * 读取并预处理页面/组件 json,id 不带扩展名。\n * 基础库运行时只把组件引用和当前路径拼在一起,不查找 miniprogram_npm、不补 /index(开发者工具编译时已解析好),\n * 所以能解析到的引用都换成组件的绝对路径\n */\n readUnitJson(id: string, app: AppJson): UnitJson {\n const json: UnitJson = { ...readJsonFile(path.join(this.root, id + '.json')) };\n const resolve = (fromId: string, ref: string) => {\n const resolved = this.resolveComponent(fromId, ref);\n return resolved ? '/' + resolved : null;\n };\n\n json.usingComponents = Object.fromEntries(\n Object.entries(json.usingComponents || {}).map(([tag, ref]) => [tag, resolve(id, ref as string) ?? ref])\n );\n if (json.componentGenerics) {\n json.componentGenerics = Object.fromEntries(Object.entries(json.componentGenerics).map(([name, generic]) => [\n name,\n typeof generic === 'object' && generic.default ? { ...generic, default: resolve(id, generic.default) ?? generic.default } : generic\n ]));\n }\n\n if (!/(^|\\/)miniprogram_npm\\//.test(id) && !this.isInIndependentSubPackage(id, app)) {\n for (const [tag, ref] of Object.entries(app.usingComponents || {})) {\n if (json.usingComponents[tag]) continue;\n // 全局引用相对 app.json 解析;解析不到的相对路径照旧换算成相对当前页面\n const resolved = resolve('app', ref);\n if (resolved || ref.startsWith('/') || /^plugin(-private)?:\\/\\//.test(ref)) {\n json.usingComponents[tag] = resolved ?? ref;\n } else {\n const relative = path.posix.relative(path.posix.dirname(id), ref);\n json.usingComponents[tag] = relative.startsWith('.') ? relative : './' + relative;\n }\n }\n }\n return json;\n }\n\n /**\n * 解析组件引用到组件路径(不带扩展名);插件组件或找不到时返回 null。\n * 规则:/ 开头为根目录绝对路径;否则先按相对路径找,再沿目录向上查找 miniprogram_npm。\n */\n resolveComponent(fromId: string, ref: string): string | null {\n if (!ref || ref.startsWith('plugin://') || ref.startsWith('plugin-private://')) return null;\n\n const fromDir = path.posix.dirname(fromId);\n const candidates: string[] = [];\n\n if (ref.startsWith('/')) {\n candidates.push(ref.slice(1));\n } else {\n candidates.push(path.posix.join(fromDir, ref));\n if (!ref.startsWith('.')) {\n let dir = fromDir;\n for (;;) {\n candidates.push(path.posix.join(dir === '.' ? '' : dir, 'miniprogram_npm', ref));\n if (dir === '.' || dir === '') break;\n dir = path.posix.dirname(dir);\n }\n }\n }\n\n for (const candidate of candidates) {\n const normalized = path.posix.normalize(candidate);\n for (const id of [normalized, path.posix.join(normalized, 'index')]) {\n if (fs.existsSync(path.join(this.root, id + '.json'))) return id;\n }\n }\n return null;\n }\n\n /** 收集页面、隐式自定义 tabBar 及它们(递归)引用到的组件 */\n collectUnits(app: AppJson): { pages: string[]; components: string[] } {\n const pages = this.allPages(app);\n const components: string[] = [];\n const visited = new Set<string>(pages);\n\n const visit = (id: string) => {\n const json = this.readUnitJson(id, app);\n const refs = Object.values(json.usingComponents);\n for (const generic of Object.values(json.componentGenerics || {})) {\n if (typeof generic === 'object' && generic.default) refs.push(generic.default);\n }\n for (const ref of refs) enter(this.resolveComponent(id, ref));\n };\n const enter = (id: string | null) => {\n if (!id || visited.has(id)) return;\n visited.add(id);\n components.push(id);\n visit(id);\n };\n\n // 自定义 tabBar 不在 usingComponents 中声明,但基础库会按固定路径创建它。\n if (app.tabBar?.custom) enter(this.resolveComponent('app', '/custom-tab-bar/index'));\n pages.forEach(visit);\n return { pages, components };\n }\n\n /** 列出代码根目录下指定扩展名的文件,返回 posix 风格的相对路径 */\n listFiles(extensions: string[]): string[] {\n const result: string[] = [];\n\n const walk = (dir: string, rel: string) => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.') || IGNORED_DIRS.has(entry.name)) continue;\n const childRel = rel ? `${rel}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(path.join(dir, entry.name), childRel);\n } else if (extensions.some(ext => entry.name.endsWith(ext))) {\n if (!rel && PROJECT_FILES.has(entry.name)) continue;\n result.push(childRel);\n }\n }\n };\n\n walk(this.root, '');\n return result.sort();\n }\n\n exists(relPath: string): boolean {\n return fs.existsSync(path.join(this.root, relPath));\n }\n\n readText(relPath: string): string {\n return fs.readFileSync(path.join(this.root, relPath), 'utf8');\n }\n\n private isInIndependentSubPackage(id: string, app: AppJson): boolean {\n return this.subPackages(app).some(pkg => pkg.independent && id.startsWith(pkg.root.replace(/\\/?$/, '/')));\n }\n}\n\nfunction readJsonFile(file: string): any {\n if (!fs.existsSync(file)) return null;\n const text = fs.readFileSync(file, 'utf8');\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new Error(`${file} 不是合法的 JSON:${(error as Error).message}`);\n }\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 * 小程序插件的代码\n *\n * 插件代码不在项目里,同开发者工具:开发服务器带着开发者 ticket 向微信下载(wxa-dev/getplugincode),\n * 只放在内存里,同一个插件版本下载一次。下载要用开发者的登录态,所以只在开启 --devtools-login 时进行;\n * 小程序的 appid 要已在管理后台添加了这个插件,并经插件开发者通过。\n *\n * 下载到的是 .wxvpkg 格式的包,里面是编译好的产物:\n * /plugin.json 插件页面表(pages)和每个页面的 window 配置(page)\n * /appservice.js 逻辑层:definePlugin(...) 注册插件,自己 requirePlugin 完成初始化\n * /pageframe.js 渲染层:插件的模板函数 $gwx_<插件 appid> 和样式\n * /pages/x/x.html 插件页面:注入样式、取模板、派发 generateFuncReady\n * /static/... 图片等资源\n * 插件页面的路径是 __plugin__/<插件 appid>/pages/x/x,基础库把 plugin://别名/页面名 解析成它再交给原生路由。\n */\n\nimport { readWxvpkgFile, readWxvpkgIndex } from '@open-wxa/wxa-runner-extractor';\nimport type { BuildResult } from '../project/AppBuilder';\nimport { requireOk, WechatDevClient } from './wechatDev';\n\nconst DOWNLOAD_TIMEOUT = 30_000;\nconst PACKAGE_MAGIC = 0xbe;\n\nexport interface PluginCode {\n /** app.json 里的引用名,plugin://<alias>/页面名 */\n alias: string;\n /** 插件 appid */\n provider: string;\n version: string;\n /** 包内路径(/ 开头)→ 内容 */\n files: Map<string, Buffer>;\n /** 插件页面的路径,如 __plugin__/wx…/pages/index/index */\n pages: string[];\n /** 插件页面的配置,键同 __wxConfig.page(路径加 .html) */\n pageConfigs: Record<string, unknown>;\n}\n\n/** 构建结果加上用到的插件:插件页面并入 pages,配置并入 __wxConfig.page */\nexport interface AppBuild extends BuildResult {\n plugins: PluginCode[];\n}\n\n/** app.json 的 plugins:引用名 → { provider, version } */\ntype DeclaredPlugins = Record<string, { provider?: string; version?: string }>;\n\nexport class PluginStore {\n /** provider@version → 下载结果;失败的不留,下次打开小程序时重试 */\n private readonly downloads = new Map<string, Promise<PluginCode>>();\n /**\n * 这次打开小程序时决定用哪些插件。同一次打开的逻辑层、业务模块、渲染层等请求都按它处理:\n * 各自去下载的话,下载失败时每个请求都会重试,结果还可能前后不一,页面列表和逻辑层对不上\n */\n private selection: Promise<PluginCode[]> | null = null;\n /** 没开 --devtools-login 的提示每个插件只说一次 */\n private readonly warned = new Set<string>();\n\n /**\n * @param wechat 开启 --devtools-login 时才有,没有时不下载插件\n */\n constructor(\n private readonly wechat: WechatDevClient | null,\n private readonly logger: Pick<Console, 'warn'>\n ) {}\n\n /** 打开小程序时(宿主取 app-info)调用:重新决定用哪些插件,下载过的直接用,上次失败的重试 */\n async refresh(build: BuildResult): Promise<AppBuild> {\n this.selection = this.select(build);\n return withPlugins(build, await this.selection);\n }\n\n /** 其余请求沿用这次打开时的决定,不触发下载;还没决定过时(如直接请求逻辑层)先决定一次 */\n async current(build: BuildResult): Promise<AppBuild> {\n this.selection ??= this.select(build);\n return withPlugins(build, await this.selection);\n }\n\n /** app.json 声明的插件;下载不了的跳过,在终端说明原因,小程序自己的页面照常可用 */\n private async select(build: BuildResult): Promise<PluginCode[]> {\n const declared: DeclaredPlugins = build.wxConfig.plugins || {};\n const results = await Promise.all(Object.entries(declared).map(([alias, { provider, version }]) =>\n provider && version ? this.load(alias, provider, version) : null\n ));\n return results.filter((plugin): plugin is PluginCode => !!plugin);\n }\n\n private async load(alias: string, provider: string, version: string): Promise<PluginCode | null> {\n const label = `插件 ${alias}(${provider}@${version})`;\n if (!this.wechat) {\n this.warnOnce(label, `[wxa-runner] ${label} 的代码要用开发者的登录态向微信下载,启动时加 --devtools-login`);\n return null;\n }\n\n const key = `${provider}@${version}`;\n let download = this.downloads.get(key);\n if (!download) {\n download = this.download(this.wechat, alias, provider, version);\n this.downloads.set(key, download);\n download.catch(() => this.downloads.delete(key));\n }\n try {\n return await download;\n } catch (error) {\n this.logger.warn(`[wxa-runner] ${label} 下载失败:${(error as Error).message}`);\n return null;\n }\n }\n\n /** @throws 没有登录态、连不上、微信拒绝或返回的不是插件代码包时,消息是原因 */\n private async download(wechat: WechatDevClient, alias: string, provider: string, version: string): Promise<PluginCode> {\n const response = await wechat.post('wxa-dev/getplugincode', { plugin_id: provider, plugin_version: version }, DOWNLOAD_TIMEOUT);\n const data = Buffer.from(await response.arrayBuffer());\n // 出错时返回的是带 baseresponse 的 JSON\n if (data[0] !== PACKAGE_MAGIC) {\n let body: { baseresponse?: { errcode?: number; errmsg?: string } } = {};\n try {\n body = JSON.parse(data.toString('utf8'));\n } catch {\n // 不是 JSON,按没有结果码处理\n }\n if (body.baseresponse?.errcode) requireOk(body, '微信拒绝下载');\n throw new Error('微信没有返回插件代码');\n }\n\n const files = new Map(readWxvpkgIndex(data).map(entry => [entry.name, Buffer.from(readWxvpkgFile(data, entry))]));\n const pluginJson = JSON.parse(files.get('/plugin.json')?.toString('utf8') || '{}');\n return {\n alias,\n provider,\n version,\n files,\n pages: Object.values<string>(pluginJson.pages || {}),\n pageConfigs: pluginJson.page || {}\n };\n }\n\n private warnOnce(key: string, message: string) {\n if (this.warned.has(key)) return;\n this.warned.add(key);\n this.logger.warn(message);\n }\n}\n\n/** 插件页面并入 pages,配置并入 __wxConfig.page */\nfunction withPlugins(build: BuildResult, plugins: PluginCode[]): AppBuild {\n if (!plugins.length) return { ...build, plugins };\n return {\n ...build,\n plugins,\n pages: [...build.pages, ...plugins.flatMap(plugin => plugin.pages)],\n wxConfig: {\n ...build.wxConfig,\n page: { ...build.wxConfig.page, ...Object.assign({}, ...plugins.map(plugin => plugin.pageConfigs)) }\n }\n };\n}\n\n/** 插件页面所属的插件,以及页面在插件包里的路径(不带扩展名) */\nexport function findPluginPage(build: AppBuild, pagePath: string): { plugin: PluginCode; innerPath: string } | null {\n for (const plugin of build.plugins) {\n const prefix = `__plugin__/${plugin.provider}/`;\n if (plugin.pages.includes(pagePath)) return { plugin, innerPath: pagePath.slice(prefix.length) };\n }\n return null;\n}\n\nexport function pluginScriptUrl(plugin: PluginCode, file: 'appservice.js' | 'pageframe.js'): string {\n return `/__wxa__/plugin/${encodeURIComponent(plugin.provider)}/${encodeURIComponent(plugin.version)}/${file}`;\n}\n","/**\n * 借开发者的登录态访问微信后台:开发者工具访问的同一组接口(servicewechat.com 下的 wxa-dev、wxa-dev-logic)\n *\n * 登录、手机号、服务市场、插件都经这里,ticket、超时、网络错误和登录态失效的提示在这里统一处理。\n * 这些接口没有公开文档,请求和响应的格式取自开发者工具的实现和实测。\n */\n\nimport { DeveloperTicket, TICKET_ENV } from '@open-wxa/wxa-runner-extractor';\n\nconst BASE_URL = 'https://servicewechat.com';\n/** 开发者工具请求这些接口时带的版本号 */\nconst CLIENT_VERSION = '1021810240';\nconst DEFAULT_TIMEOUT = 10_000;\n\nconst ERROR_HINTS: Record<number, string> = {\n // 40001:开发者工具刷新过 ticket,旧的随即作废\n 40001: '(登录态已失效,请在微信开发者工具里重新登录)',\n 40029: '(登录态已失效,请在微信开发者工具里重新登录)',\n 85023: '(当前微信账号不是该小程序的开发者)'\n};\n\nexport type FindTicket = () => DeveloperTicket | null | Promise<DeveloperTicket | null>;\n\n/**\n * 取出可用的 ticket\n *\n * @throws 没有登录态或已过期时,消息是给用户看的处理办法\n */\nexport function requireUsableTicket(ticket: DeveloperTicket | null): string {\n if (!ticket) throw new Error(`未找到微信开发者工具的登录态,请登录开发者工具,或设置环境变量 ${TICKET_ENV}`);\n if (ticket.expiredAt !== undefined && ticket.expiredAt <= Date.now()) {\n throw new Error('微信开发者工具的登录态已过期,请打开开发者工具刷新登录态');\n }\n return ticket.newticket;\n}\n\n/** 给错误码加上处理办法,如登录态失效时提示重新登录 */\nexport function explainErrcode(errcode: number | undefined): string {\n return (errcode !== undefined && ERROR_HINTS[errcode]) || '';\n}\n\n/**\n * 检查 baseresponse 里的结果码\n *\n * @throws 结果码不为 0 时,消息是 action 加上结果码、错误信息和处理办法\n */\nexport function requireOk<T extends { baseresponse?: { errcode?: number; errmsg?: string } }>(body: T, action: string): T {\n const errcode = body.baseresponse?.errcode;\n if (errcode !== 0) throw new Error(`${action} ${errcode}: ${body.baseresponse?.errmsg || '未知错误'}${explainErrcode(errcode)}`);\n return body;\n}\n\nexport class WechatDevClient {\n /**\n * @param findTicket 每次请求都重新取:开发者工具重新登录、切换账号后不用重启服务器\n */\n constructor(\n readonly appid: string,\n private readonly findTicket: FindTicket\n ) {}\n\n /**\n * POST JSON 到 path(如 wxa-dev-logic/jslogin),带上 appid 和开发者 ticket\n *\n * @throws 没有可用的登录态、超时、连不上、HTTP 状态不是 2xx 时,消息是给用户看的原因\n */\n async post(path: string, body: object, timeout = DEFAULT_TIMEOUT): Promise<Response> {\n const query = new URLSearchParams({ appid: this.appid, newticket: requireUsableTicket(await this.findTicket()), clientversion: CLIENT_VERSION });\n const response = await fetch(`${BASE_URL}/${path}?${query}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeout)\n }).catch((error: Error & { cause?: Error }) => {\n // Node 的 fetch 只报 fetch failed,具体原因(DNS、连接被拒等)在 cause 里\n throw new Error(error.name === 'TimeoutError'\n ? `请求微信服务器超时(${timeout / 1000}s)`\n : `请求微信服务器失败:${error.cause?.message ?? error.message}`);\n });\n if (!response.ok) throw new Error(`微信服务器返回 HTTP ${response.status}`);\n return response;\n }\n\n /** 同 post,返回解析后的 JSON */\n async postJson(path: string, body: object): Promise<any> {\n return (await this.post(path, body)).json();\n }\n}\n","/**\n * 宿主、逻辑层、渲染层的 HTML,以及 Worker 的入口脚本\n */\n\nimport { BuildResult, toJs } from '../project/AppBuilder';\nimport type { WebviewScript } from './DevServer';\nimport { AppBuild, PluginCode, pluginScriptUrl } from './plugins';\n\nexport function hostHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>wxa-runner</title>\n</head>\n<body>\n <div id=\"wxa-root\"></div>\n <script src=\"/__wxa__/runtime/host.js\"></script>\n</body>\n</html>`;\n}\n\n/**\n * 打开基础库的热更新开关(runtime/host/hmr.ts 依赖它):Page / Component / 模板注册时登记更新回调。\n * 必须紧跟在基础库之后、业务代码注册之前执行;只在监听文件变化时打开\n */\nfunction enableHotUpdate(hot: boolean): string {\n return hot\n ? `<script>if (typeof __virtualDOM__ !== 'undefined' && __virtualDOM__.enableUpdateWxAppCode) __virtualDOM__.enableUpdateWxAppCode();</script>\\n`\n : '';\n}\n\n/**\n * isolated:新版基础库(3.7.1 起)。逻辑层 iframe 只是主上下文,业务代码由基础库通过 WeixinJSContext\n * 放进子上下文执行(见 runtime/context.ts),逻辑层就绪的通知也由那边发出\n */\nexport function appserviceHtml(\n build: AppBuild,\n launch: { path: string; query: Record<string, string> },\n options: { hot: boolean; isolated?: boolean }\n): string {\n const wxConfig = {\n ...build.wxConfig,\n appLaunchInfo: { scene: 1001, path: launch.path, query: launch.query },\n ...(options.isolated ? { isIsolateContext: true } : {})\n };\n const v = build.version;\n // 插件在业务代码之前注册:业务代码执行时就能 requirePlugin、跳转插件页面。\n // 插件脚本也排在业务模块的 define 之前,与开发者工具一致:插件初始化时调用 requireMiniProgram() 会因导出模块还没 define 而失败,开发者工具里同样如此\n const pluginUrls = build.plugins.map(plugin => pluginScriptUrl(plugin, 'appservice.js'));\n const moduleUrls = build.modules.map(id => `/__wxa__/module/${encodeURI(id)}?v=${v}`);\n const bootstrapUrl = `/__wxa__/service-bootstrap.js?v=${v}`;\n\n if (options.isolated) {\n const scripts = [...pluginUrls, ...moduleUrls, bootstrapUrl];\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>appservice</title>\n<script>var __wxConfig = ${toJs(wxConfig)};</script>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"service\" data-app-service=\"${escapeHtml(JSON.stringify(scripts))}\"${options.hot ? ' data-hot=\"1\"' : ''}></script>\n<script src=\"/__baselib__/WAServiceMainContext.js\"></script>\n</head>\n<body></body>\n</html>`;\n }\n\n const modules = [...pluginUrls, ...moduleUrls].map(src => `<script src=\"${src}\"></script>`).join('\\n');\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>appservice</title>\n<script>var __wxConfig = ${toJs(wxConfig)};</script>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"service\"></script>\n<script src=\"/__baselib__/WAService.js\"></script>\n${enableHotUpdate(options.hot)}<script>\nif (typeof define !== 'function') {\n console.error('[wxa-runner] 基础库没有完成初始化(define 不存在),当前基础库版本可能不受支持');\n}\n</script>\n${modules}\n<script src=\"${bootstrapUrl}\"></script>\n<script>parent.__wxaHost.frameLoaded('service', 0);</script>\n</head>\n<body></body>\n</html>`;\n}\n\n/**\n * 主上下文通过 WeixinJSContext 创建的子上下文(runtime/context.ts)。\n * empty 对应 allocEmpty:不预先加载 WASubContext.js,由基础库随后 loadLibFiles\n */\nexport function subcontextHtml(id: number, empty: boolean): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>subcontext ${id}</title>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"service\" data-context-id=\"${id}\"></script>\n${empty ? '' : '<script src=\"/__baselib__/WASubContext.js\"></script>\\n'}<script>parent.__wxaContexts.loaded(${id});</script>\n</head>\n<body></body>\n</html>`;\n}\n\nexport function webviewHtml(build: AppBuild, pagePath: string, webviewId: number, options: { hot: boolean; scripts?: WebviewScript[] }): string {\n const id = Number(webviewId) || 0;\n return `<!DOCTYPE html>\n<html>\n<head>\n${webviewHead(build, pagePath, id, options.scripts)}\n${enableHotUpdate(options.hot)}<script src=\"/__wxa__/page-frame.js?v=${build.version}\"></script>\n${pageWindow(build, pagePath).disableScroll ? '<style>body{overflow-y:hidden}</style>' : ''}\n</head>\n<body>\n${scriptTags(options.scripts, 'body')}<script>\n(function () {\n var path = ${toJs(pagePath)};\n if (typeof __wxAppCode__[path + '.wxss'] === 'function') __wxAppCode__[path + '.wxss']();\n var generateFunc = $gwx('./' + path + '.wxml');\n if (generateFunc) {\n document.dispatchEvent(new CustomEvent('generateFuncReady', { detail: { generateFunc: generateFunc } }));\n } else {\n document.body.innerText = './' + path + '.wxml not found';\n console.error('[wxa-runner] ./' + path + '.wxml not found');\n }\n parent.__wxaHost.frameLoaded('webview', ${id});\n})();\n</script>\n</body>\n</html>`;\n}\n\n/**\n * Worker 的入口(/__wxa__/worker.js?id=),由逻辑层的原生 WeixinWorker 创建(runtime/workers.ts)。\n * 和开发者工具一样先放 __wxConfig 和原生接口(runtime/worker.ts),再加载 Worker 基础库和 workers 目录下的模块;\n * 模块逐个加载,DevTools 里保留原文件名和行号。\n * Worker 基础库把 console 换成转发给逻辑层的版本,转发时对象被转成文本;开发者工具加载完基础库后换回原来的,日志留在 Worker 里。\n * 基础库目录里没有 WAWorker.js 时(如只放了逻辑层和渲染层文件的旧版内置基础库),直接抛出异常说明缺少的文件,由逻辑层的 Worker 对象记入 errors()(runtime/workers.ts)\n */\nexport function workerScript(build: BuildResult, baseLib: { version: string; hasWorker: boolean }): string {\n const modules = build.workerModules.map(id => `/__wxa__/module/${encodeURI(id)}?v=${build.version}`);\n const prelude = `var __wxConfig = ${toJs(build.wxConfig)}; __wxConfig.env.USER_DATA_PATH = location.origin + \"/__wxa__/usr/\" + new URL(location.href).searchParams.get(\"session\");\nimportScripts('/__wxa__/runtime/worker.js');\n`;\n if (!baseLib.hasWorker) {\n const message = `[wxa-runner] 基础库 ${baseLib.version} 里没有 WAWorker.js,Worker 不能运行。换用开发者工具下载的基础库,或升级 wxa-runner 带上新的内置基础库`;\n return `${prelude}throw new Error(${toJs(message)});\n`;\n }\n return `${prelude}var __wxaConsole = self.console;\nimportScripts('/__baselib__/WAWorker.js');\nself.console = __wxaConsole;\nimportScripts(${modules.map(url => toJs(url)).join(', ')});\n`;\n}\n\n/**\n * 插件页面:只加载插件自己的模板和样式(pageframe.js),不加载小程序的,与开发者工具一致。\n * 页面 html 是插件包里编译好的片段,自己注入样式、取模板并派发 generateFuncReady\n */\nexport function pluginWebviewHtml(\n build: AppBuild,\n plugin: PluginCode,\n innerPath: string,\n pagePath: string,\n webviewId: number,\n options: { scripts?: WebviewScript[] } = {}\n): string {\n const id = Number(webviewId) || 0;\n const page = plugin.files.get(`/${innerPath}.html`)?.toString('utf8') ?? `<script>console.error(${JSON.stringify(`[wxa-runner] 插件 ${plugin.alias} 里没有页面 ${innerPath}`)})</script>`;\n return `<!DOCTYPE html>\n<html>\n<head>\n${webviewHead(build, pagePath, id, options.scripts)}\n<script src=\"${pluginScriptUrl(plugin, 'pageframe.js')}\"></script>\n${pageWindow(build, pagePath).disableScroll ? '<style>body{overflow-y:hidden}</style>' : ''}\n</head>\n<body>\n${scriptTags(options.scripts, 'body')}${page}\n<script>parent.__wxaHost.frameLoaded('webview', ${id});</script>\n</body>\n</html>`;\n}\n\nfunction pageWindow(build: AppBuild, pagePath: string): Record<string, any> {\n return { ...build.wxConfig.global?.window, ...build.wxConfig.page?.[pagePath + '.html']?.window };\n}\n\n/** 渲染层公共的 head:页面配置、桥和基础库;position 为 head 的注入脚本在桥之后、基础库之前(body 的见 WebviewScript) */\nfunction webviewHead(build: AppBuild, pagePath: string, id: number, scripts?: WebviewScript[]): string {\n const wxConfig = { ...build.wxConfig, window: pageWindow(build, pagePath) };\n return `<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>${escapeHtml(pagePath)}</title>\n<!-- 小程序渲染层的默认字号是 16px;不声明的话会继承浏览器设置里的默认字号。放在最前面,基础库和页面样式都能覆盖它 -->\n<style>html{font-size:16px}</style>\n<!-- 真机的滚动条是不占布局的浮层;桌面浏览器的常规滚动条和自定义 ::-webkit-scrollbar 会挤窄页面,一律隐藏。\n scrollbar-width 优先于 ::-webkit-scrollbar,页面样式不会再把滚动条加回来 -->\n<style>*{scrollbar-width:none}::-webkit-scrollbar{display:none}</style>\n<!-- 逻辑层建的 2d、webgl 画布搬进 wx-canvas 后铺满它(见 frame.ts 的 moveCanvasesIntoPages)。\n 基础库还会按逻辑层里的布局改它的位置和显隐,这里一律压住;触摸照常交给 wx-canvas 自己的 canvas -->\n<style>.wxa-service-canvas{position:absolute!important;left:0!important;top:0!important;width:100%!important;height:100%!important;visibility:inherit!important;pointer-events:none}</style>\n<script>var __wxConfig = ${toJs(wxConfig)};</script>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"webview\" data-webview-id=\"${id}\"></script>\n${scriptTags(scripts, 'head')}<script src=\"/__baselib__/WAWebview.js\"></script>`;\n}\n\n/** 注入脚本的 <script> 标签,每个一行;内联内容里的 </script 转义,不会提前结束标签 */\nfunction scriptTags(scripts: WebviewScript[] | undefined, position: 'head' | 'body'): string {\n return (scripts ?? [])\n .filter(script => (script.position ?? 'body') === position)\n .map(script => script.src !== undefined\n ? `<script src=\"${escapeHtml(script.src)}\"></script>\\n`\n : `<script>${script.content.replace(/<\\/script/gi, '<\\\\/script')}</script>\\n`)\n .join('');\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/[&<>\"]/g, ch => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!));\n}\n","/**\n * 把基础库脚本加入 Chrome DevTools 的忽略列表(source map 的 x_google_ignoreList),调试时只看业务代码\n *\n * 新版基础库用 BaseConsole 包装 console 来收集日志,业务代码的 console.log 在 DevTools 里显示的来源\n * 成了这层包装(3.17 起基础库自己把它命名为 __WXAPPLIB_IGNORE__,就是留给调试工具跳过的)。\n * 忽略列表里的帧会被 DevTools 跳过:控制台的来源链接、调用栈、单步调试都落到业务代码上。\n * source map 只在打开 DevTools 时才会请求,不影响运行。\n *\n * 映射是恒等的:原始代码就是脚本本身,每行按固定间隔打点;从忽略列表里移除后仍能在基础库里调试,\n * 位置误差不超过一个间隔\n */\n\n/** 打点间隔(列):基础库压缩成很长的行,逐字符映射太大 */\nconst STRIDE = 100;\n\nconst BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/** @param source 原始代码的地址,相对 source map 的地址解析 */\nexport function ignoreListSourceMap(code: string, source: string): string {\n let previousColumn = 0;\n const mappings = code.split('\\n').map((line, index) => {\n const segments: string[] = [];\n for (let column = 0; column === 0 || column < line.length; column += STRIDE) {\n // 各字段都是相对上一个打点的增量:生成列(每行从 0 重新算)、源文件、源行、源列\n const sourceLine = column === 0 && index > 0 ? 1 : 0;\n segments.push(vlq(column === 0 ? 0 : STRIDE) + vlq(0) + vlq(sourceLine) + vlq(column - previousColumn));\n previousColumn = column;\n }\n return segments.join(',');\n });\n return JSON.stringify({ version: 3, sources: [source], names: [], mappings: mappings.join(';'), x_google_ignoreList: [0] });\n}\n\nfunction vlq(value: number): string {\n let rest = value < 0 ? (-value << 1) | 1 : value << 1;\n let out = '';\n do {\n let digit = rest & 31;\n rest >>>= 5;\n if (rest > 0) digit |= 32;\n out += BASE64[digit];\n } while (rest > 0);\n return out;\n}\n","/**\n * 把浏览器转发来的报错和控制台输出打印到终端(浏览器端见 runtime/host/ConsoleForwarder.ts)\n *\n * 开了 --host 时局域网里的设备也能连上来发消息:去掉控制字符,免得借转义序列操纵终端;限制长度和频率,免得刷屏\n */\n\nimport type { RawData, WebSocket } from 'ws';\n\nconst MAX_LENGTH = 4000;\nconst LIMIT_PER_SECOND = 20;\n/** C0、C1 控制字符,保留换行和制表符 */\n// oxlint-disable-next-line no-control-regex -- 就是要匹配控制字符\nconst CONTROL_CHARS = /[\\u0000-\\u0008\\u000b-\\u001f\\u007f-\\u009f]/g;\n\nexport function printBrowserReports(socket: WebSocket, logger: Pick<Console, 'warn' | 'error'>) {\n let windowStart = 0;\n let printed = 0;\n let dropped = 0;\n socket.on('message', data => {\n const report = parseReport(data);\n if (!report) return;\n const now = Date.now();\n if (now - windowStart >= 1000) {\n windowStart = now;\n printed = 0;\n }\n if (printed >= LIMIT_PER_SECOND) {\n // 这一秒结束时说明省略了多少条\n if (dropped++ === 0) {\n setTimeout(() => {\n logger.warn(`[wxa-runner] 浏览器 1 秒内转发的报错太多,省略了 ${dropped} 条`);\n dropped = 0;\n }, windowStart + 1000 - now).unref();\n }\n return;\n }\n printed++;\n logger[report.level](`[wxa-runner] ${clean(report.text)}`);\n });\n}\n\nfunction parseReport(data: RawData): { level: 'warn' | 'error'; text: string } | null {\n try {\n const report = JSON.parse(data.toString());\n if (report?.type === 'console' && (report.level === 'warn' || report.level === 'error') && typeof report.text === 'string') return report;\n } catch {\n // 不是 JSON\n }\n return null;\n}\n\nfunction clean(text: string): string {\n const printable = text.replace(CONTROL_CHARS, '');\n return printable.length > MAX_LENGTH ? `${printable.slice(0, MAX_LENGTH)}…(已截断)` : printable;\n}\n\n/** frame.js 的 source map 加上忽略列表:包装 console 的代码(consoleHook.ts)不作为控制台输出的来源 */\nexport function ignoreConsoleHook(sourceMap: string): string {\n const map = JSON.parse(sourceMap);\n map.x_google_ignoreList = map.sources.flatMap((source: string, index: number) => (source.endsWith('consoleHook.ts') ? [index] : []));\n return JSON.stringify(map);\n}\n","/**\n * 网络代理:浏览器端的 wx.request 经由这里转发到真实服务器\n *\n * - 原地址写在路径里:/__wxa__/proxy/https/api.example.com/a?b=1(见 networkPanel.ts)\n * - 绕开 CORS\n * - 小程序设置的请求头放在 x-wxa-headers(JSON)里传过来,\n * 这样 cookie / referer / user-agent 等浏览器禁止设置的头也能带上\n * - 响应头和 set-cookie 以 URL 编码的 JSON 返回,浏览器端可以完整读取\n */\n\nimport type { Request, Response } from 'express';\nimport { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\nimport { pipeline } from 'node:stream/promises';\nimport { fromServerPath, PROXY_PREFIX } from '../runtime/networkPanel';\n\n// fetch 不允许或无意义的请求头\nconst DROPPED_REQUEST_HEADERS = new Set(['host', 'connection', 'content-length', 'transfer-encoding', 'keep-alive', 'upgrade', 'expect']);\n// 响应体已被解压/重新分块,这些头不再成立\nconst DROPPED_RESPONSE_HEADERS = new Set(['content-encoding', 'content-length', 'transfer-encoding', 'connection', 'set-cookie']);\n\n/**\n * 用 app.use 挂在 PROXY_PREFIX 下。原地址从未解码的 originalUrl 取:解码后路径里的 %2F 等会变成别的地址。\n * 不能用 app.all('/__wxa__/proxy/*'):Express 会先解码 * 匹配的部分,地址里有单独的 %(如 /discount/50%)时直接报错\n */\nexport async function handleProxy(req: Request, res: Response) {\n const target = fromServerPath(PROXY_PREFIX, req.originalUrl);\n if (!target) {\n res.status(400).set('x-wxa-proxy-error', '1').send(`invalid url \"${req.originalUrl}\"`);\n return;\n }\n\n let requestHeaders: Record<string, string> = {};\n try {\n requestHeaders = JSON.parse(req.get('x-wxa-headers') || '{}');\n } catch {\n // 头格式错误时按无自定义头处理\n }\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(requestHeaders)) {\n if (!DROPPED_REQUEST_HEADERS.has(key.toLowerCase()) && value !== undefined && value !== null) {\n headers[key] = String(value);\n }\n }\n // 上传文件时 multipart 的 boundary 只有浏览器生成的 content-type 里才有\n const browserContentType = req.get('content-type') || '';\n if (browserContentType.startsWith('multipart/form-data')) {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === 'content-type') delete headers[key];\n }\n headers['content-type'] = browserContentType;\n }\n\n const hasBody = !['GET', 'HEAD'].includes(req.method) && Buffer.isBuffer(req.body) && req.body.length > 0;\n\n const controller = new AbortController();\n const cancel = () => controller.abort();\n res.once('close', cancel);\n\n try {\n let upstream: globalThis.Response;\n try {\n upstream = await fetch(target, {\n method: req.method,\n headers,\n body: hasBody ? req.body : undefined,\n redirect: 'follow',\n signal: controller.signal\n });\n } catch (error) {\n if (res.destroyed || controller.signal.aborted) return;\n const cause = (error as any)?.cause?.message;\n res.status(502).set('x-wxa-proxy-error', '1').send(cause || (error as Error).message);\n return;\n }\n\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n const setCookies = typeof upstream.headers.getSetCookie === 'function' ? upstream.headers.getSetCookie() : [];\n\n res.status(upstream.status);\n upstream.headers.forEach((value, key) => {\n if (!DROPPED_RESPONSE_HEADERS.has(key)) res.setHeader(key, value);\n });\n res.setHeader('x-wxa-headers', encodeURIComponent(JSON.stringify(responseHeaders)));\n res.setHeader('x-wxa-set-cookie', encodeURIComponent(JSON.stringify(setCookies)));\n // 不等响应结束:长连接的响应头和数据块要立即到达浏览器。\n res.flushHeaders();\n if (!upstream.body) {\n res.end();\n return;\n }\n await pipeline(Readable.fromWeb(upstream.body as ReadableStream), res);\n } catch (error) {\n // 响应头已经发出,流中断时关闭连接,让客户端收到失败,而不是补发一个 502。\n if (!res.destroyed) res.destroy(error as Error);\n } finally {\n res.off('close', cancel);\n }\n}\n","/**\n * 热更新分流:文件改动能否在不刷新整页的情况下应用(浏览器端应用见 runtime/host/hmr.ts)\n */\n\nexport interface HotUpdatePlan {\n /** 模板要更新的页面和组件(不带扩展名) */\n templates: string[];\n /** 逻辑要更新的页面和组件(不带扩展名) */\n scripts: string[];\n /** 改动的样式文件(不带扩展名),包括 app.wxss 和被 @import 的文件 */\n styles: string[];\n}\n\n/**\n * @param files 相对小程序根目录的改动文件\n * @returns null 表示需要整页刷新:只要有一个文件既不是样式,也不是页面或组件自己的 WXML / JS\n */\nexport function planHotUpdate(files: string[], units: { pages: string[]; components: string[] }): HotUpdatePlan | null {\n const owners = new Set([...units.pages, ...units.components]);\n const plan: HotUpdatePlan = { templates: [], scripts: [], styles: [] };\n\n for (const file of files) {\n const id = file.replace(/\\.(wxml|js|wxss)$/, '');\n const target = file.endsWith('.wxss')\n ? plan.styles\n : !owners.has(id) ? null : file.endsWith('.wxml') ? plan.templates : file.endsWith('.js') ? plan.scripts : null;\n if (!target) return null;\n if (!target.includes(id)) target.push(id);\n }\n return plan;\n}\n","/**\n * --devtools-login 用的开发者 ticket 从哪来\n *\n * 环境变量 WECHAT_DEV_TICKET 优先。新版开发者工具(Electron)把登录态加密存放,磁盘上只剩旧版留下的、\n * 早已作废的 ticket,所以要向正在运行的开发者工具要:用它的命令行为项目开启自动化接口,\n * 再通过自动化协议的 Tool.getTicket 取当前生效的 ticket。旧版(package.nw)照旧读磁盘上的登录数据。\n *\n * 不调用 Tool.refreshTicket:刷新会让别人手里的 ticket 立即作废,ticket 过期时开发者工具取的时候会自己刷新。\n */\n\nimport { execFile } from 'child_process';\nimport { randomUUID } from 'crypto';\nimport { setTimeout as sleep } from 'timers/promises';\nimport { WebSocket } from 'ws';\nimport { DeveloperTicket, findDeveloperTicket, findElectronDevtoolsCli, TICKET_ENV } from '@open-wxa/wxa-runner-extractor';\n\nexport type TicketSource = () => Promise<DeveloperTicket | null>;\n\n/** 自动化接口的惯用端口;被占用时开发者工具会换一个,以命令行返回的为准 */\nconst AUTO_PORT = 9420;\n/** 开发者工具没在运行时命令行要先启动它,项目窗口还可能在等用户确认信任 */\nconst CLI_TIMEOUT = 60_000;\n/**\n * 取 ticket 平时 10ms 左右,项目窗口刚打开时第一次约 1s。项目窗口被关掉后开发者工具的后台可能还在监听,\n * 请求不报错而是一直挂着,超时就当自动化接口失效,重新开启\n */\nconst AUTOMATOR_TIMEOUT = 5_000;\n/** 开启自动化后项目窗口要过一会儿才登记好,之前取 ticket 会报找不到窗口(开发者工具自己的命令行开启后等 8s 再用) */\nconst WINDOW_TIMEOUT = 10_000;\nconst WINDOW_RETRY_INTERVAL = 500;\n\n/**\n * @param projectPath 项目目录(project.config.json 所在目录),开发者工具为它开启自动化接口,项目窗口没开时会打开\n * @param logger 开启自动化接口时告诉用户,因为开发者工具里可能多出一个项目窗口\n * @returns 每次调用都重新取,开发者工具重新登录、刷新 ticket 后不用重启。取不到时抛错,消息是给用户看的原因和处理办法\n */\nexport function developerTicketSource(projectPath: string, logger: Pick<Console, 'log'>): TicketSource {\n const cli = findElectronDevtoolsCli();\n if (!cli) return async () => findDeveloperTicket();\n\n let automatorPort: Promise<number> | null = null;\n // 同时发起的几次请求共用一次开启;失败了下次请求再试,用户改好设置后不用重启\n const startOnce = () => {\n if (!automatorPort) {\n const starting = startAutomation(cli, projectPath).then(port => {\n logger.log(`[wxa-runner] --devtools-login:已在微信开发者工具里为项目开启自动化接口(端口 ${port}),ticket 从开发者工具实时获取`);\n return port;\n });\n starting.catch(() => {\n if (automatorPort === starting) automatorPort = null;\n });\n automatorPort = starting;\n }\n return automatorPort;\n };\n\n return async () => {\n if (process.env[TICKET_ENV]) return { newticket: process.env[TICKET_ENV] };\n\n const port = startOnce();\n try {\n return await requestTicketOnceWindowReady(await port, projectPath);\n } catch (error) {\n if (!(error instanceof AutomatorGone)) throw error;\n // 开发者工具重启过、项目窗口被关掉:重新开启一次再试\n if (automatorPort === port) automatorPort = null;\n return requestTicketOnceWindowReady(await startOnce(), projectPath);\n }\n };\n}\n\n/** 自动化接口连不上或不响应了,消息是重新开启后还这样时给用户看的 */\nclass AutomatorGone extends Error {}\nclass WindowNotFound extends Error {}\n\nasync function requestTicketOnceWindowReady(port: number, projectPath: string): Promise<DeveloperTicket> {\n const deadline = Date.now() + WINDOW_TIMEOUT;\n for (;;) {\n try {\n return await requestTicket(port);\n } catch (error) {\n if (!(error instanceof WindowNotFound)) throw error;\n if (Date.now() >= deadline) throw new Error(`微信开发者工具里找不到项目窗口,请在微信开发者工具里打开项目 ${projectPath}`);\n await sleep(WINDOW_RETRY_INTERVAL);\n }\n }\n}\n\n/**\n * 用开发者工具的命令行为项目开启自动化接口:开发者工具没在运行时启动它,项目窗口已经开着时复用\n *\n * @returns 自动化接口的端口\n */\nasync function startAutomation(cli: string, projectPath: string): Promise<number> {\n // 开发者工具设了「CLI 访问令牌」时,命令行自己从继承的环境变量 WECHAT_DEVTOOLS_CLI_TOKEN 读取\n const stdout = await runCli(cli, ['agent', 'start', '--project', projectPath, '--auto-port', String(AUTO_PORT), '--lang', 'zh']);\n // 成功时最后打印一段 JSON;失败时退出码多半还是 0,错误以 [error] 开头打印\n let autoPort = NaN;\n try {\n autoPort = Number(JSON.parse(stdout.match(/^\\{$[\\s\\S]*?^\\}$/m)?.[0] ?? '').autoPort);\n } catch {\n // 没有 JSON,从输出里找原因\n }\n if (Number.isInteger(autoPort) && autoPort > 0) return autoPort;\n\n if (stdout.includes('服务端口已关闭')) {\n throw new Error('微信开发者工具的服务端口已关闭,请在开发者工具「设置 → 安全设置」里开启服务端口');\n }\n throw new Error(`微信开发者工具没能为项目开启自动化接口:${cliErrorMessage(stdout)}`);\n}\n\n/** @returns 命令行的标准输出;命令行退出码不为 0 时也返回,由调用方从输出里找原因 */\nfunction runCli(cli: string, args: string[]): Promise<string> {\n // Windows 上是 cli.bat,要经 cmd 运行,路径里常有空格(Program Files)\n const bat = cli.endsWith('.bat');\n const [file, fileArgs] = bat ? [`\"${cli}\"`, args.map(arg => `\"${arg}\"`)] : [cli, args];\n return new Promise((resolve, reject) => {\n const child = execFile(file, fileArgs, { shell: bat, timeout: CLI_TIMEOUT, windowsHide: true }, (error, stdout) => {\n if (error?.killed) {\n reject(new Error(`微信开发者工具的命令行 ${CLI_TIMEOUT / 1000}s 内没有完成,请看开发者工具里是否有等待确认的弹窗(如信任项目、扫码登录)`));\n } else if (error && !stdout) {\n reject(new Error(`运行微信开发者工具的命令行失败:${error.message}`));\n } else {\n resolve(stdout);\n }\n });\n child.stdin?.end();\n });\n}\n\n/**\n * 命令行把错误对象按 util.inspect 的格式打印,原因在 message 的第一行。\n * util.inspect 默认用单引号,字符串里有单引号时改用双引号,两种都有时用反引号\n */\nfunction cliErrorMessage(stdout: string): string {\n // oxlint-disable-next-line no-control-regex -- 去掉命令行输出里的 ANSI 颜色\n const output = stdout.replace(/\\x1b\\[[0-9;]*m/g, '');\n const start = output.indexOf('[error]');\n const error = (start < 0 ? output : output.slice(start + '[error]'.length)).trim();\n const message = error.match(/message: (['\"`])((?:\\\\.|(?!\\1)[^\\\\])*?)(?:\\\\n|\\1)/)?.[2];\n return message ?? (error.replace(/\\s+/g, ' ').slice(0, 200) || '命令行没有输出');\n}\n\n/**\n * 通过自动化协议取开发者工具当前的 ticket:一条 WebSocket,{ id, method, params } → { id, result | error }\n *\n * 开发者工具会把别的自动化会话的消息也广播给每个连接,自己的回包还会收到两遍,按 id 认第一条\n */\nfunction requestTicket(port: number): Promise<DeveloperTicket> {\n return new Promise((resolve, reject) => {\n const id = `wxa-runner-${randomUUID()}`;\n const socket = new WebSocket(`ws://127.0.0.1:${port}`);\n const settle = (finish: () => void) => {\n clearTimeout(timer);\n socket.removeAllListeners().on('error', () => undefined).terminate();\n finish();\n };\n const timer = setTimeout(\n () =>\n settle(() =>\n reject(new AutomatorGone(`微信开发者工具的自动化接口 ${AUTOMATOR_TIMEOUT / 1000}s 内没有响应,请确认开发者工具里打开了项目窗口`))\n ),\n AUTOMATOR_TIMEOUT\n );\n const gone = () => settle(() => reject(new AutomatorGone(`连不上微信开发者工具的自动化接口(端口 ${port}),请确认开发者工具在运行`)));\n\n socket.on('error', gone);\n socket.on('close', gone);\n socket.on('open', () => socket.send(JSON.stringify({ id, method: 'Tool.getTicket', params: {} })));\n socket.on('message', data => {\n let message;\n try {\n message = JSON.parse(String(data));\n } catch {\n return;\n }\n if (message?.id !== id) return;\n if (message.error) settle(() => reject(explainAutomatorError(String(message.error.message))));\n else if (typeof message.result?.ticket !== 'string') settle(() => reject(new Error('微信开发者工具没有返回登录票据')));\n else settle(() => resolve({ newticket: message.result.ticket, expiredAt: message.result.expiredTime }));\n });\n });\n}\n\n/** 开发者工具给的是英文,换成处理办法 */\nfunction explainAutomatorError(message: string): Error {\n if (message.includes('GUI project window is not found')) return new WindowNotFound(message);\n if (message.includes('not allow to get')) {\n return new Error('微信开发者工具不允许获取登录票据,请在开发者工具「设置 → 安全设置」里打开「允许获取工具登录票据」');\n }\n if (message.includes('need to login')) return new Error('微信开发者工具未登录,请先在开发者工具里登录');\n return new Error(`微信开发者工具返回错误:${message}`);\n}\n","/**\n * --devtools-login 的接口:借本机开发者工具的登录态,向微信换取真实的 wx.login code 和手机号,转发服务市场和插件的请求\n *\n * POST /login → { code }\n * POST /phone-number → { data, encryptedData, iv },code 在 data(JSON 字符串)里,与基础库的约定一致\n * POST /operate-wx-data { data } → { data }:wx.serviceMarket 经原生 operateWXData 发出的请求,同开发者工具转发给微信\n * POST /verify-plugin { data } → { data: { list } }:插件校验,list 是每个插件能访问的域名\n * POST /batch-get-contact { appIds } → { contactList }:插件信息\n *\n * 失败时返回 500 和 { error: 原因 }。开发者 ticket 只留在 Node 进程里,接口只接受本机访问,\n * 并校验 Host 头防止 DNS rebinding。\n */\n\nimport express, { NextFunction, Request, Response, Router } from 'express';\nimport { findDeveloperTicket } from '@open-wxa/wxa-runner-extractor';\nimport { explainErrcode, FindTicket, requireOk, WechatDevClient } from './wechatDev';\n\nconst LOOPBACK_ADDRESSES = ['127.0.0.1', '::1', '::ffff:127.0.0.1'];\nconst LOOPBACK_HOSTS = ['localhost', '127.0.0.1', '[::1]'];\n\n/**\n * 经 /operate-wx-data 转发的 operateWXData:只放行服务市场。别的(用户信息、授权等)在开发者工具里\n * 会弹窗让用户确认,不能让业务代码借开发者的登录态直接调用\n */\nconst FORWARDED_WX_DATA_APIS = ['webapi_servicemarket_jsapi_comm'];\n\n/**\n * @param findTicket 每次请求都重新查找:开发者工具重新登录、切换账号后不用重启服务器\n */\nexport function devtoolsLoginRouter(appid: string, findTicket: FindTicket = findDeveloperTicket): Router {\n const wechat = new WechatDevClient(appid, findTicket);\n const router = express.Router();\n router.use(onlyLoopback);\n\n router.post('/login', respond(async () => {\n const body = requireOk(await wechat.postJson('wxa-dev-logic/jslogin', { scope: ['snsapi_base'] }), '微信登录失败');\n if (!body.code) throw new Error('微信登录失败:微信没有返回 code');\n return { code: body.code };\n }));\n\n router.post('/phone-number', respond(async () => {\n const body = await wechat.postJson('wxa-dev-logic/jsgetuserwxphone', { appid });\n // 结果码在 jsapi_baseresponse 里,不是 jslogin 那样的 baseresponse\n const errcode = body.jsapi_baseresponse?.errcode ?? body.BaseResponse?.Ret;\n if (errcode !== 0 || typeof body.data !== 'string') {\n const errmsg = body.jsapi_baseresponse?.errmsg || body.BaseResponse?.ErrMsg?.String || '未知错误';\n throw new Error(`获取手机号失败 ${errcode}: ${errmsg}${explainErrcode(errcode)}`);\n }\n // data 原样转交:基础库从 JSON.parse(data) 里取 code 和 request_id\n const { encryptedData, iv } = JSON.parse(body.data);\n return { data: body.data, encryptedData, iv };\n }));\n\n router.post('/operate-wx-data', express.json({ limit: '10mb' }), (req, res, next) => {\n const apiName = req.body?.data?.api_name;\n if (FORWARDED_WX_DATA_APIS.includes(apiName)) return next();\n res.status(403).json({ error: `operateWXData 只转发服务市场的请求,不转发 ${apiName}` });\n }, respond(async req => {\n // 与开发者工具一致:基础库给的 data 序列化成文本放在 data 字段里\n const body = requireOk(await wechat.postJson('wxa-dev-logic/jsoperatewxdata', { data: JSON.stringify(req.body.data) }), '服务市场调用失败');\n if (typeof body.data !== 'string') throw new Error('服务市场调用失败:微信没有返回结果');\n // 服务市场自己的结果码在 data 里,由基础库解析成 invokeService 的结果\n return { data: JSON.parse(body.data) };\n }));\n\n // 插件:基础库启动时校验插件、取插件信息,插件里的网络请求要等拿到这两样才发出\n router.post('/verify-plugin', express.json(), respond(async req => {\n // 与开发者工具一致:基础库给的 data 序列化后放在 ext_info 里\n const body = requireOk(await wechat.postJson('wxa-dev-logic/verifyplugin', { ext_info: JSON.stringify(req.body?.data || {}) }), '插件校验失败');\n return { data: { list: body.list || [] } };\n }));\n\n router.post('/batch-get-contact', express.json(), respond(async req => {\n const body = requireOk(await wechat.postJson('wxa-dev-logic/batchgetcontact', { appid_list: req.body?.appIds || [] }), '获取插件信息失败');\n const contacts: Array<{ appid: string; plugin_info?: { plugin_list?: unknown[] } }> = body.contact_list || [];\n return { contactList: contacts.filter(contact => contact.plugin_info).map(contact => ({ appId: contact.appid, plugin_list: contact.plugin_info!.plugin_list })) };\n }));\n\n return router;\n}\n\nfunction onlyLoopback(req: Request, res: Response, next: NextFunction) {\n // req.hostname 去掉端口时能正确处理 IPv6 的 [::1]:3000\n if (!LOOPBACK_ADDRESSES.includes(req.socket.remoteAddress || '') || !LOOPBACK_HOSTS.includes(req.hostname)) {\n res.status(403).json({ error: '开发者登录态接口只允许本机访问' });\n return;\n }\n next();\n}\n\nfunction respond(action: (req: Request) => Promise<object>) {\n return async (req: Request, res: Response) => {\n try {\n res.json(await action(req));\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n };\n}\n","/**\n * setup 文件的发现、编译与环境变量(浏览器端执行见 runtime/host/setup.ts)\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { build, Plugin } from 'esbuild';\n\nexport const SETUP_FILE_NAMES = ['wxa.setup.ts', 'wxa.setup.js', 'wxa.setup.mjs'];\nconst SETUP_MODULE = '@open-wxa/wxa-runner-core/setup';\nconst ENV_PREFIX = 'WXA_';\n\n/** 项目目录(project.config.json 所在目录)下约定名称的 setup 文件 */\nexport function findSetupFile(projectPath: string): string | null {\n for (const name of SETUP_FILE_NAMES) {\n const file = path.join(projectPath, name);\n if (fs.existsSync(file)) return file;\n }\n return null;\n}\n\n/** 只暴露 WXA_ 前缀的变量:setup 跑在浏览器里,其余环境变量可能是不该外泄的密钥 */\nexport function collectSetupEnv(env: NodeJS.ProcessEnv): Record<string, string> {\n return Object.fromEntries(\n Object.entries(env).filter((entry): entry is [string, string] => entry[0].startsWith(ENV_PREFIX) && entry[1] !== undefined)\n );\n}\n\n/**\n * 把 setup 文件连同它 import 的文件打成一个浏览器 ES 模块\n *\n * 用户的小程序项目里通常没装本包,对它的引用直接换成运行时自带的实现。\n *\n * @throws 语法错误、import 找不到等编译错误,消息里带相对 setup 文件目录的位置\n */\nexport async function bundleSetup(file: string): Promise<string> {\n const result = await build({\n entryPoints: [file],\n absWorkingDir: path.dirname(file),\n bundle: true,\n format: 'esm',\n platform: 'browser',\n target: 'es2020',\n write: false,\n logLevel: 'silent',\n sourcemap: 'inline',\n plugins: [builtinSetupModule()]\n });\n return result.outputFiles[0].text;\n}\n\nfunction builtinSetupModule(): Plugin {\n return {\n name: 'wxa-setup-module',\n setup(pluginBuild) {\n pluginBuild.onResolve({ filter: new RegExp(`^${SETUP_MODULE}$`) }, () => ({ path: SETUP_MODULE, namespace: 'wxa-setup' }));\n pluginBuild.onLoad({ filter: /.*/, namespace: 'wxa-setup' }, () => ({\n // 与 src/setup.ts 的 defineSetup 一致:只为类型提示,运行时原样返回\n contents: 'export function defineSetup(setup) { return setup; }',\n loader: 'js'\n }));\n }\n };\n}\n","/**\n * 文件监听:把开发者一次保存引起的文件变化合并成一批报告\n */\n\nimport { createHash } from 'crypto';\nimport fs from 'fs';\nimport path from 'path';\nimport chokidar from 'chokidar';\n\nexport interface FileChanges {\n /** 相对小程序根目录、以 / 分隔的路径 */\n files: string[];\n /** 有文件新增或删除:页面、模块列表可能变了,只能整页刷新 */\n structural: boolean;\n}\n\nexport interface ProjectWatcher {\n /** 初次扫描完成;此前已存在的文件不会作为改动报告 */\n ready: Promise<void>;\n close(): Promise<void>;\n}\n\nconst DEBOUNCE = 120;\nconst IGNORED = /(^|[/\\\\])(node_modules|\\.git)([/\\\\]|$)/;\nconst FINGERPRINTED = /\\.(js|mjs|ts|json|wxml|wxss|wxs)$/;\n\n/**\n * @param root 报告的路径相对这个目录\n * @param paths 要监听的目录和文件,可以在 root 之外\n * @param onChange 变化停下 120ms 后调用。内容没变的代码文件不算改动:\n * 构建工具(如 uni-app 的监听构建)每次保存都会重写全部产物\n */\nexport function watchProject(root: string, paths: string[], onChange: (changes: FileChanges) => void): ProjectWatcher {\n let changed = new Set<string>();\n let structural = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n // 初次扫描时记下每个代码文件的内容指纹\n const fingerprints = new Map<string, string>();\n let scanned = false;\n\n const watcher = chokidar.watch(paths, { ignored: IGNORED });\n const ready = new Promise<void>(resolve => {\n watcher.on('ready', () => {\n scanned = true;\n resolve();\n });\n });\n\n const flush = () => {\n const changes = { files: [...changed], structural };\n changed = new Set();\n structural = false;\n onChange(changes);\n };\n\n watcher.on('all', (event, file) => {\n const unchanged = updateFingerprint(fingerprints, file, event);\n if (!scanned || unchanged) return;\n if (event !== 'change') structural = true;\n changed.add(path.relative(root, file).split(path.sep).join('/'));\n if (timer) clearTimeout(timer);\n timer = setTimeout(flush, DEBOUNCE);\n });\n\n return { ready, close: () => watcher.close() };\n}\n\n/** 记录文件的内容指纹;返回 true 表示内容与上次相同。图片等其他文件不读取,一律视为有变化 */\nfunction updateFingerprint(fingerprints: Map<string, string>, file: string, event: string): boolean {\n if (event === 'unlink') {\n fingerprints.delete(file);\n return false;\n }\n if ((event !== 'add' && event !== 'change') || !FINGERPRINTED.test(file)) return false;\n let next: string;\n try {\n next = createHash('sha1').update(fs.readFileSync(file)).digest('hex');\n } catch {\n return false;\n }\n const previous = fingerprints.get(file);\n fingerprints.set(file, next);\n return previous === next;\n}\n","/**\n * 开发服务器扩展:检查器这类开发工具把要用的扩展点打包成一个扩展,\n * 由 DevServer 的 extensions 选项或命令行的 --extension 加载。runner 只认这个约定,不认识具体的工具。\n *\n * (「插件」在 runner 里指小程序插件,见 plugins.ts,所以这里叫扩展)\n */\n\nimport type { DevServerMiddleware, WebviewScript } from './DevServer';\n\nexport interface DevServerExtension {\n /** 出现在报错和启动信息里 */\n name: string;\n /** 开发服务器构造时调用一次 */\n setup(context: ExtensionContext): ExtensionSetup;\n}\n\nexport interface ExtensionContext {\n /** 项目目录(DevServer 的 projectPath,绝对路径) */\n projectPath: string;\n /** 小程序代码根目录,已考虑 project.config.json 的 miniprogramRoot */\n root: string;\n}\n\nexport interface ExtensionSetup {\n webviewScripts?: WebviewScript[];\n middlewares?: DevServerMiddleware[];\n wxmlTransform?: (code: string, file: string) => string;\n /** 扩展自己的页面:启动信息里打印,命令行 --open 时打开 */\n entry?: { label: string; path: string };\n}\n\nexport interface ExtensionEntry {\n name: string;\n label: string;\n path: string;\n}\n\ntype WxmlTransform = (code: string, file: string) => string;\n\n/**\n * 把扩展合并进开发服务器自己的扩展点:脚本和中间件按顺序拼在后面,\n * wxml 转换按顺序串起来(先执行选项里直接给的,再依次执行各个扩展的)\n */\nexport function applyExtensions(\n base: ExtensionSetup,\n extensions: DevServerExtension[],\n context: ExtensionContext\n): Required<Omit<ExtensionSetup, 'entry' | 'wxmlTransform'>> & { wxmlTransform?: WxmlTransform; entries: ExtensionEntry[] } {\n const webviewScripts = [...(base.webviewScripts ?? [])];\n const middlewares = [...(base.middlewares ?? [])];\n const transforms = base.wxmlTransform ? [base.wxmlTransform] : [];\n const entries: ExtensionEntry[] = [];\n\n for (const extension of extensions) {\n let setup: ExtensionSetup;\n try {\n setup = extension.setup(context);\n } catch (error) {\n throw new Error(`扩展 ${extension.name} 初始化失败:${(error as Error).message}`);\n }\n webviewScripts.push(...(setup.webviewScripts ?? []));\n middlewares.push(...(setup.middlewares ?? []));\n if (setup.wxmlTransform) transforms.push(setup.wxmlTransform);\n if (setup.entry) entries.push({ name: extension.name, ...setup.entry });\n }\n\n const wxmlTransform = transforms.length === 0\n ? undefined\n : (code: string, file: string) => transforms.reduce((result, transform) => transform(result, file), code);\n return { webviewScripts, middlewares, wxmlTransform, entries };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACyBA,IAAAA,iBAA2B;;;ACvB3B,oBAA2B;AAUpB,IAAM,YAAN,MAAgB;AAAA;AAAA,EAOrB,YAAY,QAAkB,CAAC,GAAG;AANlC,SAAiB,iBAAa,0BAAW;AACzC,SAAQ,UAAU;AAClB,SAAQ,QAAQ,oBAAI,IAAoB,CAAC,CAAC,KAAK,EAAE,KAAK,MAAM,MAAM,OAAO,MAAM,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;AAKhH,SAAK,QAAQ,MAAM,IAAI,UAAQ,KAAK,UAAU,IAAI,CAAC;AACnD,eAAW,QAAQ,KAAK,MAAO,MAAK,MAAM,MAAM,IAAI;AAAA,EACtD;AAAA,EAEA,UAAU,UAA0B;AAClC,UAAM,WAAW,OAAO,YAAY,EAAE,EAAE,QAAQ,sBAAsB,EAAE;AACxE,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,SAAS,MAAM,GAAG,GAAG;AACtC,UAAI,CAAC,QAAQ,SAAS,IAAK;AAC3B,UAAI,SAAS,KAAM,OAAM,IAAI;AAAA,UACxB,OAAM,KAAK,IAAI;AAAA,IACtB;AACA,WAAO,MAAM,MAAM,KAAK,GAAG;AAAA,EAC7B;AAAA,EAEA,KAAK,UAAsC;AACzC,WAAO,KAAK,MAAM,IAAI,KAAK,UAAU,QAAQ,CAAC;AAAA,EAChD;AAAA,EAEA,MAAM,SAAiB,YAAY,OAAO;AACxC,UAAM,SAAS,KAAK,UAAU,OAAO;AACrC,QAAI,KAAK,MAAM,IAAI,MAAM,EAAG,OAAM,IAAI,MAAM,uBAAuB,OAAO,EAAE;AAC5E,UAAM,SAAS,OAAO,MAAM,GAAG,OAAO,YAAY,GAAG,CAAC,KAAK;AAC3D,QAAI,CAAC,KAAK,MAAM,IAAI,MAAM,GAAG,KAAK;AAChC,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,6BAA6B,OAAO,EAAE;AACtE,WAAK,MAAM,QAAQ,IAAI;AAAA,IACzB;AACA,SAAK,MAAM,IAAI,QAAQ,EAAE,KAAK,MAAM,MAAM,OAAO,MAAM,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,MAAM,GAAG,CAAC;AAAA,EAC1F;AAAA,EAEA,MAAM,UAAkB,OAA4B,SAAS,OAAO;AAClE,UAAM,OAAO,OAAO,KAAK,KAAK;AAC9B,UAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,UAAM,SAAS,OAAO,MAAM,GAAG,OAAO,YAAY,GAAG,CAAC,KAAK;AAC3D,QAAI,CAAC,KAAK,MAAM,IAAI,MAAM,GAAG,IAAK,OAAM,IAAI,MAAM,6BAA6B,QAAQ,EAAE;AACzF,UAAM,WAAW,KAAK,MAAM,IAAI,MAAM;AACtC,QAAI,UAAU,IAAK,OAAM,IAAI,MAAM,oCAAoC,QAAQ,EAAE;AACjF,UAAM,WAAW,UAAU,WAAW,OAAO,OAAO,CAAC,SAAS,MAAM,IAAI,CAAC,IAAI;AAC7E,SAAK,MAAM,IAAI,QAAQ,EAAE,KAAK,OAAO,MAAM,UAAU,OAAO,KAAK,IAAI,GAAG,MAAM,GAAG,KAAK,UAAU,IAAI,EAAE,KAAK,OAAO,GAAG,CAAC;AAAA,EACxH;AAAA,EAEA,KAAK,UAA0B;AAC7B,UAAM,OAAO,KAAK,KAAK,QAAQ;AAC/B,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,mCAAmC,QAAQ,EAAE;AACxE,QAAI,KAAK,IAAK,OAAM,IAAI,MAAM,oCAAoC,QAAQ,EAAE;AAC5E,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,QAAQ,SAA2B;AACjC,UAAM,SAAS,KAAK,UAAU,OAAO;AACrC,QAAI,CAAC,KAAK,MAAM,IAAI,MAAM,GAAG,IAAK,OAAM,IAAI,MAAM,6BAA6B,OAAO,EAAE;AACxF,UAAM,SAAS,WAAW,MAAM,MAAM,SAAS;AAC/C,WAAO,CAAC,GAAG,KAAK,MAAM,KAAK,CAAC,EACzB,OAAO,SAAO,IAAI,WAAW,MAAM,KAAK,QAAQ,UAAU,CAAC,IAAI,MAAM,OAAO,MAAM,EAAE,SAAS,GAAG,CAAC,EACjG,IAAI,SAAO,IAAI,MAAM,OAAO,MAAM,CAAC;AAAA,EACxC;AAAA,EAEA,OAAO,UAAkB,SAAgD;AACvE,UAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,6BAA6B,QAAQ,EAAE;AAClE,QAAI,KAAK,QAAQ,QAAQ,IAAK,OAAM,IAAI,MAAM,QAAQ,MAAM,mBAAmB,QAAQ,KAAK,2BAA2B,QAAQ,EAAE;AACjI,QAAI,KAAK,KAAK;AACZ,YAAM,WAAW,KAAK,QAAQ,MAAM;AACpC,UAAI,SAAS,UAAU,CAAC,QAAQ,UAAW,OAAM,IAAI,MAAM,uBAAuB,QAAQ,EAAE;AAC5F,iBAAW,OAAO,CAAC,GAAG,KAAK,MAAM,KAAK,CAAC,EAAG,KAAI,IAAI,WAAW,SAAS,GAAG,EAAG,MAAK,MAAM,OAAO,GAAG;AAAA,IACnG;AACA,SAAK,MAAM,OAAO,MAAM;AAAA,EAC1B;AAAA,EAEA,QAAQ,WAAmB,MAAgC;AACzD,YAAQ,WAAW;AAAA,MACjB,KAAK,YAAY;AACf,cAAM,OAAO,KAAK,KAAK,KAAK,QAAQ;AACpC,eAAO,KAAK,aAAa,SAAY,EAAE,MAAM,KAAK,SAAS,QAAQ,GAAG,QAAQ,KAAK,IAAI,EAAE,MAAM,KAAK,SAAS,KAAK,QAAQ,EAAE;AAAA,MAC9H;AAAA,MACA,KAAK;AAAA,MACL,KAAK,cAAc;AACjB,cAAM,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,SAAS,WAAW,KAAK,YAAY,MAAM;AAC1F,aAAK,MAAM,KAAK,UAAU,MAAM,cAAc,YAAY;AAC1D,eAAO,CAAC;AAAA,MACV;AAAA,MACA,KAAK;AACH,aAAK,MAAM,KAAK,UAAU,KAAK,KAAK,KAAK,OAAO,CAAC;AACjD,eAAO,CAAC;AAAA,MACV,KAAK;AACH,YAAI,CAAC,KAAK,KAAK,KAAK,IAAI,EAAG,OAAM,IAAI,MAAM,6BAA6B,KAAK,IAAI,EAAE;AACnF,eAAO,CAAC;AAAA,MACV,KAAK,QAAQ;AACX,cAAM,OAAO,KAAK,KAAK,KAAK,IAAI;AAChC,YAAI,CAAC,KAAM,OAAM,IAAI,MAAM,6BAA6B,KAAK,IAAI,EAAE;AACnE,cAAM,QAAQ;AAAA,UACZ,MAAM,KAAK,MAAM,QAAU;AAAA,UAC3B,MAAM,KAAK,KAAK;AAAA,UAChB,kBAAkB,KAAK,MAAM,KAAK,QAAQ,GAAI;AAAA,UAC9C,kBAAkB,KAAK,MAAM,KAAK,QAAQ,GAAI;AAAA,QAChD;AACA,eAAO,EAAE,OAAO,GAAG,MAAM;AAAA,MAC3B;AAAA,MACA,KAAK;AACH,eAAO,EAAE,MAAM,KAAK,KAAK,KAAK,QAAQ,EAAE,OAAO;AAAA,MACjD,KAAK;AACH,aAAK,MAAM,KAAK,SAAS,CAAC,CAAC,KAAK,SAAS;AACzC,eAAO,CAAC;AAAA,MACV,KAAK;AACH,eAAO,EAAE,OAAO,KAAK,QAAQ,KAAK,OAAO,EAAE;AAAA,MAC7C,KAAK;AACH,aAAK,OAAO,KAAK,UAAU,EAAE,KAAK,MAAM,CAAC;AACzC,eAAO,CAAC;AAAA,MACV,KAAK,SAAS;AACZ,cAAM,SAAS,KAAK,UAAU,KAAK,OAAO;AAC1C,cAAM,SAAS,WAAW,MAAM,MAAM,SAAS;AAC/C,YAAI,KAAK,MAAM,KAAK,UAAQ,SAAS,UAAU,KAAK,WAAW,MAAM,CAAC,GAAG;AACvE,gBAAM,IAAI,MAAM,2BAA2B,KAAK,OAAO,EAAE;AAAA,QAC3D;AACA,aAAK,OAAO,KAAK,SAAS,EAAE,KAAK,MAAM,WAAW,CAAC,CAAC,KAAK,UAAU,CAAC;AACpE,eAAO,CAAC;AAAA,MACV;AAAA,MACA;AACE,cAAM,IAAI,MAAM,oCAAoC,SAAS,EAAE;AAAA,IACnE;AAAA,EACF;AACF;;;ADnHA,IAAAC,aAAe;AACf,kBAAsD;AACtD,iBAAgB;AAChB,IAAAC,aAAe;AACf,IAAAC,eAAiB;AACjB,IAAAC,kBAAkE;AAClE,IAAAC,aAA2C;AAC3C,IAAAC,+BAAqF;;;AEhBrF,iCAAwD;AACxD,qBAA8B;;;ACbvB,IAAM,iBAAiB;AAAA,EAC5B,8BAA8B;AAAA,EAC9B,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,uBAAuB;AACzB;AAUO,SAAS,eAAe,OAA2C;AACxE,QAAM,EAAE,KAAK,OAAO,UAAU,MAAM,IAAI;AACxC,QAAM,YAAY,IAAI,iBAAiB,IAAI,MAAM,CAAC;AAElD,QAAM,OAA4B,CAAC;AACnC,aAAW,MAAM,OAAO;AACtB,UAAM,EAAE,YAAY,GAAG,OAAO,IAAI,SAAS,IAAI,EAAE,KAAK,EAAE,iBAAiB,CAAC,EAAE;AAC5E,SAAK,KAAK,OAAO,IAAI,EAAE,QAAQ,YAAY,UAAU,OAAO,SAAS;AAAA,EACvE;AAEA,QAAM,SAAS,IAAI,SACf,EAAE,GAAG,IAAI,QAAQ,MAAM,IAAI,OAAO,KAAK,IAAI,WAAS,EAAE,GAAG,MAAM,UAAU,KAAK,WAAW,QAAQ,EAAE,EAAE,IACrG;AAEJ,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO,IAAI;AAAA,IACX,WAAW,CAAC,CAAC,IAAI;AAAA,IACjB,aAAa,MAAM,YAAY,SAAS,MAAM,cAAc;AAAA,IAC5D,OAAO,CAAC,CAAC,IAAI;AAAA,IACb,SAAS,IAAI,WAAW,CAAC;AAAA,IACzB,aAAa,CAAC,CAAC,IAAI;AAAA,IACnB,SAAS,IAAI,WAAW;AAAA,IACxB,OAAO,CAAC,CAAC,IAAI;AAAA,IACb,QAAQ,EAAE,QAAQ,EAAE,GAAG,gBAAgB,GAAG,IAAI,OAAO,EAAE;AAAA,IACvD;AAAA,IACA,gBAAgB,EAAE,SAAS,KAAO,YAAY,KAAO,eAAe,KAAO,cAAc,KAAO,GAAG,IAAI,eAAe;AAAA,IACtH,KAAK,IAAI,OAAO,CAAC;AAAA,IACjB,UAAU,IAAI,YAAY;AAAA,IAC1B,SAAS,IAAI,WAAW,CAAC;AAAA,IACzB,aAAa,EAAE,GAAG,IAAI,QAAQ;AAAA,IAC9B,gBAAgB,IAAI,kBAAkB,CAAC;AAAA,IACvC,sBAAsB,IAAI,wBAAwB,CAAC;AAAA,IACnD,aAAa;AAAA,IACb,eAAe,YAAY;AAAA,IAC3B;AAAA,IACA,YAAY;AAAA,IACZ,iBAAiB;AAAA;AAAA,IAEjB,SAAS;AAAA,IACT,aAAa,EAAE,OAAO,OAAO,MAAM,IAAI,UAAU,MAAM;AAAA,IACvD,eAAe,EAAE,OAAO,MAAM,MAAM,WAAW,OAAO,CAAC,EAAE;AAAA,IACzD,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,KAAK,EAAE,gBAAgB,aAAa;AAAA,IACpC,qBAAqB;AAAA,IACrB,WAAW,EAAE,sBAAsB,IAAI,qBAAqB,IAAI,uBAAuB,IAAI,qBAAqB,EAAE;AAAA,IAClH,YAAY,CAAC;AAAA,EACf;AACF;;;AClEA,gBAAe;AACf,gBAAe;AACf,kBAAiB;AAGV,IAAM,aAAN,MAAiB;AAAA,EAKtB,YAA6B,WAAmD;AAAnD;AAJ7B,SAAQ,MAAqB;AAE7B;AAAA,SAAiB,QAAQ,oBAAI,IAAoB;AAAA,EAEgC;AAAA;AAAA,EAGjF,IAAI,YAA2B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,SAAsB,UAA4B;AACrD,UAAM,MAAO,KAAK,QAAQ,UAAAC,QAAG,YAAY,YAAAC,QAAK,KAAK,UAAAC,QAAG,OAAO,GAAG,kBAAkB,CAAC;AACnF,UAAM,UAAU,IAAI,IAAI,QAAQ;AAChC,eAAW,OAAO,CAAC,GAAG,KAAK,MAAM,KAAK,CAAC,GAAG;AACxC,UAAI,QAAQ,IAAI,GAAG,EAAG;AACtB,gBAAAF,QAAG,OAAO,YAAAC,QAAK,KAAK,KAAK,GAAG,GAAG,EAAE,OAAO,KAAK,CAAC;AAC9C,WAAK,MAAM,OAAO,GAAG;AAAA,IACvB;AACA,eAAW,OAAO,UAAU;AAC1B,YAAM,SAAS,QAAQ,SAAS,GAAG;AACnC,UAAI,KAAK,MAAM,IAAI,GAAG,MAAM,OAAQ;AACpC,YAAM,SAAS,YAAAA,QAAK,KAAK,KAAK,GAAG;AACjC,gBAAAD,QAAG,UAAU,YAAAC,QAAK,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,gBAAAD,QAAG,cAAc,QAAQ,IAAI,SAAS,OAAO,IAAI,KAAK,UAAU,QAAQ,GAAG,IAAI,MAAM;AACrF,WAAK,MAAM,IAAI,KAAK,MAAM;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,IAAK,WAAAA,QAAG,OAAO,KAAK,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClE,SAAK,MAAM;AACX,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;;;AFPA,IAAM,gBAAgB;AAAA,EACpB;AAAA,EAAW;AAAA,EAAU;AAAA,EAAW;AAAA,EAAU;AAAA,EAAY;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAY;AAAA,EACpF;AAAA,EAAgB;AAAA,EAAW;AAAA,EAAU;AAAA,EAAU;AAAA,EAAS;AAAA,EAAW;AAAA,EAAU;AAAA,EAC7E;AAAA,EAAa;AAAA,EAAY;AAAA,EAAU;AACrC,EAAE,KAAK,IAAI;AAMX,IAAM,aAAa;AASZ,IAAM,aAAN,MAAiB;AAAA,EAatB,YAAqB,SAAsB,UAA6B,CAAC,GAAG;AAAvD;AAZrB,SAAQ,UAAU;AAElB;AAAA,SAAQ,UAAU;AAClB,SAAQ,UAAmE;AAC3E,SAAQ,OAA2B;AACnC,SAAQ,QAAQ,oBAAI,IAAgB,CAAC,UAAU,QAAQ,QAAQ,IAAI,CAAC;AACpE,SAAQ,YAAkD;AAC1D,SAAQ,YAAoE;AAM1E,SAAK,aAAa,QAAQ,gBAAgB,IAAI,WAAW,QAAQ,aAAa,IAAI;AAAA,EACpF;AAAA;AAAA,EAGA,IAAI,gBAA+B;AACjC,WAAO,KAAK,YAAY,aAAa;AAAA,EACvC;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA;AAAA,EAGA,WAAW,eAAyB,CAAC,GAAY;AAC/C,QAAI,aAAa,WAAW,GAAG;AAC7B,OAAC,UAAU,QAAQ,QAAQ,IAAI,EAAE,QAAQ,UAAQ,KAAK,MAAM,IAAI,IAAkB,CAAC;AACnF,WAAK;AACL,aAAO;AAAA,IACT;AAEA,QAAI,WAAW;AACf,eAAW,QAAQ,cAAc;AAC/B,YAAM,OAAO,aAAa,IAAI;AAC9B,UAAI,CAAC,KAAM;AACX,iBAAW;AACX,WAAK,MAAM,IAAI,IAAI;AAEnB,UAAI,SAAS,UAAU;AACrB,aAAK,MAAM,IAAI,MAAM;AACrB,aAAK,MAAM,IAAI,MAAM;AAAA,MACvB;AAAA,IACF;AACA,QAAI,SAAU,MAAK;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAA8B;AAClC,UAAM,SAAS,KAAK;AACpB,eAAS;AACP,UAAI,CAAC,KAAK,WAAW,KAAK,MAAM,SAAS,KAAK,KAAK,KAAM,QAAO,KAAK;AACrE,UAAI,CAAC,KAAK,SAAS;AACjB,cAAMG,UAAS,KAAK,QAAQ,EAAE,QAAQ,MAAM;AAC1C,eAAK,UAAU;AAAA,QACjB,CAAC;AACD,aAAK,UAAU,EAAE,QAAQ,KAAK,SAAS,QAAAA,QAAO;AAAA,MAChD;AACA,YAAM,EAAE,QAAQ,OAAO,IAAI,KAAK;AAChC,YAAM,QAAQ,MAAM;AACpB,UAAI,UAAU,OAAQ,QAAO;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,IAAoB;AAClC,QAAI,OAAO,KAAK,QAAQ,SAAS,EAAE;AACnC,QAAI,WAAW,KAAK,IAAI,GAAG;AACzB,UAAI;AACF,mBAAO,8BAAc,MAAM;AAAA,UACzB,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,YAAY;AAAA,UACZ,WAAW;AAAA,QACb,CAAC,EAAE;AAAA,MACL,SAAS,OAAO;AACd,cAAM,UAAU,gBAAgB,EAAE,kCAAU,MAAgB,OAAO;AACnE,eAAO,iBAAiB,KAAK,UAAU,OAAO,CAAC;AAAA;AAAA,MACjD;AAAA,IACF;AACA,WAAO,UAAU,KAAK,UAAU,EAAE,CAAC,cAAc,aAAa,KAAK,IAAI;AAAA;AAAA;AAAA,EACzE;AAAA,EAEA,MAAc,UAAgC;AAC5C,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,QAAQ,IAAI,IAAI,KAAK,KAAK;AAChC,SAAK,MAAM,MAAM;AAEjB,QAAI;AACF,YAAM,MAAM,KAAK,QAAQ,YAAY;AACrC,YAAM,EAAE,OAAO,WAAW,IAAI,KAAK,QAAQ,aAAa,GAAG;AAC3D,YAAM,QAAQ,CAAC,GAAG,YAAY,GAAG,KAAK;AACtC,YAAM,WAAW,IAAI,IAAI,MAAM,IAAI,QAAM,CAAC,IAAI,KAAK,QAAQ,aAAa,IAAI,GAAG,CAAC,CAAC,CAAC;AAElF,YAAM,CAAC,MAAM,IAAI,IAAI,MAAM,QAAQ,IAAI;AAAA,QACrC,MAAM,IAAI,MAAM,KAAK,CAAC,KAAK,YAAY,KAAK,iBAAiB,OAAO,QAAQ,IAAI,KAAK;AAAA,QACrF,MAAM,IAAI,MAAM,KAAK,CAAC,KAAK,YAAY,KAAK,cAAc,KAAK,IAAI,KAAK;AAAA,MAC1E,CAAC;AACD,WAAK,YAAY;AACjB,WAAK,YAAY;AAEjB,YAAM,aAAa,KAAK,QAAQ,WAAW,GAAG;AAC9C,YAAM,YAAY,CAAC,SAAiB,eAAe,QAAQ,KAAK,WAAW,aAAa,GAAG;AAC3F,YAAM,UAAU,KAAK,QAAQ,UAAU,CAAC,KAAK,CAAC;AAC9C,YAAM,UAAU,QAAQ,OAAO,UAAQ,CAAC,UAAU,IAAI,CAAC;AAEvD,YAAM,mBAAmB,KAAK,gBAAgB,KAAK,OAAO,UAAU,KAAK,GAAG;AAC5E,YAAM,gBAAgB,KAAK,gBAAgB,KAAK,OAAO,UAAU,KAAK,IAAI;AAC1E,YAAM,aAAa,aAAa,OAAO,IAAI;AAC3C,YAAM,SAAsB;AAAA,QAC1B,SAAS,EAAE,KAAK;AAAA,QAChB,UAAU,eAAe;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,KAAK,QAAQ;AAAA,UACpB,aAAa,KAAK,QAAQ,YAAY,GAAG;AAAA,QAC3C,CAAC;AAAA,QACD;AAAA,QACA,eAAe,QAAQ,OAAO,SAAS;AAAA,QACvC;AAAA,QACA,kBAAkB,KAAK,uBAAuB,kBAAkB,OAAO,OAAO;AAAA,QAC9E,WAAW,GAAG,aAAa;AAAA,EAAK,UAAU;AAAA,QAC1C;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AACA,WAAK,OAAO;AACZ,aAAO;AAAA,IACT,SAAS,OAAO;AAEd,YAAM,QAAQ,UAAQ,KAAK,MAAM,IAAI,IAAI,CAAC;AAC1C,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,OAAiB,UAA4B;AAC1E,UAAM,QAAQ,KAAK,QAAQ,UAAU,CAAC,SAAS,MAAM,CAAC,EAAE,IAAI,OAAK,OAAO,CAAC;AACzE,UAAM,aAA8B,MACjC,OAAO,QAAM,KAAK,QAAQ,OAAO,KAAK,OAAO,CAAC,EAC9C,IAAI,QAAM;AACT,YAAM,OAAO,SAAS,IAAI,EAAE;AAC5B,aAAO,EAAE,MAAM,IAAI,MAAM,OAAO,KAAK,EAAE,GAAG,KAAK,iBAAiB,GAAG,KAAK,kBAAkB,CAAC,EAAE;AAAA,IAC/F,CAAC;AAEH,UAAM,MAAM,KAAK,aAAa,KAAK,WAAW,KAAK,KAAK,SAAS,MAAM,IAAI,UAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ;AAClH,UAAM,CAAC,MAAM,GAAG,IAAI,MAAM,QAAQ,IAAI;AAAA,UACpC,wCAAY,EAAE,KAAK,OAAO,YAAY,KAAK,MAAM,CAAC;AAAA,UAClD,wCAAY,EAAE,KAAK,OAAO,YAAY,KAAK,KAAK,CAAC;AAAA,IACnD,CAAC;AAED,WAAO,EAAE,MAAM,sBAAsB,IAAI,GAAG,IAAI;AAAA,EAClD;AAAA;AAAA,EAGA,MAAc,cAAc,OAAiB;AAC3C,UAAM,YAAY,MAAM,OAAO,QAAM,KAAK,QAAQ,OAAO,KAAK,OAAO,CAAC,EAAE,IAAI,QAAM,KAAK,EAAE,OAAO;AAChG,UAAM,cAAc,KAAK,QAAQ,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,UAAQ,KAAK,IAAI,EAAE,EAAE,OAAO,UAAQ,CAAC,UAAU,SAAS,IAAI,CAAC;AACvH,UAAM,EAAE,MAAM,MAAM,IAAI,UAAM,wCAAY,EAAE,KAAK,KAAK,QAAQ,MAAM,WAAW,YAAY,CAAC;AAC5F,WAAO;AAAA,MACL,MAAM,sBAAsB,IAAI;AAAA,MAChC,OAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,CAAC;AAAA,IAC1G;AAAA,EACF;AAAA;AAAA,EAGQ,gBAAgB,KAAc,OAAiB,UAA4B,KAAqB;AACtG,UAAM,QAAkB,CAAC,KAAK,+BAA+B,KAAK,GAAG,CAAC,GAAG;AAEzE,eAAW,MAAM,OAAO;AACtB,YAAM,KAAK,iBAAiB,KAAK,KAAK,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG;AAC9E,UAAI,KAAK,QAAQ,OAAO,KAAK,OAAO,GAAG;AACrC,cAAM,KAAK,iBAAiB,KAAK,KAAK,OAAO,CAAC,YAAY,KAAK,OAAO,KAAK,OAAO,CAAC,IAAI;AAAA,MACzF;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAAA,EAEQ,uBAAuB,kBAA0B,OAAiB,SAA2B;AACnG,UAAM,QAAkB,CAAC,gBAAgB;AAEzC,QAAI,QAAQ,SAAS,QAAQ,GAAG;AAC9B,YAAM,KAAK,iBAAiB,UAAU,IAAI,CAAC;AAAA,IAC7C;AACA,eAAW,MAAM,OAAO;AACtB,UAAI,QAAQ,SAAS,KAAK,KAAK,EAAG,OAAM,KAAK,iBAAiB,KAAK,OAAO,EAAE,CAAC;AAAA,IAC/E;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACF;AAEA,SAAS,aAAa,OAAiB,MAA+D;AACpG,QAAM,QAAQ,CAAC,KAAK,IAAI;AACxB,aAAW,MAAM,OAAO;AACtB,UAAM,MAAM,KAAK,MAAM,KAAK,OAAO;AACnC,QAAI,IAAK,OAAM,KAAK,iBAAiB,KAAK,KAAK,OAAO,CAAC,OAAO,GAAG,GAAG;AAAA,EACtE;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,SAAS,iBAAiB,MAAc,OAA8B;AACpE,QAAM,aAAa,QACf,eAAe,KAAK,KAAK,CAAC,mDAAmD,KAAK,IAAI,CAAC,MACvF,0BAA0B,KAAK,IAAI,CAAC;AACxC,SAAO,GAAG,UAAU;AAAA,gBAAmB,KAAK,IAAI,CAAC,sCAAsC,KAAK,kBAAkB,OAAO,6BAAS,CAAC;AACjI;AASO,SAAS,sBAAsB,MAAsB;AAC1D,SAAO,KAAK,QAAQ,qEAAqE,8BAA8B;AACzH;AAGO,SAAS,KAAK,OAAwB;AAC3C,SAAO,KAAK,UAAU,KAAK,EACxB,QAAQ,MAAM,SAAS,EACvB,QAAQ,WAAW,SAAS,EAC5B,QAAQ,WAAW,SAAS;AACjC;AAEA,SAAS,aAAa,MAAiC;AACrD,MAAI,KAAK,SAAS,OAAO,EAAG,QAAO;AACnC,MAAI,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,MAAM,EAAG,QAAO;AAC5D,MAAI,KAAK,SAAS,OAAO,EAAG,QAAO;AACnC,MAAI,KAAK,SAAS,KAAK,EAAG,QAAO;AACjC,SAAO;AACT;;;AGhTA,IAAAC,aAAe;AACf,IAAAC,eAAiB;AA0BjB,IAAM,eAAe,oBAAI,IAAI,CAAC,gBAAgB,QAAQ,SAAS,SAAS,CAAC;AAEzE,IAAM,gBAAgB,oBAAI,IAAI,CAAC,uBAAuB,+BAA+B,gBAAgB,YAAY,cAAc,CAAC;AAEzH,IAAM,cAAN,MAAkB;AAAA,EAKvB,YAAqB,aAAqB;AAArB;AACnB,UAAM,gBAAgB,aAAa,aAAAC,QAAK,KAAK,aAAa,qBAAqB,CAAC,KAAK,CAAC;AACtF,SAAK,OAAO,aAAAA,QAAK,QAAQ,aAAa,cAAc,mBAAmB,EAAE;AACzE,SAAK,QAAQ,cAAc,SAAS;AAEpC,QAAI,CAAC,WAAAC,QAAG,WAAW,aAAAD,QAAK,KAAK,KAAK,MAAM,UAAU,CAAC,GAAG;AACpD,YAAM,IAAI,MAAM,GAAG,KAAK,IAAI,gGAA0B;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,UAAM,MAAM,aAAa,aAAAA,QAAK,KAAK,KAAK,MAAM,UAAU,CAAC;AACzD,QAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,IAAI,MAAM,WAAW,GAAG;AAC/D,YAAM,IAAI,MAAM,0CAAsB;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,KAAc;AACxB,WAAO,IAAI,eAAe,IAAI,eAAe,CAAC;AAAA,EAChD;AAAA;AAAA,EAGA,WAAW,KAA6B;AACtC,UAAM,MAAM,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,IAAI,SAAS;AACzE,WAAO,MAAM,aAAAA,QAAK,MAAM,UAAU,GAAG,EAAE,QAAQ,cAAc,EAAE,IAAI;AAAA,EACrE;AAAA;AAAA,EAGA,SAAS,KAAwB;AAC/B,UAAM,QAAQ,CAAC,GAAG,IAAI,KAAK;AAC3B,eAAW,OAAO,KAAK,YAAY,GAAG,GAAG;AACvC,iBAAW,QAAQ,IAAI,OAAO;AAC5B,cAAM,OAAO,aAAAA,QAAK,MAAM,KAAK,IAAI,MAAM,IAAI;AAC3C,YAAI,CAAC,MAAM,SAAS,IAAI,EAAG,OAAM,KAAK,IAAI;AAAA,MAC5C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,IAAY,KAAwB;AAC/C,UAAM,OAAiB,EAAE,GAAG,aAAa,aAAAA,QAAK,KAAK,KAAK,MAAM,KAAK,OAAO,CAAC,EAAE;AAC7E,UAAM,UAAU,CAAC,QAAgB,QAAgB;AAC/C,YAAM,WAAW,KAAK,iBAAiB,QAAQ,GAAG;AAClD,aAAO,WAAW,MAAM,WAAW;AAAA,IACrC;AAEA,SAAK,kBAAkB,OAAO;AAAA,MAC5B,OAAO,QAAQ,KAAK,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,QAAQ,IAAI,GAAa,KAAK,GAAG,CAAC;AAAA,IACzG;AACA,QAAI,KAAK,mBAAmB;AAC1B,WAAK,oBAAoB,OAAO,YAAY,OAAO,QAAQ,KAAK,iBAAiB,EAAE,IAAI,CAAC,CAAC,MAAM,OAAO,MAAM;AAAA,QAC1G;AAAA,QACA,OAAO,YAAY,YAAY,QAAQ,UAAU,EAAE,GAAG,SAAS,SAAS,QAAQ,IAAI,QAAQ,OAAO,KAAK,QAAQ,QAAQ,IAAI;AAAA,MAC9H,CAAC,CAAC;AAAA,IACJ;AAEA,QAAI,CAAC,0BAA0B,KAAK,EAAE,KAAK,CAAC,KAAK,0BAA0B,IAAI,GAAG,GAAG;AACnF,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,IAAI,mBAAmB,CAAC,CAAC,GAAG;AAClE,YAAI,KAAK,gBAAgB,GAAG,EAAG;AAE/B,cAAM,WAAW,QAAQ,OAAO,GAAG;AACnC,YAAI,YAAY,IAAI,WAAW,GAAG,KAAK,0BAA0B,KAAK,GAAG,GAAG;AAC1E,eAAK,gBAAgB,GAAG,IAAI,YAAY;AAAA,QAC1C,OAAO;AACL,gBAAM,WAAW,aAAAA,QAAK,MAAM,SAAS,aAAAA,QAAK,MAAM,QAAQ,EAAE,GAAG,GAAG;AAChE,eAAK,gBAAgB,GAAG,IAAI,SAAS,WAAW,GAAG,IAAI,WAAW,OAAO;AAAA,QAC3E;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,QAAgB,KAA4B;AAC3D,QAAI,CAAC,OAAO,IAAI,WAAW,WAAW,KAAK,IAAI,WAAW,mBAAmB,EAAG,QAAO;AAEvF,UAAM,UAAU,aAAAA,QAAK,MAAM,QAAQ,MAAM;AACzC,UAAM,aAAuB,CAAC;AAE9B,QAAI,IAAI,WAAW,GAAG,GAAG;AACvB,iBAAW,KAAK,IAAI,MAAM,CAAC,CAAC;AAAA,IAC9B,OAAO;AACL,iBAAW,KAAK,aAAAA,QAAK,MAAM,KAAK,SAAS,GAAG,CAAC;AAC7C,UAAI,CAAC,IAAI,WAAW,GAAG,GAAG;AACxB,YAAI,MAAM;AACV,mBAAS;AACP,qBAAW,KAAK,aAAAA,QAAK,MAAM,KAAK,QAAQ,MAAM,KAAK,KAAK,mBAAmB,GAAG,CAAC;AAC/E,cAAI,QAAQ,OAAO,QAAQ,GAAI;AAC/B,gBAAM,aAAAA,QAAK,MAAM,QAAQ,GAAG;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAEA,eAAW,aAAa,YAAY;AAClC,YAAM,aAAa,aAAAA,QAAK,MAAM,UAAU,SAAS;AACjD,iBAAW,MAAM,CAAC,YAAY,aAAAA,QAAK,MAAM,KAAK,YAAY,OAAO,CAAC,GAAG;AACnE,YAAI,WAAAC,QAAG,WAAW,aAAAD,QAAK,KAAK,KAAK,MAAM,KAAK,OAAO,CAAC,EAAG,QAAO;AAAA,MAChE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAa,KAAyD;AACpE,UAAM,QAAQ,KAAK,SAAS,GAAG;AAC/B,UAAM,aAAuB,CAAC;AAC9B,UAAM,UAAU,IAAI,IAAY,KAAK;AAErC,UAAM,QAAQ,CAAC,OAAe;AAC5B,YAAM,OAAO,KAAK,aAAa,IAAI,GAAG;AACtC,YAAM,OAAO,OAAO,OAAO,KAAK,eAAe;AAC/C,iBAAW,WAAW,OAAO,OAAO,KAAK,qBAAqB,CAAC,CAAC,GAAG;AACjE,YAAI,OAAO,YAAY,YAAY,QAAQ,QAAS,MAAK,KAAK,QAAQ,OAAO;AAAA,MAC/E;AACA,iBAAW,OAAO,KAAM,OAAM,KAAK,iBAAiB,IAAI,GAAG,CAAC;AAAA,IAC9D;AACA,UAAM,QAAQ,CAAC,OAAsB;AACnC,UAAI,CAAC,MAAM,QAAQ,IAAI,EAAE,EAAG;AAC5B,cAAQ,IAAI,EAAE;AACd,iBAAW,KAAK,EAAE;AAClB,YAAM,EAAE;AAAA,IACV;AAGA,QAAI,IAAI,QAAQ,OAAQ,OAAM,KAAK,iBAAiB,OAAO,uBAAuB,CAAC;AACnF,UAAM,QAAQ,KAAK;AACnB,WAAO,EAAE,OAAO,WAAW;AAAA,EAC7B;AAAA;AAAA,EAGA,UAAU,YAAgC;AACxC,UAAM,SAAmB,CAAC;AAE1B,UAAM,OAAO,CAAC,KAAa,QAAgB;AACzC,iBAAW,SAAS,WAAAC,QAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAChE,YAAI,MAAM,KAAK,WAAW,GAAG,KAAK,aAAa,IAAI,MAAM,IAAI,EAAG;AAChE,cAAM,WAAW,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,KAAK,MAAM;AACtD,YAAI,MAAM,YAAY,GAAG;AACvB,eAAK,aAAAD,QAAK,KAAK,KAAK,MAAM,IAAI,GAAG,QAAQ;AAAA,QAC3C,WAAW,WAAW,KAAK,SAAO,MAAM,KAAK,SAAS,GAAG,CAAC,GAAG;AAC3D,cAAI,CAAC,OAAO,cAAc,IAAI,MAAM,IAAI,EAAG;AAC3C,iBAAO,KAAK,QAAQ;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,KAAK,MAAM,EAAE;AAClB,WAAO,OAAO,KAAK;AAAA,EACrB;AAAA,EAEA,OAAO,SAA0B;AAC/B,WAAO,WAAAC,QAAG,WAAW,aAAAD,QAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA,EACpD;AAAA,EAEA,SAAS,SAAyB;AAChC,WAAO,WAAAC,QAAG,aAAa,aAAAD,QAAK,KAAK,KAAK,MAAM,OAAO,GAAG,MAAM;AAAA,EAC9D;AAAA,EAEQ,0BAA0B,IAAY,KAAuB;AACnE,WAAO,KAAK,YAAY,GAAG,EAAE,KAAK,SAAO,IAAI,eAAe,GAAG,WAAW,IAAI,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC;AAAA,EAC1G;AACF;AAEA,SAAS,aAAa,MAAmB;AACvC,MAAI,CAAC,WAAAC,QAAG,WAAW,IAAI,EAAG,QAAO;AACjC,QAAM,OAAO,WAAAA,QAAG,aAAa,MAAM,MAAM;AACzC,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,GAAG,IAAI,6CAAgB,MAAgB,OAAO,EAAE;AAAA,EAClE;AACF;;;ACpNO,IAAM,eAAe;AACrB,IAAM,cAAc;AAmCpB,SAAS,eAAe,QAAgB,YAAmC;AAChF,MAAI,CAAC,WAAW,WAAW,MAAM,EAAG,QAAO;AAC3C,QAAM,QAAQ,4BAA4B,KAAK,WAAW,MAAM,OAAO,MAAM,CAAC;AAC9E,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,GAAG,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AAChD,MAAI;AACF,QAAI,IAAI,GAAG;AACX,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC3CA,IAAAC,+BAAgD;;;ACThD,kCAA4C;AAE5C,IAAM,WAAW;AAEjB,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AAExB,IAAM,cAAsC;AAAA;AAAA,EAE1C,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;AASO,SAAS,oBAAoB,QAAwC;AAC1E,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,8LAAmC,sCAAU,EAAE;AAC5E,MAAI,OAAO,cAAc,UAAa,OAAO,aAAa,KAAK,IAAI,GAAG;AACpE,UAAM,IAAI,MAAM,0KAA8B;AAAA,EAChD;AACA,SAAO,OAAO;AAChB;AAGO,SAAS,eAAe,SAAqC;AAClE,SAAQ,YAAY,UAAa,YAAY,OAAO,KAAM;AAC5D;AAOO,SAAS,UAA8E,MAAS,QAAmB;AACxH,QAAM,UAAU,KAAK,cAAc;AACnC,MAAI,YAAY,EAAG,OAAM,IAAI,MAAM,GAAG,MAAM,IAAI,OAAO,KAAK,KAAK,cAAc,UAAU,0BAAM,GAAG,eAAe,OAAO,CAAC,EAAE;AAC3H,SAAO;AACT;AAEO,IAAM,kBAAN,MAAsB;AAAA;AAAA;AAAA;AAAA,EAI3B,YACW,OACQ,YACjB;AAFS;AACQ;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOH,MAAM,KAAKC,OAAc,MAAc,UAAU,iBAAoC;AACnF,UAAM,QAAQ,IAAI,gBAAgB,EAAE,OAAO,KAAK,OAAO,WAAW,oBAAoB,MAAM,KAAK,WAAW,CAAC,GAAG,eAAe,eAAe,CAAC;AAC/I,UAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,IAAIA,KAAI,IAAI,KAAK,IAAI;AAAA,MAC3D,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB,QAAQ,YAAY,QAAQ,OAAO;AAAA,IACrC,CAAC,EAAE,MAAM,CAAC,UAAqC;AAE7C,YAAM,IAAI,MAAM,MAAM,SAAS,iBAC3B,+DAAa,UAAU,GAAI,YAC3B,+DAAa,MAAM,OAAO,WAAW,MAAM,OAAO,EAAE;AAAA,IAC1D,CAAC;AACD,QAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,mDAAgB,SAAS,MAAM,EAAE;AACnE,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,SAASA,OAAc,MAA4B;AACvD,YAAQ,MAAM,KAAK,KAAKA,OAAM,IAAI,GAAG,KAAK;AAAA,EAC5C;AACF;;;ADnEA,IAAM,mBAAmB;AACzB,IAAM,gBAAgB;AAwBf,IAAM,cAAN,MAAkB;AAAA;AAAA;AAAA;AAAA,EAcvB,YACmB,QACA,QACjB;AAFiB;AACA;AAdnB;AAAA,SAAiB,YAAY,oBAAI,IAAiC;AAKlE;AAAA;AAAA;AAAA;AAAA,SAAQ,YAA0C;AAElD;AAAA,SAAiB,SAAS,oBAAI,IAAY;AAAA,EAQvC;AAAA;AAAA,EAGH,MAAM,QAAQC,QAAuC;AACnD,SAAK,YAAY,KAAK,OAAOA,MAAK;AAClC,WAAO,YAAYA,QAAO,MAAM,KAAK,SAAS;AAAA,EAChD;AAAA;AAAA,EAGA,MAAM,QAAQA,QAAuC;AACnD,SAAK,cAAc,KAAK,OAAOA,MAAK;AACpC,WAAO,YAAYA,QAAO,MAAM,KAAK,SAAS;AAAA,EAChD;AAAA;AAAA,EAGA,MAAc,OAAOA,QAA2C;AAC9D,UAAM,WAA4BA,OAAM,SAAS,WAAW,CAAC;AAC7D,UAAM,UAAU,MAAM,QAAQ,IAAI,OAAO,QAAQ,QAAQ,EAAE;AAAA,MAAI,CAAC,CAAC,OAAO,EAAE,UAAU,QAAQ,CAAC,MAC3F,YAAY,UAAU,KAAK,KAAK,OAAO,UAAU,OAAO,IAAI;AAAA,IAC9D,CAAC;AACD,WAAO,QAAQ,OAAO,CAAC,WAAiC,CAAC,CAAC,MAAM;AAAA,EAClE;AAAA,EAEA,MAAc,KAAK,OAAe,UAAkB,SAA6C;AAC/F,UAAM,QAAQ,gBAAM,KAAK,SAAI,QAAQ,IAAI,OAAO;AAChD,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,OAAO,gBAAgB,KAAK,wJAA0C;AACpF,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,GAAG,QAAQ,IAAI,OAAO;AAClC,QAAI,WAAW,KAAK,UAAU,IAAI,GAAG;AACrC,QAAI,CAAC,UAAU;AACb,iBAAW,KAAK,SAAS,KAAK,QAAQ,OAAO,UAAU,OAAO;AAC9D,WAAK,UAAU,IAAI,KAAK,QAAQ;AAChC,eAAS,MAAM,MAAM,KAAK,UAAU,OAAO,GAAG,CAAC;AAAA,IACjD;AACA,QAAI;AACF,aAAO,MAAM;AAAA,IACf,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,gBAAgB,KAAK,kCAAU,MAAgB,OAAO,EAAE;AACzE,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,SAAS,QAAyB,OAAe,UAAkB,SAAsC;AACrH,UAAM,WAAW,MAAM,OAAO,KAAK,yBAAyB,EAAE,WAAW,UAAU,gBAAgB,QAAQ,GAAG,gBAAgB;AAC9H,UAAM,OAAO,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AAErD,QAAI,KAAK,CAAC,MAAM,eAAe;AAC7B,UAAI,OAAiE,CAAC;AACtE,UAAI;AACF,eAAO,KAAK,MAAM,KAAK,SAAS,MAAM,CAAC;AAAA,MACzC,QAAQ;AAAA,MAER;AACA,UAAI,KAAK,cAAc,QAAS,WAAU,MAAM,sCAAQ;AACxD,YAAM,IAAI,MAAM,8DAAY;AAAA,IAC9B;AAEA,UAAM,QAAQ,IAAI,QAAI,8CAAgB,IAAI,EAAE,IAAI,WAAS,CAAC,MAAM,MAAM,OAAO,SAAK,6CAAe,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;AAChH,UAAM,aAAa,KAAK,MAAM,MAAM,IAAI,cAAc,GAAG,SAAS,MAAM,KAAK,IAAI;AACjF,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,OAAO,OAAe,WAAW,SAAS,CAAC,CAAC;AAAA,MACnD,aAAa,WAAW,QAAQ,CAAC;AAAA,IACnC;AAAA,EACF;AAAA,EAEQ,SAAS,KAAa,SAAiB;AAC7C,QAAI,KAAK,OAAO,IAAI,GAAG,EAAG;AAC1B,SAAK,OAAO,IAAI,GAAG;AACnB,SAAK,OAAO,KAAK,OAAO;AAAA,EAC1B;AACF;AAGA,SAAS,YAAYA,QAAoB,SAAiC;AACxE,MAAI,CAAC,QAAQ,OAAQ,QAAO,EAAE,GAAGA,QAAO,QAAQ;AAChD,SAAO;AAAA,IACL,GAAGA;AAAA,IACH;AAAA,IACA,OAAO,CAAC,GAAGA,OAAM,OAAO,GAAG,QAAQ,QAAQ,YAAU,OAAO,KAAK,CAAC;AAAA,IAClE,UAAU;AAAA,MACR,GAAGA,OAAM;AAAA,MACT,MAAM,EAAE,GAAGA,OAAM,SAAS,MAAM,GAAG,OAAO,OAAO,CAAC,GAAG,GAAG,QAAQ,IAAI,YAAU,OAAO,WAAW,CAAC,EAAE;AAAA,IACrG;AAAA,EACF;AACF;AAGO,SAAS,eAAeA,QAAiB,UAAoE;AAClH,aAAW,UAAUA,OAAM,SAAS;AAClC,UAAM,SAAS,cAAc,OAAO,QAAQ;AAC5C,QAAI,OAAO,MAAM,SAAS,QAAQ,EAAG,QAAO,EAAE,QAAQ,WAAW,SAAS,MAAM,OAAO,MAAM,EAAE;AAAA,EACjG;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,QAAoB,MAAgD;AAClG,SAAO,mBAAmB,mBAAmB,OAAO,QAAQ,CAAC,IAAI,mBAAmB,OAAO,OAAO,CAAC,IAAI,IAAI;AAC7G;;;AE/JO,SAAS,WAAmB;AACjC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYT;AAMA,SAAS,gBAAgB,KAAsB;AAC7C,SAAO,MACH;AAAA,IACA;AACN;AAMO,SAAS,eACdC,QACA,QACA,SACQ;AACR,QAAM,WAAW;AAAA,IACf,GAAGA,OAAM;AAAA,IACT,eAAe,EAAE,OAAO,MAAM,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM;AAAA,IACrE,GAAI,QAAQ,WAAW,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAAA,EACvD;AACA,QAAM,IAAIA,OAAM;AAGhB,QAAM,aAAaA,OAAM,QAAQ,IAAI,YAAU,gBAAgB,QAAQ,eAAe,CAAC;AACvF,QAAM,aAAaA,OAAM,QAAQ,IAAI,QAAM,mBAAmB,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE;AACpF,QAAM,eAAe,mCAAmC,CAAC;AAEzD,MAAI,QAAQ,UAAU;AACpB,UAAM,UAAU,CAAC,GAAG,YAAY,GAAG,YAAY,YAAY;AAC3D,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA,2BAKgB,KAAK,QAAQ,CAAC;AAAA,gFACuC,WAAW,KAAK,UAAU,OAAO,CAAC,CAAC,IAAI,QAAQ,MAAM,kBAAkB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,EAKvJ;AAEA,QAAM,UAAU,CAAC,GAAG,YAAY,GAAG,UAAU,EAAE,IAAI,SAAO,gBAAgB,GAAG,aAAa,EAAE,KAAK,IAAI;AACrG,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,2BAKkB,KAAK,QAAQ,CAAC;AAAA;AAAA;AAAA,EAGvC,gBAAgB,QAAQ,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAK5B,OAAO;AAAA,eACM,YAAY;AAAA;AAAA;AAAA;AAAA;AAK3B;AAMO,SAAS,eAAe,IAAY,OAAwB;AACjE,SAAO;AAAA;AAAA;AAAA;AAAA,oBAIW,EAAE;AAAA,+EACyD,EAAE;AAAA,EAC/E,QAAQ,KAAK,wDAAwD,uCAAuC,EAAE;AAAA;AAAA;AAAA;AAIhH;AAEO,SAAS,YAAYA,QAAiB,UAAkB,WAAmB,SAA8D;AAC9I,QAAM,KAAK,OAAO,SAAS,KAAK;AAChC,SAAO;AAAA;AAAA;AAAA,EAGP,YAAYA,QAAO,UAAU,IAAI,QAAQ,OAAO,CAAC;AAAA,EACjD,gBAAgB,QAAQ,GAAG,CAAC,yCAAyCA,OAAM,OAAO;AAAA,EAClF,WAAWA,QAAO,QAAQ,EAAE,gBAAgB,2CAA2C,EAAE;AAAA;AAAA;AAAA,EAGzF,WAAW,QAAQ,SAAS,MAAM,CAAC;AAAA;AAAA,eAEtB,KAAK,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4CASe,EAAE;AAAA;AAAA;AAAA;AAAA;AAK9C;AASO,SAAS,aAAaA,QAAoB,SAA0D;AACzG,QAAM,UAAUA,OAAM,cAAc,IAAI,QAAM,mBAAmB,UAAU,EAAE,CAAC,MAAMA,OAAM,OAAO,EAAE;AACnG,QAAM,UAAU,oBAAoB,KAAKA,OAAM,QAAQ,CAAC;AAAA;AAAA;AAGxD,MAAI,CAAC,QAAQ,WAAW;AACtB,UAAM,UAAU,mCAAoB,QAAQ,OAAO;AACnD,WAAO,GAAG,OAAO,mBAAmB,KAAK,OAAO,CAAC;AAAA;AAAA,EAEnD;AACA,SAAO,GAAG,OAAO;AAAA;AAAA;AAAA,gBAGH,QAAQ,IAAI,SAAO,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA;AAExD;AAMO,SAAS,kBACdA,QACA,QACA,WACA,UACA,WACA,UAAyC,CAAC,GAClC;AACR,QAAM,KAAK,OAAO,SAAS,KAAK;AAChC,QAAM,OAAO,OAAO,MAAM,IAAI,IAAI,SAAS,OAAO,GAAG,SAAS,MAAM,KAAK,yBAAyB,KAAK,UAAU,6BAAmB,OAAO,KAAK,mCAAU,SAAS,EAAE,CAAC;AACtK,SAAO;AAAA;AAAA;AAAA,EAGP,YAAYA,QAAO,UAAU,IAAI,QAAQ,OAAO,CAAC;AAAA,eACpC,gBAAgB,QAAQ,cAAc,CAAC;AAAA,EACpD,WAAWA,QAAO,QAAQ,EAAE,gBAAgB,2CAA2C,EAAE;AAAA;AAAA;AAAA,EAGzF,WAAW,QAAQ,SAAS,MAAM,CAAC,GAAG,IAAI;AAAA,kDACM,EAAE;AAAA;AAAA;AAGpD;AAEA,SAAS,WAAWA,QAAiB,UAAuC;AAC1E,SAAO,EAAE,GAAGA,OAAM,SAAS,QAAQ,QAAQ,GAAGA,OAAM,SAAS,OAAO,WAAW,OAAO,GAAG,OAAO;AAClG;AAGA,SAAS,YAAYA,QAAiB,UAAkB,IAAY,SAAmC;AACrG,QAAM,WAAW,EAAE,GAAGA,OAAM,UAAU,QAAQ,WAAWA,QAAO,QAAQ,EAAE;AAC1E,SAAO;AAAA;AAAA,SAEA,WAAW,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BASF,KAAK,QAAQ,CAAC;AAAA,+EACsC,EAAE;AAAA,EAC/E,WAAW,SAAS,MAAM,CAAC;AAC7B;AAGA,SAAS,WAAW,SAAsC,UAAmC;AAC3F,UAAQ,WAAW,CAAC,GACjB,OAAO,aAAW,OAAO,YAAY,YAAY,QAAQ,EACzD,IAAI,YAAU,OAAO,QAAQ,SAC1B,gBAAgB,WAAW,OAAO,GAAG,CAAC;AAAA,IACtC,WAAW,OAAO,QAAQ,QAAQ,eAAe,YAAY,CAAC;AAAA,CAAa,EAC9E,KAAK,EAAE;AACZ;AAEA,SAAS,WAAW,MAAsB;AACxC,SAAO,KAAK,QAAQ,WAAW,SAAO,EAAE,KAAK,SAAS,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,GAAE,EAAE,CAAG;AACvG;;;AClNA,IAAM,SAAS;AAEf,IAAM,SAAS;AAGR,SAAS,oBAAoB,MAAc,QAAwB;AACxE,MAAI,iBAAiB;AACrB,QAAM,WAAW,KAAK,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,UAAU;AACrD,UAAM,WAAqB,CAAC;AAC5B,aAAS,SAAS,GAAG,WAAW,KAAK,SAAS,KAAK,QAAQ,UAAU,QAAQ;AAE3E,YAAM,aAAa,WAAW,KAAK,QAAQ,IAAI,IAAI;AACnD,eAAS,KAAK,IAAI,WAAW,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,UAAU,IAAI,IAAI,SAAS,cAAc,CAAC;AACtG,uBAAiB;AAAA,IACnB;AACA,WAAO,SAAS,KAAK,GAAG;AAAA,EAC1B,CAAC;AACD,SAAO,KAAK,UAAU,EAAE,SAAS,GAAG,SAAS,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,UAAU,SAAS,KAAK,GAAG,GAAG,qBAAqB,CAAC,CAAC,EAAE,CAAC;AAC5H;AAEA,SAAS,IAAI,OAAuB;AAClC,MAAI,OAAO,QAAQ,IAAK,CAAC,SAAS,IAAK,IAAI,SAAS;AACpD,MAAI,MAAM;AACV,KAAG;AACD,QAAI,QAAQ,OAAO;AACnB,cAAU;AACV,QAAI,OAAO,EAAG,UAAS;AACvB,WAAO,OAAO,KAAK;AAAA,EACrB,SAAS,OAAO;AAChB,SAAO;AACT;;;ACnCA,IAAM,aAAa;AACnB,IAAM,mBAAmB;AAGzB,IAAM,gBAAgB;AAEf,SAAS,oBAAoB,QAAmB,QAAyC;AAC9F,MAAI,cAAc;AAClB,MAAI,UAAU;AACd,MAAI,UAAU;AACd,SAAO,GAAG,WAAW,UAAQ;AAC3B,UAAM,SAAS,YAAY,IAAI;AAC/B,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,MAAM,eAAe,KAAM;AAC7B,oBAAc;AACd,gBAAU;AAAA,IACZ;AACA,QAAI,WAAW,kBAAkB;AAE/B,UAAI,cAAc,GAAG;AACnB,mBAAW,MAAM;AACf,iBAAO,KAAK,oHAAoC,OAAO,SAAI;AAC3D,oBAAU;AAAA,QACZ,GAAG,cAAc,MAAO,GAAG,EAAE,MAAM;AAAA,MACrC;AACA;AAAA,IACF;AACA;AACA,WAAO,OAAO,KAAK,EAAE,gBAAgB,MAAM,OAAO,IAAI,CAAC,EAAE;AAAA,EAC3D,CAAC;AACH;AAEA,SAAS,YAAY,MAAiE;AACpF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK,SAAS,CAAC;AACzC,QAAI,QAAQ,SAAS,cAAc,OAAO,UAAU,UAAU,OAAO,UAAU,YAAY,OAAO,OAAO,SAAS,SAAU,QAAO;AAAA,EACrI,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,MAAM,MAAsB;AACnC,QAAM,YAAY,KAAK,QAAQ,eAAe,EAAE;AAChD,SAAO,UAAU,SAAS,aAAa,GAAG,UAAU,MAAM,GAAG,UAAU,CAAC,yCAAW;AACrF;AAGO,SAAS,kBAAkB,WAA2B;AAC3D,QAAM,MAAM,KAAK,MAAM,SAAS;AAChC,MAAI,sBAAsB,IAAI,QAAQ,QAAQ,CAAC,QAAgB,UAAmB,OAAO,SAAS,gBAAgB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAE;AACnI,SAAO,KAAK,UAAU,GAAG;AAC3B;;;AClDA,yBAAyB;AAEzB,sBAAyB;AAIzB,IAAM,0BAA0B,oBAAI,IAAI,CAAC,QAAQ,cAAc,kBAAkB,qBAAqB,cAAc,WAAW,QAAQ,CAAC;AAExI,IAAM,2BAA2B,oBAAI,IAAI,CAAC,oBAAoB,kBAAkB,qBAAqB,cAAc,YAAY,CAAC;AAMhI,eAAsB,YAAY,KAAc,KAAe;AAC7D,QAAM,SAAS,eAAe,cAAc,IAAI,WAAW;AAC3D,MAAI,CAAC,QAAQ;AACX,QAAI,OAAO,GAAG,EAAE,IAAI,qBAAqB,GAAG,EAAE,KAAK,gBAAgB,IAAI,WAAW,GAAG;AACrF;AAAA,EACF;AAEA,MAAI,iBAAyC,CAAC;AAC9C,MAAI;AACF,qBAAiB,KAAK,MAAM,IAAI,IAAI,eAAe,KAAK,IAAI;AAAA,EAC9D,QAAQ;AAAA,EAER;AACA,QAAM,UAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc,GAAG;AACzD,QAAI,CAAC,wBAAwB,IAAI,IAAI,YAAY,CAAC,KAAK,UAAU,UAAa,UAAU,MAAM;AAC5F,cAAQ,GAAG,IAAI,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,QAAM,qBAAqB,IAAI,IAAI,cAAc,KAAK;AACtD,MAAI,mBAAmB,WAAW,qBAAqB,GAAG;AACxD,eAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,UAAI,IAAI,YAAY,MAAM,eAAgB,QAAO,QAAQ,GAAG;AAAA,IAC9D;AACA,YAAQ,cAAc,IAAI;AAAA,EAC5B;AAEA,QAAM,UAAU,CAAC,CAAC,OAAO,MAAM,EAAE,SAAS,IAAI,MAAM,KAAK,OAAO,SAAS,IAAI,IAAI,KAAK,IAAI,KAAK,SAAS;AAExG,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,SAAS,MAAM,WAAW,MAAM;AACtC,MAAI,KAAK,SAAS,MAAM;AAExB,MAAI;AACF,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,QAAQ;AAAA,QAC7B,QAAQ,IAAI;AAAA,QACZ;AAAA,QACA,MAAM,UAAU,IAAI,OAAO;AAAA,QAC3B,UAAU;AAAA,QACV,QAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,IAAI,aAAa,WAAW,OAAO,QAAS;AAChD,YAAM,QAAS,OAAe,OAAO;AACrC,UAAI,OAAO,GAAG,EAAE,IAAI,qBAAqB,GAAG,EAAE,KAAK,SAAU,MAAgB,OAAO;AACpF;AAAA,IACF;AAEA,UAAM,kBAA0C,CAAC;AACjD,aAAS,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACvC,sBAAgB,GAAG,IAAI;AAAA,IACzB,CAAC;AACD,UAAM,aAAa,OAAO,SAAS,QAAQ,iBAAiB,aAAa,SAAS,QAAQ,aAAa,IAAI,CAAC;AAE5G,QAAI,OAAO,SAAS,MAAM;AAC1B,aAAS,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACvC,UAAI,CAAC,yBAAyB,IAAI,GAAG,EAAG,KAAI,UAAU,KAAK,KAAK;AAAA,IAClE,CAAC;AACD,QAAI,UAAU,iBAAiB,mBAAmB,KAAK,UAAU,eAAe,CAAC,CAAC;AAClF,QAAI,UAAU,oBAAoB,mBAAmB,KAAK,UAAU,UAAU,CAAC,CAAC;AAEhF,QAAI,aAAa;AACjB,QAAI,CAAC,SAAS,MAAM;AAClB,UAAI,IAAI;AACR;AAAA,IACF;AACA,cAAM,0BAAS,4BAAS,QAAQ,SAAS,IAAsB,GAAG,GAAG;AAAA,EACvE,SAAS,OAAO;AAEd,QAAI,CAAC,IAAI,UAAW,KAAI,QAAQ,KAAc;AAAA,EAChD,UAAE;AACA,QAAI,IAAI,SAAS,MAAM;AAAA,EACzB;AACF;;;ACpFO,SAAS,cAAc,OAAiB,OAAwE;AACrH,QAAM,SAAS,oBAAI,IAAI,CAAC,GAAG,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC;AAC5D,QAAM,OAAsB,EAAE,WAAW,CAAC,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE;AAErE,aAAW,QAAQ,OAAO;AACxB,UAAM,KAAK,KAAK,QAAQ,qBAAqB,EAAE;AAC/C,UAAM,SAAS,KAAK,SAAS,OAAO,IAChC,KAAK,SACL,CAAC,OAAO,IAAI,EAAE,IAAI,OAAO,KAAK,SAAS,OAAO,IAAI,KAAK,YAAY,KAAK,SAAS,KAAK,IAAI,KAAK,UAAU;AAC7G,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI,CAAC,OAAO,SAAS,EAAE,EAAG,QAAO,KAAK,EAAE;AAAA,EAC1C;AACA,SAAO;AACT;;;ACpBA,2BAAyB;AACzB,IAAAC,iBAA2B;AAC3B,IAAAC,mBAAoC;AACpC,gBAA0B;AAC1B,IAAAC,+BAA0F;AAK1F,IAAM,YAAY;AAElB,IAAM,cAAc;AAKpB,IAAM,oBAAoB;AAE1B,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAOvB,SAAS,sBAAsB,aAAqB,QAA4C;AACrG,QAAM,UAAM,sDAAwB;AACpC,MAAI,CAAC,IAAK,QAAO,gBAAY,kDAAoB;AAEjD,MAAI,gBAAwC;AAE5C,QAAM,YAAY,MAAM;AACtB,QAAI,CAAC,eAAe;AAClB,YAAM,WAAW,gBAAgB,KAAK,WAAW,EAAE,KAAK,UAAQ;AAC9D,eAAO,IAAI,iLAAyD,IAAI,iFAAqB;AAC7F,eAAO;AAAA,MACT,CAAC;AACD,eAAS,MAAM,MAAM;AACnB,YAAI,kBAAkB,SAAU,iBAAgB;AAAA,MAClD,CAAC;AACD,sBAAgB;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAEA,SAAO,YAAY;AACjB,QAAI,QAAQ,IAAI,uCAAU,EAAG,QAAO,EAAE,WAAW,QAAQ,IAAI,uCAAU,EAAE;AAEzE,UAAM,OAAO,UAAU;AACvB,QAAI;AACF,aAAO,MAAM,6BAA6B,MAAM,MAAM,WAAW;AAAA,IACnE,SAAS,OAAO;AACd,UAAI,EAAE,iBAAiB,eAAgB,OAAM;AAE7C,UAAI,kBAAkB,KAAM,iBAAgB;AAC5C,aAAO,6BAA6B,MAAM,UAAU,GAAG,WAAW;AAAA,IACpE;AAAA,EACF;AACF;AAGA,IAAM,gBAAN,cAA4B,MAAM;AAAC;AACnC,IAAM,iBAAN,cAA6B,MAAM;AAAC;AAEpC,eAAe,6BAA6B,MAAc,aAA+C;AACvG,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,aAAS;AACP,QAAI;AACF,aAAO,MAAM,cAAc,IAAI;AAAA,IACjC,SAAS,OAAO;AACd,UAAI,EAAE,iBAAiB,gBAAiB,OAAM;AAC9C,UAAI,KAAK,IAAI,KAAK,SAAU,OAAM,IAAI,MAAM,wLAAkC,WAAW,EAAE;AAC3F,gBAAM,iBAAAC,YAAM,qBAAqB;AAAA,IACnC;AAAA,EACF;AACF;AAOA,eAAe,gBAAgB,KAAa,aAAsC;AAEhF,QAAM,SAAS,MAAM,OAAO,KAAK,CAAC,SAAS,SAAS,aAAa,aAAa,eAAe,OAAO,SAAS,GAAG,UAAU,IAAI,CAAC;AAE/H,MAAI,WAAW;AACf,MAAI;AACF,eAAW,OAAO,KAAK,MAAM,OAAO,MAAM,mBAAmB,IAAI,CAAC,KAAK,EAAE,EAAE,QAAQ;AAAA,EACrF,QAAQ;AAAA,EAER;AACA,MAAI,OAAO,UAAU,QAAQ,KAAK,WAAW,EAAG,QAAO;AAEvD,MAAI,OAAO,SAAS,4CAAS,GAAG;AAC9B,UAAM,IAAI,MAAM,8OAA2C;AAAA,EAC7D;AACA,QAAM,IAAI,MAAM,2HAAuB,gBAAgB,MAAM,CAAC,EAAE;AAClE;AAGA,SAAS,OAAO,KAAa,MAAiC;AAE5D,QAAM,MAAM,IAAI,SAAS,MAAM;AAC/B,QAAM,CAAC,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,GAAG,KAAK,KAAK,IAAI,SAAO,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI;AACrF,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,YAAQ,+BAAS,MAAM,UAAU,EAAE,OAAO,KAAK,SAAS,aAAa,aAAa,KAAK,GAAG,CAAC,OAAO,WAAW;AACjH,UAAI,OAAO,QAAQ;AACjB,eAAO,IAAI,MAAM,sEAAe,cAAc,GAAI,4NAAwC,CAAC;AAAA,MAC7F,WAAW,SAAS,CAAC,QAAQ;AAC3B,eAAO,IAAI,MAAM,mGAAmB,MAAM,OAAO,EAAE,CAAC;AAAA,MACtD,OAAO;AACL,gBAAQ,MAAM;AAAA,MAChB;AAAA,IACF,CAAC;AACD,UAAM,OAAO,IAAI;AAAA,EACnB,CAAC;AACH;AAMA,SAAS,gBAAgB,QAAwB;AAE/C,QAAM,SAAS,OAAO,QAAQ,mBAAmB,EAAE;AACnD,QAAM,QAAQ,OAAO,QAAQ,SAAS;AACtC,QAAM,SAAS,QAAQ,IAAI,SAAS,OAAO,MAAM,QAAQ,UAAU,MAAM,GAAG,KAAK;AACjF,QAAM,UAAU,MAAM,MAAM,mDAAmD,IAAI,CAAC;AACpF,SAAO,YAAY,MAAM,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,GAAG,KAAK;AACjE;AAOA,SAAS,cAAc,MAAwC;AAC7D,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,KAAK,kBAAc,2BAAW,CAAC;AACrC,UAAM,SAAS,IAAI,oBAAU,kBAAkB,IAAI,EAAE;AACrD,UAAM,SAAS,CAAC,WAAuB;AACrC,mBAAa,KAAK;AAClB,aAAO,mBAAmB,EAAE,GAAG,SAAS,MAAM,MAAS,EAAE,UAAU;AACnE,aAAO;AAAA,IACT;AACA,UAAM,QAAQ;AAAA,MACZ,MACE;AAAA,QAAO,MACL,OAAO,IAAI,cAAc,kFAAiB,oBAAoB,GAAI,wIAA0B,CAAC;AAAA,MAC/F;AAAA,MACF;AAAA,IACF;AACA,UAAM,OAAO,MAAM,OAAO,MAAM,OAAO,IAAI,cAAc,sHAAuB,IAAI,gFAAe,CAAC,CAAC;AAErG,WAAO,GAAG,SAAS,IAAI;AACvB,WAAO,GAAG,SAAS,IAAI;AACvB,WAAO,GAAG,QAAQ,MAAM,OAAO,KAAK,KAAK,UAAU,EAAE,IAAI,QAAQ,kBAAkB,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AACjG,WAAO,GAAG,WAAW,UAAQ;AAC3B,UAAI;AACJ,UAAI;AACF,kBAAU,KAAK,MAAM,OAAO,IAAI,CAAC;AAAA,MACnC,QAAQ;AACN;AAAA,MACF;AACA,UAAI,SAAS,OAAO,GAAI;AACxB,UAAI,QAAQ,MAAO,QAAO,MAAM,OAAO,sBAAsB,OAAO,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,eACnF,OAAO,QAAQ,QAAQ,WAAW,SAAU,QAAO,MAAM,OAAO,IAAI,MAAM,4FAAiB,CAAC,CAAC;AAAA,UACjG,QAAO,MAAM,QAAQ,EAAE,WAAW,QAAQ,OAAO,QAAQ,WAAW,QAAQ,OAAO,YAAY,CAAC,CAAC;AAAA,IACxG,CAAC;AAAA,EACH,CAAC;AACH;AAGA,SAAS,sBAAsB,SAAwB;AACrD,MAAI,QAAQ,SAAS,iCAAiC,EAAG,QAAO,IAAI,eAAe,OAAO;AAC1F,MAAI,QAAQ,SAAS,kBAAkB,GAAG;AACxC,WAAO,IAAI,MAAM,oSAAoD;AAAA,EACvE;AACA,MAAI,QAAQ,SAAS,eAAe,EAAG,QAAO,IAAI,MAAM,sIAAwB;AAChF,SAAO,IAAI,MAAM,2EAAe,OAAO,EAAE;AAC3C;;;ACnLA,qBAAiE;AACjE,IAAAC,+BAAoC;AAGpC,IAAM,qBAAqB,CAAC,aAAa,OAAO,kBAAkB;AAClE,IAAM,iBAAiB,CAAC,aAAa,aAAa,OAAO;AAMzD,IAAM,yBAAyB,CAAC,iCAAiC;AAK1D,SAAS,oBAAoB,OAAe,aAAyB,kDAA6B;AACvG,QAAM,SAAS,IAAI,gBAAgB,OAAO,UAAU;AACpD,QAAM,SAAS,eAAAC,QAAQ,OAAO;AAC9B,SAAO,IAAI,YAAY;AAEvB,SAAO,KAAK,UAAU,QAAQ,YAAY;AACxC,UAAM,OAAO,UAAU,MAAM,OAAO,SAAS,yBAAyB,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,GAAG,sCAAQ;AAC3G,QAAI,CAAC,KAAK,KAAM,OAAM,IAAI,MAAM,qFAAoB;AACpD,WAAO,EAAE,MAAM,KAAK,KAAK;AAAA,EAC3B,CAAC,CAAC;AAEF,SAAO,KAAK,iBAAiB,QAAQ,YAAY;AAC/C,UAAM,OAAO,MAAM,OAAO,SAAS,kCAAkC,EAAE,MAAM,CAAC;AAE9E,UAAM,UAAU,KAAK,oBAAoB,WAAW,KAAK,cAAc;AACvE,QAAI,YAAY,KAAK,OAAO,KAAK,SAAS,UAAU;AAClD,YAAM,SAAS,KAAK,oBAAoB,UAAU,KAAK,cAAc,QAAQ,UAAU;AACvF,YAAM,IAAI,MAAM,8CAAW,OAAO,KAAK,MAAM,GAAG,eAAe,OAAO,CAAC,EAAE;AAAA,IAC3E;AAEA,UAAM,EAAE,eAAe,GAAG,IAAI,KAAK,MAAM,KAAK,IAAI;AAClD,WAAO,EAAE,MAAM,KAAK,MAAM,eAAe,GAAG;AAAA,EAC9C,CAAC,CAAC;AAEF,SAAO,KAAK,oBAAoB,eAAAA,QAAQ,KAAK,EAAE,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS;AACnF,UAAM,UAAU,IAAI,MAAM,MAAM;AAChC,QAAI,uBAAuB,SAAS,OAAO,EAAG,QAAO,KAAK;AAC1D,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sGAAgC,OAAO,GAAG,CAAC;AAAA,EAC3E,GAAG,QAAQ,OAAM,QAAO;AAEtB,UAAM,OAAO,UAAU,MAAM,OAAO,SAAS,iCAAiC,EAAE,MAAM,KAAK,UAAU,IAAI,KAAK,IAAI,EAAE,CAAC,GAAG,kDAAU;AAClI,QAAI,OAAO,KAAK,SAAS,SAAU,OAAM,IAAI,MAAM,wGAAmB;AAEtE,WAAO,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,EAAE;AAAA,EACvC,CAAC,CAAC;AAGF,SAAO,KAAK,kBAAkB,eAAAA,QAAQ,KAAK,GAAG,QAAQ,OAAM,QAAO;AAEjE,UAAM,OAAO,UAAU,MAAM,OAAO,SAAS,8BAA8B,EAAE,UAAU,KAAK,UAAU,IAAI,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,sCAAQ;AACxI,WAAO,EAAE,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC,EAAE,EAAE;AAAA,EAC3C,CAAC,CAAC;AAEF,SAAO,KAAK,sBAAsB,eAAAA,QAAQ,KAAK,GAAG,QAAQ,OAAM,QAAO;AACrE,UAAM,OAAO,UAAU,MAAM,OAAO,SAAS,iCAAiC,EAAE,YAAY,IAAI,MAAM,UAAU,CAAC,EAAE,CAAC,GAAG,kDAAU;AACjI,UAAM,WAAgF,KAAK,gBAAgB,CAAC;AAC5G,WAAO,EAAE,aAAa,SAAS,OAAO,aAAW,QAAQ,WAAW,EAAE,IAAI,cAAY,EAAE,OAAO,QAAQ,OAAO,aAAa,QAAQ,YAAa,YAAY,EAAE,EAAE;AAAA,EAClK,CAAC,CAAC;AAEF,SAAO;AACT;AAEA,SAAS,aAAa,KAAc,KAAe,MAAoB;AAErE,MAAI,CAAC,mBAAmB,SAAS,IAAI,OAAO,iBAAiB,EAAE,KAAK,CAAC,eAAe,SAAS,IAAI,QAAQ,GAAG;AAC1G,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,6FAAkB,CAAC;AACjD;AAAA,EACF;AACA,OAAK;AACP;AAEA,SAAS,QAAQ,QAA2C;AAC1D,SAAO,OAAO,KAAc,QAAkB;AAC5C,QAAI;AACF,UAAI,KAAK,MAAM,OAAO,GAAG,CAAC;AAAA,IAC5B,SAAS,OAAO;AACd,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;AAAA,IAC1D;AAAA,EACF;AACF;;;AC9FA,IAAAC,aAAe;AACf,IAAAC,eAAiB;AACjB,IAAAC,kBAA8B;AAEvB,IAAM,mBAAmB,CAAC,gBAAgB,gBAAgB,eAAe;AAChF,IAAM,eAAe;AACrB,IAAM,aAAa;AAGZ,SAAS,cAAc,aAAoC;AAChE,aAAW,QAAQ,kBAAkB;AACnC,UAAM,OAAO,aAAAC,QAAK,KAAK,aAAa,IAAI;AACxC,QAAI,WAAAC,QAAG,WAAW,IAAI,EAAG,QAAO;AAAA,EAClC;AACA,SAAO;AACT;AAGO,SAAS,gBAAgB,KAAgD;AAC9E,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,UAAqC,MAAM,CAAC,EAAE,WAAW,UAAU,KAAK,MAAM,CAAC,MAAM,MAAS;AAAA,EAC5H;AACF;AASA,eAAsB,YAAY,MAA+B;AAC/D,QAAM,SAAS,UAAM,uBAAM;AAAA,IACzB,aAAa,CAAC,IAAI;AAAA,IAClB,eAAe,aAAAD,QAAK,QAAQ,IAAI;AAAA,IAChC,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,SAAS,CAAC,mBAAmB,CAAC;AAAA,EAChC,CAAC;AACD,SAAO,OAAO,YAAY,CAAC,EAAE;AAC/B;AAEA,SAAS,qBAA6B;AACpC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,aAAa;AACjB,kBAAY,UAAU,EAAE,QAAQ,IAAI,OAAO,IAAI,YAAY,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,cAAc,WAAW,YAAY,EAAE;AACzH,kBAAY,OAAO,EAAE,QAAQ,MAAM,WAAW,YAAY,GAAG,OAAO;AAAA;AAAA,QAElE,UAAU;AAAA,QACV,QAAQ;AAAA,MACV,EAAE;AAAA,IACJ;AAAA,EACF;AACF;;;AC3DA,IAAAE,iBAA2B;AAC3B,IAAAC,aAAe;AACf,IAAAC,eAAiB;AACjB,sBAAqB;AAerB,IAAM,WAAW;AACjB,IAAM,UAAU;AAChB,IAAM,gBAAgB;AAQf,SAAS,aAAa,MAAc,OAAiB,UAA0D;AACpH,MAAI,UAAU,oBAAI,IAAY;AAC9B,MAAI,aAAa;AACjB,MAAI,QAA8C;AAElD,QAAM,eAAe,oBAAI,IAAoB;AAC7C,MAAI,UAAU;AAEd,QAAM,UAAU,gBAAAC,QAAS,MAAM,OAAO,EAAE,SAAS,QAAQ,CAAC;AAC1D,QAAM,QAAQ,IAAI,QAAc,aAAW;AACzC,YAAQ,GAAG,SAAS,MAAM;AACxB,gBAAU;AACV,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AAED,QAAM,QAAQ,MAAM;AAClB,UAAM,UAAU,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,WAAW;AAClD,cAAU,oBAAI,IAAI;AAClB,iBAAa;AACb,aAAS,OAAO;AAAA,EAClB;AAEA,UAAQ,GAAG,OAAO,CAAC,OAAO,SAAS;AACjC,UAAM,YAAY,kBAAkB,cAAc,MAAM,KAAK;AAC7D,QAAI,CAAC,WAAW,UAAW;AAC3B,QAAI,UAAU,SAAU,cAAa;AACrC,YAAQ,IAAI,aAAAC,QAAK,SAAS,MAAM,IAAI,EAAE,MAAM,aAAAA,QAAK,GAAG,EAAE,KAAK,GAAG,CAAC;AAC/D,QAAI,MAAO,cAAa,KAAK;AAC7B,YAAQ,WAAW,OAAO,QAAQ;AAAA,EACpC,CAAC;AAED,SAAO,EAAE,OAAO,OAAO,MAAM,QAAQ,MAAM,EAAE;AAC/C;AAGA,SAAS,kBAAkB,cAAmC,MAAc,OAAwB;AAClG,MAAI,UAAU,UAAU;AACtB,iBAAa,OAAO,IAAI;AACxB,WAAO;AAAA,EACT;AACA,MAAK,UAAU,SAAS,UAAU,YAAa,CAAC,cAAc,KAAK,IAAI,EAAG,QAAO;AACjF,MAAI;AACJ,MAAI;AACF,eAAO,2BAAW,MAAM,EAAE,OAAO,WAAAC,QAAG,aAAa,IAAI,CAAC,EAAE,OAAO,KAAK;AAAA,EACtE,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,WAAW,aAAa,IAAI,IAAI;AACtC,eAAa,IAAI,MAAM,IAAI;AAC3B,SAAO,aAAa;AACtB;;;ACxCO,SAAS,gBACd,MACA,YACA,SAC0H;AAC1H,QAAM,iBAAiB,CAAC,GAAI,KAAK,kBAAkB,CAAC,CAAE;AACtD,QAAM,cAAc,CAAC,GAAI,KAAK,eAAe,CAAC,CAAE;AAChD,QAAM,aAAa,KAAK,gBAAgB,CAAC,KAAK,aAAa,IAAI,CAAC;AAChE,QAAM,UAA4B,CAAC;AAEnC,aAAW,aAAa,YAAY;AAClC,QAAI;AACJ,QAAI;AACF,cAAQ,UAAU,MAAM,OAAO;AAAA,IACjC,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,gBAAM,UAAU,IAAI,wCAAW,MAAgB,OAAO,EAAE;AAAA,IAC1E;AACA,mBAAe,KAAK,GAAI,MAAM,kBAAkB,CAAC,CAAE;AACnD,gBAAY,KAAK,GAAI,MAAM,eAAe,CAAC,CAAE;AAC7C,QAAI,MAAM,cAAe,YAAW,KAAK,MAAM,aAAa;AAC5D,QAAI,MAAM,MAAO,SAAQ,KAAK,EAAE,MAAM,UAAU,MAAM,GAAG,MAAM,MAAM,CAAC;AAAA,EACxE;AAEA,QAAM,gBAAgB,WAAW,WAAW,IACxC,SACA,CAAC,MAAc,SAAiB,WAAW,OAAO,CAAC,QAAQ,cAAc,UAAU,QAAQ,IAAI,GAAG,IAAI;AAC1G,SAAO,EAAE,gBAAgB,aAAa,eAAe,QAAQ;AAC/D;;;AlBAA,IAAM,oBAAoB,CAAC,YAAY,gBAAgB,aAAa;AA8C7D,IAAM,iBAAgC;AAAA,EAC3C,OAAO;AAAA,EACP,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,QAAQ;AAAA,EACR,UAAU;AACZ;AAEO,IAAM,YAAN,MAAgB;AAAA,EA4BrB,YAA6B,SAA2B;AAA3B;AAhB7B,SAAQ,SAA6B;AACrC,SAAQ,UAAkC;AAC1C,SAAQ,UAAiC;AACzC,SAAQ,UAAU;AAClB,SAAQ,YAAY;AAEpB;AAAA,SAAiB,eAAe,oBAAI,IAAuB;AAWzD,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,UAAU,IAAI,YAAY,aAAAC,QAAK,QAAQ,QAAQ,WAAW,CAAC;AAChE,UAAM,WAAW,gBAAgB,SAAS,QAAQ,cAAc,CAAC,GAAG,EAAE,aAAa,KAAK,QAAQ,aAAa,MAAM,KAAK,QAAQ,KAAK,CAAC;AACtI,aAAS,YAAY,QAAQ,CAAC,EAAE,MAAM,UAAU,MAAM,gBAAgB,SAAS,CAAC;AAChF,SAAK,iBAAiB,SAAS;AAC/B,SAAK,cAAc,SAAS;AAC5B,SAAK,mBAAmB,SAAS;AACjC,SAAK,cAAU,6CAAe,EAAE,SAAS,QAAQ,gBAAgB,UAAU,QAAQ,gBAAgB,CAAC;AACpG,QAAI,CAAC,KAAK,QAAQ,YAAY;AAC5B,WAAK,OAAO,KAAK,mCAAoB,KAAK,QAAQ,OAAO,qHAAsB;AAAA,IACjF;AACA,QAAI,QAAQ,cAAc,UAAa,QAAQ,kBAAkB,QAAW;AAC1E,WAAK,OAAO,KAAK,kKAAkF;AAAA,IACrG;AACA,SAAK,iBAAiB,QAAQ,iBAAiB,QAAQ,eAAe;AACtE,SAAK,eAAe,KAAK,gBAAgB,sBAAsB,KAAK,QAAQ,aAAa,KAAK,MAAM,IAAI;AACxG,SAAK,UAAU,IAAI,YAAY,KAAK,gBAAgB,IAAI,gBAAgB,KAAK,QAAQ,OAAO,KAAK,YAAY,GAAG,KAAK,MAAM;AAC3H,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,QAAQ,OAAO;AACrD,SAAK,UAAU,IAAI,WAAW,KAAK,SAAS,EAAE,eAAe,SAAS,cAAc,CAAC;AACrF,SAAK,YAAY,iBAAiB,QAAQ,OAAO,KAAK,QAAQ,WAAW;AACzE,SAAK,WAAW,gBAAgB,QAAQ,GAAG;AAC3C,SAAK,MAAM,KAAK,UAAU;AAAA,EAC5B;AAAA;AAAA,EAGA,IAAI,MAAc;AAChB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,cAAwB;AAC1B,QAAI,CAAC,KAAK,UAAW,QAAO,CAAC;AAC7B,UAAM,EAAE,KAAK,IAAI,IAAI,IAAI,KAAK,OAAO;AACrC,WAAO,OAAO,OAAO,WAAAC,QAAG,kBAAkB,CAAC,EACxC,KAAK,EACL,OAAO,CAAAC,SAAOA,QAAOA,KAAI,WAAW,UAAU,CAACA,KAAI,QAAQ,EAC3D,IAAI,CAAAA,SAAO,UAAUA,KAAK,OAAO,IAAI,IAAI,EAAE;AAAA,EAChD;AAAA,EAEA,MAAM,QAAyB;AAE7B,QAAI;AACF,YAAMC,SAAQ,MAAM,KAAK,QAAQ,MAAM;AACvC,WAAK,OAAO,IAAI,8CAAqBA,OAAM,MAAM,MAAM,4BAAQA,OAAM,WAAW,MAAM,4BAAQA,OAAM,UAAU,IAAI;AAAA,IACpH,SAAS,OAAO;AACd,WAAK,OAAO,MAAM;AAAA,EAAwB,MAAgB,OAAO,EAAE;AAAA,IACrE;AAEA,UAAM,SAAS,YAAAC,QAAK,aAAa,KAAK,GAAG;AAEzC,SAAK,UAAU,IAAI,2BAAgB,EAAE,UAAU,MAAM,YAAY,KAAK,KAAK,CAAC;AAC5E,SAAK,QAAQ,GAAG,cAAc,YAAU;AAEtC,aAAO,GAAG,SAAS,MAAM,MAAS;AAClC,UAAI,KAAK,QAAQ,eAAgB,qBAAoB,QAAQ,KAAK,MAAM;AAAA,IAC1E,CAAC;AACD,WAAO,GAAG,WAAW,CAAC,KAAK,QAAQ,SAAS;AAC1C,UAAI,IAAI,KAAK,WAAW,aAAa,GAAG;AACtC,aAAK,QAAS,cAAc,KAAK,QAAQ,MAAM,QAAM,KAAK,QAAS,KAAK,cAAc,IAAI,GAAG,CAAC;AAAA,MAChG,OAAO;AACL,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF,CAAC;AAED,UAAM,OAAO,KAAK,QAAQ,QAAQ;AAClC,UAAM,OAAO,MAAM,OAAO,QAAQ,KAAK,QAAQ,MAAM,MAAM,KAAK,MAAM;AACtE,SAAK,SAAS;AACd,SAAK,YAAY,0BAA0B,IAAI,IAAI;AACnD,SAAK,UAAU,UAAU,0BAA0B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;AAE5E,QAAI,KAAK,QAAQ,UAAU,MAAO,MAAK,cAAc;AAErD,SAAK,eAAe,EACjB,KAAK,mBAAmB,EACxB,MAAM,WAAS,KAAK,OAAO,KAAK,gIAAgD,MAAM,OAAO,EAAE,CAAC;AACnG,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAQ;AACZ,UAAM,KAAK,SAAS,MAAM;AAC1B,SAAK,SAAS,QAAQ,QAAQ,YAAU,OAAO,UAAU,CAAC;AAC1D,SAAK,SAAS,MAAM;AACpB,UAAM,SAAS,KAAK;AACpB,SAAK,SAAS;AACd,QAAI,QAAQ;AAEV,aAAO,oBAAoB;AAC3B,YAAM,IAAI,QAAc,aAAW,OAAO,MAAM,MAAM,QAAQ,CAAC,CAAC;AAAA,IAClE;AACA,SAAK,aAAa,MAAM;AACxB,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAEQ,YAAqB;AAC3B,UAAM,UAAM,gBAAAC,SAAQ;AACpB,UAAM,OAAO,KAAK,QAAQ;AAC1B,UAAM,UAAU,CAAC,QAAkB,IAAI,UAAU,iBAAiB,UAAU;AAE5E,eAAW,EAAE,MAAM,WAAW,QAAQ,KAAK,KAAK,aAAa;AAC3D,UAAI,IAAI,WAAW,CAAC,KAAK,KAAK,SAAS,QAAQ,KAAK,KAAK,IAAI,CAAC;AAAA,IAChE;AAEA,QAAI,IAAI,KAAK,CAAC,MAAM,QAAQ;AAC1B,cAAQ,GAAG;AACX,UAAI,KAAK,MAAM,EAAE,KAAK,SAAS,CAAC;AAAA,IAClC,CAAC;AAED,QAAI,IAAI,gBAAgB,CAAC,MAAM,QAAQ;AACrC,UAAI,OAAO,GAAG,EAAE,IAAI;AAAA,IACtB,CAAC;AAED,QAAI,IAAI,0BAA0B,OAAO,MAAM,QAAQ;AACrD,cAAQ,GAAG;AACX,YAAM,OAAO;AAAA,QACX,OAAO,KAAK,QAAQ;AAAA,QACpB,gBAAgB,KAAK,QAAQ;AAAA,QAC7B,QAAQ,KAAK;AAAA,QACb,eAAe,KAAK;AAAA,QACpB,gBAAgB,KAAK,QAAQ,kBAAkB;AAAA,MACjD;AACA,UAAI;AAEF,cAAMF,SAAQ,MAAM,KAAK,QAAQ,QAAQ,MAAM,KAAK,QAAQ,MAAM,CAAC;AACnE,cAAM,OAAgB,EAAE,GAAG,MAAM,SAASA,OAAM,SAAS,UAAUA,OAAM,UAAU,OAAOA,OAAM,MAAM;AACtG,YAAI,KAAK,UAAW,MAAK,QAAQ,MAAM,KAAK,UAAU,KAAK,SAAS;AACpE,YAAI,KAAK,IAAI;AAAA,MACf,SAAS,OAAO;AACd,YAAI,KAAK,EAAE,GAAG,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,GAAG,YAAa,MAAgB,QAAQ,CAAC;AAAA,MACjG;AAAA,IACF,CAAC;AAED,QAAI,IAAI,qBAAqB,OAAO,MAAM,QAAQ;AAChD,cAAQ,GAAG;AACX,UAAI,CAAC,KAAK,WAAW;AACnB,YAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAK,iCAAa;AAC/C;AAAA,MACF;AACA,UAAI;AACF,YAAI,KAAK,IAAI,EAAE,KAAK,MAAM,YAAY,KAAK,SAAS,CAAC;AAAA,MACvD,SAAS,OAAO;AACd,YAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAM,MAAgB,OAAO;AAAA,MAC5D;AAAA,IACF,CAAC;AAED,QAAI,IAAI,4BAA4B,KAAK,UAAU,CAACA,QAAO,KAAK,QAAQ;AACtE,YAAM,aAAa,OAAO,IAAI,MAAM,QAAQ,EAAE,EAAE,QAAQ,OAAO,EAAE;AACjE,YAAM,SAASA,OAAM,MAAM,SAAS,UAAU,IAC1C,EAAE,MAAM,YAAY,OAAO,OAAO,YAAY,IAAI,gBAAgB,OAAO,IAAI,MAAM,SAAS,EAAE,CAAC,CAAC,EAAE,IAClG,EAAE,MAAMA,OAAM,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE;AACtC,UAAI,KAAK,MAAM,EAAE,KAAK,eAAeA,QAAO,QAAQ,EAAE,KAAK,KAAK,YAAY,cAAU,kDAAoB,KAAK,QAAQ,OAAO,EAAE,CAAC,CAAC;AAAA,IACpI,CAAC,CAAC;AAEF,QAAI,IAAI,4BAA4B,CAAC,KAAK,QAAQ;AAChD,YAAM,KAAK,OAAO,IAAI,MAAM,EAAE;AAC9B,UAAI,CAAC,OAAO,UAAU,EAAE,KAAK,MAAM,GAAG;AACpC,YAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAK,0CAAY;AAC9C;AAAA,MACF;AACA,UAAI,KAAK,MAAM,EAAE,KAAK,eAAe,IAAI,IAAI,MAAM,UAAU,GAAG,CAAC;AAAA,IACnE,CAAC;AAED,QAAI,IAAI,oCAAoC,KAAK,UAAU,CAACA,QAAO,KAAK,KAAK,SAAS;AACpF,YAAM,WAAW,mBAAmB,IAAI,OAAO,CAAC,CAAC;AACjD,UAAI,CAACA,OAAM,MAAM,SAAS,QAAQ,EAAG,QAAO,KAAK;AACjD,YAAM,aAAa,eAAeA,QAAO,QAAQ;AACjD,YAAM,UAAU,KAAK;AACrB,UAAI,KAAK,MAAM,EAAE,KAAK,aAClB,kBAAkBA,QAAO,WAAW,QAAQ,WAAW,WAAW,UAAU,OAAO,IAAI,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,IAC7G,YAAYA,QAAO,UAAU,OAAO,IAAI,MAAM,EAAE,GAAG,EAAE,KAAK,KAAK,YAAY,QAAQ,CAAC,CAAC;AAAA,IAC3F,CAAC,CAAC;AAGF,QAAI,IAAI,wEAAwE,KAAK,UAAU,CAACA,QAAO,KAAK,KAAK,SAAS;AACxH,YAAM,EAAE,UAAU,SAAS,KAAK,IAAI,IAAI;AACxC,YAAM,OAAOA,OAAM,QAAQ,KAAK,YAAU,OAAO,aAAa,YAAY,OAAO,YAAY,OAAO,GAAG,MAAM,IAAI,IAAI,IAAI,EAAE;AAC3H,UAAI,CAAC,KAAM,QAAO,KAAK;AACvB,UAAI,KAAK,IAAI,EAAE,KAAK,IAAI;AAAA,IAC1B,CAAC,CAAC;AAEF,QAAI,IAAI,iCAAiC,KAAK,UAAU,CAACA,QAAO,KAAK,KAAK,SAAS;AACjF,YAAM,OAAOA,OAAM,QAAQ,KAAK,YAAU,OAAO,aAAa,IAAI,OAAO,CAAC,CAAC,GAAG,MAAM,IAAI,mBAAmB,IAAI,OAAO,CAAC,CAAC,CAAC;AACzH,UAAI,CAAC,KAAM,QAAO,KAAK;AACvB,UAAI,KAAK,aAAAH,QAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,0BAA0B,EAAE,KAAK,IAAI;AAAA,IAC/E,CAAC,CAAC;AAEF,QAAI,IAAI,iCAAiC,KAAK,UAAU,CAACG,QAAO,KAAK,QAAQ;AAC3E,YAAM,KAAK,mBAAmB,IAAI,OAAO,CAAC,CAAC;AAC3C,UAAI,CAACA,OAAM,QAAQ,SAAS,EAAE,KAAK,CAACA,OAAM,cAAc,SAAS,EAAE,GAAG;AACpE,YAAI,OAAO,GAAG,EAAE,KAAK,IAAI,EAAE,KAAK,iBAAiB,KAAK,UAAU,6BAAmB,EAAE,qBAAM,CAAC,GAAG;AAC/F;AAAA,MACF;AACA,UAAI,KAAK,IAAI,EAAE,KAAK,KAAK,QAAQ,gBAAgB,EAAE,CAAC;AAAA,IACtD,CAAC,CAAC;AAEF,QAAI,IAAI,sBAAsB,KAAK,UAAU,CAACA,QAAO,MAAM,QAAQ;AACjE,YAAM,YAAY,WAAAG,QAAG,WAAW,aAAAN,QAAK,KAAK,KAAK,QAAQ,KAAK,aAAa,CAAC;AAC1E,UAAI,KAAK,IAAI,EAAE,KAAK,aAAaG,QAAO,EAAE,SAAS,KAAK,QAAQ,SAAS,UAAU,CAAC,CAAC;AAAA,IACvF,CAAC,CAAC;AAEF,QAAI,IAAI,iCAAiC,KAAK,UAAU,CAACA,QAAO,MAAM,QAAQ;AAC5E,UAAI,KAAK,IAAI,EAAE,KAAKA,OAAM,gBAAgB;AAAA,IAC5C,CAAC,CAAC;AAEF,QAAI,IAAI,iCAAiC,KAAK,UAAU,CAACA,QAAO,MAAM,QAAQ;AAC5E,UAAI,KAAK,IAAI,EAAE,KAAKA,OAAM,gBAAgB;AAAA,IAC5C,CAAC,CAAC;AAEF,QAAI,IAAI,8BAA8B,KAAK,UAAU,CAACA,QAAO,MAAM,QAAQ;AACzE,UAAI,KAAK,IAAI,EAAE,KAAKA,OAAM,aAAa;AAAA,IACzC,CAAC,CAAC;AAEF,QAAI,IAAI,2BAA2B,KAAK,UAAU,CAACA,QAAO,MAAM,QAAQ;AACtE,UAAI,KAAK,IAAI,EAAE,KAAKA,OAAM,UAAU;AAAA,IACtC,CAAC,CAAC;AAEF,QAAI,IAAI,0BAA0B,KAAK,UAAU,CAACA,QAAO,MAAM,QAAQ;AACrE,UAAI,KAAK,IAAI,EAAE,KAAKA,OAAM,SAAS;AAAA,IACrC,CAAC,CAAC;AAEF,QAAI,IAAI,iCAAiC,CAAC,MAAM,KAAK,SAAS;AAC5D,YAAM,OAAO,aAAAH,QAAK,KAAK,KAAK,WAAW,GAAG,cAAc;AACxD,UAAI,CAAC,WAAAM,QAAG,WAAW,IAAI,EAAG,QAAO,KAAK;AACtC,UAAI,KAAK,MAAM,EAAE,KAAK,kBAAkB,WAAAA,QAAG,aAAa,MAAM,MAAM,CAAC,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,IAAI,oBAAoB,gBAAAD,QAAQ,OAAO,KAAK,WAAW,GAAG;AAAA,MAC5D,cAAc;AAAA;AAAA,MAEd,YAAY,CAAC,KAAK,SAAS;AACzB,YAAI,aAAAL,QAAK,SAAS,IAAI,MAAM,QAAS,KAAI,UAAU,0BAA0B,GAAG;AAAA,MAClF;AAAA,IACF,CAAC,CAAC;AAEF,UAAM,aAAa,oBAAI,IAAoB;AAC3C,QAAI,IAAI,kCAAkC,CAAC,KAAK,KAAK,SAAS;AAC5D,YAAM,OAAO,aAAAA,QAAK,QAAQ,KAAK,QAAQ,KAAK,IAAI,OAAO,CAAC,CAAC;AACzD,UAAI,CAAC,KAAK,WAAW,KAAK,QAAQ,MAAM,aAAAA,QAAK,GAAG,KAAK,CAAC,WAAAM,QAAG,WAAW,IAAI,EAAG,QAAO,KAAK;AACvF,UAAI,CAAC,WAAW,IAAI,IAAI,EAAG,YAAW,IAAI,MAAM,oBAAoB,WAAAA,QAAG,aAAa,MAAM,MAAM,GAAG,GAAG,aAAAN,QAAK,SAAS,IAAI,CAAC,WAAW,CAAC;AACrI,UAAI,KAAK,MAAM,EAAE,KAAK,WAAW,IAAI,IAAI,CAAC;AAAA,IAC5C,CAAC;AACD,QAAI,IAAI,gBAAgB,gBAAAK,QAAQ,OAAO,KAAK,QAAQ,KAAK;AAAA,MACvD,QAAQ;AAAA,MACR,YAAY,CAAC,KAAK,SAAS;AACzB,YAAI,KAAK,SAAS,KAAK,EAAG,KAAI,UAAU,aAAa,GAAG,aAAAL,QAAK,SAAS,IAAI,CAAC,MAAM;AAAA,MACnF;AAAA,IACF,CAAC,CAAC;AAEF,QAAI,IAAI,cAAc,gBAAAK,QAAQ,IAAI,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ,CAAC,GAAG,WAAW;AAEpF,QAAI,IAAI,aAAa,CAAC,MAAM,QAAQ;AAClC,UAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAK,6VACuC;AAAA,IAC3E,CAAC;AAID,UAAM,eAAe,CAAC,YAAsC;AAC1D,UAAI,CAAC,qBAAqB,KAAK,OAAO,EAAG,QAAO;AAChD,UAAI,QAAQ,KAAK,aAAa,IAAI,OAAO;AACzC,UAAI,CAAC,OAAO;AACV,gBAAQ,IAAI,UAAU,CAAC,gBAAgB,OAAO,IAAI,gBAAgB,OAAO,EAAE,CAAC;AAC5E,aAAK,aAAa,IAAI,SAAS,KAAK;AAAA,MACtC;AACA,aAAO;AAAA,IACT;AACA,QAAI,KAAK,wBAAwB,gBAAAA,QAAQ,KAAK,EAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,QAAQ;AAC/E,YAAM,QAAQ,aAAa,IAAI,OAAO,OAAO;AAC7C,UAAI,CAAC,OAAO;AACV,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,8BAA8B,IAAI,OAAO,OAAO,GAAG,CAAC;AAClF;AAAA,MACF;AAEA,UAAI;AACF,YAAI,KAAK,EAAE,QAAQ,MAAM,QAAQ,IAAI,KAAK,WAAW,IAAI,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC;AAAA,MAC7E,SAAS,OAAO;AACd,YAAI,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;AAAA,MAC9C;AAAA,IACF,CAAC;AAGD,QAAI,KAAK,yBAAyB,gBAAAA,QAAQ,IAAI,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,QAAQ;AACjG,YAAM,OAAO,OAAO,IAAI,MAAM,QAAQ,KAAK;AAC3C,UAAI,CAAC,eAAe,KAAK,IAAI,GAAG;AAC9B,YAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAK,8CAAW,IAAI,EAAE;AACnD;AAAA,MACF;AACA,YAAM,QAAQ,aAAa,IAAI,OAAO,OAAO;AAC7C,UAAI,CAAC,OAAO;AACV,YAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAK,8CAAW,IAAI,OAAO,OAAO,EAAE;AACjE;AAAA,MACF;AACA,YAAM,WAAW,gBAAgB,IAAI,OAAO,OAAO,QAAI,2BAAW,CAAC,IAAI,IAAI;AAC3E,YAAM,MAAM,UAAU,OAAO,SAAS,IAAI,IAAI,IAAI,IAAI,OAAO,OAAO,MAAM,CAAC,CAAC;AAC5E,UAAI,KAAK,EAAE,KAAK,GAAG,IAAI,QAAQ,MAAM,IAAI,IAAI,MAAM,CAAC,GAAG,QAAQ,GAAG,CAAC;AAAA,IACrE,CAAC;AACD,QAAI,IAAI,yBAAyB,CAAC,KAAK,QAAQ;AAC7C,YAAM,OAAO,IAAI,OAAO;AACxB,YAAM,OAAO,SAAS,eAAe,SAAS,gBAAY,6CAAe,IAAI,IAAI;AACjF,UAAI,CAAC,MAAM;AACT,YAAI,OAAO,GAAG,EAAE,IAAI;AACpB;AAAA,MACF;AACA,UAAI,KAAK,2BAA2B,EAAE,IAAI,iBAAiB,uBAAuB,EAAE,KAAK,IAAI;AAAA,IAC/F,CAAC;AAED,QAAI,IAAkD,sCAAsC,CAAC,KAAK,QAAQ;AACxG,YAAM,QAAQ,KAAK,aAAa,IAAI,IAAI,OAAO,OAAO;AACtD,YAAM,OAAO,OAAO,KAAK,YAAY,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC;AAC7F,UAAI,CAAC,QAAQ,KAAK,KAAK;AACrB,YAAI,OAAO,GAAG,EAAE,IAAI;AACpB;AAAA,MACF;AACA,YAAM,OAAO,KAAK;AAClB,UAAI,KAAK,aAAAL,QAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC;AAEpC,UAAI,UAAU,QAAQ,IAAI,KAAK,IAAI,GAAG;AAEtC,UAAI,UAAU,iBAAiB,OAAO;AACtC,YAAM,SAAS,IAAI,MAAM,KAAK,MAAM;AACpC,UAAI,WAAW,IAAI;AACjB,YAAI,OAAO,GAAG,EAAE,UAAU,iBAAiB,WAAW,KAAK,MAAM,EAAE;AACnE,YAAI,IAAI;AACR;AAAA,MACF;AACA,UAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,WAAW,OAAO,WAAW,GAAG;AAC3E,cAAM,EAAE,OAAO,IAAI,IAAI,OAAO,CAAC;AAC/B,YAAI,OAAO,GAAG,EAAE,UAAU,iBAAiB,SAAS,KAAK,IAAI,GAAG,IAAI,KAAK,MAAM,EAAE;AACjF,YAAI,KAAK,KAAK,SAAS,OAAO,MAAM,CAAC,CAAC;AACtC;AAAA,MACF;AACA,UAAI,KAAK,IAAI;AAAA,IACf,CAAC;AACD,QAAI,OAAuC,2BAA2B,CAAC,KAAK,QAAQ;AAClF,UAAI;AACF,cAAM,QAAQ,KAAK,aAAa,IAAI,IAAI,OAAO,OAAO;AACtD,YAAI,CAAC,MAAO,OAAM,IAAI,MAAM,gBAAgB;AAC5C,cAAM,OAAO,gBAAgB,IAAI,OAAO,OAAO,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,KAAK,MAAM,CAAC;AAClF,YAAI,OAAO,GAAG,EAAE,IAAI;AAAA,MACtB,QAAQ;AACN,YAAI,OAAO,GAAG,EAAE,IAAI;AAAA,MACtB;AAAA,IACF,CAAC;AAED,QAAI,KAAK,aAAc,KAAI,IAAI,gBAAgB,oBAAoB,KAAK,QAAQ,OAAO,KAAK,YAAY,CAAC;AAGzG,QAAI,IAAI,oBAAoB,gBAAAK,QAAQ,OAAO,IAAI,CAAC;AAChD,QAAI,IAAI,gBAAAA,QAAQ,OAAO,IAAI,CAAC;AAE5B,QAAI,IAAI,CAAC,OAAc,MAAe,KAAe,UAAwB;AAC3E,WAAK,OAAO,MAAM,gBAAgB,KAAK;AACvC,UAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,OAAO;AAAA,IACjD,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,UAAU,MAAsD;AAC5E,QAAI;AACF,YAAM,YAAY,IAAI;AACtB,aAAO,EAAE,KAAK,KAAK,SAAS;AAAA,IAC9B,SAAS,OAAO;AACd,aAAO,EAAE,KAAK,KAAK,UAAU,OAAQ,MAAgB,QAAQ;AAAA,IAC/D;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,eAAkC;AAC9C,WAAO,KAAK,QAAQ,QAAQ,MAAM,KAAK,QAAQ,MAAM,CAAC;AAAA,EACxD;AAAA;AAAA,EAGQ,UAAU,SAAqF;AACrG,WAAO,OAAO,KAAc,KAAe,SAAuB;AAChE,UAAI,UAAU,iBAAiB,UAAU;AACzC,UAAIF;AACJ,UAAI;AACF,QAAAA,SAAQ,MAAM,KAAK,aAAa;AAAA,MAClC,SAAS,OAAO;AACd,YAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,KAAM,MAAgB,OAAO;AAC1D;AAAA,MACF;AACA,UAAI;AACF,gBAAQA,QAAO,KAAK,KAAK,IAAI;AAAA,MAC/B,SAAS,OAAO;AACd,aAAK,KAAK;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAqB;AAC3B,UAAM,aAAa;AAAA,MACjB,KAAK,QAAQ;AAAA,MACb,aAAAH,QAAK,KAAK,WAAW,SAAS;AAAA,MAC9B,aAAAA,QAAK,KAAK,WAAW,YAAY;AAAA,MACjC,aAAAA,QAAK,KAAK,WAAW,oBAAoB;AAAA,IAC3C,EAAE,OAAO,CAAC,QAAuB,CAAC,CAAC,GAAG;AACtC,UAAM,QAAQ,WAAW,KAAK,SAAO,WAAAM,QAAG,WAAW,aAAAN,QAAK,KAAK,KAAK,SAAS,CAAC,CAAC;AAC7E,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,0HAAqC;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAY,aAAsB;AAChC,WAAO,KAAK,QAAQ,UAAU;AAAA,EAChC;AAAA,EAEQ,gBAAgB;AAEtB,QAAI,kBAAkB;AAGtB,UAAM,UAAU,CAAC,KAAK,QAAQ,IAAI;AAClC,QAAI,KAAK,aAAa,aAAAA,QAAK,SAAS,KAAK,QAAQ,MAAM,KAAK,SAAS,EAAE,WAAW,IAAI,EAAG,SAAQ,KAAK,KAAK,SAAS;AAEpH,SAAK,UAAU,aAAa,KAAK,QAAQ,MAAM,SAAS,OAAO,EAAE,OAAO,WAAW,MAAM;AACvF,YAAM,aAAa,cAAc;AACjC,WAAK,QAAQ,WAAW,KAAK;AAC7B,YAAM,QAAQ,MAAM,SAAS,IAAI,GAAG,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,WAAM,MAAM,MAAM,wBAAS,MAAM,KAAK,IAAI;AAE1G,UAAI;AACF,cAAMG,SAAQ,MAAM,KAAK,QAAQ,MAAM;AACvC,0BAAkB;AAClB,cAAM,OAAO,aAAa,OAAO,cAAc,OAAOA,MAAK;AAC3D,aAAK,OAAO,IAAI,gBAAgB,KAAK,qDAAaA,OAAM,UAAU,KAAK,OAAO,6BAAS,EAAE,EAAE;AAC3F,aAAK,UAAU,OAAO,EAAE,MAAM,OAAO,SAASA,OAAM,SAAS,GAAG,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AAAA,MAC7F,SAAS,OAAO;AACd,0BAAkB;AAClB,cAAM,UAAW,MAAgB;AACjC,aAAK,OAAO,MAAM;AAAA,EAAuB,OAAO,EAAE;AAClD,aAAK,UAAU,EAAE,MAAM,SAAS,QAAQ,CAAC;AAAA,MAC3C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,UAAU,SAAkC;AAClD,UAAM,OAAO,KAAK,UAAU,OAAO;AACnC,SAAK,SAAS,QAAQ,QAAQ,YAAU;AACtC,UAAI,OAAO,eAAe,qBAAU,KAAM,QAAO,KAAK,IAAI;AAAA,IAC5D,CAAC;AAAA,EACH;AACF;AAEA,IAAM,eAAe;AAErB,IAAM,4BAA4B,oBAAI,IAAI,CAAC,CAAC,WAAW,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC;AAGzF,eAAe,OAAO,QAAqB,MAA0B,MAAc,QAAgD;AACjI,WAAS,YAAY,QAAQ,gBAAgB,aAAa;AAExD,UAAM,QAAS,MAAM,sBAAsB,SAAS,KAAM,CAAE,MAAM,KAAK,QAAQ,WAAW,IAAI;AAC9F,QAAI,CAAC,OAAO;AACV,YAAM,SAAU,OAAO,QAAQ,EAAsB;AACrD,UAAI,SAAS,UAAa,WAAW,aAAc,QAAO,KAAK,6BAAmB,YAAY,+CAAY,MAAM,EAAE;AAClH,aAAO;AAAA,IACT;AACA,QAAI,SAAS,OAAW,OAAM,IAAI,MAAM,gBAAM,IAAI,+IAAiC;AAAA,EACrF;AACF;AAGA,SAAS,KAAK,QAAoB,MAAc,MAAgC;AAC9E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,UAAU,CAAC,UAAkC,MAAM,SAAS,eAAe,QAAQ,KAAK,IAAI,OAAO,KAAK;AAC9G,WAAO,KAAK,SAAS,OAAO;AAC5B,WAAO,OAAO,MAAM,MAAM,MAAM;AAC9B,aAAO,IAAI,SAAS,OAAO;AAC3B,cAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,sBAAsB,MAAgC;AACnE,aAAW,WAAW,CAAC,aAAa,OAAO,WAAW,IAAI,GAAG;AAC3D,UAAM,QAAQ,WAAAD,QAAI,aAAa;AAE/B,UAAM,OAAO,MAAM,KAAK,OAAO,MAAM,OAAO,EAAE,MAAM,MAAM,IAAI;AAC9D,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,IAAI,QAAQ,aAAW,MAAM,MAAM,OAAO,CAAC;AAAA,EACnD;AACA,SAAO;AACT;AAMA,SAAS,gBAAgB,WAAyB;AAChD,QAAM,UAAU,OAAO,cAAc,YAAY,kBAAkB,KAAK,SAAS;AACjF,QAAM,QAAQ,UAAU,UAAU,YAAY,IAAI;AAClD,QAAM,WAAW,kBAAkB,KAAK,YAAU,UAAU,UAAU,MAAM,WAAW,SAAS,GAAG,CAAC;AACpG,MAAI,CAAC,WAAW,UAAU;AACxB,UAAM,IAAI;AAAA,MACR,kCAAS,OAAO,SAAS,CAAC,0RACD,kBAAkB,KAAK,QAAG,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,QAAoC,aAAoC;AAChG,MAAI,WAAW,MAAO,QAAO;AAC7B,MAAI,CAAC,OAAQ,QAAO,cAAc,WAAW;AAC7C,QAAM,OAAO,aAAAF,QAAK,QAAQ,MAAM;AAChC,MAAI,CAAC,WAAAM,QAAG,WAAW,IAAI,EAAG,OAAM,IAAI,MAAM,8CAAgB,IAAI,EAAE;AAChE,SAAO;AACT;","names":["import_crypto","import_fs","import_os","import_path","import_express","import_ws","import_wxa_runner_extractor","fs","path","os","result","import_fs","import_path","path","fs","import_wxa_runner_extractor","path","build","build","import_crypto","import_promises","import_wxa_runner_extractor","sleep","import_wxa_runner_extractor","express","import_fs","import_path","import_esbuild","path","fs","import_crypto","import_fs","import_path","chokidar","path","fs","path","os","net","build","http","express","fs"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server/DevServer.ts","../src/server/FileStore.ts","../src/project/AppBuilder.ts","../src/project/StyleMirror.ts","../src/project/wxConfig.ts","../src/project/WxmlMirror.ts","../src/project/MiniProgram.ts","../src/runtime/networkPanel.ts","../src/server/plugins.ts","../src/server/wechatDev.ts","../src/server/html.ts","../src/server/ignoreList.ts","../src/server/forwardConsole.ts","../src/server/proxy.ts","../src/server/hmr.ts","../src/server/developerTicket.ts","../src/server/devtoolsLogin.ts","../src/server/setup.ts","../src/server/watcher.ts","../src/server/extensions.ts"],"sourcesContent":["/**\n * wxa-runner-core(Node 端入口)\n *\n * 浏览器端运行时单独打包为 dist/runtime/host.js 与 dist/runtime/frame.js。\n */\n\nexport { DevServer, DEFAULT_DEVICE } from './server/DevServer';\nexport type { DevServerMiddleware, DevServerOptions, WebviewScript } from './server/DevServer';\nexport type { DevServerExtension, ExtensionContext, ExtensionEntry, ExtensionSetup } from './server/extensions';\nexport { AppBuilder } from './project/AppBuilder';\nexport type { AppBuilderOptions, BuildResult } from './project/AppBuilder';\nexport { MiniProgram } from './project/MiniProgram';\nexport type { AppJson, UnitJson } from './project/MiniProgram';\nexport { createWxConfig } from './project/wxConfig';\nexport type { AppInfo, DeviceProfile, ForwardConsole } from './runtime/types';\nexport type { ApiContext, ApiHandler, ApiResult } from './runtime/host/api/registry';\nexport type { FrameError } from './runtime/host/Host';\nexport type { PageSnapshot, RecordedRequest, WxaTestApi } from './runtime/host/testApi';\nexport type {\n MockConfig, MockRequest, MockResponse, MockValue, NetworkConfig, RouteHandler,\n SetupApi, SetupConfig, SetupContext, SetupDefinition\n} from './setup';\n","/**\n * 开发服务器\n *\n * / 宿主页面\n * /__wxa__/app-info.json 构建信息(__wxConfig、页面列表、设备参数、setup)\n * /__wxa__/setup.js 编译后的 setup 文件\n * /__wxa__/appservice.html 逻辑层\n * /__wxa__/webview/<page>.html 渲染层(路径与页面一致,wxml 里的相对资源路径因此能正确解析)\n * /__wxa__/module/<file>.js 单个业务 JS 模块(含 workers 目录下的)\n * /__wxa__/worker.js?id= Worker 的入口\n * /__wxa__/service-templates.js、page-templates.js 两层的模板(热更新时重新下发)\n * /__wxa__/page-styles.js 渲染层的样式(热更新时重新下发)\n * /__baselib__/* 官方基础库\n * /__wxa__/proxy/<协议>/<域名><路径> 网络代理,如 /__wxa__/proxy/https/api.example.com/a?b=1\n * /__wxa__/mock/<协议>/<域名><路径> 被拦截的请求在 Network 面板里的地址,由 Service Worker(runtime/sw.js)返回响应\n * /__wxa__/fs/<会话> 文件系统接口(FileSystemManager),每个浏览器会话一份文件,会话标识见 runtime/fileSession.ts\n * /__wxa__/tmp/<会话> 临时文件:POST ?type=png 保存,返回可直接访问的地址(GET 支持分段请求);对该地址 HEAD 查大小、DELETE 删除\n * /__wxa__/usr/<会话>/<路径> 用户目录(USER_DATA_PATH)下的文件,image 等组件和 uploadFile 按地址读取\n * /__wxa__/region/<kind> 地区选择器用的行政区划数据(districts / streets),取自本机开发者工具\n * /__wxa__/api/* --devtools-login:wx.login 的 code、手机号,服务市场、插件的请求转发,只允许本机访问\n * /__wxa__/ws 文件变化通知:热更新(hot)或整页刷新(reload);开启 forwardConsole 时浏览器从这里发来报错\n * middlewares / 扩展挂载的路径 排在 runner 自己的路由之前\n * 其余路径 小程序目录下的静态资源\n */\n\nimport { randomUUID } from 'crypto';\nimport { FileStore } from './FileStore';\nimport fs from 'fs';\nimport http, { IncomingMessage, ServerResponse } from 'http';\nimport net from 'net';\nimport os from 'os';\nimport path from 'path';\nimport express, { Express, NextFunction, Request, Response } from 'express';\nimport { WebSocket, WebSocketServer } from 'ws';\nimport { readRegionData, resolveBaseLib, ResolvedBaseLib, usesIsolatedContext } from '@open-wxa/wxa-runner-extractor';\nimport { AppBuilder } from '../project/AppBuilder';\nimport { MiniProgram } from '../project/MiniProgram';\nimport { ignoredStyleSources } from '../project/StyleMirror';\nimport { MOCK_PREFIX, PROXY_PREFIX } from '../runtime/networkPanel';\nimport type { AppInfo, DeviceProfile, ForwardConsole } from '../runtime/types';\nimport { appserviceHtml, hostHtml, pluginWebviewHtml, subcontextHtml, webviewHtml, workerScript } from './html';\nimport { ignoreListSourceMap } from './ignoreList';\nimport { ignoreConsoleHook, printBrowserReports } from './forwardConsole';\nimport { handleProxy } from './proxy';\nimport { planHotUpdate } from './hmr';\nimport { developerTicketSource, TicketSource } from './developerTicket';\nimport { AppBuild, findPluginPage, PluginStore } from './plugins';\nimport { devtoolsLoginRouter } from './devtoolsLogin';\nimport { requireUsableTicket, WechatDevClient } from './wechatDev';\nimport { bundleSetup, collectSetupEnv, findSetupFile } from './setup';\nimport { ProjectWatcher, watchProject } from './watcher';\nimport { applyExtensions, DevServerExtension, ExtensionEntry } from './extensions';\n\n/** 注入每个渲染层页面的脚本,src 与 content 二选一 */\nexport type WebviewScript = ({ src: string; content?: never } | { content: string; src?: never }) & {\n /**\n * 'head':在基础库(WAWebview.js)之前执行,用于要赶在基础库之前注册事件监听的脚本,执行时还没有 document.body;\n * 'body'(默认):在 <body> 开头、页面开始渲染之前执行。不能放在 <body> 末尾:基础库渲染时会换掉 body,\n * 之后才解析到的脚本落在脱离文档的旧 body 里,不会执行\n */\n position?: 'head' | 'body';\n};\n\n/** 挂在开发服务器上的中间件:按前缀匹配,handler 收到的 req.url 已去掉 path 这段前缀 */\nexport interface DevServerMiddleware {\n /** 以 / 开头的字面量路径前缀,如 /__tool__;不能是 /,不能含通配符和参数,也不能落在 runner 保留的前缀下(见 RESERVED_PREFIXES) */\n path: string;\n handler: (req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => void) => void;\n}\n\n/** runner 自己使用的路径前缀,中间件不能占用 */\nconst RESERVED_PREFIXES = ['/__wxa__', '/__baselib__', '/__plugin__'];\n\nexport interface DevServerOptions {\n projectPath: string;\n /** 不传时从 3000 起找空闲的端口;指定的端口被占用时启动失败;传 0 使用随机端口 */\n port?: number;\n /** 监听地址,默认 localhost;0.0.0.0 或 :: 时局域网也能访问 */\n host?: string;\n /** 指定基础库版本,默认使用本机已安装的最新兼容版本 */\n baseLibVersion?: string;\n baseLibCacheDir?: string;\n watch?: boolean;\n device?: Partial<DeviceProfile>;\n /**\n * 小程序启动前执行的 setup 文件;默认使用项目目录下的 wxa.setup.ts / .js / .mjs,传 false 不使用\n * 环境变量在构造时读取,只暴露 WXA_ 前缀的变量\n */\n setup?: string | false;\n /** 浏览器端运行时(host.js / frame.js)所在目录,默认取构建产物 */\n runtimeDir?: string;\n /**\n * 借本机微信开发者工具的登录态访问微信后台:真实的 wx.login code 和手机号、服务市场、插件。\n * 要先登录开发者工具,会真实请求微信\n */\n devtoolsLogin?: boolean;\n /** @deprecated 改名为 devtoolsLogin */\n realLogin?: boolean;\n /**\n * 把浏览器里的报错打印到终端:'errors' 转发运行时错误和未实现 API 的提醒,'all' 再加上 console.warn / console.error。\n * 默认不转发;命令行默认 'errors',检测到编程助手时 'all'\n */\n forwardConsole?: ForwardConsole;\n /** 注入每个渲染层页面(含插件页面、跳转后新建的页面)的脚本,供检查器等开发工具使用 */\n webviewScripts?: WebviewScript[];\n /** 挂在开发服务器上的中间件,供开发工具提供自己的页面和接口 */\n middlewares?: DevServerMiddleware[];\n /**\n * wxml 交给 wcc 编译前的转换,file 是相对小程序根目录的路径(如 pages/index/index.wxml)。\n * 不能改变行数,编译错误和热更新才能对应到源文件;相同输入要返回相同输出。源文件不会被修改\n */\n wxmlTransform?: (code: string, file: string) => string;\n /** 开发服务器扩展:把上面几个扩展点打包在一起的开发工具,按顺序合并在直接给出的选项之后,见 extensions.ts */\n extensions?: DevServerExtension[];\n logger?: Pick<Console, 'log' | 'warn' | 'error'>;\n}\n\nexport const DEFAULT_DEVICE: DeviceProfile = {\n model: 'iPhone X',\n screenWidth: 375,\n screenHeight: 812,\n pixelRatio: 3,\n statusBarHeight: 44,\n safeAreaBottom: 34,\n system: 'iOS 16.0',\n platform: 'devtools'\n};\n\nexport class DevServer {\n readonly project: MiniProgram;\n readonly builder: AppBuilder;\n readonly baseLib: ResolvedBaseLib;\n /** 生效的 setup 文件绝对路径,没有时为 null */\n readonly setupFile: string | null;\n /** 扩展提供的页面,按扩展的顺序 */\n readonly extensionEntries: ExtensionEntry[];\n private readonly setupEnv: Record<string, string>;\n private readonly device: DeviceProfile;\n private readonly logger: Pick<Console, 'log' | 'warn' | 'error'>;\n private readonly app: Express;\n private server: http.Server | null = null;\n private sockets: WebSocketServer | null = null;\n private watcher: ProjectWatcher | null = null;\n private address = '';\n private lanAccess = false;\n /** 运行时生成的临时文件(canvas 导出、拍照等),随服务器进程存在 */\n private readonly fileSessions = new Map<string, FileStore>();\n private readonly devtoolsLogin: boolean;\n /** 开启 --devtools-login 时才有 */\n private readonly ticketSource: TicketSource | null;\n private readonly plugins: PluginStore;\n\n /** 选项里直接给出的扩展点与各个扩展合并后的结果 */\n private readonly webviewScripts: WebviewScript[];\n private readonly middlewares: DevServerMiddleware[];\n\n constructor(private readonly options: DevServerOptions) {\n this.logger = options.logger || console;\n this.project = new MiniProgram(path.resolve(options.projectPath));\n for (const { plugin, files } of ignoredStyleSources(this.project, this.project.styleSetting)) {\n this.logger.warn(\n `[wxa-runner] ${files.length} 个 ${plugin} 样式文件不会生效(如 ${files[0]}):project.config.json 的 setting.useCompilerPlugins 没有开启 ${plugin},开发者工具同样不编译它们`\n );\n }\n const extended = applyExtensions(options, options.extensions ?? [], { projectPath: this.project.projectPath, root: this.project.root });\n extended.middlewares.forEach(({ path: mountPath }) => assertMountPath(mountPath));\n this.webviewScripts = extended.webviewScripts;\n this.middlewares = extended.middlewares;\n this.extensionEntries = extended.entries;\n this.baseLib = resolveBaseLib({ version: options.baseLibVersion, cacheDir: options.baseLibCacheDir });\n if (!this.baseLib.compatible) {\n this.logger.warn(`[wxa-runner] 基础库 ${this.baseLib.version} 高于已验证的版本范围,可能无法正常运行`);\n }\n if (options.realLogin !== undefined && options.devtoolsLogin === undefined) {\n this.logger.warn('[wxa-runner] realLogin(--real-login)已改名为 devtoolsLogin(--devtools-login),旧名以后会移除');\n }\n this.devtoolsLogin = (options.devtoolsLogin ?? options.realLogin) === true;\n this.ticketSource = this.devtoolsLogin ? developerTicketSource(this.project.projectPath, this.logger) : null;\n this.plugins = new PluginStore(this.ticketSource && new WechatDevClient(this.project.appid, this.ticketSource), this.logger);\n this.device = { ...DEFAULT_DEVICE, ...options.device };\n this.builder = new AppBuilder(this.project, { wxmlTransform: extended.wxmlTransform });\n this.setupFile = resolveSetupFile(options.setup, this.project.projectPath);\n this.setupEnv = collectSetupEnv(process.env);\n this.app = this.createApp();\n }\n\n /** 本机访问的地址 */\n get url(): string {\n return this.address;\n }\n\n /** 局域网里其他设备访问的地址,每块网卡一个;只监听本机时为空 */\n get networkUrls(): string[] {\n if (!this.lanAccess) return [];\n const { port } = new URL(this.address);\n return Object.values(os.networkInterfaces())\n .flat()\n .filter(net => net && net.family === 'IPv4' && !net.internal)\n .map(net => `http://${net!.address}:${port}`);\n }\n\n async start(): Promise<string> {\n // 先构建一次:编译错误在终端里立即可见\n try {\n const build = await this.builder.build();\n this.logger.log(`[wxa-runner] 编译完成:${build.pages.length} 个页面,${build.components.length} 个组件,${build.durationMs}ms`);\n } catch (error) {\n this.logger.error(`[wxa-runner] 编译失败:\\n${(error as Error).message}`);\n }\n\n const server = http.createServer(this.app);\n // 浏览器只发来报错,单条用不了 64KB\n this.sockets = new WebSocketServer({ noServer: true, maxPayload: 64 * 1024 });\n this.sockets.on('connection', socket => {\n // 消息超过 maxPayload 等协议错误时 ws 会断开这个连接;没有监听器的 error 事件会让整个进程退出\n socket.on('error', () => undefined);\n if (this.options.forwardConsole) printBrowserReports(socket, this.logger);\n });\n server.on('upgrade', (req, socket, head) => {\n if (req.url?.startsWith('/__wxa__/ws')) {\n this.sockets!.handleUpgrade(req, socket, head, ws => this.sockets!.emit('connection', ws, req));\n } else {\n socket.destroy();\n }\n });\n\n const host = this.options.host || 'localhost';\n const port = await listen(server, this.options.port, host, this.logger);\n this.server = server;\n this.lanAccess = LOCAL_HOST_OF_ANY_ADDRESS.has(host);\n this.address = `http://${LOCAL_HOST_OF_ANY_ADDRESS.get(host) ?? host}:${port}`;\n\n if (this.options.watch !== false) this.startWatching();\n // 启动时先取一次:新版开发者工具要先为项目开启自动化接口,第一次 wx.login 就不用等;不可用时在终端提示原因\n this.ticketSource?.()\n .then(requireUsableTicket)\n .catch(error => this.logger.warn(`[wxa-runner] 开发者工具的登录态暂不可用(--devtools-login):${error.message}`));\n return this.address;\n }\n\n async close() {\n await this.watcher?.close();\n this.sockets?.clients.forEach(client => client.terminate());\n this.sockets?.close();\n const server = this.server;\n this.server = null;\n if (server) {\n // 浏览器和 fetch 的 keep-alive 连接会让 close() 一直等到超时\n server.closeAllConnections();\n await new Promise<void>(resolve => server.close(() => resolve()));\n }\n this.fileSessions.clear();\n this.builder.dispose();\n }\n\n private createApp(): Express {\n const app = express();\n const root = this.project.root;\n const noStore = (res: Response) => res.setHeader('Cache-Control', 'no-store');\n\n for (const { path: mountPath, handler } of this.middlewares) {\n app.use(mountPath, (req, res, next) => handler(req, res, next));\n }\n\n app.get('/', (_req, res) => {\n noStore(res);\n res.type('html').send(hostHtml());\n });\n\n app.get('/favicon.ico', (_req, res) => {\n res.status(204).end();\n });\n\n app.get('/__wxa__/app-info.json', async (_req, res) => {\n noStore(res);\n const base = {\n appid: this.project.appid,\n baseLibVersion: this.baseLib.version,\n device: this.device,\n devtoolsLogin: this.devtoolsLogin,\n forwardConsole: this.options.forwardConsole ?? false\n };\n try {\n // 宿主打开小程序时先取 app-info:这时重新决定用哪些插件,之后的请求都按这个结果\n const build = await this.plugins.refresh(await this.builder.build());\n const info: AppInfo = { ...base, version: build.version, wxConfig: build.wxConfig, pages: build.pages };\n if (this.setupFile) info.setup = await this.setupInfo(this.setupFile);\n res.json(info);\n } catch (error) {\n res.json({ ...base, version: 0, wxConfig: {}, pages: [], buildError: (error as Error).message });\n }\n });\n\n app.get('/__wxa__/setup.js', async (_req, res) => {\n noStore(res);\n if (!this.setupFile) {\n res.status(404).type('text').send('没有 setup 文件');\n return;\n }\n try {\n res.type('js').send(await bundleSetup(this.setupFile));\n } catch (error) {\n res.status(500).type('text').send((error as Error).message);\n }\n });\n\n app.get('/__wxa__/appservice.html', this.withBuild((build, req, res) => {\n const launchPath = String(req.query.path || '').replace(/^\\//, '');\n const launch = build.pages.includes(launchPath)\n ? { path: launchPath, query: Object.fromEntries(new URLSearchParams(String(req.query.query || ''))) }\n : { path: build.pages[0], query: {} };\n res.type('html').send(appserviceHtml(build, launch, { hot: this.hotEnabled, isolated: usesIsolatedContext(this.baseLib.version) }));\n }));\n\n app.get('/__wxa__/subcontext.html', (req, res) => {\n const id = Number(req.query.id);\n if (!Number.isInteger(id) || id <= 0) {\n res.status(400).type('text').send('子上下文 id 无效');\n return;\n }\n res.type('html').send(subcontextHtml(id, req.query.empty === '1'));\n });\n\n app.get(/^\\/__wxa__\\/webview\\/(.+)\\.html$/, this.withBuild((build, req, res, next) => {\n const pagePath = decodeURIComponent(req.params[0]);\n if (!build.pages.includes(pagePath)) return next();\n const pluginPage = findPluginPage(build, pagePath);\n const scripts = this.webviewScripts;\n res.type('html').send(pluginPage\n ? pluginWebviewHtml(build, pluginPage.plugin, pluginPage.innerPath, pagePath, Number(req.query.id), { scripts })\n : webviewHtml(build, pagePath, Number(req.query.id), { hot: this.hotEnabled, scripts }));\n }));\n\n // 插件的逻辑层、渲染层代码\n app.get('/__wxa__/plugin/:provider/:version/:file(appservice.js|pageframe.js)', this.withBuild((build, req, res, next) => {\n const { provider, version, file } = req.params;\n const code = build.plugins.find(plugin => plugin.provider === provider && plugin.version === version)?.files.get(`/${file}`);\n if (!code) return next();\n res.type('js').send(code);\n }));\n // 插件页面里的图片等资源:基础库把插件里的相对路径和 / 开头的路径都改写成站点根下的 /__plugin__/<插件 appid>/…\n app.get(/^\\/__plugin__\\/([^/]+)(\\/.+)$/, this.withBuild((build, req, res, next) => {\n const file = build.plugins.find(plugin => plugin.provider === req.params[0])?.files.get(decodeURIComponent(req.params[1]));\n if (!file) return next();\n res.type(path.extname(req.params[1]) || 'application/octet-stream').send(file);\n }));\n\n app.get(/^\\/__wxa__\\/module\\/(.+\\.js)$/, this.withBuild((build, req, res) => {\n const id = decodeURIComponent(req.params[0]);\n if (!build.modules.includes(id) && !build.workerModules.includes(id)) {\n res.status(404).type('js').send(`console.error(${JSON.stringify(`[wxa-runner] 模块 ${id} 不存在`)})`);\n return;\n }\n res.type('js').send(this.builder.getModuleScript(id));\n }));\n\n app.get('/__wxa__/worker.js', this.withBuild((build, _req, res) => {\n const hasWorker = fs.existsSync(path.join(this.baseLib.dir, 'WAWorker.js'));\n res.type('js').send(workerScript(build, { version: this.baseLib.version, hasWorker }));\n }));\n\n app.get('/__wxa__/service-bootstrap.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.serviceBootstrap);\n }));\n\n app.get('/__wxa__/service-templates.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.serviceTemplates);\n }));\n\n app.get('/__wxa__/page-templates.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.pageTemplates);\n }));\n\n app.get('/__wxa__/page-styles.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.pageStyles);\n }));\n\n app.get('/__wxa__/page-frame.js', this.withBuild((build, _req, res) => {\n res.type('js').send(build.pageFrame);\n }));\n\n app.get('/__wxa__/runtime/frame.js.map', (_req, res, next) => {\n const file = path.join(this.runtimeDir(), 'frame.js.map');\n if (!fs.existsSync(file)) return next();\n res.type('json').send(ignoreConsoleHook(fs.readFileSync(file, 'utf8')));\n });\n app.use('/__wxa__/runtime', express.static(this.runtimeDir(), {\n cacheControl: false,\n // Service Worker 默认只能接管自己所在目录下的页面,宿主页面在根路径\n setHeaders: (res, file) => {\n if (path.basename(file) === 'sw.js') res.setHeader('Service-Worker-Allowed', '/');\n }\n }));\n // 基础库脚本加入 DevTools 的忽略列表,原始代码就是脚本本身(换个地址,免得和脚本混为一个文件)\n const sourceMaps = new Map<string, string>();\n app.get(/^\\/__baselib__\\/(.+\\.js)\\.map$/, (req, res, next) => {\n const file = path.resolve(this.baseLib.dir, req.params[0]);\n if (!file.startsWith(this.baseLib.dir + path.sep) || !fs.existsSync(file)) return next();\n if (!sourceMaps.has(file)) sourceMaps.set(file, ignoreListSourceMap(fs.readFileSync(file, 'utf8'), `${path.basename(file)}?original`));\n res.type('json').send(sourceMaps.get(file));\n });\n app.use('/__baselib__', express.static(this.baseLib.dir, {\n maxAge: '1d',\n setHeaders: (res, file) => {\n if (file.endsWith('.js')) res.setHeader('SourceMap', `${path.basename(file)}.map`);\n }\n }));\n // 用 app.use 而不是 app.all('…/*'):后者会先解码路径,见 handleProxy\n app.use(PROXY_PREFIX, express.raw({ type: () => true, limit: '100mb' }), handleProxy);\n // 被拦截的请求本该由 Service Worker 返回响应,到这里说明它没有生效\n app.use(MOCK_PREFIX, (_req, res) => {\n res.status(503).type('text').send('这个请求已被拦截规则拦下,这里只用于在 Network 面板里显示它。'\n + 'Service Worker 没有生效(如 DevTools 勾选了 Bypass for network),看不到拦截规则给出的响应');\n });\n\n // 每个浏览器会话一份 FileStore:刷新复用,不同的浏览器上下文(Playwright 的每个用例)互不可见。\n // 会话标识要拼进文件地址,只接受 fileSession() 生成的格式;不合法时返回 null\n const sessionFiles = (session: string): FileStore | null => {\n if (!/^[a-z0-9-]{1,80}$/i.test(session)) return null;\n let files = this.fileSessions.get(session);\n if (!files) {\n files = new FileStore([`/__wxa__/usr/${session}`, `/__wxa__/tmp/${session}`]);\n this.fileSessions.set(session, files);\n }\n return files;\n };\n app.post('/__wxa__/fs/:session', express.json({ limit: '150mb' }), (req, res) => {\n const files = sessionFiles(req.params.session);\n if (!files) {\n res.status(400).json({ error: `invalid filesystem session ${req.params.session}` });\n return;\n }\n // 文件不存在等是接口的正常失败,照样返回 200,免得每次失败都在浏览器控制台留下一条请求错误(基础库启动时就会探测不存在的文件)\n try {\n res.json({ result: files.execute(req.body.operation, req.body.args || {}) });\n } catch (error) {\n res.json({ error: (error as Error).message });\n }\n });\n\n // 返回完整的 http 地址:image、video 组件只原样使用 http(s) 地址。\n app.post('/__wxa__/tmp/:session', express.raw({ type: () => true, limit: '100mb' }), (req, res) => {\n const type = String(req.query.type || 'png');\n if (!/^[a-z0-9]+$/i.test(type)) {\n res.status(400).type('text').send(`非法的文件类型 ${type}`);\n return;\n }\n const files = sessionFiles(req.params.session);\n if (!files) {\n res.status(400).type('text').send(`非法的会话标识 ${req.params.session}`);\n return;\n }\n const filePath = `/__wxa__/tmp/${req.params.session}/${randomUUID()}.${type}`;\n files.write(filePath, Buffer.isBuffer(req.body) ? req.body : Buffer.alloc(0));\n res.json({ url: `${req.protocol}://${req.get('host')}${filePath}` });\n });\n app.get('/__wxa__/region/:kind', (req, res) => {\n const kind = req.params.kind;\n const data = kind === 'districts' || kind === 'streets' ? readRegionData(kind) : null;\n if (!data) {\n res.status(404).end();\n return;\n }\n res.type('text/plain; charset=utf-8').set('Cache-Control', 'public, max-age=86400').send(data);\n });\n\n app.get<{ kind: string; session: string; 0: string }>('/__wxa__/:kind(usr|tmp)/:session/*', (req, res) => {\n const files = this.fileSessions.get(req.params.session);\n const node = files?.stat(`/__wxa__/${req.params.kind}/${req.params.session}/` + req.params[0]);\n if (!node || node.dir) {\n res.status(404).end();\n return;\n }\n const data = node.data;\n res.type(path.extname(req.params[0]));\n // 每次写入更新版本号,追加和 Range 请求不再对整份文件计算哈希。\n res.setHeader('ETag', `\"${node.etag}\"`);\n // 支持分段请求,video 组件播放临时文件时才能跳转(不支持时浏览器认为视频不能跳转,seek 不起作用)\n res.setHeader('Accept-Ranges', 'bytes');\n const ranges = req.range(data.length);\n if (ranges === -1) {\n res.status(416).setHeader('Content-Range', `bytes */${data.length}`);\n res.end();\n return;\n }\n if (Array.isArray(ranges) && ranges.type === 'bytes' && ranges.length === 1) {\n const { start, end } = ranges[0];\n res.status(206).setHeader('Content-Range', `bytes ${start}-${end}/${data.length}`);\n res.send(data.subarray(start, end + 1));\n return;\n }\n res.send(data);\n });\n app.delete<{ session: string; 0: string }>('/__wxa__/tmp/:session/*', (req, res) => {\n try {\n const files = this.fileSessions.get(req.params.session);\n if (!files) throw new Error('file not exist');\n files.remove(`/__wxa__/tmp/${req.params.session}/` + req.params[0], { dir: false });\n res.status(204).end();\n } catch {\n res.status(404).end();\n }\n });\n\n if (this.ticketSource) app.use('/__wxa__/api', devtoolsLoginRouter(this.project.appid, this.ticketSource));\n\n // 渲染层页面路径下的相对资源(如 ../../images/a.png)\n app.use('/__wxa__/webview', express.static(root));\n app.use(express.static(root));\n\n app.use((error: Error, _req: Request, res: Response, _next: NextFunction) => {\n this.logger.error('[wxa-runner]', error);\n res.status(500).type('text').send(error.message);\n });\n\n return app;\n }\n\n /** 先编译一遍 setup:编译错误随 app-info 交给宿主显示,而不是让浏览器 import 失败 */\n private async setupInfo(file: string): Promise<NonNullable<AppInfo['setup']>> {\n try {\n await bundleSetup(file);\n return { env: this.setupEnv };\n } catch (error) {\n return { env: this.setupEnv, error: (error as Error).message };\n }\n }\n\n /** 构建结果并入这次打开小程序时决定用的插件 */\n private async currentBuild(): Promise<AppBuild> {\n return this.plugins.current(await this.builder.build());\n }\n\n /** 需要构建结果的路由;构建失败时返回错误文本 */\n private withBuild(handler: (build: AppBuild, req: Request, res: Response, next: NextFunction) => void) {\n return async (req: Request, res: Response, next: NextFunction) => {\n res.setHeader('Cache-Control', 'no-store');\n let build: AppBuild;\n try {\n build = await this.currentBuild();\n } catch (error) {\n res.status(500).type('text').send((error as Error).message);\n return;\n }\n try {\n handler(build, req, res, next);\n } catch (error) {\n next(error);\n }\n };\n }\n\n private runtimeDir(): string {\n const candidates = [\n this.options.runtimeDir,\n path.join(__dirname, 'runtime'),\n path.join(__dirname, '../runtime'),\n path.join(__dirname, '../../dist/runtime')\n ].filter((dir): dir is string => !!dir);\n const found = candidates.find(dir => fs.existsSync(path.join(dir, 'host.js')));\n if (!found) {\n throw new Error('找不到浏览器端运行时(host.js),请先执行 pnpm build');\n }\n return found;\n }\n\n /** 只在监听文件变化时打开基础库的热更新开关,跑测试(watch: false)时运行环境与真机一致 */\n private get hotEnabled(): boolean {\n return this.options.watch !== false;\n }\n\n private startWatching() {\n // 上次编译失败时页面上显示着错误,修好后整页刷新才能清掉\n let lastBuildFailed = false;\n\n // 项目目录下的 setup 文件不一定在小程序根目录(miniprogramRoot)里\n const watched = [this.project.root];\n const outsideRoot = (file: string) => path.relative(this.project.root, file).startsWith('..');\n if (this.setupFile && outsideRoot(this.setupFile)) watched.push(this.setupFile);\n // less / sass 编译插件的设置在这里,改了要重新编译样式\n const projectConfig = path.join(this.project.projectPath, 'project.config.json');\n if (outsideRoot(projectConfig) && fs.existsSync(projectConfig)) watched.push(projectConfig);\n\n this.watcher = watchProject(this.project.root, watched, async ({ files, structural }) => {\n const reloadOnly = structural || lastBuildFailed;\n this.builder.invalidate(files);\n const label = files.length > 3 ? `${files.slice(0, 3).join(', ')} 等 ${files.length} 个文件` : files.join(', ');\n\n try {\n const build = await this.builder.build();\n lastBuildFailed = false;\n const plan = reloadOnly ? null : planHotUpdate(files, build);\n this.logger.log(`[wxa-runner] ${label} 已更新,重新编译 ${build.durationMs}ms${plan ? ',热更新' : ''}`);\n this.broadcast(plan ? { type: 'hot', version: build.version, ...plan } : { type: 'reload' });\n } catch (error) {\n lastBuildFailed = true;\n const message = (error as Error).message;\n this.logger.error(`[wxa-runner] 编译失败:\\n${message}`);\n this.broadcast({ type: 'error', message });\n }\n });\n }\n\n private broadcast(message: Record<string, unknown>) {\n const data = JSON.stringify(message);\n this.sockets?.clients.forEach(client => {\n if (client.readyState === WebSocket.OPEN) client.send(data);\n });\n }\n}\n\nconst DEFAULT_PORT = 3000;\n/** 监听所有地址时,本机访问用的地址:0.0.0.0 只监听 IPv4,localhost 可能解析到 IPv6 的 ::1 */\nconst LOCAL_HOST_OF_ANY_ADDRESS = new Map([['0.0.0.0', '127.0.0.1'], ['::', 'localhost']]);\n\n/** 开始监听,返回实际的端口。没指定端口时从 3000 起往后找空闲的,换了端口在终端提示 */\nasync function listen(server: http.Server, port: number | undefined, host: string, logger: Pick<Console, 'warn'>): Promise<number> {\n for (let candidate = port ?? DEFAULT_PORT; ; candidate++) {\n // macOS 允许本机地址和所有地址上各有一个进程占着同一端口,两个方向都能绑定成功,打开 localhost 会进到哪边说不准\n const taken = (await takenOnLocalAddresses(candidate)) || !(await bind(server, candidate, host));\n if (!taken) {\n const actual = (server.address() as net.AddressInfo).port;\n if (port === undefined && actual !== DEFAULT_PORT) logger.warn(`[wxa-runner] 端口 ${DEFAULT_PORT} 已被占用,改用 ${actual}`);\n return actual;\n }\n if (port !== undefined) throw new Error(`端口 ${port} 已被占用:先关闭占用它的进程,或用 --port 换一个端口`);\n }\n}\n\n/** 返回 false 表示端口已被占用 */\nfunction bind(server: net.Server, port: number, host: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n const onError = (error: NodeJS.ErrnoException) => (error.code === 'EADDRINUSE' ? resolve(false) : reject(error));\n server.once('error', onError);\n server.listen(port, host, () => {\n server.off('error', onError);\n resolve(true);\n });\n });\n}\n\nasync function takenOnLocalAddresses(port: number): Promise<boolean> {\n for (const address of ['127.0.0.1', '::1', '0.0.0.0', '::']) {\n const probe = net.createServer();\n // 没有这个地址(如关掉了 IPv6)时不算占用\n const free = await bind(probe, port, address).catch(() => true);\n if (!free) return true;\n await new Promise(resolve => probe.close(resolve));\n }\n return false;\n}\n\n/**\n * 中间件路径不能盖住宿主页面,也不能落在 runner 保留的前缀下。\n * Express 把路径当模式匹配(支持 * 和 :参数)且不区分大小写,所以只收字面量路径,按小写比较保留前缀\n */\nfunction assertMountPath(mountPath: string): void {\n const literal = typeof mountPath === 'string' && /^(\\/[\\w.~-]+)+$/.test(mountPath);\n const lower = literal ? mountPath.toLowerCase() : '';\n const reserved = RESERVED_PREFIXES.some(prefix => lower === prefix || lower.startsWith(prefix + '/'));\n if (!literal || reserved) {\n throw new Error(\n `中间件路径 ${String(mountPath)} 不可用:要以 / 开头,只含字母、数字和 _ . ~ -(不支持通配符和参数),不能是 /,` +\n `也不能用 wxa-runner 保留的前缀 ${RESERVED_PREFIXES.join('、')}(不区分大小写)`\n );\n }\n}\n\nfunction resolveSetupFile(option: string | false | undefined, projectPath: string): string | null {\n if (option === false) return null;\n if (!option) return findSetupFile(projectPath);\n const file = path.resolve(option);\n if (!fs.existsSync(file)) throw new Error(`找不到 setup 文件:${file}`);\n return file;\n}\n","/** 开发服务器持有的文件存储;文件 API、下载、上传和资源 URL 共用这些字节。 */\n\nimport { randomUUID } from 'crypto';\n\ninterface FsNode {\n dir: boolean;\n data: Buffer;\n mtime: number;\n etag: string;\n}\n\n/** 基础库会往 http://usr/ 写运行日志;业务代码也可以通过 FileSystemManager 读写 */\nexport class FileStore {\n private readonly etagPrefix = randomUUID();\n private version = 0;\n private nodes = new Map<string, FsNode>([['/', { dir: true, data: Buffer.alloc(0), mtime: Date.now(), etag: '' }]]);\n private readonly roots: string[];\n\n /** @param roots 预先创建的目录(如用户目录)。rmdir 不能删除它们和它们的上级目录:删掉之后再写 USER_DATA_PATH 都会失败 */\n constructor(roots: string[] = []) {\n this.roots = roots.map(root => this.normalize(root));\n for (const root of this.roots) this.mkdir(root, true);\n }\n\n normalize(filePath: string): string {\n const stripped = String(filePath || '').replace(/^[a-z]+:\\/\\/[^/]*/i, '');\n const parts: string[] = [];\n for (const part of stripped.split('/')) {\n if (!part || part === '.') continue;\n if (part === '..') parts.pop();\n else parts.push(part);\n }\n return '/' + parts.join('/');\n }\n\n stat(filePath: string): FsNode | undefined {\n return this.nodes.get(this.normalize(filePath));\n }\n\n mkdir(dirPath: string, recursive = false) {\n const target = this.normalize(dirPath);\n if (this.nodes.has(target)) throw new Error(`file already exists ${dirPath}`);\n const parent = target.slice(0, target.lastIndexOf('/')) || '/';\n if (!this.nodes.get(parent)?.dir) {\n if (!recursive) throw new Error(`no such file or directory ${dirPath}`);\n this.mkdir(parent, true);\n }\n this.nodes.set(target, { dir: true, data: Buffer.alloc(0), mtime: Date.now(), etag: '' });\n }\n\n write(filePath: string, input: string | Uint8Array, append = false) {\n const data = Buffer.from(input);\n const target = this.normalize(filePath);\n const parent = target.slice(0, target.lastIndexOf('/')) || '/';\n if (!this.nodes.get(parent)?.dir) throw new Error(`no such file or directory ${filePath}`);\n const existing = this.nodes.get(target);\n if (existing?.dir) throw new Error(`illegal operation on a directory ${filePath}`);\n const contents = append && existing ? Buffer.concat([existing.data, data]) : data;\n this.nodes.set(target, { dir: false, data: contents, mtime: Date.now(), etag: `${this.etagPrefix}-${++this.version}` });\n }\n\n read(filePath: string): Buffer {\n const node = this.stat(filePath);\n if (!node) throw new Error(`no such file or directory, open ${filePath}`);\n if (node.dir) throw new Error(`illegal operation on a directory ${filePath}`);\n return node.data;\n }\n\n readdir(dirPath: string): string[] {\n const target = this.normalize(dirPath);\n if (!this.nodes.get(target)?.dir) throw new Error(`no such file or directory ${dirPath}`);\n const prefix = target === '/' ? '/' : target + '/';\n return [...this.nodes.keys()]\n .filter(key => key.startsWith(prefix) && key !== target && !key.slice(prefix.length).includes('/'))\n .map(key => key.slice(prefix.length));\n }\n\n remove(filePath: string, options: { dir: boolean; recursive?: boolean }) {\n const target = this.normalize(filePath);\n const node = this.nodes.get(target);\n if (!node) throw new Error(`no such file or directory ${filePath}`);\n if (node.dir !== options.dir) throw new Error(options.dir ? `not a directory ${filePath}` : `operation not permitted ${filePath}`);\n if (node.dir) {\n const children = this.readdir(target);\n if (children.length && !options.recursive) throw new Error(`directory not empty ${filePath}`);\n for (const key of [...this.nodes.keys()]) if (key.startsWith(target + '/')) this.nodes.delete(key);\n }\n this.nodes.delete(target);\n }\n\n /** 文件 API 经开发服务器调用的操作,参数和返回值的字段名与基础库一致 */\n execute(operation: string, args: any): Record<string, any> {\n if (!Object.prototype.hasOwnProperty.call(this.operations, operation)) {\n throw new Error(`unsupported filesystem operation ${operation}`);\n }\n return this.operations[operation](args);\n }\n\n private readonly operations: Record<string, (args: any) => Record<string, any>> = {\n readFile: ({ filePath, encoding }) => {\n const data = this.read(filePath);\n return encoding === undefined ? { data: data.toString('base64'), binary: true } : { data: data.toString(encoding) };\n },\n writeFile: args => this.writeEncoded(args, false),\n appendFile: args => this.writeEncoded(args, true),\n copyFile: ({ srcPath, destPath }) => {\n this.write(destPath, this.read(srcPath));\n return {};\n },\n access: ({ path }) => {\n this.existing(path);\n return {};\n },\n stat: ({ path }) => {\n const node = this.existing(path);\n const stats = {\n mode: node.dir ? 0o40755 : 0o100644,\n size: node.data.length,\n lastAccessedTime: Math.floor(node.mtime / 1000),\n lastModifiedTime: Math.floor(node.mtime / 1000)\n };\n return { stats, ...stats };\n },\n getFileInfo: ({ filePath }) => ({ size: this.read(filePath).length }),\n mkdir: ({ dirPath, recursive }) => {\n this.mkdir(dirPath, !!recursive);\n return {};\n },\n readdir: ({ dirPath }) => ({ files: this.readdir(dirPath) }),\n unlink: ({ filePath }) => {\n this.remove(filePath, { dir: false });\n return {};\n },\n rmdir: ({ dirPath, recursive }) => {\n this.assertNotRoot(dirPath);\n this.remove(dirPath, { dir: true, recursive: !!recursive });\n return {};\n }\n };\n\n private writeEncoded(args: { filePath: string; data?: string; binary?: boolean; encoding?: BufferEncoding }, append: boolean) {\n this.write(args.filePath, Buffer.from(args.data ?? '', args.binary ? 'base64' : args.encoding || 'utf8'), append);\n return {};\n }\n\n private existing(filePath: string): FsNode {\n const node = this.stat(filePath);\n if (!node) throw new Error(`no such file or directory ${filePath}`);\n return node;\n }\n\n private assertNotRoot(dirPath: string) {\n const target = this.normalize(dirPath);\n const prefix = target === '/' ? '/' : target + '/';\n if (this.roots.some(root => root === target || root.startsWith(prefix))) {\n throw new Error(`operation not permitted ${dirPath}`);\n }\n }\n}\n","/**\n * 把小程序项目构建成官方基础库能直接加载的形式\n *\n * 逻辑层(appservice):\n * 1. 裁剪版 $gwx(wcc -xc),基础库用它了解组件的节点结构\n * 2. 每个 JS 文件单独一个 define(\"x.js\", fn) 脚本(便于在 DevTools 里按原文件调试)\n * 3. bootstrap:注册 __wxAppCode__ 的 json/wxml(serviceTemplates,热更新时单独下发),\n * require(\"app.js\"),再依次 require 组件和页面\n *\n * 渲染层(page-frame):\n * 1. 完整版 $gwx(wcc -cc)与每个页面/组件的 __wxAppCode__ json / wxml(pageTemplates)\n * 2. wcsc 的公共样式运行时 + app.wxss,与每个页面/组件的 __wxAppCode__ wxss(pageStyles)。\n * 开启 less / sass 编译插件时,先把 .less / .scss / .sass 编译成 .wxss(见 StyleMirror)\n * 两部分在热更新时分别下发\n * 样式和模板里的 env(safe-area-inset-*) 改写成 CSS 变量,见 rewriteSafeAreaInsets\n *\n * Worker:workers 目录下的 JS 不进逻辑层,同样包装成 define 脚本,由 Worker 入口(server/html.ts 的 workerScript)加载\n */\n\nimport { compileWxml, compileWxss, ComponentTags } from '@open-wxa/wxa-runner-compiler';\nimport { transformSync } from 'esbuild';\nimport { AppJson, MiniProgram } from './MiniProgram';\nimport { StyleMirror } from './StyleMirror';\nimport { createWxConfig } from './wxConfig';\nimport { WxmlMirror } from './WxmlMirror';\n\nexport interface BuildResult {\n version: number;\n wxConfig: Record<string, any>;\n /** 所有 JS 模块 id(如 \"pages/index/index.js\"),逻辑层按此顺序加载 define 脚本 */\n modules: string[];\n /** workers 目录下的 JS 模块 id,Worker 按此顺序加载 define 脚本 */\n workerModules: string[];\n /** 逻辑层的 $gwx 与 __wxAppCode__ json/wxml,不含 require */\n serviceTemplates: string;\n serviceBootstrap: string;\n pageFrame: string;\n /** 渲染层的 $gwx 与 __wxAppCode__ json/wxml,不含样式(热更新时单独下发) */\n pageTemplates: string;\n /** 渲染层的样式:公共样式立即注入,页面和组件的样式注册到 __wxAppCode__(热更新时单独下发) */\n pageStyles: string;\n pages: string[];\n components: string[];\n durationMs: number;\n}\n\n/** define 包装函数的参数:屏蔽浏览器全局对象,与开发者工具一致 */\nconst MODULE_PARAMS = [\n 'require', 'module', 'exports', 'window', 'document', 'frames', 'self', 'location', 'navigator',\n 'localStorage', 'history', 'Caches', 'screen', 'alert', 'confirm', 'prompt', 'XMLHttpRequest',\n 'WebSocket', 'Reporter', 'webkit', 'WeixinJSCore'\n].join(', ');\n\n/**\n * import / export 语句:在行首,或者在压缩成一行的代码里紧跟着 ; 或 }。\n * 不匹配 import() 动态导入,也不匹配 importance 这类变量名\n */\nconst ESM_SYNTAX = /(?:^|[;}])\\s*(?:import\\s*[{*'\"]|import\\s+[\\w$]|export\\s*[{*]|export\\s+(?:default|const|let|var|function|class|async)\\b)/m;\n\ntype ChangeKind = 'config' | 'wxml' | 'wxss' | 'js';\n\nexport interface AppBuilderOptions {\n /** wxml 交给 wcc 前的转换,见 DevServerOptions.wxmlTransform */\n wxmlTransform?: (code: string, file: string) => string;\n}\n\nexport class AppBuilder {\n private version = 0;\n /** invalidate 标记过的变化次数;每次构建记下开始时覆盖到第几次 */\n private changes = 0;\n private pending: { covers: number; result: Promise<BuildResult> } | null = null;\n private last: BuildResult | null = null;\n private dirty = new Set<ChangeKind>(['config', 'wxml', 'wxss', 'js']);\n private wxmlCache: { full: string; cut: string } | null = null;\n private wxssCache: { comm: string; pages: Record<string, string> } | null = null;\n\n /** 设置了 wxmlTransform 时才有 */\n private readonly wxmlMirror: WxmlMirror | null;\n /** 开启了 less / sass 编译插件时才有;插件设置变了就换一个 */\n private styleMirror: { setting: string; mirror: StyleMirror } | null = null;\n\n constructor(readonly project: MiniProgram, options: AppBuilderOptions = {}) {\n this.wxmlMirror = options.wxmlTransform ? new WxmlMirror(options.wxmlTransform) : null;\n }\n\n /** wxmlTransform 的镜像目录;没有设置转换或还没编译过时为 null */\n get wxmlMirrorDir(): string | null {\n return this.wxmlMirror?.directory ?? null;\n }\n\n /** 删除 wxmlTransform 和样式预处理的镜像目录,开发服务器关闭时调用 */\n dispose(): void {\n this.wxmlMirror?.dispose();\n this.styleMirror?.mirror.dispose();\n }\n\n /** 根据变化的文件标记需要重新构建的部分;返回 true 表示需要刷新 */\n invalidate(changedFiles: string[] = []): boolean {\n if (changedFiles.length === 0) {\n ['config', 'wxml', 'wxss', 'js'].forEach(kind => this.dirty.add(kind as ChangeKind));\n this.changes++;\n return true;\n }\n\n let relevant = false;\n for (const file of changedFiles) {\n const kind = classifyFile(file);\n if (!kind) continue;\n relevant = true;\n this.dirty.add(kind);\n // json 决定组件关系,wxml/wxss 的编译参数都依赖它\n if (kind === 'config') {\n this.dirty.add('wxml');\n this.dirty.add('wxss');\n }\n }\n if (relevant) this.changes++;\n return relevant;\n }\n\n /**\n * 返回包含调用前所有变化的构建结果。并发调用共享同一次构建;\n * 进行中的构建开始得比最近一次变化早时(可能已读到旧文件),等它结束后再构建一次\n */\n async build(): Promise<BuildResult> {\n const wanted = this.changes;\n for (;;) {\n if (!this.pending && this.dirty.size === 0 && this.last) return this.last;\n if (!this.pending) {\n const result = this.doBuild().finally(() => {\n this.pending = null;\n });\n this.pending = { covers: this.changes, result };\n }\n const { covers, result } = this.pending;\n const built = await result;\n if (covers >= wanted) return built;\n }\n }\n\n /**\n * 单个 JS 模块的 define 包装\n *\n * 包装头和代码第一行写在同一行,行号与源文件一致。使用 import/export 的文件\n * 先转换为 CommonJS(对应开发者工具的「ES6 转 ES5」),并内联 source map。\n */\n getModuleScript(id: string): string {\n let code = this.project.readText(id);\n if (ESM_SYNTAX.test(code)) {\n try {\n code = transformSync(code, {\n format: 'cjs',\n loader: 'js',\n target: 'es2020',\n sourcefile: id,\n sourcemap: 'inline'\n }).code;\n } catch (error) {\n const message = `[wxa-runner] ${id} 转换失败:${(error as Error).message}`;\n return `console.error(${JSON.stringify(message)});\\n`;\n }\n }\n return `define(${JSON.stringify(id)}, function(${MODULE_PARAMS}){${code}\\n});\\n`;\n }\n\n private async doBuild(): Promise<BuildResult> {\n const start = Date.now();\n const dirty = new Set(this.dirty);\n this.dirty.clear();\n\n try {\n const app = this.project.readAppJson();\n const { pages, components } = this.project.collectUnits(app);\n const units = [...components, ...pages];\n const unitJson = new Map(units.map(id => [id, this.project.readUnitJson(id, app)]));\n\n const [wxml, wxss] = await Promise.all([\n dirty.has('wxml') || !this.wxmlCache ? this.compileTemplates(units, unitJson) : this.wxmlCache,\n dirty.has('wxss') || !this.wxssCache ? this.compileStyles(units) : this.wxssCache\n ]);\n this.wxmlCache = wxml;\n this.wxssCache = wxss;\n\n const workersDir = this.project.workersDir(app);\n const inWorkers = (file: string) => workersDir !== null && file.startsWith(workersDir + '/');\n const scripts = this.project.listFiles(['.js']);\n const modules = scripts.filter(file => !inWorkers(file));\n\n const serviceTemplates = this.createTemplates(app, units, unitJson, wxml.cut);\n const pageTemplates = this.createTemplates(app, units, unitJson, wxml.full);\n const pageStyles = createStyles(units, wxss);\n const result: BuildResult = {\n version: ++this.version,\n wxConfig: createWxConfig({\n app,\n pages,\n unitJson,\n appid: this.project.appid,\n subPackages: this.project.subPackages(app)\n }),\n modules,\n workerModules: scripts.filter(inWorkers),\n serviceTemplates,\n serviceBootstrap: this.createServiceBootstrap(serviceTemplates, units, modules),\n pageFrame: `${pageTemplates}\\n${pageStyles}`,\n pageTemplates,\n pageStyles,\n pages,\n components,\n durationMs: Date.now() - start\n };\n this.last = result;\n return result;\n } catch (error) {\n // 构建失败时保留脏标记,下次请求重新尝试\n dirty.forEach(kind => this.dirty.add(kind));\n throw error;\n }\n }\n\n private async compileTemplates(units: string[], unitJson: Map<string, any>) {\n const files = this.project.listFiles(['.wxml', '.wxs']).map(f => './' + f);\n const components: ComponentTags[] = units\n .filter(id => this.project.exists(id + '.wxml'))\n .map(id => {\n const json = unitJson.get(id);\n return { path: id, tags: Object.keys({ ...json.usingComponents, ...json.componentGenerics }) };\n });\n\n const cwd = this.wxmlMirror ? this.wxmlMirror.sync(this.project, files.map(file => file.slice(2))) : this.project.root;\n const [full, cut] = await Promise.all([\n compileWxml({ cwd, files, components, cut: false }),\n compileWxml({ cwd, files, components, cut: true })\n ]);\n // 只有渲染层的完整版带内联 style\n return { full: rewriteSafeAreaInsets(full), cut };\n }\n\n /** 与开发者工具一致,项目里的 wxss 全部交给 wcsc:被 @import 的文件(如 uni-app 的 common/main.wxss)也要在列表里 */\n private async compileStyles(units: string[]) {\n const mirror = this.currentStyleMirror();\n const { cwd, files } = mirror ? await mirror.sync(this.project) : { cwd: this.project.root, files: this.project.listFiles(['.wxss']) };\n const styles = new Set(files);\n const pageFiles = units.filter(id => styles.has(id + '.wxss')).map(id => `./${id}.wxss`);\n const commonFiles = files.map(file => `./${file}`).filter(file => !pageFiles.includes(file));\n const { comm, pages } = await compileWxss({ cwd, pageFiles, commonFiles });\n return {\n comm: rewriteSafeAreaInsets(comm),\n pages: Object.fromEntries(Object.entries(pages).map(([file, css]) => [file, rewriteSafeAreaInsets(css)]))\n };\n }\n\n private currentStyleMirror(): StyleMirror | null {\n const setting = this.project.styleSetting;\n const key = JSON.stringify(setting);\n if (this.styleMirror?.setting !== key) {\n this.styleMirror?.mirror.dispose();\n this.styleMirror = setting.plugins.length > 0 ? { setting: key, mirror: new StyleMirror(setting) } : null;\n }\n return this.styleMirror?.mirror ?? null;\n }\n\n /** $gwx 加上各页面、组件的 json / wxml 注册;逻辑层用裁剪版 $gwx,渲染层用完整版 */\n private createTemplates(app: AppJson, units: string[], unitJson: Map<string, any>, gwx: string): string {\n const lines: string[] = [gwx, `__wxAppCode__[\"app.json\"] = ${toJs(app)};`];\n\n for (const id of units) {\n lines.push(`__wxAppCode__[${toJs(id + '.json')}] = ${toJs(unitJson.get(id))};`);\n if (this.project.exists(id + '.wxml')) {\n lines.push(`__wxAppCode__[${toJs(id + '.wxml')}] = $gwx(${toJs('./' + id + '.wxml')});`);\n }\n }\n return lines.join('\\n');\n }\n\n private createServiceBootstrap(serviceTemplates: string, units: string[], modules: string[]): string {\n const lines: string[] = [serviceTemplates];\n\n if (modules.includes('app.js')) {\n lines.push(requireStatement('app.js', null));\n }\n for (const id of units) {\n if (modules.includes(id + '.js')) lines.push(requireStatement(id + '.js', id));\n }\n return lines.join('\\n');\n }\n}\n\nfunction createStyles(units: string[], wxss: { comm: string; pages: Record<string, string> }): string {\n const lines = [wxss.comm];\n for (const id of units) {\n const css = wxss.pages[id + '.wxss'];\n if (css) lines.push(`__wxAppCode__[${toJs(id + '.wxss')}] = ${css};`);\n }\n return lines.join('\\n');\n}\n\n/** 某个模块执行出错时只影响它自己,其余页面照常注册 */\nfunction requireStatement(file: string, route: string | null): string {\n const routeSetup = route\n ? `__wxRoute = ${toJs(route)}; __wxRouteBegin = true; __wxAppCurrentFile__ = ${toJs(file)};`\n : `__wxAppCurrentFile__ = ${toJs(file)};`;\n return `${routeSetup}\\ntry { require(${toJs(file)}); } catch (error) { console.error(${toJs('[wxa-runner] ' + file + ' 执行出错\\n')}, error); }`;\n}\n\n/**\n * env(safe-area-inset-*) / constant(safe-area-inset-*) → var(--wxa-safe-area-inset-*)\n *\n * 桌面浏览器里这些 env() 恒为 0,而真机上的值取决于页面窗口是否贴着屏幕边缘(tabBar 页面底部为 0),\n * 所以改成变量,由宿主按页面写入(PageView.setSafeAreaInsets)。只替换函数名和参数名,\n * fallback 原样保留——wcsc 会把其中的 rpx 拆成数组片段,不能整体解析。\n */\nexport function rewriteSafeAreaInsets(code: string): string {\n return code.replace(/\\b(?:env|constant)\\(\\s*safe-area-inset-(top|right|bottom|left)\\b/g, 'var(--wxa-safe-area-inset-$1');\n}\n\n/** JSON 序列化并转义 </script> 与行分隔符,结果可安全嵌入脚本 */\nexport function toJs(value: unknown): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n\nfunction classifyFile(file: string): ChangeKind | null {\n if (file.endsWith('.json')) return 'config';\n if (file.endsWith('.wxml') || file.endsWith('.wxs')) return 'wxml';\n // less / sass 可以引用 .css\n if (/\\.(wxss|less|scss|sass|css)$/.test(file)) return 'wxss';\n if (file.endsWith('.js')) return 'js';\n return null;\n}\n","/**\n * 样式预处理:project.config.json 的 setting.useCompilerPlugins 开启 less / sass 时,\n * 按开发者工具(summer 编译器的 summer-less、summer-sass 插件)的规则把 .less / .scss / .sass 编译成同名的 .wxss\n *\n * - 同一路径有多种源文件时,预处理文件覆盖 .wxss;less 和 sass 都开启时,在 useCompilerPlugins 里排在后面的优先,.scss 优先于 .sass\n * - 除公共文件本身外,每个 .less 先引用小程序根目录的 app.less(lessSetting.commonUseFilePath),\n * 每个 .scss / .sass 先 @use global.scss 或 global.sass(sassSetting);公共文件不存在时跳过\n * - @import \"x.wxss\"; 原样保留,由 wcsc 处理\n * - 编译器优先用项目里安装的 less / sass,没装时用 wxa-runner 自带的(开发者工具也自带编译器)\n *\n * wcsc 只接收文件路径、自己从磁盘读文件:和 WxmlMirror 一样,把编译结果和原有的 .wxss 写进临时目录,让 wcsc 在这里编译。\n */\n\nimport fs from 'fs';\nimport { createRequire } from 'module';\nimport os from 'os';\nimport path from 'path';\nimport { pathToFileURL } from 'url';\nimport type { MiniProgram } from './MiniProgram';\n\nexport type StylePluginName = 'less' | 'sass';\n\nexport interface StyleSetting {\n /** 开启的样式插件,按 useCompilerPlugins 里的顺序 */\n plugins: StylePluginName[];\n /** [\"less\", { globalVars }] 写法给出的 less 全局变量 */\n lessGlobalVars: Record<string, string>;\n /** 相对小程序根目录 */\n lessCommonFile: string;\n sassCommonFile: string;\n scssCommonFile: string;\n}\n\nconst PLUGIN_EXTENSIONS: Record<StylePluginName, string[]> = {\n less: ['.less'],\n sass: ['.sass', '.scss']\n};\n\n/** 与开发者工具相同的写法识别:带引号、以分号结尾的 @import \"x.wxss\"; */\nconst IMPORT_WXSS = /(?:^|\\s)?(?:@import)(?:\\s*)?([\"'])([^\"']+.wxss)\\1(?:\\s*);/g;\n\n/**\n * 读取 project.config.json 的 setting。useCompilerPlugins 的每一项是插件名,或 [插件名, 选项];\n * typescript 等非样式插件在这里忽略\n */\nexport function readStyleSetting(setting: any): StyleSetting {\n const plugins: StylePluginName[] = [];\n let lessGlobalVars: Record<string, string> = {};\n for (const item of Array.isArray(setting?.useCompilerPlugins) ? setting.useCompilerPlugins : []) {\n const [name, options] = Array.isArray(item) ? item : [item, undefined];\n if ((name !== 'less' && name !== 'sass') || plugins.includes(name)) continue;\n plugins.push(name);\n if (name === 'less' && options?.globalVars) lessGlobalVars = options.globalVars;\n }\n return {\n plugins,\n lessGlobalVars,\n lessCommonFile: setting?.lessSetting?.commonUseFilePath || 'app.less',\n sassCommonFile: setting?.sassSetting?.sassCommonUseFilePath || 'global.sass',\n scssCommonFile: setting?.sassSetting?.scssCommonUseFilePath || 'global.scss'\n };\n}\n\n/** 项目里有、但对应插件没有开启的预处理文件:开发者工具同样不编译它们,样式不会生效 */\nexport function ignoredStyleSources(project: MiniProgram, setting: StyleSetting): Array<{ plugin: StylePluginName; files: string[] }> {\n return (Object.keys(PLUGIN_EXTENSIONS) as StylePluginName[])\n .filter(plugin => !setting.plugins.includes(plugin))\n .map(plugin => ({ plugin, files: project.listFiles(PLUGIN_EXTENSIONS[plugin]) }))\n .filter(({ files }) => files.length > 0);\n}\n\nexport class StyleMirror {\n private dir: string | null = null;\n /** 已写入的 .wxss 与写入的内容 */\n private readonly files = new Map<string, string>();\n private readonly compilers = new Map<StylePluginName, Promise<any>>();\n\n constructor(private readonly setting: StyleSetting) {}\n\n /** 镜像目录;还没同步过时为 null */\n get directory(): string | null {\n return this.dir;\n }\n\n /**\n * 编译全部预处理文件,与原有的 .wxss 一起写进镜像目录。\n * @returns 镜像目录,以及其中全部 .wxss 的相对路径\n */\n async sync(project: MiniProgram): Promise<{ cwd: string; files: string[] }> {\n const sources = this.pickSources(project);\n const outputs = await Promise.all(\n [...sources].map(async ([target, source]) => [target, await this.compile(project, source)] as const)\n );\n\n const dir = (this.dir ??= fs.mkdtempSync(path.join(os.tmpdir(), 'wxa-runner-wxss-')));\n for (const rel of [...this.files.keys()]) {\n if (sources.has(rel)) continue;\n fs.rmSync(path.join(dir, rel), { force: true });\n this.files.delete(rel);\n }\n for (const [rel, css] of outputs) {\n if (this.files.get(rel) === css) continue;\n const target = path.join(dir, rel);\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, css);\n this.files.set(rel, css);\n }\n return { cwd: dir, files: [...sources.keys()] };\n }\n\n dispose(): void {\n if (this.dir) fs.rmSync(this.dir, { recursive: true, force: true });\n this.dir = null;\n this.files.clear();\n }\n\n /** 每个 .wxss 由哪个源文件生成:键为 .wxss 的相对路径 */\n private pickSources(project: MiniProgram): Map<string, string> {\n const extensions = ['.wxss', ...this.setting.plugins.flatMap(plugin => PLUGIN_EXTENSIONS[plugin])];\n const sources = new Map<string, string>();\n for (const file of project.listFiles(extensions)) {\n // _ 开头的 sass 文件也编译:可能是页面自己的样式,开发者工具同样不跳过\n const ext = path.extname(file);\n const target = file.slice(0, -ext.length) + '.wxss';\n const current = sources.get(target);\n if (!current || extensions.indexOf(ext) > extensions.indexOf(path.extname(current))) sources.set(target, file);\n }\n return sources;\n }\n\n private async compile(project: MiniProgram, file: string): Promise<string> {\n const ext = path.extname(file);\n if (ext === '.wxss') return project.readText(file);\n const compiler = await this.loadCompiler(ext === '.less' ? 'less' : 'sass', project);\n try {\n return ext === '.less' ? await this.compileLess(compiler, project, file) : this.compileSass(compiler, project, file);\n } catch (error) {\n throw new Error(`${file} 编译失败:${describeError(project, error)}`);\n }\n }\n\n private async compileLess(less: any, project: MiniProgram, file: string): Promise<string> {\n const common = this.setting.lessCommonFile;\n // 全局变量和公共文件写在源文件的第一行,编译错误的行号与源文件一致。\n // 不用 less 的 globalVars 选项:它在前面另加一行,报错的行号会多 1\n const prefix = Object.entries(this.setting.lessGlobalVars).map(([name, value]) => `@${name.replace(/^@/, '')}: ${value};`);\n if (file !== common && project.exists(common)) prefix.push(`@import (optional, reference) '${toRoot(file)}/${common}';`);\n let code = prefix.map(statement => statement + ' ').join('') + project.readText(file);\n // 加上 ?css,less 就当作 CSS 引用原样输出\n code = code.replace(IMPORT_WXSS, (statement, _quote, target) => statement.replace(target, `${target}?css`));\n\n const { css } = await less.render(code, {\n filename: path.join(project.root, file),\n paths: [project.root]\n });\n return css.replace(/(@import\\s*[\"'][^\"']+\\.wxss)\\?css([\"'])/g, '$1$2');\n }\n\n private compileSass(sass: any, project: MiniProgram, file: string): string {\n const indented = file.endsWith('.sass');\n const preferred = indented ? this.setting.sassCommonFile : this.setting.scssCommonFile;\n const fallback = indented ? this.setting.scssCommonFile : this.setting.sassCommonFile;\n const common = project.exists(preferred) ? preferred : project.exists(fallback) ? fallback : null;\n let code = project.readText(file);\n if (common && file !== preferred && file !== fallback) {\n // 缩进语法的 @use 要单独一行;scss 写在同一行,行号与源文件一致\n code = `@use '${toRoot(file)}/${common}'${indented ? '\\n' : '; '}${code}`;\n }\n // 引用路径以 .css 结尾时 sass 原样输出,编译后再改回 .wxss\n const imported = new Set<string>();\n code = code.replace(IMPORT_WXSS, (statement, _quote, target: string) => {\n imported.add(target);\n return statement.replace(target, `${target.slice(0, -'.wxss'.length)}.css`);\n });\n\n // 项目里装的旧版 sass(1.45 以前)只有 renderSync,开发者工具用的也是这套旧接口\n const css: string = typeof sass.compileString === 'function'\n ? sass.compileString(code, { url: pathToFileURL(path.join(project.root, file)), syntax: indented ? 'indented' : 'scss', loadPaths: [project.root] }).css\n : sass.renderSync({ data: code, file: path.join(project.root, file), indentedSyntax: indented, includePaths: [project.root] }).css.toString();\n return css.replace(/(@import\\s*[\"'])([^\"']+)\\.css([\"'])/g, (statement: string, head: string, target: string, tail: string) =>\n imported.has(`${target}.wxss`) ? `${head}${target}.wxss${tail}` : statement\n );\n }\n\n /** 用到时才加载:先从小程序根目录和项目目录向上查找 node_modules,找不到时用 wxa-runner 自带的 */\n private loadCompiler(name: StylePluginName, project: MiniProgram): Promise<any> {\n let loading = this.compilers.get(name);\n if (!loading) {\n loading = importCompiler(name, project);\n this.compilers.set(name, loading);\n }\n return loading;\n }\n}\n\nasync function importCompiler(name: StylePluginName, project: MiniProgram): Promise<any> {\n let resolved: string | null = null;\n try {\n resolved = createRequire(path.join(project.root, 'package.json')).resolve(name, { paths: [project.root, project.projectPath] });\n } catch {\n // 项目里没装\n }\n // 包名写成字面量,打包工具才知道它们是外部依赖\n const module = resolved ? await import(pathToFileURL(resolved).href) : name === 'less' ? await import('less') : await import('sass');\n // CommonJS 包(如 less)的接口在 default 上;sass 不要读 default,会打印弃用提示\n const entry = name === 'less' ? 'render' : 'renderSync';\n return typeof module[entry] === 'function' ? module : module.default;\n}\n\n/** 从文件所在目录回到小程序根目录的相对路径,如 pages/a/a.less → ../.. */\nfunction toRoot(file: string): string {\n const dir = path.posix.dirname(file);\n return dir === '.' ? '.' : dir.split('/').map(() => '..').join('/');\n}\n\n/** less 的错误带出错的文件和行列;sass 的错误信息里已经有出错位置 */\nfunction describeError(project: MiniProgram, error: any): string {\n if (typeof error?.line === 'number' && error.filename) {\n const file = path.relative(project.root, error.filename).split(path.sep).join('/');\n return `${file}:${error.line}:${(error.column ?? 0) + 1} ${error.message}`;\n }\n return error?.message ?? String(error);\n}\n","/**\n * 生成基础库读取的 __wxConfig,字段与开发者工具保持一致\n */\n\nimport { AppJson, UnitJson } from './MiniProgram';\n\nexport const DEFAULT_WINDOW = {\n navigationBarBackgroundColor: '#000000',\n navigationBarTextStyle: 'white',\n navigationBarTitleText: '',\n backgroundColor: '#ffffff',\n backgroundTextStyle: 'dark',\n enablePullDownRefresh: false,\n onReachBottomDistance: 50\n};\n\nexport interface WxConfigInput {\n app: AppJson;\n pages: string[];\n unitJson: Map<string, UnitJson>;\n appid: string;\n subPackages: NonNullable<AppJson['subPackages']>;\n}\n\nexport function createWxConfig(input: WxConfigInput): Record<string, any> {\n const { app, pages, unitJson, appid } = input;\n const entryPage = app.entryPagePath || app.pages[0];\n\n const page: Record<string, any> = {};\n for (const id of pages) {\n const { singlePage, ...window } = unitJson.get(id) || { usingComponents: {} };\n page[id + '.html'] = { window, singlePage, renderer: window.renderer };\n }\n\n const tabBar = app.tabBar\n ? { ...app.tabBar, list: app.tabBar.list.map(item => ({ ...item, pagePath: item.pagePath + '.html' })) }\n : undefined;\n\n return {\n ...app,\n pages: app.pages,\n resizable: !!app.resizable,\n subPackages: input.subPackages.length ? input.subPackages : undefined,\n debug: !!app.debug,\n widgets: app.widgets || [],\n customClose: !!app.customClose,\n workers: app.workers || '',\n cloud: !!app.cloud,\n global: { window: { ...DEFAULT_WINDOW, ...app.window } },\n page,\n networkTimeout: { request: 60000, uploadFile: 60000, connectSocket: 60000, downloadFile: 60000, ...app.networkTimeout },\n ext: app.ext || {},\n extAppid: app.extAppid || '',\n plugins: app.plugins || {},\n mainPlugins: { ...app.plugins },\n useExtendedLib: app.useExtendedLib || {},\n requiredPrivateInfos: app.requiredPrivateInfos || [],\n __warning__: '',\n entryPagePath: entryPage + '.html',\n tabBar,\n isLazyLoad: false,\n lazyCodeLoading: undefined,\n // 以下字段由开发者工具在运行时注入\n appname: appid,\n accountInfo: { appId: appid, icon: '', nickname: appid },\n appLaunchInfo: { scene: 1001, path: entryPage, query: {} },\n envVersion: 'develop',\n platform: 'devtools',\n env: { USER_DATA_PATH: 'http://usr' },\n isPluginMiniProgram: false,\n wxAppInfo: { maxRequestConcurrent: 10, maxUploadConcurrent: 10, maxDownloadConcurrent: 10, maxWebsocketConnect: 5 },\n deviceinfo: {}\n };\n}\n","/**\n * wxmlTransform 的镜像目录\n *\n * wcc 只接收文件路径、自己从磁盘读文件,转换不能只在内存里做:把转换后的 .wxml 和原样的 .wxs\n * 写进临时目录,编译时把 wcc 的工作目录指向这里。相对路径和行号与源文件一致,编译错误照常指向源文件。\n */\n\nimport fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { MiniProgram } from './MiniProgram';\n\nexport class WxmlMirror {\n private dir: string | null = null;\n /** 已写入的文件:源内容(判断要不要重新转换)与写入的内容 */\n private readonly files = new Map<string, string>();\n\n constructor(private readonly transform: (code: string, file: string) => string) {}\n\n /** 镜像目录;还没同步过时为 null */\n get directory(): string | null {\n return this.dir;\n }\n\n /**\n * 让镜像目录与项目里的 wxml / wxs 一致,返回镜像目录。\n * 只重写源内容变化的文件;项目里已删除的文件同时从镜像目录删除,被引用时 wcc 照常报错\n */\n sync(project: MiniProgram, relPaths: string[]): string {\n const dir = (this.dir ??= fs.mkdtempSync(path.join(os.tmpdir(), 'wxa-runner-wxml-')));\n const current = new Set(relPaths);\n for (const rel of [...this.files.keys()]) {\n if (current.has(rel)) continue;\n fs.rmSync(path.join(dir, rel), { force: true });\n this.files.delete(rel);\n }\n for (const rel of relPaths) {\n const source = project.readText(rel);\n if (this.files.get(rel) === source) continue;\n const target = path.join(dir, rel);\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, rel.endsWith('.wxml') ? this.transform(source, rel) : source);\n this.files.set(rel, source);\n }\n return dir;\n }\n\n dispose(): void {\n if (this.dir) fs.rmSync(this.dir, { recursive: true, force: true });\n this.dir = null;\n this.files.clear();\n }\n}\n","/**\n * 小程序项目结构解析\n *\n * 负责读取 app.json / 页面与组件 json,并按开发者工具的规则做预处理:\n * - app.json 的全局 usingComponents 展开到每个页面和组件(miniprogram_npm 内除外)\n * - 每个页面/组件 json 都保证有 usingComponents 字段\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { readStyleSetting, StyleSetting } from './StyleMirror';\n\nexport interface AppJson {\n pages: string[];\n entryPagePath?: string;\n window?: Record<string, any>;\n tabBar?: {\n custom?: boolean;\n list: Array<{ pagePath: string; text?: string; iconPath?: string; selectedIconPath?: string }>;\n [key: string]: any;\n };\n subPackages?: Array<{ root: string; pages: string[]; independent?: boolean; [key: string]: any }>;\n subpackages?: AppJson['subPackages'];\n usingComponents?: Record<string, string>;\n /** isSubpackage:Worker 代码作为分包,业务先调 wx.preDownloadSubpackage({ packageType: 'workers' }) 再创建 Worker */\n workers?: string | { path: string; isSubpackage?: boolean };\n [key: string]: any;\n}\n\nexport interface UnitJson {\n usingComponents: Record<string, string>;\n componentGenerics?: Record<string, boolean | { default?: string }>;\n component?: boolean;\n [key: string]: any;\n}\n\nconst IGNORED_DIRS = new Set(['node_modules', '.git', '.idea', '.vscode']);\n// wxa.setup.js 是 wxa-runner 的启动前脚本,不属于小程序\nconst PROJECT_FILES = new Set(['project.config.json', 'project.private.config.json', 'sitemap.json', 'app.json', 'wxa.setup.js']);\n\nexport class MiniProgram {\n /** 小程序代码根目录(已考虑 project.config.json 的 miniprogramRoot) */\n readonly root: string;\n readonly appid: string;\n\n constructor(readonly projectPath: string) {\n const projectConfig = readJsonFile(path.join(projectPath, 'project.config.json')) || {};\n this.root = path.resolve(projectPath, projectConfig.miniprogramRoot || '');\n this.appid = projectConfig.appid || 'touristappid';\n\n if (!fs.existsSync(path.join(this.root, 'app.json'))) {\n throw new Error(`${this.root} 下没有 app.json,不是有效的小程序目录`);\n }\n }\n\n /** project.config.json 里与 less / sass 编译插件有关的设置;每次重新读取,开发中修改了也能生效 */\n get styleSetting(): StyleSetting {\n return readStyleSetting(readJsonFile(path.join(this.projectPath, 'project.config.json'))?.setting);\n }\n\n readAppJson(): AppJson {\n const app = readJsonFile(path.join(this.root, 'app.json'));\n if (!app || !Array.isArray(app.pages) || app.pages.length === 0) {\n throw new Error('app.json 缺少 pages 配置');\n }\n return app;\n }\n\n subPackages(app: AppJson) {\n return app.subPackages || app.subpackages || [];\n }\n\n /** Worker 代码所在目录,不带首尾的 /;没有配置 workers 时为 null */\n workersDir(app: AppJson): string | null {\n const dir = typeof app.workers === 'string' ? app.workers : app.workers?.path;\n return dir ? path.posix.normalize(dir).replace(/^\\/+|\\/+$/g, '') : null;\n }\n\n /** 主包页面 + 分包页面(带 root 前缀) */\n allPages(app: AppJson): string[] {\n const pages = [...app.pages];\n for (const pkg of this.subPackages(app)) {\n for (const page of pkg.pages) {\n const full = path.posix.join(pkg.root, page);\n if (!pages.includes(full)) pages.push(full);\n }\n }\n return pages;\n }\n\n /**\n * 读取并预处理页面/组件 json,id 不带扩展名。\n * 基础库运行时只把组件引用和当前路径拼在一起,不查找 miniprogram_npm、不补 /index(开发者工具编译时已解析好),\n * 所以能解析到的引用都换成组件的绝对路径\n */\n readUnitJson(id: string, app: AppJson): UnitJson {\n const json: UnitJson = { ...readJsonFile(path.join(this.root, id + '.json')) };\n const resolve = (fromId: string, ref: string) => {\n const resolved = this.resolveComponent(fromId, ref);\n return resolved ? '/' + resolved : null;\n };\n\n json.usingComponents = Object.fromEntries(\n Object.entries(json.usingComponents || {}).map(([tag, ref]) => [tag, resolve(id, ref as string) ?? ref])\n );\n if (json.componentGenerics) {\n json.componentGenerics = Object.fromEntries(Object.entries(json.componentGenerics).map(([name, generic]) => [\n name,\n typeof generic === 'object' && generic.default ? { ...generic, default: resolve(id, generic.default) ?? generic.default } : generic\n ]));\n }\n\n if (!/(^|\\/)miniprogram_npm\\//.test(id) && !this.isInIndependentSubPackage(id, app)) {\n for (const [tag, ref] of Object.entries(app.usingComponents || {})) {\n if (json.usingComponents[tag]) continue;\n // 全局引用相对 app.json 解析;解析不到的相对路径照旧换算成相对当前页面\n const resolved = resolve('app', ref);\n if (resolved || ref.startsWith('/') || /^plugin(-private)?:\\/\\//.test(ref)) {\n json.usingComponents[tag] = resolved ?? ref;\n } else {\n const relative = path.posix.relative(path.posix.dirname(id), ref);\n json.usingComponents[tag] = relative.startsWith('.') ? relative : './' + relative;\n }\n }\n }\n return json;\n }\n\n /**\n * 解析组件引用到组件路径(不带扩展名);插件组件或找不到时返回 null。\n * 规则:/ 开头为根目录绝对路径;否则先按相对路径找,再沿目录向上查找 miniprogram_npm。\n */\n resolveComponent(fromId: string, ref: string): string | null {\n if (!ref || ref.startsWith('plugin://') || ref.startsWith('plugin-private://')) return null;\n\n const fromDir = path.posix.dirname(fromId);\n const candidates: string[] = [];\n\n if (ref.startsWith('/')) {\n candidates.push(ref.slice(1));\n } else {\n candidates.push(path.posix.join(fromDir, ref));\n if (!ref.startsWith('.')) {\n let dir = fromDir;\n for (;;) {\n candidates.push(path.posix.join(dir === '.' ? '' : dir, 'miniprogram_npm', ref));\n if (dir === '.' || dir === '') break;\n dir = path.posix.dirname(dir);\n }\n }\n }\n\n for (const candidate of candidates) {\n const normalized = path.posix.normalize(candidate);\n for (const id of [normalized, path.posix.join(normalized, 'index')]) {\n if (fs.existsSync(path.join(this.root, id + '.json'))) return id;\n }\n }\n return null;\n }\n\n /** 收集页面、隐式自定义 tabBar 及它们(递归)引用到的组件 */\n collectUnits(app: AppJson): { pages: string[]; components: string[] } {\n const pages = this.allPages(app);\n const components: string[] = [];\n const visited = new Set<string>(pages);\n\n const visit = (id: string) => {\n const json = this.readUnitJson(id, app);\n const refs = Object.values(json.usingComponents);\n for (const generic of Object.values(json.componentGenerics || {})) {\n if (typeof generic === 'object' && generic.default) refs.push(generic.default);\n }\n for (const ref of refs) enter(this.resolveComponent(id, ref));\n };\n const enter = (id: string | null) => {\n if (!id || visited.has(id)) return;\n visited.add(id);\n components.push(id);\n visit(id);\n };\n\n // 自定义 tabBar 不在 usingComponents 中声明,但基础库会按固定路径创建它。\n if (app.tabBar?.custom) enter(this.resolveComponent('app', '/custom-tab-bar/index'));\n pages.forEach(visit);\n return { pages, components };\n }\n\n /** 列出代码根目录下指定扩展名的文件,返回 posix 风格的相对路径 */\n listFiles(extensions: string[]): string[] {\n const result: string[] = [];\n\n const walk = (dir: string, rel: string) => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.') || IGNORED_DIRS.has(entry.name)) continue;\n const childRel = rel ? `${rel}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(path.join(dir, entry.name), childRel);\n } else if (extensions.some(ext => entry.name.endsWith(ext))) {\n if (!rel && PROJECT_FILES.has(entry.name)) continue;\n result.push(childRel);\n }\n }\n };\n\n walk(this.root, '');\n return result.sort();\n }\n\n exists(relPath: string): boolean {\n return fs.existsSync(path.join(this.root, relPath));\n }\n\n readText(relPath: string): string {\n return fs.readFileSync(path.join(this.root, relPath), 'utf8');\n }\n\n private isInIndependentSubPackage(id: string, app: AppJson): boolean {\n return this.subPackages(app).some(pkg => pkg.independent && id.startsWith(pkg.root.replace(/\\/?$/, '/')));\n }\n}\n\nfunction readJsonFile(file: string): any {\n if (!fs.existsSync(file)) return null;\n const text = fs.readFileSync(file, 'utf8');\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new Error(`${file} 不是合法的 JSON:${(error as Error).message}`);\n }\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 * 小程序插件的代码\n *\n * 插件代码不在项目里,同开发者工具:开发服务器带着开发者 ticket 向微信下载(wxa-dev/getplugincode),\n * 只放在内存里,同一个插件版本下载一次。下载要用开发者的登录态,所以只在开启 --devtools-login 时进行;\n * 小程序的 appid 要已在管理后台添加了这个插件,并经插件开发者通过。\n *\n * 下载到的是 .wxvpkg 格式的包,里面是编译好的产物:\n * /plugin.json 插件页面表(pages)和每个页面的 window 配置(page)\n * /appservice.js 逻辑层:definePlugin(...) 注册插件,自己 requirePlugin 完成初始化\n * /pageframe.js 渲染层:插件的模板函数 $gwx_<插件 appid> 和样式\n * /pages/x/x.html 插件页面:注入样式、取模板、派发 generateFuncReady\n * /static/... 图片等资源\n * 插件页面的路径是 __plugin__/<插件 appid>/pages/x/x,基础库把 plugin://别名/页面名 解析成它再交给原生路由。\n */\n\nimport { readWxvpkgFile, readWxvpkgIndex } from '@open-wxa/wxa-runner-extractor';\nimport type { BuildResult } from '../project/AppBuilder';\nimport { requireOk, WechatDevClient } from './wechatDev';\n\nconst DOWNLOAD_TIMEOUT = 30_000;\nconst PACKAGE_MAGIC = 0xbe;\n\nexport interface PluginCode {\n /** app.json 里的引用名,plugin://<alias>/页面名 */\n alias: string;\n /** 插件 appid */\n provider: string;\n version: string;\n /** 包内路径(/ 开头)→ 内容 */\n files: Map<string, Buffer>;\n /** 插件页面的路径,如 __plugin__/wx…/pages/index/index */\n pages: string[];\n /** 插件页面的配置,键同 __wxConfig.page(路径加 .html) */\n pageConfigs: Record<string, unknown>;\n}\n\n/** 构建结果加上用到的插件:插件页面并入 pages,配置并入 __wxConfig.page */\nexport interface AppBuild extends BuildResult {\n plugins: PluginCode[];\n}\n\n/** app.json 的 plugins:引用名 → { provider, version } */\ntype DeclaredPlugins = Record<string, { provider?: string; version?: string }>;\n\nexport class PluginStore {\n /** provider@version → 下载结果;失败的不留,下次打开小程序时重试 */\n private readonly downloads = new Map<string, Promise<PluginCode>>();\n /**\n * 这次打开小程序时决定用哪些插件。同一次打开的逻辑层、业务模块、渲染层等请求都按它处理:\n * 各自去下载的话,下载失败时每个请求都会重试,结果还可能前后不一,页面列表和逻辑层对不上\n */\n private selection: Promise<PluginCode[]> | null = null;\n /** 没开 --devtools-login 的提示每个插件只说一次 */\n private readonly warned = new Set<string>();\n\n /**\n * @param wechat 开启 --devtools-login 时才有,没有时不下载插件\n */\n constructor(\n private readonly wechat: WechatDevClient | null,\n private readonly logger: Pick<Console, 'warn'>\n ) {}\n\n /** 打开小程序时(宿主取 app-info)调用:重新决定用哪些插件,下载过的直接用,上次失败的重试 */\n async refresh(build: BuildResult): Promise<AppBuild> {\n this.selection = this.select(build);\n return withPlugins(build, await this.selection);\n }\n\n /** 其余请求沿用这次打开时的决定,不触发下载;还没决定过时(如直接请求逻辑层)先决定一次 */\n async current(build: BuildResult): Promise<AppBuild> {\n this.selection ??= this.select(build);\n return withPlugins(build, await this.selection);\n }\n\n /** app.json 声明的插件;下载不了的跳过,在终端说明原因,小程序自己的页面照常可用 */\n private async select(build: BuildResult): Promise<PluginCode[]> {\n const declared: DeclaredPlugins = build.wxConfig.plugins || {};\n const results = await Promise.all(Object.entries(declared).map(([alias, { provider, version }]) =>\n provider && version ? this.load(alias, provider, version) : null\n ));\n return results.filter((plugin): plugin is PluginCode => !!plugin);\n }\n\n private async load(alias: string, provider: string, version: string): Promise<PluginCode | null> {\n const label = `插件 ${alias}(${provider}@${version})`;\n if (!this.wechat) {\n this.warnOnce(label, `[wxa-runner] ${label} 的代码要用开发者的登录态向微信下载,启动时加 --devtools-login`);\n return null;\n }\n\n const key = `${provider}@${version}`;\n let download = this.downloads.get(key);\n if (!download) {\n download = this.download(this.wechat, alias, provider, version);\n this.downloads.set(key, download);\n download.catch(() => this.downloads.delete(key));\n }\n try {\n return await download;\n } catch (error) {\n this.logger.warn(`[wxa-runner] ${label} 下载失败:${(error as Error).message}`);\n return null;\n }\n }\n\n /** @throws 没有登录态、连不上、微信拒绝或返回的不是插件代码包时,消息是原因 */\n private async download(wechat: WechatDevClient, alias: string, provider: string, version: string): Promise<PluginCode> {\n const response = await wechat.post('wxa-dev/getplugincode', { plugin_id: provider, plugin_version: version }, DOWNLOAD_TIMEOUT);\n const data = Buffer.from(await response.arrayBuffer());\n // 出错时返回的是带 baseresponse 的 JSON\n if (data[0] !== PACKAGE_MAGIC) {\n let body: { baseresponse?: { errcode?: number; errmsg?: string } } = {};\n try {\n body = JSON.parse(data.toString('utf8'));\n } catch {\n // 不是 JSON,按没有结果码处理\n }\n if (body.baseresponse?.errcode) requireOk(body, '微信拒绝下载');\n throw new Error('微信没有返回插件代码');\n }\n\n const files = new Map(readWxvpkgIndex(data).map(entry => [entry.name, Buffer.from(readWxvpkgFile(data, entry))]));\n const pluginJson = JSON.parse(files.get('/plugin.json')?.toString('utf8') || '{}');\n return {\n alias,\n provider,\n version,\n files,\n pages: Object.values<string>(pluginJson.pages || {}),\n pageConfigs: pluginJson.page || {}\n };\n }\n\n private warnOnce(key: string, message: string) {\n if (this.warned.has(key)) return;\n this.warned.add(key);\n this.logger.warn(message);\n }\n}\n\n/** 插件页面并入 pages,配置并入 __wxConfig.page */\nfunction withPlugins(build: BuildResult, plugins: PluginCode[]): AppBuild {\n if (!plugins.length) return { ...build, plugins };\n return {\n ...build,\n plugins,\n pages: [...build.pages, ...plugins.flatMap(plugin => plugin.pages)],\n wxConfig: {\n ...build.wxConfig,\n page: { ...build.wxConfig.page, ...Object.assign({}, ...plugins.map(plugin => plugin.pageConfigs)) }\n }\n };\n}\n\n/** 插件页面所属的插件,以及页面在插件包里的路径(不带扩展名) */\nexport function findPluginPage(build: AppBuild, pagePath: string): { plugin: PluginCode; innerPath: string } | null {\n for (const plugin of build.plugins) {\n const prefix = `__plugin__/${plugin.provider}/`;\n if (plugin.pages.includes(pagePath)) return { plugin, innerPath: pagePath.slice(prefix.length) };\n }\n return null;\n}\n\nexport function pluginScriptUrl(plugin: PluginCode, file: 'appservice.js' | 'pageframe.js'): string {\n return `/__wxa__/plugin/${encodeURIComponent(plugin.provider)}/${encodeURIComponent(plugin.version)}/${file}`;\n}\n","/**\n * 借开发者的登录态访问微信后台:开发者工具访问的同一组接口(servicewechat.com 下的 wxa-dev、wxa-dev-logic)\n *\n * 登录、手机号、服务市场、插件都经这里,ticket、超时、网络错误和登录态失效的提示在这里统一处理。\n * 这些接口没有公开文档,请求和响应的格式取自开发者工具的实现和实测。\n */\n\nimport { DeveloperTicket, TICKET_ENV } from '@open-wxa/wxa-runner-extractor';\n\nconst BASE_URL = 'https://servicewechat.com';\n/** 开发者工具请求这些接口时带的版本号 */\nconst CLIENT_VERSION = '1021810240';\nconst DEFAULT_TIMEOUT = 10_000;\n\nconst ERROR_HINTS: Record<number, string> = {\n // 40001:开发者工具刷新过 ticket,旧的随即作废\n 40001: '(登录态已失效,请在微信开发者工具里重新登录)',\n 40029: '(登录态已失效,请在微信开发者工具里重新登录)',\n 85023: '(当前微信账号不是该小程序的开发者)'\n};\n\nexport type FindTicket = () => DeveloperTicket | null | Promise<DeveloperTicket | null>;\n\n/**\n * 取出可用的 ticket\n *\n * @throws 没有登录态或已过期时,消息是给用户看的处理办法\n */\nexport function requireUsableTicket(ticket: DeveloperTicket | null): string {\n if (!ticket) throw new Error(`未找到微信开发者工具的登录态,请登录开发者工具,或设置环境变量 ${TICKET_ENV}`);\n if (ticket.expiredAt !== undefined && ticket.expiredAt <= Date.now()) {\n throw new Error('微信开发者工具的登录态已过期,请打开开发者工具刷新登录态');\n }\n return ticket.newticket;\n}\n\n/** 给错误码加上处理办法,如登录态失效时提示重新登录 */\nexport function explainErrcode(errcode: number | undefined): string {\n return (errcode !== undefined && ERROR_HINTS[errcode]) || '';\n}\n\n/**\n * 检查 baseresponse 里的结果码\n *\n * @throws 结果码不为 0 时,消息是 action 加上结果码、错误信息和处理办法\n */\nexport function requireOk<T extends { baseresponse?: { errcode?: number; errmsg?: string } }>(body: T, action: string): T {\n const errcode = body.baseresponse?.errcode;\n if (errcode !== 0) throw new Error(`${action} ${errcode}: ${body.baseresponse?.errmsg || '未知错误'}${explainErrcode(errcode)}`);\n return body;\n}\n\nexport class WechatDevClient {\n /**\n * @param findTicket 每次请求都重新取:开发者工具重新登录、切换账号后不用重启服务器\n */\n constructor(\n readonly appid: string,\n private readonly findTicket: FindTicket\n ) {}\n\n /**\n * POST JSON 到 path(如 wxa-dev-logic/jslogin),带上 appid 和开发者 ticket\n *\n * @throws 没有可用的登录态、超时、连不上、HTTP 状态不是 2xx 时,消息是给用户看的原因\n */\n async post(path: string, body: object, timeout = DEFAULT_TIMEOUT): Promise<Response> {\n const query = new URLSearchParams({ appid: this.appid, newticket: requireUsableTicket(await this.findTicket()), clientversion: CLIENT_VERSION });\n const response = await fetch(`${BASE_URL}/${path}?${query}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeout)\n }).catch((error: Error & { cause?: Error }) => {\n // Node 的 fetch 只报 fetch failed,具体原因(DNS、连接被拒等)在 cause 里\n throw new Error(error.name === 'TimeoutError'\n ? `请求微信服务器超时(${timeout / 1000}s)`\n : `请求微信服务器失败:${error.cause?.message ?? error.message}`);\n });\n if (!response.ok) throw new Error(`微信服务器返回 HTTP ${response.status}`);\n return response;\n }\n\n /** 同 post,返回解析后的 JSON */\n async postJson(path: string, body: object): Promise<any> {\n return (await this.post(path, body)).json();\n }\n}\n","/**\n * 宿主、逻辑层、渲染层的 HTML,以及 Worker 的入口脚本\n */\n\nimport { BuildResult, toJs } from '../project/AppBuilder';\nimport type { WebviewScript } from './DevServer';\nimport { AppBuild, PluginCode, pluginScriptUrl } from './plugins';\n\nexport function hostHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>wxa-runner</title>\n</head>\n<body>\n <div id=\"wxa-root\"></div>\n <script src=\"/__wxa__/runtime/host.js\"></script>\n</body>\n</html>`;\n}\n\n/**\n * 打开基础库的热更新开关(runtime/host/hmr.ts 依赖它):Page / Component / 模板注册时登记更新回调。\n * 必须紧跟在基础库之后、业务代码注册之前执行;只在监听文件变化时打开\n */\nfunction enableHotUpdate(hot: boolean): string {\n return hot\n ? `<script>if (typeof __virtualDOM__ !== 'undefined' && __virtualDOM__.enableUpdateWxAppCode) __virtualDOM__.enableUpdateWxAppCode();</script>\\n`\n : '';\n}\n\n/**\n * isolated:新版基础库(3.7.1 起)。逻辑层 iframe 只是主上下文,业务代码由基础库通过 WeixinJSContext\n * 放进子上下文执行(见 runtime/context.ts),逻辑层就绪的通知也由那边发出\n */\nexport function appserviceHtml(\n build: AppBuild,\n launch: { path: string; query: Record<string, string> },\n options: { hot: boolean; isolated?: boolean }\n): string {\n const wxConfig = {\n ...build.wxConfig,\n appLaunchInfo: { scene: 1001, path: launch.path, query: launch.query },\n ...(options.isolated ? { isIsolateContext: true } : {})\n };\n const v = build.version;\n // 插件在业务代码之前注册:业务代码执行时就能 requirePlugin、跳转插件页面。\n // 插件脚本也排在业务模块的 define 之前,与开发者工具一致:插件初始化时调用 requireMiniProgram() 会因导出模块还没 define 而失败,开发者工具里同样如此\n const pluginUrls = build.plugins.map(plugin => pluginScriptUrl(plugin, 'appservice.js'));\n const moduleUrls = build.modules.map(id => `/__wxa__/module/${encodeURI(id)}?v=${v}`);\n const bootstrapUrl = `/__wxa__/service-bootstrap.js?v=${v}`;\n\n if (options.isolated) {\n const scripts = [...pluginUrls, ...moduleUrls, bootstrapUrl];\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>appservice</title>\n<script>var __wxConfig = ${toJs(wxConfig)};</script>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"service\" data-app-service=\"${escapeHtml(JSON.stringify(scripts))}\"${options.hot ? ' data-hot=\"1\"' : ''}></script>\n<script src=\"/__baselib__/WAServiceMainContext.js\"></script>\n</head>\n<body></body>\n</html>`;\n }\n\n const modules = [...pluginUrls, ...moduleUrls].map(src => `<script src=\"${src}\"></script>`).join('\\n');\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>appservice</title>\n<script>var __wxConfig = ${toJs(wxConfig)};</script>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"service\"></script>\n<script src=\"/__baselib__/WAService.js\"></script>\n${enableHotUpdate(options.hot)}<script>\nif (typeof define !== 'function') {\n console.error('[wxa-runner] 基础库没有完成初始化(define 不存在),当前基础库版本可能不受支持');\n}\n</script>\n${modules}\n<script src=\"${bootstrapUrl}\"></script>\n<script>parent.__wxaHost.frameLoaded('service', 0);</script>\n</head>\n<body></body>\n</html>`;\n}\n\n/**\n * 主上下文通过 WeixinJSContext 创建的子上下文(runtime/context.ts)。\n * empty 对应 allocEmpty:不预先加载 WASubContext.js,由基础库随后 loadLibFiles\n */\nexport function subcontextHtml(id: number, empty: boolean): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>subcontext ${id}</title>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"service\" data-context-id=\"${id}\"></script>\n${empty ? '' : '<script src=\"/__baselib__/WASubContext.js\"></script>\\n'}<script>parent.__wxaContexts.loaded(${id});</script>\n</head>\n<body></body>\n</html>`;\n}\n\nexport function webviewHtml(build: AppBuild, pagePath: string, webviewId: number, options: { hot: boolean; scripts?: WebviewScript[] }): string {\n const id = Number(webviewId) || 0;\n return `<!DOCTYPE html>\n<html>\n<head>\n${webviewHead(build, pagePath, id, options.scripts)}\n${enableHotUpdate(options.hot)}<script src=\"/__wxa__/page-frame.js?v=${build.version}\"></script>\n${pageWindow(build, pagePath).disableScroll ? '<style>body{overflow-y:hidden}</style>' : ''}\n</head>\n<body>\n${scriptTags(options.scripts, 'body')}<script>\n(function () {\n var path = ${toJs(pagePath)};\n if (typeof __wxAppCode__[path + '.wxss'] === 'function') __wxAppCode__[path + '.wxss']();\n var generateFunc = $gwx('./' + path + '.wxml');\n if (generateFunc) {\n document.dispatchEvent(new CustomEvent('generateFuncReady', { detail: { generateFunc: generateFunc } }));\n } else {\n document.body.innerText = './' + path + '.wxml not found';\n console.error('[wxa-runner] ./' + path + '.wxml not found');\n }\n parent.__wxaHost.frameLoaded('webview', ${id});\n})();\n</script>\n</body>\n</html>`;\n}\n\n/**\n * Worker 的入口(/__wxa__/worker.js?id=),由逻辑层的原生 WeixinWorker 创建(runtime/workers.ts)。\n * 和开发者工具一样先放 __wxConfig 和原生接口(runtime/worker.ts),再加载 Worker 基础库和 workers 目录下的模块;\n * 模块逐个加载,DevTools 里保留原文件名和行号。\n * Worker 基础库把 console 换成转发给逻辑层的版本,转发时对象被转成文本;开发者工具加载完基础库后换回原来的,日志留在 Worker 里。\n * 基础库目录里没有 WAWorker.js 时(如只放了逻辑层和渲染层文件的旧版内置基础库),直接抛出异常说明缺少的文件,由逻辑层的 Worker 对象记入 errors()(runtime/workers.ts)\n */\nexport function workerScript(build: BuildResult, baseLib: { version: string; hasWorker: boolean }): string {\n const modules = build.workerModules.map(id => `/__wxa__/module/${encodeURI(id)}?v=${build.version}`);\n const prelude = `var __wxConfig = ${toJs(build.wxConfig)}; __wxConfig.env.USER_DATA_PATH = location.origin + \"/__wxa__/usr/\" + new URL(location.href).searchParams.get(\"session\");\nimportScripts('/__wxa__/runtime/worker.js');\n`;\n if (!baseLib.hasWorker) {\n const message = `[wxa-runner] 基础库 ${baseLib.version} 里没有 WAWorker.js,Worker 不能运行。换用开发者工具下载的基础库,或升级 wxa-runner 带上新的内置基础库`;\n return `${prelude}throw new Error(${toJs(message)});\n`;\n }\n return `${prelude}var __wxaConsole = self.console;\nimportScripts('/__baselib__/WAWorker.js');\nself.console = __wxaConsole;\nimportScripts(${modules.map(url => toJs(url)).join(', ')});\n`;\n}\n\n/**\n * 插件页面:只加载插件自己的模板和样式(pageframe.js),不加载小程序的,与开发者工具一致。\n * 页面 html 是插件包里编译好的片段,自己注入样式、取模板并派发 generateFuncReady\n */\nexport function pluginWebviewHtml(\n build: AppBuild,\n plugin: PluginCode,\n innerPath: string,\n pagePath: string,\n webviewId: number,\n options: { scripts?: WebviewScript[] } = {}\n): string {\n const id = Number(webviewId) || 0;\n const page = plugin.files.get(`/${innerPath}.html`)?.toString('utf8') ?? `<script>console.error(${JSON.stringify(`[wxa-runner] 插件 ${plugin.alias} 里没有页面 ${innerPath}`)})</script>`;\n return `<!DOCTYPE html>\n<html>\n<head>\n${webviewHead(build, pagePath, id, options.scripts)}\n<script src=\"${pluginScriptUrl(plugin, 'pageframe.js')}\"></script>\n${pageWindow(build, pagePath).disableScroll ? '<style>body{overflow-y:hidden}</style>' : ''}\n</head>\n<body>\n${scriptTags(options.scripts, 'body')}${page}\n<script>parent.__wxaHost.frameLoaded('webview', ${id});</script>\n</body>\n</html>`;\n}\n\nfunction pageWindow(build: AppBuild, pagePath: string): Record<string, any> {\n return { ...build.wxConfig.global?.window, ...build.wxConfig.page?.[pagePath + '.html']?.window };\n}\n\n/** 渲染层公共的 head:页面配置、桥和基础库;position 为 head 的注入脚本在桥之后、基础库之前(body 的见 WebviewScript) */\nfunction webviewHead(build: AppBuild, pagePath: string, id: number, scripts?: WebviewScript[]): string {\n const wxConfig = { ...build.wxConfig, window: pageWindow(build, pagePath) };\n return `<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>${escapeHtml(pagePath)}</title>\n<!-- 小程序渲染层的默认字号是 16px;不声明的话会继承浏览器设置里的默认字号。放在最前面,基础库和页面样式都能覆盖它 -->\n<style>html{font-size:16px}</style>\n<!-- 真机的滚动条是不占布局的浮层;桌面浏览器的常规滚动条和自定义 ::-webkit-scrollbar 会挤窄页面,一律隐藏。\n scrollbar-width 优先于 ::-webkit-scrollbar,页面样式不会再把滚动条加回来 -->\n<style>*{scrollbar-width:none}::-webkit-scrollbar{display:none}</style>\n<!-- 逻辑层建的 2d、webgl 画布搬进 wx-canvas 后铺满它(见 frame.ts 的 moveCanvasesIntoPages)。\n 基础库还会按逻辑层里的布局改它的位置和显隐,这里一律压住;触摸照常交给 wx-canvas 自己的 canvas -->\n<style>.wxa-service-canvas{position:absolute!important;left:0!important;top:0!important;width:100%!important;height:100%!important;visibility:inherit!important;pointer-events:none}</style>\n<script>var __wxConfig = ${toJs(wxConfig)};</script>\n<script src=\"/__wxa__/runtime/frame.js\" data-kind=\"webview\" data-webview-id=\"${id}\"></script>\n${scriptTags(scripts, 'head')}<script src=\"/__baselib__/WAWebview.js\"></script>`;\n}\n\n/** 注入脚本的 <script> 标签,每个一行;内联内容里的 </script 转义,不会提前结束标签 */\nfunction scriptTags(scripts: WebviewScript[] | undefined, position: 'head' | 'body'): string {\n return (scripts ?? [])\n .filter(script => (script.position ?? 'body') === position)\n .map(script => script.src !== undefined\n ? `<script src=\"${escapeHtml(script.src)}\"></script>\\n`\n : `<script>${script.content.replace(/<\\/script/gi, '<\\\\/script')}</script>\\n`)\n .join('');\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/[&<>\"]/g, ch => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!));\n}\n","/**\n * 把基础库脚本加入 Chrome DevTools 的忽略列表(source map 的 x_google_ignoreList),调试时只看业务代码\n *\n * 新版基础库用 BaseConsole 包装 console 来收集日志,业务代码的 console.log 在 DevTools 里显示的来源\n * 成了这层包装(3.17 起基础库自己把它命名为 __WXAPPLIB_IGNORE__,就是留给调试工具跳过的)。\n * 忽略列表里的帧会被 DevTools 跳过:控制台的来源链接、调用栈、单步调试都落到业务代码上。\n * source map 只在打开 DevTools 时才会请求,不影响运行。\n *\n * 映射是恒等的:原始代码就是脚本本身,每行按固定间隔打点;从忽略列表里移除后仍能在基础库里调试,\n * 位置误差不超过一个间隔\n */\n\n/** 打点间隔(列):基础库压缩成很长的行,逐字符映射太大 */\nconst STRIDE = 100;\n\nconst BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/** @param source 原始代码的地址,相对 source map 的地址解析 */\nexport function ignoreListSourceMap(code: string, source: string): string {\n let previousColumn = 0;\n const mappings = code.split('\\n').map((line, index) => {\n const segments: string[] = [];\n for (let column = 0; column === 0 || column < line.length; column += STRIDE) {\n // 各字段都是相对上一个打点的增量:生成列(每行从 0 重新算)、源文件、源行、源列\n const sourceLine = column === 0 && index > 0 ? 1 : 0;\n segments.push(vlq(column === 0 ? 0 : STRIDE) + vlq(0) + vlq(sourceLine) + vlq(column - previousColumn));\n previousColumn = column;\n }\n return segments.join(',');\n });\n return JSON.stringify({ version: 3, sources: [source], names: [], mappings: mappings.join(';'), x_google_ignoreList: [0] });\n}\n\nfunction vlq(value: number): string {\n let rest = value < 0 ? (-value << 1) | 1 : value << 1;\n let out = '';\n do {\n let digit = rest & 31;\n rest >>>= 5;\n if (rest > 0) digit |= 32;\n out += BASE64[digit];\n } while (rest > 0);\n return out;\n}\n","/**\n * 把浏览器转发来的报错和控制台输出打印到终端(浏览器端见 runtime/host/ConsoleForwarder.ts)\n *\n * 开了 --host 时局域网里的设备也能连上来发消息:去掉控制字符,免得借转义序列操纵终端;限制长度和频率,免得刷屏\n */\n\nimport type { RawData, WebSocket } from 'ws';\n\nconst MAX_LENGTH = 4000;\nconst LIMIT_PER_SECOND = 20;\n/** C0、C1 控制字符,保留换行和制表符 */\n// oxlint-disable-next-line no-control-regex -- 就是要匹配控制字符\nconst CONTROL_CHARS = /[\\u0000-\\u0008\\u000b-\\u001f\\u007f-\\u009f]/g;\n\nexport function printBrowserReports(socket: WebSocket, logger: Pick<Console, 'warn' | 'error'>) {\n let windowStart = 0;\n let printed = 0;\n let dropped = 0;\n socket.on('message', data => {\n const report = parseReport(data);\n if (!report) return;\n const now = Date.now();\n if (now - windowStart >= 1000) {\n windowStart = now;\n printed = 0;\n }\n if (printed >= LIMIT_PER_SECOND) {\n // 这一秒结束时说明省略了多少条\n if (dropped++ === 0) {\n setTimeout(() => {\n logger.warn(`[wxa-runner] 浏览器 1 秒内转发的报错太多,省略了 ${dropped} 条`);\n dropped = 0;\n }, windowStart + 1000 - now).unref();\n }\n return;\n }\n printed++;\n logger[report.level](`[wxa-runner] ${clean(report.text)}`);\n });\n}\n\nfunction parseReport(data: RawData): { level: 'warn' | 'error'; text: string } | null {\n try {\n const report = JSON.parse(data.toString());\n if (report?.type === 'console' && (report.level === 'warn' || report.level === 'error') && typeof report.text === 'string') return report;\n } catch {\n // 不是 JSON\n }\n return null;\n}\n\nfunction clean(text: string): string {\n const printable = text.replace(CONTROL_CHARS, '');\n return printable.length > MAX_LENGTH ? `${printable.slice(0, MAX_LENGTH)}…(已截断)` : printable;\n}\n\n/** frame.js 的 source map 加上忽略列表:包装 console 的代码(consoleHook.ts)不作为控制台输出的来源 */\nexport function ignoreConsoleHook(sourceMap: string): string {\n const map = JSON.parse(sourceMap);\n map.x_google_ignoreList = map.sources.flatMap((source: string, index: number) => (source.endsWith('consoleHook.ts') ? [index] : []));\n return JSON.stringify(map);\n}\n","/**\n * 网络代理:浏览器端的 wx.request 经由这里转发到真实服务器\n *\n * - 原地址写在路径里:/__wxa__/proxy/https/api.example.com/a?b=1(见 networkPanel.ts)\n * - 绕开 CORS\n * - 小程序设置的请求头放在 x-wxa-headers(JSON)里传过来,\n * 这样 cookie / referer / user-agent 等浏览器禁止设置的头也能带上\n * - 响应头和 set-cookie 以 URL 编码的 JSON 返回,浏览器端可以完整读取\n */\n\nimport type { Request, Response } from 'express';\nimport { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\nimport { pipeline } from 'node:stream/promises';\nimport { fromServerPath, PROXY_PREFIX } from '../runtime/networkPanel';\n\n// fetch 不允许或无意义的请求头\nconst DROPPED_REQUEST_HEADERS = new Set(['host', 'connection', 'content-length', 'transfer-encoding', 'keep-alive', 'upgrade', 'expect']);\n// 响应体已被解压/重新分块,这些头不再成立\nconst DROPPED_RESPONSE_HEADERS = new Set(['content-encoding', 'content-length', 'transfer-encoding', 'connection', 'set-cookie']);\n\n/**\n * 用 app.use 挂在 PROXY_PREFIX 下。原地址从未解码的 originalUrl 取:解码后路径里的 %2F 等会变成别的地址。\n * 不能用 app.all('/__wxa__/proxy/*'):Express 会先解码 * 匹配的部分,地址里有单独的 %(如 /discount/50%)时直接报错\n */\nexport async function handleProxy(req: Request, res: Response) {\n const target = fromServerPath(PROXY_PREFIX, req.originalUrl);\n if (!target) {\n sendProxyError(res, 400, `invalid url \"${req.originalUrl}\"`);\n return;\n }\n\n const controller = new AbortController();\n const cancel = () => controller.abort();\n res.once('close', cancel);\n\n try {\n let upstream: globalThis.Response;\n try {\n upstream = await fetch(target, {\n method: req.method,\n headers: forwardedRequestHeaders(req.get('x-wxa-headers'), req.get('content-type')),\n body: requestBody(req),\n redirect: 'follow',\n signal: controller.signal\n });\n } catch (error) {\n if (res.destroyed || controller.signal.aborted) return;\n sendProxyError(res, 502, fetchErrorMessage(error));\n return;\n }\n await relayResponse(upstream, res);\n } catch (error) {\n // 响应头已经发出,流中断时关闭连接,让客户端收到失败,而不是补发一个 502。\n if (!res.destroyed) res.destroy(error as Error);\n } finally {\n res.off('close', cancel);\n }\n}\n\nfunction requestBody(req: Request): BodyInit | undefined {\n const hasBody = !['GET', 'HEAD'].includes(req.method) && Buffer.isBuffer(req.body) && req.body.length > 0;\n return hasBody ? req.body : undefined;\n}\n\n/** fetch 连不上时 message 只有 \"fetch failed\",具体原因(ECONNREFUSED 等)在 cause 里 */\nfunction fetchErrorMessage(error: unknown): string {\n return (error as any)?.cause?.message || (error as Error).message;\n}\n\nfunction sendProxyError(res: Response, status: number, message: string) {\n res.status(status).set('x-wxa-proxy-error', '1').send(message);\n}\n\n/**\n * 小程序设置的请求头,去掉 fetch 不允许或无意义的。上传文件时 multipart 的 boundary 只有浏览器生成的\n * content-type 里才有,所以这时 content-type 用浏览器的\n */\nfunction forwardedRequestHeaders(encoded: string | undefined, browserContentType = ''): Record<string, string> {\n const multipart = browserContentType.startsWith('multipart/form-data');\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(parseHeaders(encoded))) {\n const name = key.toLowerCase();\n if (DROPPED_REQUEST_HEADERS.has(name) || (multipart && name === 'content-type') || value === undefined || value === null) continue;\n headers[key] = String(value);\n }\n if (multipart) headers['content-type'] = browserContentType;\n return headers;\n}\n\n/** 头格式错误时按无自定义头处理 */\nfunction parseHeaders(encoded = '{}'): Record<string, unknown> {\n try {\n return JSON.parse(encoded);\n } catch {\n return {};\n }\n}\n\n/** 照搬状态码和响应头,另把全部响应头和 set-cookie 编码进 x-wxa-headers / x-wxa-set-cookie,再流式转发响应体 */\nasync function relayResponse(upstream: globalThis.Response, res: Response) {\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n if (!DROPPED_RESPONSE_HEADERS.has(key)) res.setHeader(key, value);\n });\n res.status(upstream.status);\n res.setHeader('x-wxa-headers', encodeURIComponent(JSON.stringify(responseHeaders)));\n const setCookies = typeof upstream.headers.getSetCookie === 'function' ? upstream.headers.getSetCookie() : [];\n res.setHeader('x-wxa-set-cookie', encodeURIComponent(JSON.stringify(setCookies)));\n // 不等响应结束:长连接的响应头和数据块要立即到达浏览器。\n res.flushHeaders();\n if (!upstream.body) {\n res.end();\n return;\n }\n await pipeline(Readable.fromWeb(upstream.body as ReadableStream), res);\n}\n","/**\n * 热更新分流:文件改动能否在不刷新整页的情况下应用(浏览器端应用见 runtime/host/hmr.ts)\n */\n\nexport interface HotUpdatePlan {\n /** 模板要更新的页面和组件(不带扩展名) */\n templates: string[];\n /** 逻辑要更新的页面和组件(不带扩展名) */\n scripts: string[];\n /** 改动的样式文件(不带扩展名),包括 app.wxss、被 @import 的文件,以及 less / sass 源文件和它们引用的 .css */\n styles: string[];\n}\n\nconst STYLE_FILE = /\\.(wxss|less|scss|sass|css)$/;\n\n/**\n * @param files 相对小程序根目录的改动文件\n * @returns null 表示需要整页刷新:只要有一个文件既不是样式,也不是页面或组件自己的 WXML / JS\n */\nexport function planHotUpdate(files: string[], units: { pages: string[]; components: string[] }): HotUpdatePlan | null {\n const owners = new Set([...units.pages, ...units.components]);\n const plan: HotUpdatePlan = { templates: [], scripts: [], styles: [] };\n\n for (const file of files) {\n const id = file.replace(/\\.(wxml|js|wxss|less|scss|sass|css)$/, '');\n const target = STYLE_FILE.test(file)\n ? plan.styles\n : !owners.has(id) ? null : file.endsWith('.wxml') ? plan.templates : file.endsWith('.js') ? plan.scripts : null;\n if (!target) return null;\n if (!target.includes(id)) target.push(id);\n }\n return plan;\n}\n","/**\n * --devtools-login 用的开发者 ticket 从哪来\n *\n * 环境变量 WECHAT_DEV_TICKET 优先。新版开发者工具(Electron)把登录态加密存放,磁盘上只剩旧版留下的、\n * 早已作废的 ticket,所以要向正在运行的开发者工具要:用它的命令行为项目开启自动化接口,\n * 再通过自动化协议的 Tool.getTicket 取当前生效的 ticket。旧版(package.nw)照旧读磁盘上的登录数据。\n *\n * 不调用 Tool.refreshTicket:刷新会让别人手里的 ticket 立即作废,ticket 过期时开发者工具取的时候会自己刷新。\n */\n\nimport { execFile } from 'child_process';\nimport { randomUUID } from 'crypto';\nimport { setTimeout as sleep } from 'timers/promises';\nimport { WebSocket } from 'ws';\nimport { DeveloperTicket, findDeveloperTicket, findElectronDevtoolsCli, TICKET_ENV } from '@open-wxa/wxa-runner-extractor';\n\nexport type TicketSource = () => Promise<DeveloperTicket | null>;\n\n/** 自动化接口的惯用端口;被占用时开发者工具会换一个,以命令行返回的为准 */\nconst AUTO_PORT = 9420;\n/** 开发者工具没在运行时命令行要先启动它,项目窗口还可能在等用户确认信任 */\nconst CLI_TIMEOUT = 60_000;\n/**\n * 取 ticket 平时 10ms 左右,项目窗口刚打开时第一次约 1s。项目窗口被关掉后开发者工具的后台可能还在监听,\n * 请求不报错而是一直挂着,超时就当自动化接口失效,重新开启\n */\nconst AUTOMATOR_TIMEOUT = 5_000;\n/** 开启自动化后项目窗口要过一会儿才登记好,之前取 ticket 会报找不到窗口(开发者工具自己的命令行开启后等 8s 再用) */\nconst WINDOW_TIMEOUT = 10_000;\nconst WINDOW_RETRY_INTERVAL = 500;\n\n/**\n * @param projectPath 项目目录(project.config.json 所在目录),开发者工具为它开启自动化接口,项目窗口没开时会打开\n * @param logger 开启自动化接口时告诉用户,因为开发者工具里可能多出一个项目窗口\n * @returns 每次调用都重新取,开发者工具重新登录、刷新 ticket 后不用重启。取不到时抛错,消息是给用户看的原因和处理办法\n */\nexport function developerTicketSource(projectPath: string, logger: Pick<Console, 'log'>): TicketSource {\n const cli = findElectronDevtoolsCli();\n if (!cli) return async () => findDeveloperTicket();\n\n let automatorPort: Promise<number> | null = null;\n // 同时发起的几次请求共用一次开启;失败了下次请求再试,用户改好设置后不用重启\n const startOnce = () => {\n if (!automatorPort) {\n const starting = startAutomation(cli, projectPath).then(port => {\n logger.log(`[wxa-runner] --devtools-login:已在微信开发者工具里为项目开启自动化接口(端口 ${port}),ticket 从开发者工具实时获取`);\n return port;\n });\n starting.catch(() => {\n if (automatorPort === starting) automatorPort = null;\n });\n automatorPort = starting;\n }\n return automatorPort;\n };\n\n return async () => {\n if (process.env[TICKET_ENV]) return { newticket: process.env[TICKET_ENV] };\n\n const port = startOnce();\n try {\n return await requestTicketOnceWindowReady(await port, projectPath);\n } catch (error) {\n if (!(error instanceof AutomatorGone)) throw error;\n // 开发者工具重启过、项目窗口被关掉:重新开启一次再试\n if (automatorPort === port) automatorPort = null;\n return requestTicketOnceWindowReady(await startOnce(), projectPath);\n }\n };\n}\n\n/** 自动化接口连不上或不响应了,消息是重新开启后还这样时给用户看的 */\nclass AutomatorGone extends Error {}\nclass WindowNotFound extends Error {}\n\nasync function requestTicketOnceWindowReady(port: number, projectPath: string): Promise<DeveloperTicket> {\n const deadline = Date.now() + WINDOW_TIMEOUT;\n for (;;) {\n try {\n return await requestTicket(port);\n } catch (error) {\n if (!(error instanceof WindowNotFound)) throw error;\n if (Date.now() >= deadline) throw new Error(`微信开发者工具里找不到项目窗口,请在微信开发者工具里打开项目 ${projectPath}`);\n await sleep(WINDOW_RETRY_INTERVAL);\n }\n }\n}\n\n/**\n * 用开发者工具的命令行为项目开启自动化接口:开发者工具没在运行时启动它,项目窗口已经开着时复用\n *\n * @returns 自动化接口的端口\n */\nasync function startAutomation(cli: string, projectPath: string): Promise<number> {\n // 开发者工具设了「CLI 访问令牌」时,命令行自己从继承的环境变量 WECHAT_DEVTOOLS_CLI_TOKEN 读取\n const stdout = await runCli(cli, ['agent', 'start', '--project', projectPath, '--auto-port', String(AUTO_PORT), '--lang', 'zh']);\n // 成功时最后打印一段 JSON;失败时退出码多半还是 0,错误以 [error] 开头打印\n let autoPort = NaN;\n try {\n autoPort = Number(JSON.parse(stdout.match(/^\\{$[\\s\\S]*?^\\}$/m)?.[0] ?? '').autoPort);\n } catch {\n // 没有 JSON,从输出里找原因\n }\n if (Number.isInteger(autoPort) && autoPort > 0) return autoPort;\n\n if (stdout.includes('服务端口已关闭')) {\n throw new Error('微信开发者工具的服务端口已关闭,请在开发者工具「设置 → 安全设置」里开启服务端口');\n }\n throw new Error(`微信开发者工具没能为项目开启自动化接口:${cliErrorMessage(stdout)}`);\n}\n\n/** @returns 命令行的标准输出;命令行退出码不为 0 时也返回,由调用方从输出里找原因 */\nfunction runCli(cli: string, args: string[]): Promise<string> {\n // Windows 上是 cli.bat,要经 cmd 运行,路径里常有空格(Program Files)\n const bat = cli.endsWith('.bat');\n const [file, fileArgs] = bat ? [`\"${cli}\"`, args.map(arg => `\"${arg}\"`)] : [cli, args];\n return new Promise((resolve, reject) => {\n const child = execFile(file, fileArgs, { shell: bat, timeout: CLI_TIMEOUT, windowsHide: true }, (error, stdout) => {\n if (error?.killed) {\n reject(new Error(`微信开发者工具的命令行 ${CLI_TIMEOUT / 1000}s 内没有完成,请看开发者工具里是否有等待确认的弹窗(如信任项目、扫码登录)`));\n } else if (error && !stdout) {\n reject(new Error(`运行微信开发者工具的命令行失败:${error.message}`));\n } else {\n resolve(stdout);\n }\n });\n child.stdin?.end();\n });\n}\n\n/**\n * 命令行把错误对象按 util.inspect 的格式打印,原因在 message 的第一行。\n * util.inspect 默认用单引号,字符串里有单引号时改用双引号,两种都有时用反引号\n */\nfunction cliErrorMessage(stdout: string): string {\n // oxlint-disable-next-line no-control-regex -- 去掉命令行输出里的 ANSI 颜色\n const output = stdout.replace(/\\x1b\\[[0-9;]*m/g, '');\n const start = output.indexOf('[error]');\n const error = (start < 0 ? output : output.slice(start + '[error]'.length)).trim();\n const message = error.match(/message: (['\"`])((?:\\\\.|(?!\\1)[^\\\\])*?)(?:\\\\n|\\1)/)?.[2];\n return message ?? (error.replace(/\\s+/g, ' ').slice(0, 200) || '命令行没有输出');\n}\n\n/**\n * 通过自动化协议取开发者工具当前的 ticket:一条 WebSocket,{ id, method, params } → { id, result | error }\n *\n * 开发者工具会把别的自动化会话的消息也广播给每个连接,自己的回包还会收到两遍,按 id 认第一条\n */\nfunction requestTicket(port: number): Promise<DeveloperTicket> {\n return new Promise((resolve, reject) => {\n const id = `wxa-runner-${randomUUID()}`;\n const socket = new WebSocket(`ws://127.0.0.1:${port}`);\n const settle = (finish: () => void) => {\n clearTimeout(timer);\n socket.removeAllListeners().on('error', () => undefined).terminate();\n finish();\n };\n const timer = setTimeout(\n () =>\n settle(() =>\n reject(new AutomatorGone(`微信开发者工具的自动化接口 ${AUTOMATOR_TIMEOUT / 1000}s 内没有响应,请确认开发者工具里打开了项目窗口`))\n ),\n AUTOMATOR_TIMEOUT\n );\n const gone = () => settle(() => reject(new AutomatorGone(`连不上微信开发者工具的自动化接口(端口 ${port}),请确认开发者工具在运行`)));\n\n socket.on('error', gone);\n socket.on('close', gone);\n socket.on('open', () => socket.send(JSON.stringify({ id, method: 'Tool.getTicket', params: {} })));\n socket.on('message', data => {\n let message;\n try {\n message = JSON.parse(String(data));\n } catch {\n return;\n }\n if (message?.id !== id) return;\n if (message.error) settle(() => reject(explainAutomatorError(String(message.error.message))));\n else if (typeof message.result?.ticket !== 'string') settle(() => reject(new Error('微信开发者工具没有返回登录票据')));\n else settle(() => resolve({ newticket: message.result.ticket, expiredAt: message.result.expiredTime }));\n });\n });\n}\n\n/** 开发者工具给的是英文,换成处理办法 */\nfunction explainAutomatorError(message: string): Error {\n if (message.includes('GUI project window is not found')) return new WindowNotFound(message);\n if (message.includes('not allow to get')) {\n return new Error('微信开发者工具不允许获取登录票据,请在开发者工具「设置 → 安全设置」里打开「允许获取工具登录票据」');\n }\n if (message.includes('need to login')) return new Error('微信开发者工具未登录,请先在开发者工具里登录');\n return new Error(`微信开发者工具返回错误:${message}`);\n}\n","/**\n * --devtools-login 的接口:借本机开发者工具的登录态,向微信换取真实的 wx.login code 和手机号,转发服务市场和插件的请求\n *\n * POST /login → { code }\n * POST /phone-number → { data, encryptedData, iv },code 在 data(JSON 字符串)里,与基础库的约定一致\n * POST /operate-wx-data { data } → { data }:wx.serviceMarket 经原生 operateWXData 发出的请求,同开发者工具转发给微信\n * POST /verify-plugin { data } → { data: { list } }:插件校验,list 是每个插件能访问的域名\n * POST /batch-get-contact { appIds } → { contactList }:插件信息\n *\n * 失败时返回 500 和 { error: 原因 }。开发者 ticket 只留在 Node 进程里,接口只接受本机访问,\n * 并校验 Host 头防止 DNS rebinding。\n */\n\nimport express, { NextFunction, Request, Response, Router } from 'express';\nimport { findDeveloperTicket } from '@open-wxa/wxa-runner-extractor';\nimport { explainErrcode, FindTicket, requireOk, WechatDevClient } from './wechatDev';\n\nconst LOOPBACK_ADDRESSES = ['127.0.0.1', '::1', '::ffff:127.0.0.1'];\nconst LOOPBACK_HOSTS = ['localhost', '127.0.0.1', '[::1]'];\n\n/**\n * 经 /operate-wx-data 转发的 operateWXData:只放行服务市场。别的(用户信息、授权等)在开发者工具里\n * 会弹窗让用户确认,不能让业务代码借开发者的登录态直接调用\n */\nconst FORWARDED_WX_DATA_APIS = ['webapi_servicemarket_jsapi_comm'];\n\n/**\n * @param findTicket 每次请求都重新查找:开发者工具重新登录、切换账号后不用重启服务器\n */\nexport function devtoolsLoginRouter(appid: string, findTicket: FindTicket = findDeveloperTicket): Router {\n const wechat = new WechatDevClient(appid, findTicket);\n const router = express.Router();\n router.use(onlyLoopback);\n\n router.post('/login', respond(async () => {\n const body = requireOk(await wechat.postJson('wxa-dev-logic/jslogin', { scope: ['snsapi_base'] }), '微信登录失败');\n if (!body.code) throw new Error('微信登录失败:微信没有返回 code');\n return { code: body.code };\n }));\n\n router.post('/phone-number', respond(async () => {\n const body = await wechat.postJson('wxa-dev-logic/jsgetuserwxphone', { appid });\n // 结果码在 jsapi_baseresponse 里,不是 jslogin 那样的 baseresponse\n const errcode = body.jsapi_baseresponse?.errcode ?? body.BaseResponse?.Ret;\n if (errcode !== 0 || typeof body.data !== 'string') {\n const errmsg = body.jsapi_baseresponse?.errmsg || body.BaseResponse?.ErrMsg?.String || '未知错误';\n throw new Error(`获取手机号失败 ${errcode}: ${errmsg}${explainErrcode(errcode)}`);\n }\n // data 原样转交:基础库从 JSON.parse(data) 里取 code 和 request_id\n const { encryptedData, iv } = JSON.parse(body.data);\n return { data: body.data, encryptedData, iv };\n }));\n\n router.post('/operate-wx-data', express.json({ limit: '10mb' }), (req, res, next) => {\n const apiName = req.body?.data?.api_name;\n if (FORWARDED_WX_DATA_APIS.includes(apiName)) return next();\n res.status(403).json({ error: `operateWXData 只转发服务市场的请求,不转发 ${apiName}` });\n }, respond(async req => {\n // 与开发者工具一致:基础库给的 data 序列化成文本放在 data 字段里\n const body = requireOk(await wechat.postJson('wxa-dev-logic/jsoperatewxdata', { data: JSON.stringify(req.body.data) }), '服务市场调用失败');\n if (typeof body.data !== 'string') throw new Error('服务市场调用失败:微信没有返回结果');\n // 服务市场自己的结果码在 data 里,由基础库解析成 invokeService 的结果\n return { data: JSON.parse(body.data) };\n }));\n\n // 插件:基础库启动时校验插件、取插件信息,插件里的网络请求要等拿到这两样才发出\n router.post('/verify-plugin', express.json(), respond(async req => {\n // 与开发者工具一致:基础库给的 data 序列化后放在 ext_info 里\n const body = requireOk(await wechat.postJson('wxa-dev-logic/verifyplugin', { ext_info: JSON.stringify(req.body?.data || {}) }), '插件校验失败');\n return { data: { list: body.list || [] } };\n }));\n\n router.post('/batch-get-contact', express.json(), respond(async req => {\n const body = requireOk(await wechat.postJson('wxa-dev-logic/batchgetcontact', { appid_list: req.body?.appIds || [] }), '获取插件信息失败');\n const contacts: Array<{ appid: string; plugin_info?: { plugin_list?: unknown[] } }> = body.contact_list || [];\n return { contactList: contacts.filter(contact => contact.plugin_info).map(contact => ({ appId: contact.appid, plugin_list: contact.plugin_info!.plugin_list })) };\n }));\n\n return router;\n}\n\nfunction onlyLoopback(req: Request, res: Response, next: NextFunction) {\n // req.hostname 去掉端口时能正确处理 IPv6 的 [::1]:3000\n if (!LOOPBACK_ADDRESSES.includes(req.socket.remoteAddress || '') || !LOOPBACK_HOSTS.includes(req.hostname)) {\n res.status(403).json({ error: '开发者登录态接口只允许本机访问' });\n return;\n }\n next();\n}\n\nfunction respond(action: (req: Request) => Promise<object>) {\n return async (req: Request, res: Response) => {\n try {\n res.json(await action(req));\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n };\n}\n","/**\n * setup 文件的发现、编译与环境变量(浏览器端执行见 runtime/host/setup.ts)\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { build, Plugin } from 'esbuild';\n\nexport const SETUP_FILE_NAMES = ['wxa.setup.ts', 'wxa.setup.js', 'wxa.setup.mjs'];\nconst SETUP_MODULE = '@open-wxa/wxa-runner-core/setup';\nconst ENV_PREFIX = 'WXA_';\n\n/** 项目目录(project.config.json 所在目录)下约定名称的 setup 文件 */\nexport function findSetupFile(projectPath: string): string | null {\n for (const name of SETUP_FILE_NAMES) {\n const file = path.join(projectPath, name);\n if (fs.existsSync(file)) return file;\n }\n return null;\n}\n\n/** 只暴露 WXA_ 前缀的变量:setup 跑在浏览器里,其余环境变量可能是不该外泄的密钥 */\nexport function collectSetupEnv(env: NodeJS.ProcessEnv): Record<string, string> {\n return Object.fromEntries(\n Object.entries(env).filter((entry): entry is [string, string] => entry[0].startsWith(ENV_PREFIX) && entry[1] !== undefined)\n );\n}\n\n/**\n * 把 setup 文件连同它 import 的文件打成一个浏览器 ES 模块\n *\n * 用户的小程序项目里通常没装本包,对它的引用直接换成运行时自带的实现。\n *\n * @throws 语法错误、import 找不到等编译错误,消息里带相对 setup 文件目录的位置\n */\nexport async function bundleSetup(file: string): Promise<string> {\n const result = await build({\n entryPoints: [file],\n absWorkingDir: path.dirname(file),\n bundle: true,\n format: 'esm',\n platform: 'browser',\n target: 'es2020',\n write: false,\n logLevel: 'silent',\n sourcemap: 'inline',\n plugins: [builtinSetupModule()]\n });\n return result.outputFiles[0].text;\n}\n\nfunction builtinSetupModule(): Plugin {\n return {\n name: 'wxa-setup-module',\n setup(pluginBuild) {\n pluginBuild.onResolve({ filter: new RegExp(`^${SETUP_MODULE}$`) }, () => ({ path: SETUP_MODULE, namespace: 'wxa-setup' }));\n pluginBuild.onLoad({ filter: /.*/, namespace: 'wxa-setup' }, () => ({\n // 与 src/setup.ts 的 defineSetup 一致:只为类型提示,运行时原样返回\n contents: 'export function defineSetup(setup) { return setup; }',\n loader: 'js'\n }));\n }\n };\n}\n","/**\n * 文件监听:把开发者一次保存引起的文件变化合并成一批报告\n */\n\nimport { createHash } from 'crypto';\nimport fs from 'fs';\nimport path from 'path';\nimport chokidar from 'chokidar';\n\nexport interface FileChanges {\n /** 相对小程序根目录、以 / 分隔的路径 */\n files: string[];\n /** 有文件新增或删除:页面、模块列表可能变了,只能整页刷新 */\n structural: boolean;\n}\n\nexport interface ProjectWatcher {\n /** 初次扫描完成;此前已存在的文件不会作为改动报告 */\n ready: Promise<void>;\n close(): Promise<void>;\n}\n\nconst DEBOUNCE = 120;\nconst IGNORED = /(^|[/\\\\])(node_modules|\\.git)([/\\\\]|$)/;\nconst FINGERPRINTED = /\\.(js|mjs|ts|json|wxml|wxss|wxs|less|scss|sass|css)$/;\n\n/**\n * @param root 报告的路径相对这个目录\n * @param paths 要监听的目录和文件,可以在 root 之外\n * @param onChange 变化停下 120ms 后调用。内容没变的代码文件不算改动:\n * 构建工具(如 uni-app 的监听构建)每次保存都会重写全部产物\n */\nexport function watchProject(root: string, paths: string[], onChange: (changes: FileChanges) => void): ProjectWatcher {\n let changed = new Set<string>();\n let structural = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n // 初次扫描时记下每个代码文件的内容指纹\n const fingerprints = new Map<string, string>();\n let scanned = false;\n\n const watcher = chokidar.watch(paths, { ignored: IGNORED });\n const ready = new Promise<void>(resolve => {\n watcher.on('ready', () => {\n scanned = true;\n resolve();\n });\n });\n\n const flush = () => {\n const changes = { files: [...changed], structural };\n changed = new Set();\n structural = false;\n onChange(changes);\n };\n\n watcher.on('all', (event, file) => {\n const unchanged = updateFingerprint(fingerprints, file, event);\n if (!scanned || unchanged) return;\n if (event !== 'change') structural = true;\n changed.add(path.relative(root, file).split(path.sep).join('/'));\n if (timer) clearTimeout(timer);\n timer = setTimeout(flush, DEBOUNCE);\n });\n\n return { ready, close: () => watcher.close() };\n}\n\n/** 记录文件的内容指纹;返回 true 表示内容与上次相同。图片等其他文件不读取,一律视为有变化 */\nfunction updateFingerprint(fingerprints: Map<string, string>, file: string, event: string): boolean {\n if (event === 'unlink') {\n fingerprints.delete(file);\n return false;\n }\n if ((event !== 'add' && event !== 'change') || !FINGERPRINTED.test(file)) return false;\n let next: string;\n try {\n next = createHash('sha1').update(fs.readFileSync(file)).digest('hex');\n } catch {\n return false;\n }\n const previous = fingerprints.get(file);\n fingerprints.set(file, next);\n return previous === next;\n}\n","/**\n * 开发服务器扩展:检查器这类开发工具把要用的扩展点打包成一个扩展,\n * 由 DevServer 的 extensions 选项或命令行的 --extension 加载。runner 只认这个约定,不认识具体的工具。\n *\n * (「插件」在 runner 里指小程序插件,见 plugins.ts,所以这里叫扩展)\n */\n\nimport type { DevServerMiddleware, WebviewScript } from './DevServer';\n\nexport interface DevServerExtension {\n /** 出现在报错和启动信息里 */\n name: string;\n /** 开发服务器构造时调用一次 */\n setup(context: ExtensionContext): ExtensionSetup;\n}\n\nexport interface ExtensionContext {\n /** 项目目录(DevServer 的 projectPath,绝对路径) */\n projectPath: string;\n /** 小程序代码根目录,已考虑 project.config.json 的 miniprogramRoot */\n root: string;\n}\n\nexport interface ExtensionSetup {\n webviewScripts?: WebviewScript[];\n middlewares?: DevServerMiddleware[];\n wxmlTransform?: (code: string, file: string) => string;\n /** 扩展自己的页面:启动信息里打印,命令行 --open 时打开 */\n entry?: { label: string; path: string };\n}\n\nexport interface ExtensionEntry {\n name: string;\n label: string;\n path: string;\n}\n\ntype WxmlTransform = (code: string, file: string) => string;\n\n/**\n * 把扩展合并进开发服务器自己的扩展点:脚本和中间件按顺序拼在后面,\n * wxml 转换按顺序串起来(先执行选项里直接给的,再依次执行各个扩展的)\n */\nexport function applyExtensions(\n base: ExtensionSetup,\n extensions: DevServerExtension[],\n context: ExtensionContext\n): Required<Omit<ExtensionSetup, 'entry' | 'wxmlTransform'>> & { wxmlTransform?: WxmlTransform; entries: ExtensionEntry[] } {\n const webviewScripts = [...(base.webviewScripts ?? [])];\n const middlewares = [...(base.middlewares ?? [])];\n const transforms = base.wxmlTransform ? [base.wxmlTransform] : [];\n const entries: ExtensionEntry[] = [];\n\n for (const extension of extensions) {\n let setup: ExtensionSetup;\n try {\n setup = extension.setup(context);\n } catch (error) {\n throw new Error(`扩展 ${extension.name} 初始化失败:${(error as Error).message}`);\n }\n webviewScripts.push(...(setup.webviewScripts ?? []));\n middlewares.push(...(setup.middlewares ?? []));\n if (setup.wxmlTransform) transforms.push(setup.wxmlTransform);\n if (setup.entry) entries.push({ name: extension.name, ...setup.entry });\n }\n\n const wxmlTransform = transforms.length === 0\n ? undefined\n : (code: string, file: string) => transforms.reduce((result, transform) => transform(result, file), code);\n return { webviewScripts, middlewares, wxmlTransform, entries };\n}\n"],"mappings":"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","names":["import_crypto","path","import_fs","import_os","import_path","import_express","import_ws","import_wxa_runner_extractor","fs","path","os","module","import_fs","import_os","import_path","fs","path","os","result","import_fs","import_path","path","fs","import_wxa_runner_extractor","path","build","build","import_crypto","import_promises","import_wxa_runner_extractor","sleep","import_wxa_runner_extractor","express","import_fs","import_path","import_esbuild","path","fs","import_crypto","import_fs","import_path","chokidar","path","fs","path","os","net","build","http","express","fs"]}