@dimina-kit/devtools 0.4.0-dev.20260703051110 → 0.4.0-dev.20260703101348

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.
Files changed (55) hide show
  1. package/dist/main/index.bundle.js +395 -49
  2. package/dist/main/ipc/bridge-router.d.ts +8 -0
  3. package/dist/main/ipc/bridge-router.js +352 -38
  4. package/dist/main/services/console-forward/index.d.ts +12 -1
  5. package/dist/main/services/console-forward/index.js +99 -1
  6. package/dist/main/services/diagnostics/index.d.ts +49 -0
  7. package/dist/main/services/diagnostics/index.js +61 -0
  8. package/dist/main/services/network-forward/index.js +32 -0
  9. package/dist/main/services/notifications/renderer-notifier.d.ts +39 -0
  10. package/dist/main/services/notifications/renderer-notifier.js +4 -1
  11. package/dist/main/services/projects/project-repository.js +2 -1
  12. package/dist/main/services/views/simulator-session-policy.js +17 -0
  13. package/dist/main/services/workbench-context.d.ts +10 -0
  14. package/dist/main/services/workspace/workspace-service.js +12 -3
  15. package/dist/main/windows/service-host-window/create.d.ts +15 -1
  16. package/dist/main/windows/service-host-window/create.js +11 -3
  17. package/dist/preload/shared/api-compat.js +18 -55
  18. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  19. package/dist/preload/windows/main.cjs.map +1 -1
  20. package/dist/preload/windows/simulator.cjs +117 -44
  21. package/dist/preload/windows/simulator.cjs.map +3 -3
  22. package/dist/preload/windows/simulator.js +117 -44
  23. package/dist/renderer/assets/index-BwzPwCmM.js +49 -0
  24. package/dist/renderer/assets/{input-Cjk0wSEh.js → input-CTb_le7F.js} +2 -2
  25. package/dist/renderer/assets/ipc-transport-BPWIV5hA.css +1 -0
  26. package/dist/renderer/assets/{ipc-transport-OZS-KmOW.js → ipc-transport-Ck5Xa8Tu.js} +2 -2
  27. package/dist/renderer/assets/popover-B1Zu2UQu.js +2 -0
  28. package/dist/renderer/assets/{select-BQDXi5ih.js → select-ozSk5Pt6.js} +2 -2
  29. package/dist/renderer/assets/{settings-tP3Px2KR.js → settings-CNwGOI22.js} +2 -2
  30. package/dist/renderer/assets/settings-api-DMbMp1Eq.js +2 -0
  31. package/dist/renderer/assets/{workbenchSettings-COhuFF-i.js → workbenchSettings-Cr4EHo5w.js} +2 -2
  32. package/dist/renderer/entries/main/index.html +6 -6
  33. package/dist/renderer/entries/popover/index.html +5 -5
  34. package/dist/renderer/entries/settings/index.html +5 -5
  35. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  36. package/dist/shared/bridge-channels.d.ts +22 -0
  37. package/dist/shared/ipc-channels.d.ts +3 -0
  38. package/dist/shared/ipc-channels.js +9 -0
  39. package/dist/shared/request-core.d.ts +84 -0
  40. package/dist/shared/request-core.js +168 -0
  41. package/dist/shared/simulator-api-metadata.d.ts +22 -17
  42. package/dist/shared/simulator-api-metadata.js +36 -0
  43. package/dist/shared/types.d.ts +7 -4
  44. package/dist/simulator/assets/{device-shell-CiLAPa0I.js → device-shell-C-wcFq3Z.js} +2 -2
  45. package/dist/simulator/assets/{jsx-runtime-CDK-o-S0.js → jsx-runtime-BDTY6fEq.js} +2 -2
  46. package/dist/simulator/assets/simulator-DU3-fS3v.js +10 -0
  47. package/dist/simulator/assets/simulator-mini-app-DzfMfnVM.js +2 -0
  48. package/dist/simulator/simulator.html +2 -2
  49. package/package.json +6 -6
  50. package/dist/renderer/assets/index-D-ksyN1p.js +0 -49
  51. package/dist/renderer/assets/ipc-transport-D5dKIti1.css +0 -1
  52. package/dist/renderer/assets/popover-CQVvOe90.js +0 -2
  53. package/dist/renderer/assets/settings-api-B6x2mhaD.js +0 -2
  54. package/dist/simulator/assets/simulator-Dvnxry3y.js +0 -10
  55. package/dist/simulator/assets/simulator-mini-app-Bt639XL_.js +0 -2
@@ -393,6 +393,9 @@ var ProjectChannel = {
393
393
  CaptureThumbnail: "project:captureThumbnail",
394
394
  GetThumbnail: "project:getThumbnail"
395
395
  };
396
+ var SessionChannel = {
397
+ RuntimeStatus: "session:runtimeStatus"
398
+ };
396
399
  var ProjectFsChannel = {
397
400
  GetRoot: "project:fs:getRoot",
398
401
  ReadFile: "project:fs:readFile",
@@ -1105,6 +1108,9 @@ function createRendererNotifier(ctx) {
1105
1108
  projectStatus(payload) {
1106
1109
  sendToMain(ProjectChannel.Status, payload);
1107
1110
  },
1111
+ sessionRuntimeStatus(payload) {
1112
+ sendToMain(SessionChannel.RuntimeStatus, payload);
1113
+ },
1108
1114
  compileLog(payload) {
1109
1115
  sendToMain(ProjectChannel.CompileLog, payload);
1110
1116
  },
@@ -3927,7 +3933,8 @@ function getProjectPages(dirPath) {
3927
3933
  pages: appJson.pages || [],
3928
3934
  entryPagePath: appJson.entryPagePath || appJson.pages?.[0] || ""
3929
3935
  };
3930
- } catch {
3936
+ } catch (err2) {
3937
+ log2.warn(`Failed to read project pages from ${appJsonPath}`, err2);
3931
3938
  return { pages: [], entryPagePath: "" };
3932
3939
  }
3933
3940
  }
@@ -4029,8 +4036,8 @@ function createWorkspaceService(ctx) {
4029
4036
  let lastClosedProjectPath = "";
4030
4037
  let logGeneration = 0;
4031
4038
  const opLock = createOpLock();
4032
- function sendStatus(status2, message, hotReload) {
4033
- ctx.notify.projectStatus(hotReload ? { status: status2, message, hotReload: true } : { status: status2, message });
4039
+ function sendStatus(status2, message, hotReload, pages, watcherDead) {
4040
+ ctx.notify.projectStatus({ status: status2, message, ...hotReload ? { hotReload: true } : {}, ...pages ? { pages } : {}, ...watcherDead ? { watcher: "dead" } : {} });
4034
4041
  }
4035
4042
  function bestEffort(label, fn) {
4036
4043
  try {
@@ -4091,8 +4098,13 @@ function createWorkspaceService(ctx) {
4091
4098
  sourcemap: true,
4092
4099
  fileTypes: ctx.fileTypes,
4093
4100
  watch: compile.watch,
4094
- onRebuild: () => sendStatus("ready", "\u7F16\u8BD1\u5B8C\u6210\uFF0C\u5DF2\u91CD\u542F", true),
4101
+ onRebuild: () => {
4102
+ const { pages } = getProjectPages(projectPath);
4103
+ sendStatus("ready", "\u7F16\u8BD1\u5B8C\u6210\uFF0C\u5DF2\u91CD\u542F", true, pages.length ? pages : void 0);
4104
+ },
4095
4105
  onBuildError: (err2) => sendStatus("error", String(err2)),
4106
+ // Watcher died mid-session (EMFILE, permission loss, …): non-fatal, so 'ready' stays but `watcher: 'dead'` flags that saves no longer auto-rebuild.
4107
+ onWatcherError: () => sendStatus("ready", "\u6587\u4EF6\u76D1\u542C\u5DF2\u505C\u6B62\uFF0C\u4FDD\u5B58\u4E0D\u518D\u89E6\u53D1\u81EA\u52A8\u7F16\u8BD1", false, void 0, true),
4096
4108
  onLog: (entry) => {
4097
4109
  if (sessionGeneration !== logGeneration) return;
4098
4110
  ctx.notify.compileLog({ stream: entry.stream, text: entry.text, at: Date.now() });
@@ -4957,11 +4969,30 @@ import { app as app12, ipcMain as ipcMain3, protocol as protocol2, session as el
4957
4969
  import path17 from "node:path";
4958
4970
  import { pathToFileURL as pathToFileURL3 } from "node:url";
4959
4971
 
4972
+ // src/shared/request-core.ts
4973
+ var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
4974
+ var MAX_TIMEOUT_MS = 2147483647;
4975
+ function resolveTimeoutBudgetMs(timeout) {
4976
+ const t = Number(timeout);
4977
+ return Number.isFinite(t) && t > 0 && t <= MAX_TIMEOUT_MS ? t : DEFAULT_REQUEST_TIMEOUT_MS;
4978
+ }
4979
+
4960
4980
  // src/shared/simulator-api-metadata.ts
4961
4981
  var PERSISTENT_SIMULATOR_APIS = /* @__PURE__ */ new Set(["audioListen"]);
4962
4982
  function isPersistentSimulatorApi(name) {
4963
4983
  return PERSISTENT_SIMULATOR_APIS.has(name);
4964
4984
  }
4985
+ var NETWORK_BUDGET_SIMULATOR_APIS = /* @__PURE__ */ new Set([
4986
+ "request",
4987
+ "downloadFile",
4988
+ "uploadFile"
4989
+ ]);
4990
+ var API_CALL_WATCHDOG_MS = 5e3;
4991
+ function apiCallWatchdogMs(name, params) {
4992
+ if (!NETWORK_BUDGET_SIMULATOR_APIS.has(name)) return API_CALL_WATCHDOG_MS;
4993
+ const budget = resolveTimeoutBudgetMs(params?.timeout);
4994
+ return Math.min(budget + API_CALL_WATCHDOG_MS, MAX_TIMEOUT_MS);
4995
+ }
4965
4996
 
4966
4997
  // src/main/ipc/session-listener-bag.ts
4967
4998
  function createSessionListenerBag() {
@@ -5128,10 +5159,13 @@ function buildServiceHostSpawnUrl(opts) {
5128
5159
  }
5129
5160
  return url.toString();
5130
5161
  }
5131
- function navigateServiceHost(win, url) {
5162
+ function navigateServiceHost(win, url, opts) {
5132
5163
  const loaded = Promise.resolve(win.loadURL(url)).then(
5133
5164
  () => void 0,
5134
- () => void 0
5165
+ (err2) => {
5166
+ opts?.onLoadFailed?.(err2);
5167
+ return void 0;
5168
+ }
5135
5169
  );
5136
5170
  if (!app10.isPackaged && process.env.NODE_ENV !== "test") {
5137
5171
  const w = win;
@@ -5170,7 +5204,7 @@ function serviceHostSpec(appId, projectPath) {
5170
5204
  }
5171
5205
  function createServiceHostWindow(opts) {
5172
5206
  const win = constructServiceHostWindow({ appId: opts.appId, partition: miniappPartition(opts.appId, opts.projectPath) });
5173
- void navigateServiceHost(win, buildServiceHostSpawnUrl(opts));
5207
+ void navigateServiceHost(win, buildServiceHostSpawnUrl(opts), { onLoadFailed: opts.onLoadFailed });
5174
5208
  return win;
5175
5209
  }
5176
5210
 
@@ -5487,9 +5521,49 @@ function buildForwardScript(level, args) {
5487
5521
  return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}]('[\u89C6\u56FE]',...a)}catch(_){}})()
5488
5522
  //# sourceURL=${RENDER_FORWARD_SOURCE_URL}`;
5489
5523
  }
5490
- function createConsoleForwarder(bridge) {
5524
+ var DIAGNOSTIC_CONSOLE_CALL = {
5525
+ error: "console.error",
5526
+ warn: "console.warn",
5527
+ info: "console.info"
5528
+ };
5529
+ function buildDiagnosticScript(severity, message) {
5530
+ const call = DIAGNOSTIC_CONSOLE_CALL[severity];
5531
+ const argsJson = JSON.stringify([`[dimina-kit] ${message}`]);
5532
+ return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});${call}(...a)}catch(_){}})()
5533
+ //# sourceURL=${RENDER_FORWARD_SOURCE_URL}`;
5534
+ }
5535
+ function createConsoleForwarder(bridge, diagnostics) {
5491
5536
  const sinks = /* @__PURE__ */ new Set();
5492
5537
  const registry = new DisposableRegistry4();
5538
+ const pendingBySession = /* @__PURE__ */ new Map();
5539
+ const pendingGlobal = [];
5540
+ const readySessions = /* @__PURE__ */ new Set();
5541
+ function injectDiagnostic(wc, d) {
5542
+ wc.executeJavaScript(buildDiagnosticScript(d.severity, d.message), true).catch(() => {
5543
+ });
5544
+ }
5545
+ function handleDiagnostic(d) {
5546
+ if (d.appSessionId) {
5547
+ const wc2 = readySessions.has(d.appSessionId) && bridge.getServiceWcForBridge ? bridge.getServiceWcForBridge(d.appSessionId) : null;
5548
+ if (wc2 && !wc2.isDestroyed()) {
5549
+ injectDiagnostic(wc2, d);
5550
+ return;
5551
+ }
5552
+ const bucket = pendingBySession.get(d.appSessionId);
5553
+ if (bucket) bucket.push(d);
5554
+ else pendingBySession.set(d.appSessionId, [d]);
5555
+ return;
5556
+ }
5557
+ const wc = bridge.getServiceWc();
5558
+ if (wc && !wc.isDestroyed()) {
5559
+ injectDiagnostic(wc, d);
5560
+ return;
5561
+ }
5562
+ pendingGlobal.push(d);
5563
+ }
5564
+ if (diagnostics) {
5565
+ registry.add(diagnostics.subscribe(handleDiagnostic, { replay: true }));
5566
+ }
5493
5567
  function forwardRenderToServiceHost(entry) {
5494
5568
  let wc = null;
5495
5569
  if (entry.bridgeId && bridge.getServiceWcForBridge) {
@@ -5526,13 +5600,84 @@ function createConsoleForwarder(bridge) {
5526
5600
  sinks.delete(sink);
5527
5601
  }));
5528
5602
  },
5603
+ notifyServiceHostReady(appSessionId) {
5604
+ readySessions.add(appSessionId);
5605
+ const wc = bridge.getServiceWcForBridge ? bridge.getServiceWcForBridge(appSessionId) : null;
5606
+ if (!wc) return;
5607
+ const sessionEntries = pendingBySession.get(appSessionId);
5608
+ if (sessionEntries) {
5609
+ for (const d of sessionEntries) injectDiagnostic(wc, d);
5610
+ pendingBySession.delete(appSessionId);
5611
+ }
5612
+ if (pendingGlobal.length) {
5613
+ for (const d of pendingGlobal) injectDiagnostic(wc, d);
5614
+ pendingGlobal.length = 0;
5615
+ }
5616
+ },
5529
5617
  dispose() {
5530
5618
  sinks.clear();
5619
+ pendingBySession.clear();
5620
+ pendingGlobal.length = 0;
5621
+ readySessions.clear();
5531
5622
  return registry.disposeAll();
5532
5623
  }
5533
5624
  };
5534
5625
  }
5535
5626
 
5627
+ // src/main/services/diagnostics/index.ts
5628
+ var DEFAULT_BUFFER_CAP = 200;
5629
+ var CONSOLE_METHOD = {
5630
+ error: "error",
5631
+ warn: "warn",
5632
+ info: "info"
5633
+ };
5634
+ function createDiagnosticsBus(opts) {
5635
+ const bufferCap = opts?.bufferCap && opts.bufferCap > 0 ? opts.bufferCap : DEFAULT_BUFFER_CAP;
5636
+ const buffer = [];
5637
+ const sinks = /* @__PURE__ */ new Set();
5638
+ let disposed = false;
5639
+ return {
5640
+ report(d) {
5641
+ if (disposed) return;
5642
+ const entry = { ...d, ts: Date.now() };
5643
+ buffer.push(entry);
5644
+ if (buffer.length > bufferCap) buffer.shift();
5645
+ console[CONSOLE_METHOD[entry.severity]](`[dimina-kit:${entry.code}] ${entry.message}`);
5646
+ for (const sink of sinks) {
5647
+ try {
5648
+ sink(entry);
5649
+ } catch {
5650
+ }
5651
+ }
5652
+ },
5653
+ subscribe(sink, subOpts) {
5654
+ const replay = subOpts?.replay ?? true;
5655
+ if (replay) {
5656
+ for (const entry of buffer) {
5657
+ try {
5658
+ sink(entry);
5659
+ } catch {
5660
+ }
5661
+ }
5662
+ }
5663
+ sinks.add(sink);
5664
+ let released = false;
5665
+ return {
5666
+ dispose() {
5667
+ if (released) return;
5668
+ released = true;
5669
+ sinks.delete(sink);
5670
+ }
5671
+ };
5672
+ },
5673
+ dispose() {
5674
+ disposed = true;
5675
+ sinks.clear();
5676
+ buffer.length = 0;
5677
+ }
5678
+ };
5679
+ }
5680
+
5536
5681
  // src/main/services/simulator-storage/index.ts
5537
5682
  import { app as app11, webContents as wcStatic } from "electron";
5538
5683
  import { DisposableRegistry as DisposableRegistry5 } from "@dimina-kit/electron-deck/main";
@@ -6103,6 +6248,7 @@ function rewriteSourceMappingUrl(source, scriptUrl) {
6103
6248
  //# sourceMappingURL=${absolute}`;
6104
6249
  }
6105
6250
  var STACK_ID = "stack_0";
6251
+ var LAUNCH_TIMEOUT_MS = 2e4;
6106
6252
  var PREWARM_MAX_POOL_SIZE = 4;
6107
6253
  function resolvePrewarmPoolSize() {
6108
6254
  if (process.env.DIMINA_PREWARM_DISABLE === "1") return 0;
@@ -6124,7 +6270,6 @@ function summarizeBridgeMsg(payload) {
6124
6270
  const parts = [type, bridgeId ? `bridge=${bridgeId}` : void 0].filter(Boolean);
6125
6271
  return parts.length > 0 ? parts.join(" ") : void 0;
6126
6272
  }
6127
- var API_CALL_TIMEOUT_MS = 5e3;
6128
6273
  function findAppSessionByAppId(state, appId) {
6129
6274
  let match;
6130
6275
  for (const ap of state.appSessions.values()) if (ap.appId === appId) match = ap;
@@ -6294,13 +6439,20 @@ function installBridgeRouter(ctx) {
6294
6439
  ;
6295
6440
  globalThis.__diminaResourceCensus = () => bridgeHandle.census?.();
6296
6441
  }
6297
- const consoleForwarder = createConsoleForwarder(bridgeHandle);
6442
+ const ownsDiagnosticsBus = ctx.diagnostics === void 0;
6443
+ const diagnosticsBus = ctx.diagnostics ?? createDiagnosticsBus();
6444
+ ctx.diagnostics = diagnosticsBus;
6445
+ const consoleForwarder = createConsoleForwarder(bridgeHandle, diagnosticsBus);
6298
6446
  ctx.consoleForwarder = consoleForwarder;
6299
6447
  ctx.guestConsole = consoleForwarder;
6300
6448
  ctx.registry.add(() => {
6301
6449
  void consoleForwarder.dispose();
6302
6450
  ctx.consoleForwarder = void 0;
6303
6451
  ctx.guestConsole = void 0;
6452
+ if (ownsDiagnosticsBus) {
6453
+ diagnosticsBus.dispose();
6454
+ ctx.diagnostics = void 0;
6455
+ }
6304
6456
  });
6305
6457
  const onActivePage = (event, payload) => {
6306
6458
  const ap = state.appSessions.get(payload.appSessionId);
@@ -6460,6 +6612,39 @@ function installBridgeRouter(ctx) {
6460
6612
  );
6461
6613
  });
6462
6614
  }
6615
+ function clearLaunchTimer(ap) {
6616
+ if (ap.launchTimer === null) return;
6617
+ clearTimeout(ap.launchTimer);
6618
+ ap.launchTimer = null;
6619
+ }
6620
+ function startLaunchTimer(state, ctx, ap) {
6621
+ ap.launchTimer = setTimeout(() => {
6622
+ ap.launchTimer = null;
6623
+ if (ap.running) return;
6624
+ if (state.appSessions.get(ap.appSessionId) !== ap) return;
6625
+ const reason = `Service host did not report readiness within ${LAUNCH_TIMEOUT_MS}ms`;
6626
+ ctx.diagnostics?.report({
6627
+ severity: "error",
6628
+ code: "launch-timeout",
6629
+ message: reason,
6630
+ appSessionId: ap.appSessionId
6631
+ });
6632
+ pushRuntimeStatus(ctx, ap, { phase: "launch-failed", code: "timeout", reason });
6633
+ }, LAUNCH_TIMEOUT_MS);
6634
+ }
6635
+ function markSessionRunning(ctx, ap, page) {
6636
+ if (!page.isRoot || ap.running) return;
6637
+ ap.running = true;
6638
+ clearLaunchTimer(ap);
6639
+ pushRuntimeStatus(ctx, ap, { phase: "running" });
6640
+ }
6641
+ function pushRuntimeStatus(ctx, session5, status2) {
6642
+ ctx.notify?.sessionRuntimeStatus?.({
6643
+ appId: session5.appId,
6644
+ ...status2,
6645
+ ...session5.pageFallback ? { pageFallback: session5.pageFallback } : {}
6646
+ });
6647
+ }
6463
6648
  async function handleSpawn(state, ctx, event, opts) {
6464
6649
  const appId = opts.appId;
6465
6650
  if (!appId) throw new Error("[bridge-router] spawn requires appId");
@@ -6485,20 +6670,48 @@ async function handleSpawn(state, ctx, event, opts) {
6485
6670
  ...selectedDevice ? deviceInfoToHostEnv(selectedDevice) : {}
6486
6671
  });
6487
6672
  const appConfig = await loadAppConfig(
6488
- resourceServer ? resourceServer.baseUrl : `${resourceBaseUrl}${appId}/${root}/`
6673
+ resourceServer ? resourceServer.baseUrl : `${resourceBaseUrl}${appId}/${root}/`,
6674
+ ({ url, error }) => {
6675
+ ctx.diagnostics?.report({
6676
+ severity: "error",
6677
+ code: "app-config-unreachable",
6678
+ message: `app-config.json unreachable at ${url}: ${String(error)}`,
6679
+ appSessionId
6680
+ });
6681
+ }
6489
6682
  );
6490
6683
  const manifest = buildAppManifest(appConfig, pagePath);
6491
- const rootWindowConfig = resolvePageWindowConfig(appConfig, pagePath);
6492
- const isTab = isTabPage(appConfig, pagePath);
6684
+ const { resolvedPagePath, pageFallbackApplied } = resolveRootPagePath(manifest, pagePath);
6685
+ if (pageFallbackApplied) {
6686
+ reportPageNotFound(ctx, appSessionId, pagePath, resolvedPagePath);
6687
+ }
6688
+ const rootWindowConfig = resolvePageWindowConfig(appConfig, resolvedPagePath);
6689
+ const isTab = isTabPage(appConfig, resolvedPagePath);
6493
6690
  const usedPool = state.pool !== null;
6494
6691
  let poolEntryId = null;
6495
6692
  let serviceWindow;
6693
+ const reportServiceHostNavigationFailed = (spawnUrl, err2) => {
6694
+ const message = `Failed to navigate service host to ${spawnUrl}: ${String(err2)}`;
6695
+ ctx.diagnostics?.report({
6696
+ severity: "error",
6697
+ code: "service-host-navigation-failed",
6698
+ message,
6699
+ appSessionId
6700
+ });
6701
+ const ap = state.appSessions.get(appSessionId);
6702
+ if (ap) clearLaunchTimer(ap);
6703
+ pushRuntimeStatus(
6704
+ ctx,
6705
+ ap ?? { appId, pageFallback: pageFallbackApplied ? { requested: pagePath, resolved: resolvedPagePath } : null },
6706
+ { phase: "launch-failed", code: "service-host-navigation-failed", reason: message }
6707
+ );
6708
+ };
6496
6709
  if (state.pool) {
6497
6710
  const acquired = await state.pool.acquire(serviceHostSpec());
6498
6711
  serviceWindow = acquired.win;
6499
6712
  poolEntryId = acquired.entryId;
6500
6713
  } else {
6501
- serviceWindow = createServiceHostWindow({
6714
+ const freshWindowOptions = {
6502
6715
  bridgeId,
6503
6716
  appId,
6504
6717
  // Same (appId, projectPath) pair the simulator WCV uses, so this project's
@@ -6508,12 +6721,16 @@ async function handleSpawn(state, ctx, event, opts) {
6508
6721
  // awaits above would otherwise give the service host a different path than
6509
6722
  // the simulator WCV was built with, splitting the partition.
6510
6723
  projectPath: workspaceProjectPath || void 0,
6511
- pagePath,
6724
+ pagePath: resolvedPagePath,
6512
6725
  pkgRoot,
6513
6726
  root,
6514
6727
  resourceBaseUrl,
6515
6728
  hostEnvSnapshot: hostEnv,
6516
6729
  apiNamespaces
6730
+ };
6731
+ serviceWindow = createServiceHostWindow({
6732
+ ...freshWindowOptions,
6733
+ onLoadFailed: (err2) => reportServiceHostNavigationFailed(buildServiceHostSpawnUrl(freshWindowOptions), err2)
6517
6734
  });
6518
6735
  }
6519
6736
  const appSession = {
@@ -6537,12 +6754,15 @@ async function handleSpawn(state, ctx, event, opts) {
6537
6754
  poolEntryId,
6538
6755
  onServiceBoot: null,
6539
6756
  listenerBag: createSessionListenerBag(),
6540
- registryHandle: null
6757
+ registryHandle: null,
6758
+ running: false,
6759
+ launchTimer: null,
6760
+ pageFallback: pageFallbackApplied ? { requested: pagePath, resolved: resolvedPagePath } : null
6541
6761
  };
6542
6762
  const rootPage = {
6543
6763
  bridgeId,
6544
6764
  appSessionId,
6545
- pagePath,
6765
+ pagePath: resolvedPagePath,
6546
6766
  query: opts.query ?? {},
6547
6767
  isRoot: true,
6548
6768
  isTab,
@@ -6587,28 +6807,43 @@ async function handleSpawn(state, ctx, event, opts) {
6587
6807
  };
6588
6808
  appSession.onServiceBoot = bootOnServiceLoad;
6589
6809
  serviceWindow.webContents.on("did-finish-load", bootOnServiceLoad);
6590
- void navigateServiceHost(
6591
- serviceWindow,
6592
- buildServiceHostSpawnUrl({
6593
- bridgeId,
6594
- appId,
6595
- pagePath,
6596
- pkgRoot,
6597
- root,
6598
- resourceBaseUrl,
6599
- hostEnvSnapshot: hostEnv,
6600
- apiNamespaces
6601
- })
6602
- );
6810
+ const spawnUrl = buildServiceHostSpawnUrl({
6811
+ bridgeId,
6812
+ appId,
6813
+ pagePath: resolvedPagePath,
6814
+ pkgRoot,
6815
+ root,
6816
+ resourceBaseUrl,
6817
+ hostEnvSnapshot: hostEnv,
6818
+ apiNamespaces
6819
+ });
6820
+ void navigateServiceHost(serviceWindow, spawnUrl, {
6821
+ onLoadFailed: (err2) => reportServiceHostNavigationFailed(spawnUrl, err2)
6822
+ });
6603
6823
  } else {
6604
6824
  serviceWindow.webContents.once("did-finish-load", () => {
6605
6825
  void bootServiceHost(state, appSession, ctx);
6606
6826
  });
6607
6827
  }
6828
+ const onServiceCrashed = () => {
6829
+ clearLaunchTimer(appSession);
6830
+ ctx.diagnostics?.report({
6831
+ severity: "error",
6832
+ code: "service-host-crashed",
6833
+ message: `Service host renderer process gone for appSessionId=${appSessionId}`,
6834
+ appSessionId
6835
+ });
6836
+ pushRuntimeStatus(ctx, appSession, { phase: "crashed", code: "service-host-crashed" });
6837
+ };
6838
+ appSession.listenerBag.on(serviceWindow.webContents, "render-process-gone", onServiceCrashed);
6839
+ pushRuntimeStatus(ctx, appSession, { phase: "launching" });
6840
+ startLaunchTimer(state, ctx, appSession);
6608
6841
  return {
6609
6842
  appSessionId,
6610
6843
  bridgeId,
6611
6844
  pagePath,
6845
+ resolvedPagePath,
6846
+ pageFallbackApplied,
6612
6847
  serviceWcId: serviceWindow.webContents.id,
6613
6848
  resourceBaseUrl,
6614
6849
  manifest,
@@ -6622,6 +6857,9 @@ async function handlePageOpen(state, event, opts) {
6622
6857
  throw new Error("[bridge-router] PAGE_OPEN rejected: caller not bound to app session");
6623
6858
  }
6624
6859
  const pagePath = normalizePagePath(opts.pagePath);
6860
+ if (ap.manifest.source === "app-config" && !ap.manifest.pages.includes(pagePath)) {
6861
+ throw new Error(`[bridge-router] PAGE_OPEN rejected: page-not-found "${pagePath}" is not in the compiled manifest`);
6862
+ }
6625
6863
  const bridgeId = opts.bridgeId || newBridgeId();
6626
6864
  const windowConfig = resolvePageWindowConfig(ap.appConfig, pagePath);
6627
6865
  const isTab = isTabPage(ap.appConfig, pagePath);
@@ -6681,15 +6919,18 @@ function handleNavCallback(state, sender, payload) {
6681
6919
  }
6682
6920
  async function bootServiceHost(state, ap, ctx) {
6683
6921
  if (state.appSessions.get(ap.appSessionId) !== ap) return;
6922
+ ctx.consoleForwarder?.notifyServiceHostReady?.(ap.appSessionId);
6684
6923
  ap.logicInjected = await injectLogicBundle(ap);
6685
6924
  if (!ap.logicInjected) {
6686
- reportLogicLoadFailure(ap, ctx);
6925
+ const reason = reportLogicLoadFailure(ap, ctx);
6926
+ clearLaunchTimer(ap);
6927
+ pushRuntimeStatus(ctx, ap, { phase: "launch-failed", code: "logic-bundle-unreachable", reason });
6687
6928
  return;
6688
6929
  }
6689
6930
  const rootPage = ap.pages.get(ap.appSessionId);
6690
6931
  const rootMissing = !!rootPage && !pageInManifest(ap, rootPage.pagePath);
6691
6932
  if (rootMissing) {
6692
- reportPageNotFound(ap, ctx, rootPage.pagePath);
6933
+ reportPageNotFound(ctx, ap.appSessionId, rootPage.pagePath);
6693
6934
  } else if (rootPage) {
6694
6935
  forwardToService(ap, makeLoadResource(ap, rootPage, "service"));
6695
6936
  }
@@ -6723,16 +6964,30 @@ async function injectLogicBundle(ap) {
6723
6964
  }
6724
6965
  function reportLogicLoadFailure(ap, ctx) {
6725
6966
  const hint = ap.appId === "unknown" ? ' appId could not be resolved (it fell back to "unknown") \u2014 the mini-program likely failed to compile or its project manifest/app config is missing.' : "";
6726
- const message = `[dimina-kit] Failed to load the mini-program logic bundle from ${logicBundleUrl(ap)}. The service runtime has no registered modules, so no page can mount.` + hint + ` Verify the project compiled successfully and that the resource server serves "${ap.appId}/${ap.root}/".`;
6727
- console.error(message);
6967
+ const shortReason = `[dimina-kit] Failed to load the mini-program logic bundle from ${logicBundleUrl(ap)}.`;
6968
+ const message = `${shortReason} The service runtime has no registered modules, so no page can mount.` + hint + ` Verify the project compiled successfully and that the resource server serves "${ap.appId}/${ap.root}/".`;
6969
+ ctx.diagnostics?.report({
6970
+ severity: "error",
6971
+ code: "logic-bundle-unreachable",
6972
+ message,
6973
+ appSessionId: ap.appSessionId
6974
+ });
6728
6975
  ctx.guestConsole?.emit({ source: "service", level: "error", args: [message] });
6976
+ return shortReason;
6729
6977
  }
6730
6978
  function pageInManifest(ap, pagePath) {
6979
+ if (ap.manifest.source !== "app-config") return true;
6731
6980
  return ap.manifest.pages.includes(normalizePagePath(pagePath));
6732
6981
  }
6733
- function reportPageNotFound(ap, ctx, pagePath) {
6734
- const message = `Page[${pagePath}] not found. May be caused by: 1. Forgetting to add page route in app.json. 2. Invoking Page() in async task.`;
6735
- console.error(`[bridge-router] ${message}`);
6982
+ function reportPageNotFound(ctx, appSessionId, pagePath, fallbackTo) {
6983
+ const base = `Page[${pagePath}] not found. May be caused by: 1. Forgetting to add page route in app.json. 2. Invoking Page() in async task.`;
6984
+ const message = fallbackTo ? `${base} Falling back to "${fallbackTo}".` : base;
6985
+ ctx.diagnostics?.report({
6986
+ severity: "error",
6987
+ code: "page-not-found",
6988
+ message,
6989
+ appSessionId
6990
+ });
6736
6991
  ctx.guestConsole?.emit({ source: "service", level: "error", args: [message] });
6737
6992
  }
6738
6993
  function maybeSendResourceLoaded(ap, page) {
@@ -6789,6 +7044,11 @@ function routeFromRender(state, ap, page, msg, ctx) {
6789
7044
  handleContainerMsg(ap, page, msg, ctx, state);
6790
7045
  }
6791
7046
  }
7047
+ function reportServiceUncaughtError(ctx, ap, body) {
7048
+ const severity = body.level === "error" ? "error" : body.level === "warn" ? "warn" : "info";
7049
+ const message = Array.isArray(body.args) ? body.args.map((a) => String(a)).join(" ") : String(body.args ?? "");
7050
+ ctx.diagnostics?.report({ severity, code: "service-uncaught-error", message, appSessionId: ap.appSessionId });
7051
+ }
6792
7052
  function handleContainerMsg(ap, page, msg, ctx, state) {
6793
7053
  switch (msg.type) {
6794
7054
  case "serviceResourceLoaded":
@@ -6807,22 +7067,31 @@ function handleContainerMsg(ap, page, msg, ctx, state) {
6807
7067
  ap.simulatorWc.send(SIMULATOR_EVENTS.DOM_READY, { bridgeId: page.bridgeId });
6808
7068
  }
6809
7069
  state.emitRenderEvent({ kind: "domReady", appId: ap.appId, bridgeId: page.bridgeId });
7070
+ markSessionRunning(ctx, ap, page);
6810
7071
  break;
6811
7072
  case "invokeAPI":
6812
7073
  void handleSimulatorApi(state, ap, page, msg.body, ctx);
6813
7074
  break;
6814
7075
  case "serviceHostError": {
6815
- console.warn("[bridge-router] service host error:", msg.body);
6816
7076
  const errBody = msg.body;
6817
7077
  const errArg = errBody?.message ?? msg.body;
7078
+ ctx.diagnostics?.report({
7079
+ severity: "error",
7080
+ code: "service-host-error",
7081
+ message: String(errArg),
7082
+ appSessionId: ap.appSessionId
7083
+ });
6818
7084
  for (const id of state.appLifecycle.listeners(ap.appSessionId, "onError")) {
6819
7085
  sendCallback(ap, id, errArg);
6820
7086
  }
6821
7087
  break;
6822
7088
  }
6823
- case "consoleLog":
7089
+ case "consoleLog": {
6824
7090
  ctx.guestConsole?.emit(msg.body);
7091
+ const body = msg.body;
7092
+ if (body?.source === "service") reportServiceUncaughtError(ctx, ap, body);
6825
7093
  break;
7094
+ }
6826
7095
  case "storageChanged":
6827
7096
  ctx.onServiceStorageChanged?.(ap.appId, msg.body);
6828
7097
  break;
@@ -6903,16 +7172,44 @@ function handleNavBarApi(ap, page, name, params) {
6903
7172
  sendCallback(ap, params.success, successResult);
6904
7173
  sendCallback(ap, params.complete, successResult);
6905
7174
  }
7175
+ function failActionCallback(ap, params, errMsg) {
7176
+ const fail = { errMsg };
7177
+ sendCallback(ap, params.fail, fail);
7178
+ sendCallback(ap, params.complete, fail);
7179
+ }
6906
7180
  function sendActionOrFail(ap, eventName, payload, name, params) {
6907
7181
  if (!ap.simulatorWc.isDestroyed()) {
6908
7182
  ap.simulatorWc.send(eventName, payload);
6909
7183
  return;
6910
7184
  }
6911
- const fail = { errMsg: `${name}:fail simulator window destroyed` };
6912
- sendCallback(ap, params.fail, fail);
6913
- sendCallback(ap, params.complete, fail);
7185
+ failActionCallback(ap, params, `${name}:fail simulator window destroyed`);
7186
+ }
7187
+ function extractNavTargetPagePath(params) {
7188
+ const raw = params.url;
7189
+ if (typeof raw !== "string" || !raw) return void 0;
7190
+ return normalizePagePath(raw.split("?")[0] ?? raw);
6914
7191
  }
6915
- function handleNavActionApi(ap, page, name, params) {
7192
+ function checkNavTarget(ap, name, targetPagePath) {
7193
+ if (ap.manifest.source !== "app-config") return { ok: true };
7194
+ if (!ap.manifest.pages.includes(targetPagePath)) {
7195
+ return { ok: false, errMsg: `${name}:fail page "${targetPagePath}" is not found`, reportNotFound: true };
7196
+ }
7197
+ if (name === "switchTab") {
7198
+ const inTabBar = ap.manifest.tabBar?.list.some((item) => normalizePagePath(item.pagePath) === targetPagePath) ?? false;
7199
+ if (!inTabBar) return { ok: false, errMsg: "switchTab:fail can not switch to no-tabBar page" };
7200
+ }
7201
+ return { ok: true };
7202
+ }
7203
+ function handleNavActionApi(ap, ctx, page, name, params) {
7204
+ const targetPagePath = extractNavTargetPagePath(params);
7205
+ if (targetPagePath !== void 0) {
7206
+ const verdict = checkNavTarget(ap, name, targetPagePath);
7207
+ if (!verdict.ok) {
7208
+ if (verdict.reportNotFound) reportPageNotFound(ctx, ap.appSessionId, targetPagePath);
7209
+ failActionCallback(ap, params, verdict.errMsg);
7210
+ return;
7211
+ }
7212
+ }
6916
7213
  const payload = {
6917
7214
  appSessionId: ap.appSessionId,
6918
7215
  bridgeId: page.bridgeId,
@@ -6974,7 +7271,7 @@ async function handleSimulatorApi(state, ap, page, body, ctx) {
6974
7271
  return;
6975
7272
  }
6976
7273
  if (NAV_ACTION_NAMES.has(name)) {
6977
- handleNavActionApi(ap, page, name, params);
7274
+ handleNavActionApi(ap, ctx, page, name, params);
6978
7275
  return;
6979
7276
  }
6980
7277
  if (TAB_ACTION_NAMES.has(name)) {
@@ -7016,7 +7313,7 @@ function forwardApiCallToSimulator(state, ap, page, name, params) {
7016
7313
  const fail = { errMsg: `${pending.name}:fail no handler (timeout)` };
7017
7314
  sendCallback(target, pending.callbacks.fail, fail);
7018
7315
  sendCallback(target, pending.callbacks.complete, fail);
7019
- }, API_CALL_TIMEOUT_MS);
7316
+ }, apiCallWatchdogMs(name, params));
7020
7317
  state.pendingApiCalls.set(requestId, {
7021
7318
  appSessionId: ap.appSessionId,
7022
7319
  callbacks,
@@ -7065,7 +7362,12 @@ function handleApiResponse(state, sender, payload) {
7065
7362
  sendCallback(ap, pending.callbacks.success, payload.result);
7066
7363
  sendCallback(ap, pending.callbacks.complete, payload.result ?? { errMsg: `${pending.name}:ok` });
7067
7364
  } else {
7068
- const fail = { errMsg: payload.errMsg ?? `${pending.name}:fail` };
7365
+ const result = payload.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? payload.result : void 0;
7366
+ const resultErrMsg = typeof result?.errMsg === "string" ? result.errMsg : void 0;
7367
+ const fail = {
7368
+ ...result,
7369
+ errMsg: payload.errMsg || resultErrMsg || `${pending.name}:fail`
7370
+ };
7069
7371
  sendCallback(ap, pending.callbacks.fail, fail);
7070
7372
  sendCallback(ap, pending.callbacks.complete, fail);
7071
7373
  }
@@ -7259,6 +7561,7 @@ async function disposeAppSession(state, appSessionId, opts = {}) {
7259
7561
  const ap = state.appSessions.get(appSessionId);
7260
7562
  if (!ap) return;
7261
7563
  state.appSessions.delete(appSessionId);
7564
+ clearLaunchTimer(ap);
7262
7565
  const registryHandle = ap.registryHandle;
7263
7566
  ap.registryHandle = null;
7264
7567
  void registryHandle?.dispose();
@@ -7276,25 +7579,45 @@ async function disposeAppSession(state, appSessionId, opts = {}) {
7276
7579
  });
7277
7580
  }
7278
7581
  }
7279
- async function loadAppConfig(resourceBase) {
7582
+ async function loadAppConfig(resourceBase, onUnreachable) {
7280
7583
  const cfgUrl = new URL("app-config.json", resourceBase.endsWith("/") ? resourceBase : `${resourceBase}/`).toString();
7281
7584
  try {
7282
7585
  const res = await fetch(cfgUrl);
7283
7586
  if (!res.ok) {
7587
+ const error = new Error(`app-config.json fetch ${res.status} at ${cfgUrl}`);
7284
7588
  console.warn(`[bridge-router] no app-config.json at ${cfgUrl} (${res.status})`);
7589
+ onUnreachable?.({ url: cfgUrl, error });
7285
7590
  return {};
7286
7591
  }
7287
7592
  return await res.json();
7288
7593
  } catch (error) {
7289
7594
  console.warn("[bridge-router] failed to fetch/parse app-config.json:", error);
7595
+ onUnreachable?.({ url: cfgUrl, error });
7290
7596
  return {};
7291
7597
  }
7292
7598
  }
7293
7599
  function buildAppManifest(appConfig, fallbackEntry) {
7294
7600
  const entry = appConfig.app?.entryPagePath || fallbackEntry;
7295
- const pages = appConfig.app?.pages?.length ? appConfig.app.pages : [entry];
7601
+ const hasCompiledPages = !!appConfig.app?.pages?.length;
7602
+ const pages = hasCompiledPages ? appConfig.app.pages : [entry];
7296
7603
  const tabBar = appConfig.app?.tabBar && Array.isArray(appConfig.app.tabBar.list) && appConfig.app.tabBar.list.length > 0 ? appConfig.app.tabBar : void 0;
7297
- return { entryPagePath: normalizePagePath(entry), pages: pages.map(normalizePagePath), tabBar };
7604
+ return {
7605
+ entryPagePath: normalizePagePath(entry),
7606
+ pages: pages.map(normalizePagePath),
7607
+ tabBar,
7608
+ // 'app-config' means `pages` above is the real compiled list mount gates
7609
+ // can trust; 'fallback' means app-config.json was unreachable and `pages`
7610
+ // is just the single requested page — nothing to validate membership
7611
+ // against, so every gate keyed on this source lets it through unchanged.
7612
+ source: hasCompiledPages ? "app-config" : "fallback"
7613
+ };
7614
+ }
7615
+ function resolveRootPagePath(manifest, requestedPagePath) {
7616
+ if (manifest.source !== "app-config" || manifest.pages.includes(requestedPagePath)) {
7617
+ return { resolvedPagePath: requestedPagePath, pageFallbackApplied: false };
7618
+ }
7619
+ const resolvedPagePath = manifest.pages.includes(manifest.entryPagePath) ? manifest.entryPagePath : manifest.pages[0];
7620
+ return { resolvedPagePath, pageFallbackApplied: true };
7298
7621
  }
7299
7622
  function resolvePageWindowConfig(appConfig, pagePath) {
7300
7623
  const normalized = normalizePagePath(pagePath);
@@ -8971,6 +9294,7 @@ function createNetworkForwarder(bridge) {
8971
9294
  let sink = "idle";
8972
9295
  let probeConsoleBuffer = [];
8973
9296
  let readyTimeoutTimer = null;
9297
+ let probeDeadline = null;
8974
9298
  let dispatchQueue = [];
8975
9299
  let flushScheduled = false;
8976
9300
  let readyRetryTimer = null;
@@ -8981,6 +9305,7 @@ function createNetworkForwarder(bridge) {
8981
9305
  function beginProbing() {
8982
9306
  if (sink === "probing") return;
8983
9307
  sink = "probing";
9308
+ probeDeadline = Date.now() + DEVTOOLS_READY_TIMEOUT_MS;
8984
9309
  if (readyTimeoutTimer) clearTimeout(readyTimeoutTimer);
8985
9310
  readyTimeoutTimer = setTimeout(() => {
8986
9311
  readyTimeoutTimer = null;
@@ -8989,6 +9314,7 @@ function createNetworkForwarder(bridge) {
8989
9314
  }
8990
9315
  function markReady() {
8991
9316
  sink = "ready";
9317
+ probeDeadline = null;
8992
9318
  if (readyTimeoutTimer) {
8993
9319
  clearTimeout(readyTimeoutTimer);
8994
9320
  readyTimeoutTimer = null;
@@ -9001,6 +9327,7 @@ function createNetworkForwarder(bridge) {
9001
9327
  }
9002
9328
  function degradeToConsole() {
9003
9329
  sink = "degraded";
9330
+ probeDeadline = null;
9004
9331
  dispatchQueue = [];
9005
9332
  if (readyTimeoutTimer) {
9006
9333
  clearTimeout(readyTimeoutTimer);
@@ -9105,9 +9432,17 @@ function createNetworkForwarder(bridge) {
9105
9432
  }
9106
9433
  function scheduleReadyRetry() {
9107
9434
  if (readyRetryTimer || sink === "ready" || sink === "degraded") return;
9435
+ if (probeDeadline !== null && Date.now() >= probeDeadline) {
9436
+ degradeToConsole();
9437
+ return;
9438
+ }
9108
9439
  readyRetryTimer = setTimeout(() => {
9109
9440
  readyRetryTimer = null;
9110
9441
  if (sink === "degraded") return;
9442
+ if (probeDeadline !== null && Date.now() >= probeDeadline) {
9443
+ degradeToConsole();
9444
+ return;
9445
+ }
9111
9446
  if (dispatchQueue.length > 0) scheduleFlush();
9112
9447
  }, READY_RETRY_MS);
9113
9448
  }
@@ -9146,6 +9481,7 @@ function createNetworkForwarder(bridge) {
9146
9481
  dispatchQueue = [];
9147
9482
  probeConsoleBuffer = [];
9148
9483
  sink = "idle";
9484
+ probeDeadline = null;
9149
9485
  if (readyRetryTimer) {
9150
9486
  clearTimeout(readyRetryTimer);
9151
9487
  readyRetryTimer = null;
@@ -9296,6 +9632,7 @@ function createNetworkForwarder(bridge) {
9296
9632
  clearTimeout(readyRetryTimer);
9297
9633
  readyRetryTimer = null;
9298
9634
  }
9635
+ probeDeadline = null;
9299
9636
  probeConsoleBuffer = [];
9300
9637
  if (!devtoolsWc) {
9301
9638
  sink = "idle";
@@ -9319,6 +9656,7 @@ function createNetworkForwarder(bridge) {
9319
9656
  }
9320
9657
  });
9321
9658
  }
9659
+ sink = "idle";
9322
9660
  beginProbing();
9323
9661
  if (dispatchQueue.length > 0) scheduleFlush();
9324
9662
  }
@@ -10388,6 +10726,11 @@ function setupSimulatorTempFiles(simSession) {
10388
10726
  // src/main/services/views/simulator-session-policy.ts
10389
10727
  import { session as session3 } from "electron";
10390
10728
  import { toDisposable as toDisposable7 } from "@dimina-kit/electron-deck/main";
10729
+ var CORS_OVERRIDE_HEADERS = /* @__PURE__ */ new Set([
10730
+ "access-control-allow-origin",
10731
+ "access-control-allow-headers",
10732
+ "access-control-allow-methods"
10733
+ ]);
10391
10734
  function applySimulatorWebRequestPolicy(simulatorSession) {
10392
10735
  simulatorSession.webRequest.onBeforeSendHeaders((details, callback) => {
10393
10736
  const forcedReferer = getSimulatorServicewechatReferer();
@@ -10398,6 +10741,9 @@ function applySimulatorWebRequestPolicy(simulatorSession) {
10398
10741
  });
10399
10742
  simulatorSession.webRequest.onHeadersReceived((details, callback) => {
10400
10743
  const headers = details.responseHeaders ?? {};
10744
+ for (const key of Object.keys(headers)) {
10745
+ if (CORS_OVERRIDE_HEADERS.has(key.toLowerCase())) delete headers[key];
10746
+ }
10401
10747
  headers["access-control-allow-origin"] = ["*"];
10402
10748
  headers["access-control-allow-headers"] = ["*"];
10403
10749
  headers["access-control-allow-methods"] = ["*"];