@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.
- package/dist/main/index.bundle.js +395 -49
- package/dist/main/ipc/bridge-router.d.ts +8 -0
- package/dist/main/ipc/bridge-router.js +352 -38
- package/dist/main/services/console-forward/index.d.ts +12 -1
- package/dist/main/services/console-forward/index.js +99 -1
- package/dist/main/services/diagnostics/index.d.ts +49 -0
- package/dist/main/services/diagnostics/index.js +61 -0
- package/dist/main/services/network-forward/index.js +32 -0
- package/dist/main/services/notifications/renderer-notifier.d.ts +39 -0
- package/dist/main/services/notifications/renderer-notifier.js +4 -1
- package/dist/main/services/projects/project-repository.js +2 -1
- package/dist/main/services/views/simulator-session-policy.js +17 -0
- package/dist/main/services/workbench-context.d.ts +10 -0
- package/dist/main/services/workspace/workspace-service.js +12 -3
- package/dist/main/windows/service-host-window/create.d.ts +15 -1
- package/dist/main/windows/service-host-window/create.js +11 -3
- package/dist/preload/shared/api-compat.js +18 -55
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs.map +1 -1
- package/dist/preload/windows/simulator.cjs +117 -44
- package/dist/preload/windows/simulator.cjs.map +3 -3
- package/dist/preload/windows/simulator.js +117 -44
- package/dist/renderer/assets/index-BwzPwCmM.js +49 -0
- package/dist/renderer/assets/{input-Cjk0wSEh.js → input-CTb_le7F.js} +2 -2
- package/dist/renderer/assets/ipc-transport-BPWIV5hA.css +1 -0
- package/dist/renderer/assets/{ipc-transport-OZS-KmOW.js → ipc-transport-Ck5Xa8Tu.js} +2 -2
- package/dist/renderer/assets/popover-B1Zu2UQu.js +2 -0
- package/dist/renderer/assets/{select-BQDXi5ih.js → select-ozSk5Pt6.js} +2 -2
- package/dist/renderer/assets/{settings-tP3Px2KR.js → settings-CNwGOI22.js} +2 -2
- package/dist/renderer/assets/settings-api-DMbMp1Eq.js +2 -0
- package/dist/renderer/assets/{workbenchSettings-COhuFF-i.js → workbenchSettings-Cr4EHo5w.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +5 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/shared/bridge-channels.d.ts +22 -0
- package/dist/shared/ipc-channels.d.ts +3 -0
- package/dist/shared/ipc-channels.js +9 -0
- package/dist/shared/request-core.d.ts +84 -0
- package/dist/shared/request-core.js +168 -0
- package/dist/shared/simulator-api-metadata.d.ts +22 -17
- package/dist/shared/simulator-api-metadata.js +36 -0
- package/dist/shared/types.d.ts +7 -4
- package/dist/simulator/assets/{device-shell-CiLAPa0I.js → device-shell-C-wcFq3Z.js} +2 -2
- package/dist/simulator/assets/{jsx-runtime-CDK-o-S0.js → jsx-runtime-BDTY6fEq.js} +2 -2
- package/dist/simulator/assets/simulator-DU3-fS3v.js +10 -0
- package/dist/simulator/assets/simulator-mini-app-DzfMfnVM.js +2 -0
- package/dist/simulator/simulator.html +2 -2
- package/package.json +6 -6
- package/dist/renderer/assets/index-D-ksyN1p.js +0 -49
- package/dist/renderer/assets/ipc-transport-D5dKIti1.css +0 -1
- package/dist/renderer/assets/popover-CQVvOe90.js +0 -2
- package/dist/renderer/assets/settings-api-B6x2mhaD.js +0 -2
- package/dist/simulator/assets/simulator-Dvnxry3y.js +0 -10
- 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(
|
|
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: () =>
|
|
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
|
-
() =>
|
|
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
|
-
|
|
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
|
|
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
|
|
6492
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
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(
|
|
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
|
|
6727
|
-
|
|
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(
|
|
6734
|
-
const
|
|
6735
|
-
|
|
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
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
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
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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 {
|
|
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"] = ["*"];
|