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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -118,12 +118,12 @@ var FileStore = class {
118
118
  for (const [key, value] of entries) this.nodes.set(target + key.slice(source.length), value);
119
119
  return {};
120
120
  },
121
- access: ({ path: path7 }) => {
122
- this.existing(path7);
121
+ access: ({ path: path8 }) => {
122
+ this.existing(path8);
123
123
  return {};
124
124
  },
125
- stat: ({ path: path7 }) => {
126
- const node = this.existing(path7);
125
+ stat: ({ path: path8 }) => {
126
+ const node = this.existing(path8);
127
127
  const stats = {
128
128
  mode: node.dir ? 16877 : 33188,
129
129
  size: node.data.length,
@@ -476,8 +476,8 @@ import fs2 from "fs";
476
476
  import os2 from "os";
477
477
  import path2 from "path";
478
478
  var WxmlMirror = class {
479
- constructor(transform) {
480
- this.transform = transform;
479
+ constructor(transform2) {
480
+ this.transform = transform2;
481
481
  this.dir = null;
482
482
  /** 已写入的文件:源内容(判断要不要重新转换)与写入的内容 */
483
483
  this.files = /* @__PURE__ */ new Map();
@@ -1309,9 +1309,9 @@ var DROPPED_RESPONSE_HEADERS = /* @__PURE__ */ new Set(["content-encoding", "con
1309
1309
  var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
1310
1310
  async function proxyFetch(request, options = {}) {
1311
1311
  const url = new URL(request.url);
1312
- const path7 = url.pathname + url.search;
1313
- const target = fromServerPath(PROXY_PREFIX, path7);
1314
- if (!target) return proxyError(400, `invalid url "${path7}"`);
1312
+ const path8 = url.pathname + url.search;
1313
+ const target = fromServerPath(PROXY_PREFIX, path8);
1314
+ if (!target) return proxyError(400, `invalid url "${path8}"`);
1315
1315
  try {
1316
1316
  let current = new URL(target);
1317
1317
  if (options.isAllowed && !options.isAllowed(current)) return forbiddenHost(current, 0);
@@ -1519,11 +1519,12 @@ import { findDeveloperTicket, findElectronDevtoolsCli, TICKET_ENV } from "@open-
1519
1519
  var AUTO_PORT = 9420;
1520
1520
  var CLI_TIMEOUT = 6e4;
1521
1521
  var AUTOMATOR_TIMEOUT = 5e3;
1522
+ var LOGIN_TIMEOUT = 2e4;
1522
1523
  var WINDOW_TIMEOUT = 1e4;
1523
1524
  var WINDOW_RETRY_INTERVAL = 500;
1524
- function developerTicketSource(projectPath, logger) {
1525
+ function devtoolsSession(projectPath, logger) {
1525
1526
  const cli = findElectronDevtoolsCli();
1526
- if (!cli) return async () => findDeveloperTicket();
1527
+ if (!cli) return { findTicket: async () => findDeveloperTicket(), loginCode: null };
1527
1528
  let automatorPort = null;
1528
1529
  const startOnce = () => {
1529
1530
  if (!automatorPort) {
@@ -1538,15 +1539,31 @@ function developerTicketSource(projectPath, logger) {
1538
1539
  }
1539
1540
  return automatorPort;
1540
1541
  };
1541
- return async () => {
1542
- if (process.env[TICKET_ENV]) return { newticket: process.env[TICKET_ENV] };
1542
+ const withRestart = async (run) => {
1543
1543
  const port = startOnce();
1544
1544
  try {
1545
- return await requestTicketOnceWindowReady(await port, projectPath);
1545
+ return await run(await port);
1546
1546
  } catch (error) {
1547
1547
  if (!(error instanceof AutomatorGone)) throw error;
1548
1548
  if (automatorPort === port) automatorPort = null;
1549
- return requestTicketOnceWindowReady(await startOnce(), projectPath);
1549
+ return run(await startOnce());
1550
+ }
1551
+ };
1552
+ let loginCodeNoticed = false;
1553
+ return {
1554
+ findTicket: async () => {
1555
+ if (process.env[TICKET_ENV]) return { newticket: process.env[TICKET_ENV] };
1556
+ return withRestart((port) => onceWindowReady(() => requestTicket(port), projectPath));
1557
+ },
1558
+ loginCode: async () => {
1559
+ const code = await withRestart((port) => onceWindowReady(() => requestLoginCode(port), projectPath));
1560
+ if (!loginCodeNoticed) {
1561
+ loginCodeNoticed = true;
1562
+ logger.log(
1563
+ "[wxa-runner] --devtools-login\uFF1A\u5FAE\u4FE1\u540E\u53F0\u4E0D\u7ED9\u8FD9\u4E2A appid \u53D6\u767B\u5F55\u7968\u636E\uFF0Cwx.login \u7684 code \u6539\u7531\u5F00\u53D1\u8005\u5DE5\u5177\u7684\u6A21\u62DF\u5668\u83B7\u53D6\uFF1B\u624B\u673A\u53F7\u3001\u670D\u52A1\u5E02\u573A\u548C\u63D2\u4EF6\u6CA1\u6709\u8FD9\u6761\u8DEF\uFF0C\u8C03\u7528\u65F6\u4F1A\u5931\u8D25"
1564
+ );
1565
+ }
1566
+ return code;
1550
1567
  }
1551
1568
  };
1552
1569
  }
@@ -1554,11 +1571,13 @@ var AutomatorGone = class extends Error {
1554
1571
  };
1555
1572
  var WindowNotFound = class extends Error {
1556
1573
  };
1557
- async function requestTicketOnceWindowReady(port, projectPath) {
1574
+ var TicketNotAllowed = class extends Error {
1575
+ };
1576
+ async function onceWindowReady(run, projectPath) {
1558
1577
  const deadline = Date.now() + WINDOW_TIMEOUT;
1559
1578
  for (; ; ) {
1560
1579
  try {
1561
- return await requestTicket(port);
1580
+ return await run();
1562
1581
  } catch (error) {
1563
1582
  if (!(error instanceof WindowNotFound)) throw error;
1564
1583
  if (Date.now() >= deadline) throw new Error(`\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u91CC\u627E\u4E0D\u5230\u9879\u76EE\u7A97\u53E3\uFF0C\u8BF7\u5728\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u91CC\u6253\u5F00\u9879\u76EE ${projectPath}`);
@@ -1602,7 +1621,7 @@ function cliErrorMessage(stdout) {
1602
1621
  const message = error.match(/message: (['"`])((?:\\.|(?!\1)[^\\])*?)(?:\\n|\1)/)?.[2];
1603
1622
  return message ?? (error.replace(/\s+/g, " ").slice(0, 200) || "\u547D\u4EE4\u884C\u6CA1\u6709\u8F93\u51FA");
1604
1623
  }
1605
- function requestTicket(port) {
1624
+ function sendCommand(port, method, params, timeout) {
1606
1625
  return new Promise((resolve, reject) => {
1607
1626
  const id = `wxa-runner-${randomUUID()}`;
1608
1627
  const socket = new WebSocket2(`ws://127.0.0.1:${port}`);
@@ -1612,15 +1631,13 @@ function requestTicket(port) {
1612
1631
  finish();
1613
1632
  };
1614
1633
  const timer = setTimeout(
1615
- () => settle(
1616
- () => reject(new AutomatorGone(`\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u7684\u81EA\u52A8\u5316\u63A5\u53E3 ${AUTOMATOR_TIMEOUT / 1e3}s \u5185\u6CA1\u6709\u54CD\u5E94\uFF0C\u8BF7\u786E\u8BA4\u5F00\u53D1\u8005\u5DE5\u5177\u91CC\u6253\u5F00\u4E86\u9879\u76EE\u7A97\u53E3`))
1617
- ),
1618
- AUTOMATOR_TIMEOUT
1634
+ () => settle(() => reject(new AutomatorGone(`\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u7684\u81EA\u52A8\u5316\u63A5\u53E3 ${timeout / 1e3}s \u5185\u6CA1\u6709\u54CD\u5E94\uFF0C\u8BF7\u786E\u8BA4\u5F00\u53D1\u8005\u5DE5\u5177\u91CC\u6253\u5F00\u4E86\u9879\u76EE\u7A97\u53E3`))),
1635
+ timeout
1619
1636
  );
1620
1637
  const gone = () => settle(() => reject(new AutomatorGone(`\u8FDE\u4E0D\u4E0A\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u7684\u81EA\u52A8\u5316\u63A5\u53E3\uFF08\u7AEF\u53E3 ${port}\uFF09\uFF0C\u8BF7\u786E\u8BA4\u5F00\u53D1\u8005\u5DE5\u5177\u5728\u8FD0\u884C`)));
1621
1638
  socket.on("error", gone);
1622
1639
  socket.on("close", gone);
1623
- socket.on("open", () => socket.send(JSON.stringify({ id, method: "Tool.getTicket", params: {} })));
1640
+ socket.on("open", () => socket.send(JSON.stringify({ id, method, params })));
1624
1641
  socket.on("message", (data) => {
1625
1642
  let message;
1626
1643
  try {
@@ -1630,16 +1647,33 @@ function requestTicket(port) {
1630
1647
  }
1631
1648
  if (message?.id !== id) return;
1632
1649
  if (message.error) settle(() => reject(explainAutomatorError(String(message.error.message))));
1633
- else if (typeof message.result?.ticket !== "string") settle(() => reject(new Error("\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u6CA1\u6709\u8FD4\u56DE\u767B\u5F55\u7968\u636E")));
1634
- else settle(() => resolve({ newticket: message.result.ticket, expiredAt: message.result.expiredTime }));
1650
+ else settle(() => resolve(message.result ?? {}));
1635
1651
  });
1636
1652
  });
1637
1653
  }
1654
+ async function requestTicket(port) {
1655
+ const result = await sendCommand(port, "Tool.getTicket", {}, AUTOMATOR_TIMEOUT);
1656
+ if (typeof result.ticket !== "string") throw new Error("\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u6CA1\u6709\u8FD4\u56DE\u767B\u5F55\u7968\u636E");
1657
+ return { newticket: result.ticket, expiredAt: result.expiredTime };
1658
+ }
1659
+ async function requestLoginCode(port) {
1660
+ const result = await sendCommand(port, "App.callWxMethod", { method: "login", args: [{}] }, LOGIN_TIMEOUT);
1661
+ const { code, errMsg } = result.result ?? {};
1662
+ if (typeof code !== "string" || !code) {
1663
+ throw new Error(`\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u7684\u6A21\u62DF\u5668\u6CA1\u6709\u8FD4\u56DE code${errMsg ? `\uFF1A${errMsg}` : ""}`);
1664
+ }
1665
+ return code;
1666
+ }
1638
1667
  function explainAutomatorError(message) {
1639
1668
  if (message.includes("GUI project window is not found")) return new WindowNotFound(message);
1640
- if (message.includes("not allow to get")) {
1669
+ if (message.includes("navigate to security settings")) {
1641
1670
  return new Error("\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u4E0D\u5141\u8BB8\u83B7\u53D6\u767B\u5F55\u7968\u636E\uFF0C\u8BF7\u5728\u5F00\u53D1\u8005\u5DE5\u5177\u300C\u8BBE\u7F6E \u2192 \u5B89\u5168\u8BBE\u7F6E\u300D\u91CC\u6253\u5F00\u300C\u5141\u8BB8\u83B7\u53D6\u5DE5\u5177\u767B\u5F55\u7968\u636E\u300D");
1642
1671
  }
1672
+ if (message.includes("not allow to get")) {
1673
+ return new TicketNotAllowed(
1674
+ `\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u4E0D\u7ED9\u8FD9\u4E2A appid \u53D6\u767B\u5F55\u7968\u636E\uFF1A\u662F\u5426\u5141\u8BB8\u7531\u5FAE\u4FE1\u540E\u53F0\u4E0B\u53D1\uFF0C\u8FD9\u4E2A appid \u6CA1\u6709\u5F00\uFF0C\u300C\u8BBE\u7F6E \u2192 \u5B89\u5168\u8BBE\u7F6E\u300D\u91CC\u4E5F\u5C31\u4E0D\u663E\u793A\u300C\u5141\u8BB8\u83B7\u53D6\u5DE5\u5177\u767B\u5F55\u7968\u636E\u300D\uFF0C\u672C\u673A\u6539\u4E0D\u4E86\u3002wx.login \u4F1A\u81EA\u52A8\u6539\u7531\u5F00\u53D1\u8005\u5DE5\u5177\u7684\u6A21\u62DF\u5668\u83B7\u53D6\uFF1B\u624B\u673A\u53F7\u548C\u670D\u52A1\u5E02\u573A\u8BF7\u53BB\u6389 --devtools-login\uFF0C\u7528 setup \u7684 mock \u9020\u6570\u636E\uFF0C\u6216\u53E6\u53D6\u4E00\u5F20\u7968\u636E\u7528\u73AF\u5883\u53D8\u91CF ${TICKET_ENV} \u4F20\u8FDB\u6765`
1675
+ );
1676
+ }
1643
1677
  if (message.includes("need to login")) return new Error("\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u5728\u5F00\u53D1\u8005\u5DE5\u5177\u91CC\u767B\u5F55");
1644
1678
  return new Error(`\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u8FD4\u56DE\u9519\u8BEF\uFF1A${message}`);
1645
1679
  }
@@ -1686,9 +1720,9 @@ var WechatDevClient = class {
1686
1720
  *
1687
1721
  * @throws 没有可用的登录态、超时、连不上、HTTP 状态不是 2xx 时,消息是给用户看的原因
1688
1722
  */
1689
- async post(path7, body, timeout = DEFAULT_TIMEOUT) {
1723
+ async post(path8, body, timeout = DEFAULT_TIMEOUT) {
1690
1724
  const query = new URLSearchParams({ appid: this.appid, newticket: requireUsableTicket(await this.findTicket()), clientversion: CLIENT_VERSION });
1691
- const response = await fetch(`${BASE_URL}/${path7}?${query}`, {
1725
+ const response = await fetch(`${BASE_URL}/${path8}?${query}`, {
1692
1726
  method: "POST",
1693
1727
  headers: { "Content-Type": "application/json" },
1694
1728
  body: JSON.stringify(body),
@@ -1700,8 +1734,8 @@ var WechatDevClient = class {
1700
1734
  return response;
1701
1735
  }
1702
1736
  /** 同 post,返回解析后的 JSON */
1703
- async postJson(path7, body) {
1704
- return (await this.post(path7, body)).json();
1737
+ async postJson(path8, body) {
1738
+ return (await this.post(path8, body)).json();
1705
1739
  }
1706
1740
  };
1707
1741
 
@@ -1800,14 +1834,19 @@ import { findDeveloperTicket as findDeveloperTicket2 } from "@open-wxa/wxa-runne
1800
1834
  var LOOPBACK_ADDRESSES = ["127.0.0.1", "::1", "::ffff:127.0.0.1"];
1801
1835
  var LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "[::1]"];
1802
1836
  var FORWARDED_WX_DATA_APIS = ["webapi_servicemarket_jsapi_comm"];
1803
- function devtoolsLoginRouter(appid, findTicket = findDeveloperTicket2) {
1837
+ function devtoolsLoginRouter(appid, findTicket = findDeveloperTicket2, loginCode) {
1804
1838
  const wechat = new WechatDevClient(appid, findTicket);
1805
1839
  const router = express.Router();
1806
1840
  router.use(onlyLoopback);
1807
1841
  router.post("/login", respond(async () => {
1808
- const body = requireOk(await wechat.postJson("wxa-dev-logic/jslogin", { scope: ["snsapi_base"] }), "\u5FAE\u4FE1\u767B\u5F55\u5931\u8D25");
1809
- if (!body.code) throw new Error("\u5FAE\u4FE1\u767B\u5F55\u5931\u8D25\uFF1A\u5FAE\u4FE1\u6CA1\u6709\u8FD4\u56DE code");
1810
- return { code: body.code };
1842
+ try {
1843
+ const body = requireOk(await wechat.postJson("wxa-dev-logic/jslogin", { scope: ["snsapi_base"] }), "\u5FAE\u4FE1\u767B\u5F55\u5931\u8D25");
1844
+ if (!body.code) throw new Error("\u5FAE\u4FE1\u767B\u5F55\u5931\u8D25\uFF1A\u5FAE\u4FE1\u6CA1\u6709\u8FD4\u56DE code");
1845
+ return { code: body.code };
1846
+ } catch (error) {
1847
+ if (!loginCode || !(error instanceof TicketNotAllowed)) throw error;
1848
+ return { code: await loginCode() };
1849
+ }
1811
1850
  }));
1812
1851
  router.post("/phone-number", respond(async () => {
1813
1852
  const body = await wechat.postJson("wxa-dev-logic/jsgetuserwxphone", { appid });
@@ -1980,7 +2019,7 @@ function applyExtensions(base, extensions, context) {
1980
2019
  if (setup.wxmlTransform) transforms.push(setup.wxmlTransform);
1981
2020
  if (setup.entry) entries.push({ name: extension.name, ...setup.entry });
1982
2021
  }
1983
- const wxmlTransform = transforms.length === 0 ? void 0 : (code, file) => transforms.reduce((result, transform) => transform(result, file), code);
2022
+ const wxmlTransform = transforms.length === 0 ? void 0 : (code, file) => transforms.reduce((result, transform2) => transform2(result, file), code);
1984
2023
  return { webviewScripts, middlewares, wxmlTransform, entries };
1985
2024
  }
1986
2025
 
@@ -2016,11 +2055,9 @@ var DevServer = class {
2016
2055
  if (!this.baseLib.compatible) {
2017
2056
  this.logger.warn(`[wxa-runner] \u57FA\u7840\u5E93 ${this.baseLib.version} \u9AD8\u4E8E\u5DF2\u9A8C\u8BC1\u7684\u7248\u672C\u8303\u56F4\uFF0C\u53EF\u80FD\u65E0\u6CD5\u6B63\u5E38\u8FD0\u884C`);
2018
2057
  }
2019
- if (options.realLogin !== void 0 && options.devtoolsLogin === void 0) {
2020
- this.logger.warn("[wxa-runner] realLogin\uFF08--real-login\uFF09\u5DF2\u6539\u540D\u4E3A devtoolsLogin\uFF08--devtools-login\uFF09\uFF0C\u65E7\u540D\u4EE5\u540E\u4F1A\u79FB\u9664");
2021
- }
2022
- this.devtoolsLogin = (options.devtoolsLogin ?? options.realLogin) === true;
2023
- this.ticketSource = this.devtoolsLogin ? developerTicketSource(this.project.projectPath, this.logger) : null;
2058
+ this.devtoolsLogin = options.devtoolsLogin === true;
2059
+ this.devtools = this.devtoolsLogin ? devtoolsSession(this.project.projectPath, this.logger) : null;
2060
+ this.ticketSource = this.devtools?.findTicket ?? null;
2024
2061
  this.plugins = new PluginStore(this.ticketSource && new WechatDevClient(this.project.appid, this.ticketSource), this.logger);
2025
2062
  this.device = { ...DEFAULT_DEVICE, ...options.device };
2026
2063
  this.builder = new AppBuilder(this.project, { wxmlTransform: extended.wxmlTransform });
@@ -2078,7 +2115,10 @@ ${error.message}`);
2078
2115
  this.server = server;
2079
2116
  this.lanAccess = LOCAL_HOST_OF_ANY_ADDRESS.has(host);
2080
2117
  this.address = `http://${LOCAL_HOST_OF_ANY_ADDRESS.get(host) ?? host}:${port}`;
2081
- this.ticketSource?.().then(requireUsableTicket).catch((error) => this.logger.warn(`[wxa-runner] \u5F00\u53D1\u8005\u5DE5\u5177\u7684\u767B\u5F55\u6001\u6682\u4E0D\u53EF\u7528\uFF08--devtools-login\uFF09\uFF1A${error.message}`));
2118
+ this.ticketSource?.().then(requireUsableTicket).catch((error) => {
2119
+ if (error instanceof TicketNotAllowed && this.devtools?.loginCode) return;
2120
+ this.logger.warn(`[wxa-runner] \u5F00\u53D1\u8005\u5DE5\u5177\u7684\u767B\u5F55\u6001\u6682\u4E0D\u53EF\u7528\uFF08--devtools-login\uFF09\uFF1A${error.message}`);
2121
+ });
2082
2122
  return this.address;
2083
2123
  }
2084
2124
  async close() {
@@ -2116,6 +2156,7 @@ ${error.message}`);
2116
2156
  appid: this.project.appid,
2117
2157
  baseLibVersion: this.baseLib.version,
2118
2158
  device: this.device,
2159
+ pageTransition: this.options.pageTransition ?? false,
2119
2160
  devtoolsLogin: this.devtoolsLogin,
2120
2161
  socketProxy: true,
2121
2162
  forwardConsole: this.options.forwardConsole ?? false,
@@ -2257,7 +2298,7 @@ ${error.message}`);
2257
2298
  res.status(404).end();
2258
2299
  }
2259
2300
  });
2260
- if (this.ticketSource) app.use("/__wxa__/api", devtoolsLoginRouter(this.project.appid, this.ticketSource));
2301
+ if (this.devtools) app.use("/__wxa__/api", devtoolsLoginRouter(this.project.appid, this.devtools.findTicket, this.devtools.loginCode));
2261
2302
  app.use("/__wxa__/webview", express2.static(root));
2262
2303
  app.use(express2.static(root));
2263
2304
  app.use((error, _req, res, _next) => {
@@ -2410,17 +2451,96 @@ function findRuntimeDir(explicit) {
2410
2451
  }
2411
2452
  return found;
2412
2453
  }
2454
+
2455
+ // src/server/config.ts
2456
+ import { randomUUID as randomUUID3 } from "crypto";
2457
+ import fs7 from "fs";
2458
+ import path7 from "path";
2459
+ import { pathToFileURL as pathToFileURL2 } from "url";
2460
+ import { transform } from "esbuild";
2461
+ var CONFIG_FILE_NAMES = ["wxa.config.ts", "wxa.config.mts", "wxa.config.js", "wxa.config.mjs", "wxa.config.cjs"];
2462
+ var CONFIG_KEYS = /* @__PURE__ */ new Set([
2463
+ "project",
2464
+ "port",
2465
+ "host",
2466
+ "open",
2467
+ "baselib",
2468
+ "watch",
2469
+ "setup",
2470
+ "devtoolsLogin",
2471
+ "forwardConsole",
2472
+ "extensions",
2473
+ "pageTransition",
2474
+ "webViewWindow"
2475
+ ]);
2476
+ function findConfigFile(dir) {
2477
+ for (const name of CONFIG_FILE_NAMES) {
2478
+ const file = path7.join(dir, name);
2479
+ if (fs7.existsSync(file)) return file;
2480
+ }
2481
+ return null;
2482
+ }
2483
+ async function loadConfigFile(file, warn) {
2484
+ let exported;
2485
+ try {
2486
+ exported = await importConfig(file);
2487
+ } catch (error) {
2488
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6 ${file} \u52A0\u8F7D\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`);
2489
+ }
2490
+ if (typeof exported !== "object" || exported === null || Array.isArray(exported)) {
2491
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6 ${file} \u8981\u9ED8\u8BA4\u5BFC\u51FA\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u5982 export default { port: 3000 }`);
2492
+ }
2493
+ const config = exported;
2494
+ const unknown = Object.keys(config).filter((key) => !CONFIG_KEYS.has(key));
2495
+ if (unknown.length) warn(`\u914D\u7F6E\u6587\u4EF6 ${file} \u91CC\u6709\u4E0D\u8BA4\u8BC6\u7684\u914D\u7F6E\u9879\uFF1A${unknown.join("\u3001")}\uFF0C\u5DF2\u5FFD\u7565`);
2496
+ const dir = path7.dirname(file);
2497
+ const resolve = (value) => path7.resolve(dir, value);
2498
+ return {
2499
+ ...config,
2500
+ project: config.project && resolve(config.project),
2501
+ setup: typeof config.setup === "string" ? resolve(config.setup) : config.setup,
2502
+ extensions: config.extensions?.map((extension) => typeof extension === "string" && extension.startsWith(".") ? resolve(extension) : extension)
2503
+ };
2504
+ }
2505
+ async function importConfig(file) {
2506
+ if (!/\.m?ts$/.test(file)) return defaultExport(await import(pathToFileURL2(file).href));
2507
+ const { code } = await transform(fs7.readFileSync(file, "utf8"), {
2508
+ loader: "ts",
2509
+ format: "esm",
2510
+ platform: "node",
2511
+ sourcefile: file,
2512
+ define: {
2513
+ __dirname: JSON.stringify(path7.dirname(file)),
2514
+ __filename: JSON.stringify(file),
2515
+ "import.meta.url": JSON.stringify(pathToFileURL2(file).href)
2516
+ }
2517
+ });
2518
+ const compiled = `${file}.${randomUUID3()}.mjs`;
2519
+ fs7.writeFileSync(compiled, code);
2520
+ try {
2521
+ return defaultExport(await import(pathToFileURL2(compiled).href));
2522
+ } finally {
2523
+ fs7.rmSync(compiled, { force: true });
2524
+ }
2525
+ }
2526
+ function defaultExport(module) {
2527
+ const exported = module.default;
2528
+ return exported?.__esModule ? exported.default : exported;
2529
+ }
2413
2530
  export {
2414
2531
  AppBuilder,
2532
+ CONFIG_FILE_NAMES,
2415
2533
  DEFAULT_DEVICE,
2416
2534
  DevServer,
2417
2535
  LOCAL_HOST_OF_ANY_ADDRESS,
2418
2536
  MiniProgram,
2419
2537
  bundleSetup,
2420
2538
  createWxConfig,
2539
+ findConfigFile,
2421
2540
  findRuntimeDir,
2422
2541
  findSetupFile,
2423
2542
  handleProxy,
2424
- listen
2543
+ listen,
2544
+ loadConfigFile
2425
2545
  };
2426
2546
  //# sourceMappingURL=index.mjs.map