@dimina-kit/devtools 0.4.0-dev.20260701083540 → 0.4.0-dev.20260702145840
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/app/app.js +11 -0
- package/dist/main/app/max-listeners-diagnostic.d.ts +32 -0
- package/dist/main/app/max-listeners-diagnostic.js +63 -0
- package/dist/main/index.bundle.js +1657 -1158
- package/dist/main/ipc/bridge-router.d.ts +33 -4
- package/dist/main/ipc/bridge-router.js +200 -51
- package/dist/main/ipc/session-listener-bag.d.ts +41 -0
- package/dist/main/ipc/session-listener-bag.js +40 -0
- package/dist/main/ipc/simulator.js +5 -5
- package/dist/main/ipc/views.js +8 -19
- package/dist/main/services/automation/wait-active-page.d.ts +4 -2
- package/dist/main/services/elements-forward/index.js +19 -0
- package/dist/main/services/network-forward/index.js +13 -0
- package/dist/main/services/render-inspect/index.d.ts +9 -0
- package/dist/main/services/render-inspect/index.js +13 -1
- package/dist/main/services/simulator-storage/index.d.ts +9 -0
- package/dist/main/services/simulator-storage/index.js +26 -1
- package/dist/main/services/simulator-wxml/index.js +117 -11
- package/dist/main/services/views/apply-view-ops.d.ts +11 -0
- package/dist/main/services/views/apply-view-ops.js +22 -0
- package/dist/main/services/views/destroy-child-view.d.ts +9 -0
- package/dist/main/services/views/destroy-child-view.js +23 -0
- package/dist/main/services/views/host-toolbar-view.d.ts +21 -0
- package/dist/main/services/views/host-toolbar-view.js +249 -0
- package/dist/main/services/views/inject-when-ready.d.ts +41 -0
- package/dist/main/services/views/inject-when-ready.js +62 -0
- package/dist/main/services/views/native-simulator-devtools-host.d.ts +26 -0
- package/dist/main/services/views/native-simulator-devtools-host.js +484 -0
- package/dist/main/services/views/native-simulator-view.d.ts +28 -0
- package/dist/main/services/views/native-simulator-view.js +428 -0
- package/dist/main/services/views/overlay-panels-view.d.ts +29 -0
- package/dist/main/services/views/overlay-panels-view.js +150 -0
- package/dist/main/services/views/placement-reconciler.d.ts +73 -0
- package/dist/main/services/views/placement-reconciler.js +120 -0
- package/dist/main/services/views/placement-test-driver.d.ts +25 -0
- package/dist/main/services/views/placement-test-driver.js +48 -0
- package/dist/main/services/views/resolve-project-editor-target.d.ts +13 -0
- package/dist/main/services/views/resolve-project-editor-target.js +33 -0
- package/dist/main/services/views/view-manager.d.ts +28 -70
- package/dist/main/services/views/view-manager.js +66 -1514
- package/dist/main/services/views/workbench-view.d.ts +15 -0
- package/dist/main/services/views/workbench-view.js +170 -0
- package/dist/main/services/workbench-context.d.ts +10 -0
- package/dist/preload/windows/host-toolbar-runtime.cjs +6 -13
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs +10 -1
- package/dist/preload/windows/main.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs +6 -3
- package/dist/preload/windows/simulator.cjs.map +2 -2
- package/dist/preload/windows/simulator.js +6 -3
- package/dist/render-host/render-inspect.js +35 -1
- package/dist/renderer/assets/index-ChF9V4r-.js +49 -0
- package/dist/renderer/assets/{input-DR7bfyQE.js → input-Cjk0wSEh.js} +2 -2
- package/dist/renderer/assets/ipc-transport-D5dKIti1.css +1 -0
- package/dist/renderer/assets/{ipc-transport-3Arg8jPC.js → ipc-transport-OZS-KmOW.js} +2 -2
- package/dist/renderer/assets/{popover-CPZX3MrT.js → popover-CQVvOe90.js} +2 -2
- package/dist/renderer/assets/{select-BxyPlVyJ.js → select-BQDXi5ih.js} +2 -2
- package/dist/renderer/assets/{settings-api-CtPPJF-F.js → settings-api-B6x2mhaD.js} +2 -2
- package/dist/renderer/assets/{settings-CG_OR03F.js → settings-tP3Px2KR.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-ClqCBGOa.js → workbenchSettings-Bim9ol9R.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/service-host/sync-api-patch.js +33 -3
- package/dist/shared/bridge-channels.d.ts +17 -0
- package/dist/shared/bridge-channels.js +9 -0
- package/dist/shared/ipc-channels.d.ts +29 -14
- package/dist/shared/ipc-channels.js +16 -17
- package/dist/shared/ipc-schemas.d.ts +25 -17
- package/dist/shared/ipc-schemas.js +38 -22
- package/dist/shared/view-ids.d.ts +19 -0
- package/dist/shared/view-ids.js +25 -0
- package/dist/simulator/assets/{bridge-channels-BUQ5AbvJ.js → bridge-channels-zhsumfky.js} +2 -2
- package/dist/simulator/assets/{device-shell-CT3LRnTB.js → device-shell-CUl0ILfn.js} +2 -2
- package/dist/simulator/assets/{simulator-BizhGGE3.js → simulator-Dz8iGcgy.js} +5 -5
- package/dist/simulator/assets/{simulator-mini-app-BfNuDF3R.js → simulator-mini-app-Bt639XL_.js} +2 -2
- package/dist/simulator/simulator.html +2 -1
- package/package.json +4 -4
- package/dist/renderer/assets/index-HE9Xr9bQ.js +0 -49
- package/dist/renderer/assets/ipc-transport-Dt0jR7Ir.css +0 -1
|
@@ -108,6 +108,39 @@ function setupCdpPort() {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
// src/main/app/max-listeners-diagnostic.ts
|
|
112
|
+
function callSafe(fn) {
|
|
113
|
+
try {
|
|
114
|
+
return fn();
|
|
115
|
+
} catch {
|
|
116
|
+
return void 0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function describeMaxListenersWarning(warning) {
|
|
120
|
+
if (warning.name !== "MaxListenersExceededWarning") return null;
|
|
121
|
+
const w = warning;
|
|
122
|
+
const emitter = w.emitter ?? void 0;
|
|
123
|
+
return {
|
|
124
|
+
event: w.type,
|
|
125
|
+
count: w.count,
|
|
126
|
+
wcId: typeof emitter?.id === "number" ? emitter.id : void 0,
|
|
127
|
+
wcType: callSafe(() => emitter?.getType?.()),
|
|
128
|
+
url: callSafe(() => emitter?.getURL?.()),
|
|
129
|
+
destroyed: callSafe(() => emitter?.isDestroyed?.()),
|
|
130
|
+
stack: warning.stack
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function installMaxListenersWarningDiagnostic(log3 = (r) => console.warn("[max-listeners]", JSON.stringify(r))) {
|
|
134
|
+
const onWarning = (warning) => {
|
|
135
|
+
const report = describeMaxListenersWarning(warning);
|
|
136
|
+
if (report) log3(report);
|
|
137
|
+
};
|
|
138
|
+
process.on("warning", onWarning);
|
|
139
|
+
return () => {
|
|
140
|
+
process.removeListener("warning", onWarning);
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
111
144
|
// src/main/ipc/project-fs.ts
|
|
112
145
|
import fs2 from "node:fs/promises";
|
|
113
146
|
import nodeFs from "node:fs";
|
|
@@ -306,15 +339,18 @@ var SimulatorChannel = {
|
|
|
306
339
|
// Ask main to create the simulator as a top-level WebContentsView (so nested
|
|
307
340
|
// render-host <webview>s can attach). Native-host is the sole runtime.
|
|
308
341
|
AttachNative: "simulator:attach-native",
|
|
309
|
-
// Renderer reports the device-bezel inner-screen rect (CSS px from content
|
|
310
|
-
// top-left) + zoom so main can overlay the simulator WCV on it.
|
|
311
|
-
SetNativeBounds: "simulator:set-native-bounds",
|
|
312
342
|
// Renderer pushes the selected device's LOGICAL metrics (screen size,
|
|
313
343
|
// pixelRatio, statusBarHeight, …) when the device dropdown changes. Main
|
|
314
344
|
// maps it to a HostEnvSnapshot and live-updates the running service-host
|
|
315
345
|
// window — the authoritative `wx.getSystemInfoSync()` source — so the
|
|
316
346
|
// mini-app sees the selected device without a relaunch.
|
|
317
347
|
SetDeviceInfo: "simulator:set-device-info",
|
|
348
|
+
// Ask main to soft-reload the LIVE simulator WCV after a watcher rebuild:
|
|
349
|
+
// main forwards a SIMULATOR_EVENTS.RELAUNCH into the shell (which boots a
|
|
350
|
+
// new app session and swaps when ready) instead of destroying the view.
|
|
351
|
+
// Resolves false when there is no live+ready shell — the renderer then falls
|
|
352
|
+
// back to the hard AttachNative rebuild.
|
|
353
|
+
SoftReload: "simulator:soft-reload",
|
|
318
354
|
Detach: "simulator:detach",
|
|
319
355
|
Console: "simulator:console",
|
|
320
356
|
// Main → renderer push of the visible top-of-stack page route whenever the
|
|
@@ -353,7 +389,11 @@ var SimulatorElementChannel = {
|
|
|
353
389
|
};
|
|
354
390
|
var SimulatorWxmlChannel = {
|
|
355
391
|
GetSnapshot: "simulator:wxml:snapshot",
|
|
356
|
-
Event: "simulator:wxml:event"
|
|
392
|
+
Event: "simulator:wxml:event",
|
|
393
|
+
// renderer→main: whether the WXML panel is currently visible/active. Main
|
|
394
|
+
// only installs the render-guest DOM MutationObserver + pushes live tree
|
|
395
|
+
// updates while active, so an unseen panel never drives a full Vue-tree walk.
|
|
396
|
+
SetActive: "simulator:wxml:setActive"
|
|
357
397
|
};
|
|
358
398
|
var SimulatorAppDataChannel = {
|
|
359
399
|
GetSnapshot: "simulator:appdata:snapshot",
|
|
@@ -423,14 +463,6 @@ var DialogChannel = {
|
|
|
423
463
|
OpenDirectory: "dialog:openDirectory"
|
|
424
464
|
};
|
|
425
465
|
var ViewChannel = {
|
|
426
|
-
/** Update the simulator DevTools view's bounds (or hide if w/h = 0). */
|
|
427
|
-
SimulatorDevtoolsBounds: "view:simulator:devtools-bounds",
|
|
428
|
-
/**
|
|
429
|
-
* Host-controllable toolbar WebContentsView (sits ABOVE the devtools built-in
|
|
430
|
-
* header). Forward anchor: the main renderer reports the toolbar placeholder's
|
|
431
|
-
* bounds (or w/h=0 to hide). invoke.
|
|
432
|
-
*/
|
|
433
|
-
HostToolbarBounds: "view:host-toolbar:bounds",
|
|
434
466
|
/**
|
|
435
467
|
* Reverse size-advertiser: the host-toolbar WCV's OWN renderer advertises its
|
|
436
468
|
* intrinsic content height so main reserves exactly that much. Payload
|
|
@@ -463,12 +495,13 @@ var ViewChannel = {
|
|
|
463
495
|
*/
|
|
464
496
|
HostToolbarGetHeight: "view:host-toolbar:get-height",
|
|
465
497
|
/**
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
498
|
+
* Renderer → main: the window-level placement snapshot (one monotonic epoch
|
|
499
|
+
* per commit tick, one generation per renderer lifetime) that drives the view
|
|
500
|
+
* reconciler. The single source of truth for every managed native view's
|
|
501
|
+
* bounds/visibility/z-order — supersedes the per-view bounds channels above.
|
|
502
|
+
* invoke.
|
|
470
503
|
*/
|
|
471
|
-
|
|
504
|
+
PlacementSnapshot: "view:placement-snapshot"
|
|
472
505
|
};
|
|
473
506
|
var PopoverChannel = {
|
|
474
507
|
Show: "popover:show",
|
|
@@ -820,7 +853,7 @@ function registerProjectFsIpc(ctx) {
|
|
|
820
853
|
// src/main/app/app.ts
|
|
821
854
|
import { app as app15, BrowserWindow as BrowserWindow8, nativeImage, session as session4 } from "electron";
|
|
822
855
|
import fs12 from "fs";
|
|
823
|
-
import
|
|
856
|
+
import path23 from "path";
|
|
824
857
|
|
|
825
858
|
// src/main/utils/paths.ts
|
|
826
859
|
import fs3 from "fs";
|
|
@@ -1107,10 +1140,341 @@ function createRendererNotifier(ctx) {
|
|
|
1107
1140
|
};
|
|
1108
1141
|
}
|
|
1109
1142
|
|
|
1110
|
-
// src/main/services/
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1143
|
+
// src/main/services/safe-area/index.ts
|
|
1144
|
+
function guestInsets(device, isTabPage2) {
|
|
1145
|
+
const top = device?.safeAreaInsets.top ?? 0;
|
|
1146
|
+
const bottom = isTabPage2 ? 0 : device?.safeAreaInsets.bottom ?? 0;
|
|
1147
|
+
return { top, topMax: top, right: 0, rightMax: 0, bottom, bottomMax: bottom, left: 0, leftMax: 0 };
|
|
1148
|
+
}
|
|
1149
|
+
function createSafeAreaController(options = {}) {
|
|
1150
|
+
const attached = /* @__PURE__ */ new Map();
|
|
1151
|
+
function override(wc, device, isTabPage2) {
|
|
1152
|
+
if (wc.isDestroyed()) return;
|
|
1153
|
+
void wc.debugger.sendCommand("Emulation.setSafeAreaInsetsOverride", { insets: guestInsets(device, isTabPage2) }).catch((err) => {
|
|
1154
|
+
console.warn("[safe-area] setSafeAreaInsetsOverride failed:", err instanceof Error ? err.message : err);
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
return {
|
|
1158
|
+
applyToGuest: (wc, device, isTabPage2) => {
|
|
1159
|
+
if (!wc || wc.isDestroyed() || attached.has(wc)) {
|
|
1160
|
+
if (wc && !wc.isDestroyed() && attached.has(wc)) override(wc, device, isTabPage2);
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
try {
|
|
1164
|
+
wc.debugger.attach("1.3");
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
console.warn("[safe-area] debugger.attach failed; env(safe-area-inset-*) stays 0:", err instanceof Error ? err.message : err);
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
attached.set(wc, isTabPage2);
|
|
1170
|
+
if (options.connections) {
|
|
1171
|
+
options.connections.acquire(wc).own(() => attached.delete(wc));
|
|
1172
|
+
} else {
|
|
1173
|
+
wc.once("destroyed", () => attached.delete(wc));
|
|
1174
|
+
}
|
|
1175
|
+
override(wc, device, isTabPage2);
|
|
1176
|
+
},
|
|
1177
|
+
reapplyAll: (device) => {
|
|
1178
|
+
for (const [wc, isTabPage2] of attached) override(wc, device, isTabPage2);
|
|
1179
|
+
},
|
|
1180
|
+
dispose: () => {
|
|
1181
|
+
for (const wc of attached.keys()) {
|
|
1182
|
+
try {
|
|
1183
|
+
if (!wc.isDestroyed()) wc.debugger.detach();
|
|
1184
|
+
} catch {
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
attached.clear();
|
|
1188
|
+
}
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/main/services/views/placement-reconciler.ts
|
|
1193
|
+
import { reconcile, createInitialState } from "@dimina-kit/electron-deck/layout";
|
|
1194
|
+
|
|
1195
|
+
// src/main/services/views/apply-view-ops.ts
|
|
1196
|
+
function applyViewOps(ops, target) {
|
|
1197
|
+
for (const op of ops) {
|
|
1198
|
+
switch (op.kind) {
|
|
1199
|
+
case "detach":
|
|
1200
|
+
target.detach(op.viewId);
|
|
1201
|
+
break;
|
|
1202
|
+
case "setVisible":
|
|
1203
|
+
target.setVisible(op.viewId, op.visible);
|
|
1204
|
+
break;
|
|
1205
|
+
case "setBounds":
|
|
1206
|
+
target.setBounds(op.viewId, op.bounds, op.extra);
|
|
1207
|
+
break;
|
|
1208
|
+
case "attach":
|
|
1209
|
+
target.attach(op.viewId);
|
|
1210
|
+
break;
|
|
1211
|
+
case "reorder":
|
|
1212
|
+
target.reorder(op.order);
|
|
1213
|
+
break;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// src/main/services/views/placement-reconciler.ts
|
|
1219
|
+
function createPlacementReconciler(ctx) {
|
|
1220
|
+
let placementState = createInitialState();
|
|
1221
|
+
let epochCounter = 0;
|
|
1222
|
+
let rendererGeneration = 0;
|
|
1223
|
+
const baseDesired = /* @__PURE__ */ new Map();
|
|
1224
|
+
const overlayDesired = /* @__PURE__ */ new Map();
|
|
1225
|
+
const slots = /* @__PURE__ */ new Map();
|
|
1226
|
+
function gateReadiness(v) {
|
|
1227
|
+
const slot = slots.get(v.viewId);
|
|
1228
|
+
if (slot?.gateHidden?.()) return { ...v, placement: { visible: false } };
|
|
1229
|
+
return v;
|
|
1230
|
+
}
|
|
1231
|
+
const viewTarget = {
|
|
1232
|
+
attach(viewId) {
|
|
1233
|
+
if (ctx.windows.mainWindow.isDestroyed()) return;
|
|
1234
|
+
const slot = slots.get(viewId);
|
|
1235
|
+
if (!slot) return;
|
|
1236
|
+
if (slot.beforeAttach?.()) return;
|
|
1237
|
+
const view = slot.ensureView ? slot.ensureView() : slot.getView();
|
|
1238
|
+
if (!view) return;
|
|
1239
|
+
ctx.windows.mainWindow.contentView.addChildView(view);
|
|
1240
|
+
slot.setAdded?.(true);
|
|
1241
|
+
},
|
|
1242
|
+
detach(viewId) {
|
|
1243
|
+
const slot = slots.get(viewId);
|
|
1244
|
+
const view = slot?.getView() ?? null;
|
|
1245
|
+
if (view && !ctx.windows.mainWindow.isDestroyed()) {
|
|
1246
|
+
try {
|
|
1247
|
+
ctx.windows.mainWindow.contentView.removeChildView(view);
|
|
1248
|
+
} catch {
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
slot?.setAdded?.(false);
|
|
1252
|
+
},
|
|
1253
|
+
setBounds(viewId, bounds, extra) {
|
|
1254
|
+
const slot = slots.get(viewId);
|
|
1255
|
+
const view = slot?.getView() ?? null;
|
|
1256
|
+
if (!view || view.webContents.isDestroyed()) return;
|
|
1257
|
+
if (slot?.applyBounds) {
|
|
1258
|
+
slot.applyBounds(view, bounds, extra);
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
view.setBounds(bounds);
|
|
1262
|
+
},
|
|
1263
|
+
setVisible(viewId, visible) {
|
|
1264
|
+
const view = slots.get(viewId)?.getView() ?? null;
|
|
1265
|
+
if (!view) return;
|
|
1266
|
+
try {
|
|
1267
|
+
view.setVisible(visible);
|
|
1268
|
+
} catch {
|
|
1269
|
+
}
|
|
1270
|
+
},
|
|
1271
|
+
reorder(order) {
|
|
1272
|
+
if (order.length <= 1 || ctx.windows.mainWindow.isDestroyed()) return;
|
|
1273
|
+
const cv = ctx.windows.mainWindow.contentView;
|
|
1274
|
+
for (const viewId of order) {
|
|
1275
|
+
const view = slots.get(viewId)?.getView() ?? null;
|
|
1276
|
+
if (view) {
|
|
1277
|
+
try {
|
|
1278
|
+
cv.addChildView(view);
|
|
1279
|
+
} catch {
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
function ensureLazyViews() {
|
|
1286
|
+
for (const [viewId, slot] of slots) {
|
|
1287
|
+
slot.ensureLazy?.(baseDesired.get(viewId));
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
function reconcileNow() {
|
|
1291
|
+
ensureLazyViews();
|
|
1292
|
+
const views = [];
|
|
1293
|
+
for (const v of baseDesired.values()) views.push(gateReadiness(v));
|
|
1294
|
+
for (const v of overlayDesired.values()) views.push(v);
|
|
1295
|
+
const result = reconcile(placementState, {
|
|
1296
|
+
generation: rendererGeneration,
|
|
1297
|
+
epoch: ++epochCounter,
|
|
1298
|
+
views
|
|
1299
|
+
});
|
|
1300
|
+
placementState = result.state;
|
|
1301
|
+
applyViewOps(result.ops, viewTarget);
|
|
1302
|
+
}
|
|
1303
|
+
function setPlacementSnapshot(snapshot) {
|
|
1304
|
+
rendererGeneration = snapshot.generation;
|
|
1305
|
+
baseDesired.clear();
|
|
1306
|
+
for (const v of snapshot.views) baseDesired.set(v.viewId, v);
|
|
1307
|
+
reconcileNow();
|
|
1308
|
+
}
|
|
1309
|
+
return {
|
|
1310
|
+
registerView: (viewId, slot) => {
|
|
1311
|
+
slots.set(viewId, slot);
|
|
1312
|
+
},
|
|
1313
|
+
reconcileNow,
|
|
1314
|
+
setPlacementSnapshot,
|
|
1315
|
+
forgetActual: (viewId) => {
|
|
1316
|
+
placementState.actual.delete(viewId);
|
|
1317
|
+
},
|
|
1318
|
+
setBaseDesired: (viewId, desired) => {
|
|
1319
|
+
baseDesired.set(viewId, desired);
|
|
1320
|
+
},
|
|
1321
|
+
deleteBaseDesired: (viewId) => {
|
|
1322
|
+
baseDesired.delete(viewId);
|
|
1323
|
+
},
|
|
1324
|
+
setOverlayDesired: (viewId, desired) => {
|
|
1325
|
+
overlayDesired.set(viewId, desired);
|
|
1326
|
+
},
|
|
1327
|
+
deleteOverlayDesired: (viewId) => {
|
|
1328
|
+
overlayDesired.delete(viewId);
|
|
1329
|
+
},
|
|
1330
|
+
hasOverlayDesired: (viewId) => overlayDesired.has(viewId)
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// src/main/services/views/workbench-view.ts
|
|
1335
|
+
import { nativeTheme as nativeTheme3, WebContentsView as WebContentsView2 } from "electron";
|
|
1336
|
+
|
|
1337
|
+
// src/shared/view-ids.ts
|
|
1338
|
+
var VIEW_ID = {
|
|
1339
|
+
simulator: "simulator",
|
|
1340
|
+
simulatorDevtools: "simulator-devtools",
|
|
1341
|
+
workbench: "workbench",
|
|
1342
|
+
hostToolbar: "host-toolbar",
|
|
1343
|
+
settings: "settings",
|
|
1344
|
+
popover: "popover"
|
|
1345
|
+
};
|
|
1346
|
+
var VIEW_LAYER = {
|
|
1347
|
+
base: 0,
|
|
1348
|
+
hostToolbar: 5,
|
|
1349
|
+
settings: 10,
|
|
1350
|
+
popover: 20
|
|
1351
|
+
};
|
|
1352
|
+
|
|
1353
|
+
// src/main/services/views/destroy-child-view.ts
|
|
1354
|
+
function destroyChildView(mainWindow, view) {
|
|
1355
|
+
if (!view) return;
|
|
1356
|
+
if (!mainWindow.isDestroyed()) {
|
|
1357
|
+
try {
|
|
1358
|
+
mainWindow.contentView.removeChildView(view);
|
|
1359
|
+
} catch {
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
try {
|
|
1363
|
+
if (!view.webContents.isDestroyed()) {
|
|
1364
|
+
view.webContents.close();
|
|
1365
|
+
}
|
|
1366
|
+
} catch {
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// src/main/services/views/workbench-view.ts
|
|
1371
|
+
function createWorkbenchView(ctx, reconciler) {
|
|
1372
|
+
let workbenchView = null;
|
|
1373
|
+
let workbenchThemeSyncBound = false;
|
|
1374
|
+
let workbenchUrl = null;
|
|
1375
|
+
function workbenchThemeScheme() {
|
|
1376
|
+
return nativeTheme3.shouldUseDarkColors ? "dark" : "light";
|
|
1377
|
+
}
|
|
1378
|
+
function pushWorkbenchTheme() {
|
|
1379
|
+
if (!workbenchView || workbenchView.webContents.isDestroyed()) return;
|
|
1380
|
+
const wc = workbenchView.webContents;
|
|
1381
|
+
if (typeof wc.executeJavaScript !== "function") return;
|
|
1382
|
+
const script = `window.__WB_SET_THEME && window.__WB_SET_THEME(${JSON.stringify(workbenchThemeScheme())})`;
|
|
1383
|
+
wc.executeJavaScript(script, true).catch(() => {
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
async function attachWorkbench(url) {
|
|
1387
|
+
if (workbenchView) return;
|
|
1388
|
+
const view = new WebContentsView2({
|
|
1389
|
+
webPreferences: {
|
|
1390
|
+
nodeIntegration: false,
|
|
1391
|
+
contextIsolation: true,
|
|
1392
|
+
sandbox: false
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
workbenchView = view;
|
|
1396
|
+
if (!workbenchThemeSyncBound) {
|
|
1397
|
+
nativeTheme3.on("updated", pushWorkbenchTheme);
|
|
1398
|
+
workbenchThemeSyncBound = true;
|
|
1399
|
+
}
|
|
1400
|
+
try {
|
|
1401
|
+
view.webContents.setWindowOpenHandler(({ url: target }) => handleWindowOpenExternal(target));
|
|
1402
|
+
} catch {
|
|
1403
|
+
}
|
|
1404
|
+
ctx.windows.mainWindow.contentView.addChildView(view);
|
|
1405
|
+
const loadUrl = `${url}index.html?theme=${workbenchThemeScheme()}`;
|
|
1406
|
+
await view.webContents.loadURL(loadUrl).catch((err) => {
|
|
1407
|
+
console.error("[workbench] attachWorkbench \u2014 loadURL failed", err);
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
function setWorkbenchSource(url) {
|
|
1411
|
+
workbenchUrl = url;
|
|
1412
|
+
}
|
|
1413
|
+
function detachWorkbench() {
|
|
1414
|
+
if (workbenchThemeSyncBound) {
|
|
1415
|
+
nativeTheme3.removeListener("updated", pushWorkbenchTheme);
|
|
1416
|
+
workbenchThemeSyncBound = false;
|
|
1417
|
+
}
|
|
1418
|
+
destroyChildView(ctx.windows.mainWindow, workbenchView);
|
|
1419
|
+
workbenchView = null;
|
|
1420
|
+
reconciler.deleteBaseDesired(VIEW_ID.workbench);
|
|
1421
|
+
reconciler.reconcileNow();
|
|
1422
|
+
}
|
|
1423
|
+
function workspaceUriFor(rel) {
|
|
1424
|
+
const encoded = rel.split("/").map(encodeURIComponent).join("/");
|
|
1425
|
+
return `file:///workspace/${encoded}`;
|
|
1426
|
+
}
|
|
1427
|
+
function tryRevealInWorkbench(uri, zeroLine, zeroCol) {
|
|
1428
|
+
if (!workbenchView || workbenchView.webContents.isDestroyed()) {
|
|
1429
|
+
return Promise.resolve(false);
|
|
1430
|
+
}
|
|
1431
|
+
const script = `(async () => {
|
|
1432
|
+
try {
|
|
1433
|
+
const P = window.__WB_PROBE; if (!P) return false
|
|
1434
|
+
const vscode = P.vscode
|
|
1435
|
+
const uri = vscode.Uri.parse(${JSON.stringify(uri)})
|
|
1436
|
+
const doc = await vscode.workspace.openTextDocument(uri)
|
|
1437
|
+
const pos = new vscode.Position(${zeroLine}, ${zeroCol})
|
|
1438
|
+
await vscode.window.showTextDocument(doc, { selection: new vscode.Range(pos, pos) })
|
|
1439
|
+
return true
|
|
1440
|
+
} catch (e) { return false }
|
|
1441
|
+
})()`;
|
|
1442
|
+
return workbenchView.webContents.executeJavaScript(script, true).then((ok) => ok === true).catch(() => false);
|
|
1443
|
+
}
|
|
1444
|
+
function openFileInWorkbench(relPath, line, column) {
|
|
1445
|
+
if (!workbenchView || workbenchView.webContents.isDestroyed()) return false;
|
|
1446
|
+
const uri = workspaceUriFor(relPath.replace(/^\/+/, ""));
|
|
1447
|
+
const zeroLine = Math.max(0, Math.floor(line) - 1);
|
|
1448
|
+
const zeroCol = Math.max(0, Math.floor(column) - 1);
|
|
1449
|
+
void (async () => {
|
|
1450
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
1451
|
+
if (!workbenchView || workbenchView.webContents.isDestroyed()) return;
|
|
1452
|
+
if (await tryRevealInWorkbench(uri, zeroLine, zeroCol)) return;
|
|
1453
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
1454
|
+
}
|
|
1455
|
+
console.error("[workbench] openFileInWorkbench: workbench never became ready for", uri);
|
|
1456
|
+
})();
|
|
1457
|
+
return true;
|
|
1458
|
+
}
|
|
1459
|
+
reconciler.registerView(VIEW_ID.workbench, {
|
|
1460
|
+
getView: () => workbenchView,
|
|
1461
|
+
gateHidden: () => !workbenchView && !workbenchUrl,
|
|
1462
|
+
beforeAttach: () => {
|
|
1463
|
+
if (!workbenchView && workbenchUrl) {
|
|
1464
|
+
void attachWorkbench(workbenchUrl);
|
|
1465
|
+
return true;
|
|
1466
|
+
}
|
|
1467
|
+
return false;
|
|
1468
|
+
},
|
|
1469
|
+
ensureLazy: (desired) => {
|
|
1470
|
+
if (desired?.placement.visible && !workbenchView && workbenchUrl) void attachWorkbench(workbenchUrl);
|
|
1471
|
+
}
|
|
1472
|
+
});
|
|
1473
|
+
return { attachWorkbench, setWorkbenchSource, detachWorkbench, openFileInWorkbench };
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// src/main/services/views/native-simulator-devtools-host.ts
|
|
1477
|
+
import { WebContentsView as WebContentsView3 } from "electron";
|
|
1114
1478
|
|
|
1115
1479
|
// src/shared/open-in-editor.ts
|
|
1116
1480
|
var OPEN_IN_EDITOR_SCHEME = "dimina-open-in-editor";
|
|
@@ -1484,55 +1848,6 @@ function buildDevtoolsProjectSourceLinksScript(context) {
|
|
|
1484
1848
|
`;
|
|
1485
1849
|
}
|
|
1486
1850
|
|
|
1487
|
-
// src/main/services/safe-area/index.ts
|
|
1488
|
-
function guestInsets(device, isTabPage2) {
|
|
1489
|
-
const top = device?.safeAreaInsets.top ?? 0;
|
|
1490
|
-
const bottom = isTabPage2 ? 0 : device?.safeAreaInsets.bottom ?? 0;
|
|
1491
|
-
return { top, topMax: top, right: 0, rightMax: 0, bottom, bottomMax: bottom, left: 0, leftMax: 0 };
|
|
1492
|
-
}
|
|
1493
|
-
function createSafeAreaController(options = {}) {
|
|
1494
|
-
const attached = /* @__PURE__ */ new Map();
|
|
1495
|
-
function override(wc, device, isTabPage2) {
|
|
1496
|
-
if (wc.isDestroyed()) return;
|
|
1497
|
-
void wc.debugger.sendCommand("Emulation.setSafeAreaInsetsOverride", { insets: guestInsets(device, isTabPage2) }).catch((err) => {
|
|
1498
|
-
console.warn("[safe-area] setSafeAreaInsetsOverride failed:", err instanceof Error ? err.message : err);
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
return {
|
|
1502
|
-
applyToGuest: (wc, device, isTabPage2) => {
|
|
1503
|
-
if (!wc || wc.isDestroyed() || attached.has(wc)) {
|
|
1504
|
-
if (wc && !wc.isDestroyed() && attached.has(wc)) override(wc, device, isTabPage2);
|
|
1505
|
-
return;
|
|
1506
|
-
}
|
|
1507
|
-
try {
|
|
1508
|
-
wc.debugger.attach("1.3");
|
|
1509
|
-
} catch (err) {
|
|
1510
|
-
console.warn("[safe-area] debugger.attach failed; env(safe-area-inset-*) stays 0:", err instanceof Error ? err.message : err);
|
|
1511
|
-
return;
|
|
1512
|
-
}
|
|
1513
|
-
attached.set(wc, isTabPage2);
|
|
1514
|
-
if (options.connections) {
|
|
1515
|
-
options.connections.acquire(wc).own(() => attached.delete(wc));
|
|
1516
|
-
} else {
|
|
1517
|
-
wc.once("destroyed", () => attached.delete(wc));
|
|
1518
|
-
}
|
|
1519
|
-
override(wc, device, isTabPage2);
|
|
1520
|
-
},
|
|
1521
|
-
reapplyAll: (device) => {
|
|
1522
|
-
for (const [wc, isTabPage2] of attached) override(wc, device, isTabPage2);
|
|
1523
|
-
},
|
|
1524
|
-
dispose: () => {
|
|
1525
|
-
for (const wc of attached.keys()) {
|
|
1526
|
-
try {
|
|
1527
|
-
if (!wc.isDestroyed()) wc.debugger.detach();
|
|
1528
|
-
} catch {
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
attached.clear();
|
|
1532
|
-
}
|
|
1533
|
-
};
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
1851
|
// src/main/services/views/devtools-tabs.ts
|
|
1537
1852
|
var DEVTOOLS_KEPT_VIEW_IDS = ["elements", "console", "network", "sources"];
|
|
1538
1853
|
function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
|
|
@@ -1602,6 +1917,44 @@ function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
|
|
|
1602
1917
|
|
|
1603
1918
|
// src/main/services/elements-forward/index.ts
|
|
1604
1919
|
import { webContents as electronWebContents } from "electron";
|
|
1920
|
+
|
|
1921
|
+
// src/main/services/views/inject-when-ready.ts
|
|
1922
|
+
function isFrontendSettled(wc) {
|
|
1923
|
+
try {
|
|
1924
|
+
if (wc.isDestroyed()) return false;
|
|
1925
|
+
const url = wc.getURL();
|
|
1926
|
+
const mainFrameLoading = typeof wc.isLoadingMainFrame === "function" ? wc.isLoadingMainFrame() : wc.isLoading();
|
|
1927
|
+
return !mainFrameLoading && url !== "" && url !== "about:blank";
|
|
1928
|
+
} catch {
|
|
1929
|
+
return false;
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
function createLoadDeferredInjector() {
|
|
1933
|
+
const pending = /* @__PURE__ */ new WeakMap();
|
|
1934
|
+
return function injectWhenReady(wc, kind, run) {
|
|
1935
|
+
if (wc.isDestroyed()) return;
|
|
1936
|
+
if (isFrontendSettled(wc)) {
|
|
1937
|
+
run();
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
let kinds = pending.get(wc);
|
|
1941
|
+
if (!kinds) {
|
|
1942
|
+
kinds = /* @__PURE__ */ new Map();
|
|
1943
|
+
pending.set(wc, kinds);
|
|
1944
|
+
}
|
|
1945
|
+
const alreadyHooked = kinds.has(kind);
|
|
1946
|
+
kinds.set(kind, run);
|
|
1947
|
+
if (alreadyHooked) return;
|
|
1948
|
+
wc.once("did-stop-loading", () => {
|
|
1949
|
+
const runner = kinds.get(kind);
|
|
1950
|
+
kinds.delete(kind);
|
|
1951
|
+
if (!runner || wc.isDestroyed()) return;
|
|
1952
|
+
runner();
|
|
1953
|
+
});
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
// src/main/services/elements-forward/index.ts
|
|
1605
1958
|
var RENDER_DOMAIN_PREFIXES = [
|
|
1606
1959
|
"DOM.",
|
|
1607
1960
|
"CSS.",
|
|
@@ -1718,6 +2071,7 @@ function installElementsForward(deps) {
|
|
|
1718
2071
|
}
|
|
1719
2072
|
function dispatchToFrontend(message) {
|
|
1720
2073
|
if (disposed || devtoolsWc.isDestroyed()) return;
|
|
2074
|
+
if (!isFrontendSettled(devtoolsWc)) return;
|
|
1721
2075
|
let json;
|
|
1722
2076
|
try {
|
|
1723
2077
|
json = JSON.stringify(message);
|
|
@@ -1750,6 +2104,7 @@ function installElementsForward(deps) {
|
|
|
1750
2104
|
}
|
|
1751
2105
|
function pushDocumentUpdated() {
|
|
1752
2106
|
if (disposed || devtoolsWc.isDestroyed()) return;
|
|
2107
|
+
if (!isFrontendSettled(devtoolsWc)) return;
|
|
1753
2108
|
let script;
|
|
1754
2109
|
try {
|
|
1755
2110
|
script = buildDocumentUpdatedScript();
|
|
@@ -1922,6 +2277,7 @@ function installElementsForward(deps) {
|
|
|
1922
2277
|
stop();
|
|
1923
2278
|
return;
|
|
1924
2279
|
}
|
|
2280
|
+
if (!isFrontendSettled(devtoolsWc)) return;
|
|
1925
2281
|
devtoolsWc.executeJavaScript(buildReconcileScript()).then((res) => {
|
|
1926
2282
|
if (disposed) return;
|
|
1927
2283
|
const r = res ?? {};
|
|
@@ -2106,191 +2462,380 @@ function installServiceConsoleForward(deps) {
|
|
|
2106
2462
|
return { stop };
|
|
2107
2463
|
}
|
|
2108
2464
|
|
|
2109
|
-
// src/main/services/
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
return {
|
|
2124
|
-
x: 0,
|
|
2125
|
-
y: headerHeight,
|
|
2126
|
-
width: Math.max(1, contentWidth),
|
|
2127
|
-
height: Math.max(1, contentHeight - headerHeight)
|
|
2128
|
-
};
|
|
2129
|
-
}
|
|
2130
|
-
function computePopoverBounds(contentWidth, contentHeight, headerHeight) {
|
|
2131
|
-
return {
|
|
2132
|
-
x: 0,
|
|
2133
|
-
y: headerHeight,
|
|
2134
|
-
width: Math.max(1, contentWidth),
|
|
2135
|
-
height: contentHeight - headerHeight
|
|
2136
|
-
};
|
|
2137
|
-
}
|
|
2138
|
-
|
|
2139
|
-
// src/main/services/simulator/custom-apis.ts
|
|
2140
|
-
async function handleCustomApiBridgeRequest(apis, req) {
|
|
2465
|
+
// src/main/services/views/resolve-project-editor-target.ts
|
|
2466
|
+
import fs4 from "node:fs";
|
|
2467
|
+
import path7 from "path";
|
|
2468
|
+
function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFile = (absolutePath) => fs4.statSync(absolutePath).isFile()) {
|
|
2469
|
+
const sourceContext = projectSourceContextFromServiceHostUrl(
|
|
2470
|
+
serviceHostUrl,
|
|
2471
|
+
activeProjectRoot
|
|
2472
|
+
);
|
|
2473
|
+
if (!sourceContext) return null;
|
|
2474
|
+
const rel = resourceUrlToProjectRelativePath(req.url, sourceContext);
|
|
2475
|
+
if (!rel) return null;
|
|
2476
|
+
const absolute = path7.resolve(sourceContext.projectRoot, ...rel.split("/"));
|
|
2477
|
+
const fromRoot = path7.relative(path7.resolve(sourceContext.projectRoot), absolute);
|
|
2478
|
+
if (!fromRoot || fromRoot.startsWith("..") || path7.isAbsolute(fromRoot)) return null;
|
|
2141
2479
|
try {
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
return { id: req.id, error: err instanceof Error ? err.message : String(err) };
|
|
2480
|
+
if (!isFile(absolute)) return null;
|
|
2481
|
+
} catch {
|
|
2482
|
+
return null;
|
|
2146
2483
|
}
|
|
2147
|
-
}
|
|
2148
|
-
function createSimulatorApiRegistry() {
|
|
2149
|
-
const handlers2 = /* @__PURE__ */ new Map();
|
|
2150
2484
|
return {
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
if (handlers2.get(name) === handler) handlers2.delete(name);
|
|
2155
|
-
};
|
|
2156
|
-
},
|
|
2157
|
-
list() {
|
|
2158
|
-
return Array.from(handlers2.keys());
|
|
2159
|
-
},
|
|
2160
|
-
has(name) {
|
|
2161
|
-
return handlers2.has(name);
|
|
2162
|
-
},
|
|
2163
|
-
async invoke(name, params) {
|
|
2164
|
-
const handler = handlers2.get(name);
|
|
2165
|
-
if (!handler) throw new Error(`Simulator API "${name}" is not registered`);
|
|
2166
|
-
return await handler(params);
|
|
2167
|
-
},
|
|
2168
|
-
clear() {
|
|
2169
|
-
handlers2.clear();
|
|
2170
|
-
}
|
|
2485
|
+
path: rel,
|
|
2486
|
+
line: typeof req.line === "number" ? req.line + 1 : void 0,
|
|
2487
|
+
column: typeof req.column === "number" ? req.column + 1 : void 0
|
|
2171
2488
|
};
|
|
2172
2489
|
}
|
|
2173
2490
|
|
|
2174
|
-
// src/main/services/views/
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
return `${base}-p${djb2(projectPath).toString(36)}`;
|
|
2183
|
-
}
|
|
2184
|
-
function miniappPartition(appId, projectPath) {
|
|
2185
|
-
if (!appId) return SHARED_MINIAPP_PARTITION;
|
|
2186
|
-
return `${PARTITION_PREFIX}${miniappPartitionKey(appId, projectPath)}`;
|
|
2187
|
-
}
|
|
2188
|
-
function djb2(input) {
|
|
2189
|
-
let h = 5381;
|
|
2190
|
-
for (let i = 0; i < input.length; i++) {
|
|
2191
|
-
h = (h << 5) + h + input.charCodeAt(i) >>> 0;
|
|
2491
|
+
// src/main/services/views/native-simulator-devtools-host.ts
|
|
2492
|
+
var DEVTOOLS_HOST_EXEC_JS_MAX_LISTENERS = 50;
|
|
2493
|
+
function raiseExecuteJavaScriptListenerCeiling(wc) {
|
|
2494
|
+
try {
|
|
2495
|
+
if (wc.isDestroyed()) return;
|
|
2496
|
+
if (wc.getMaxListeners() >= DEVTOOLS_HOST_EXEC_JS_MAX_LISTENERS) return;
|
|
2497
|
+
wc.setMaxListeners(DEVTOOLS_HOST_EXEC_JS_MAX_LISTENERS);
|
|
2498
|
+
} catch {
|
|
2192
2499
|
}
|
|
2193
|
-
return h;
|
|
2194
2500
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2501
|
+
function createDevtoolsHost(ctx, reconciler, deps) {
|
|
2502
|
+
let simulatorView = null;
|
|
2503
|
+
let simulatorViewAdded = false;
|
|
2504
|
+
let nativeDevtoolsSourceWc = null;
|
|
2505
|
+
let devtoolsHostUsed = false;
|
|
2506
|
+
let unsubscribeNativeRenderEvents = null;
|
|
2507
|
+
let stopElementsForward = null;
|
|
2508
|
+
let stopServiceConsole = null;
|
|
2509
|
+
let nativeDevtoolsRetryTimer = null;
|
|
2510
|
+
let nativeDevtoolsRetryToken = 0;
|
|
2511
|
+
const injectWhenReady = createLoadDeferredInjector();
|
|
2512
|
+
const openInEditorWiredWcIds = /* @__PURE__ */ new Set();
|
|
2513
|
+
function clearNativeDevtoolsRetry() {
|
|
2514
|
+
nativeDevtoolsRetryToken++;
|
|
2515
|
+
if (nativeDevtoolsRetryTimer) {
|
|
2516
|
+
clearTimeout(nativeDevtoolsRetryTimer);
|
|
2517
|
+
nativeDevtoolsRetryTimer = null;
|
|
2204
2518
|
}
|
|
2205
2519
|
}
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
}
|
|
2210
|
-
function configureMiniappSession(partition) {
|
|
2211
|
-
const alreadyConfigured = configuredPartitions.has(partition);
|
|
2212
|
-
configuredPartitions.add(partition);
|
|
2213
|
-
if (configurators.size === 0) return null;
|
|
2214
|
-
const sess = electron.session.fromPartition(partition);
|
|
2215
|
-
if (alreadyConfigured) return sess;
|
|
2216
|
-
for (const fn of configurators) {
|
|
2520
|
+
function closeNativeDevtoolsSource() {
|
|
2521
|
+
const source = nativeDevtoolsSourceWc;
|
|
2522
|
+
nativeDevtoolsSourceWc = null;
|
|
2217
2523
|
try {
|
|
2218
|
-
|
|
2219
|
-
} catch
|
|
2220
|
-
console.warn("[miniapp-partition] configurator failed for", partition, err);
|
|
2524
|
+
stopServiceConsole?.();
|
|
2525
|
+
} catch {
|
|
2221
2526
|
}
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
var registrationId = null;
|
|
2230
|
-
function acquireHostToolbarSessionRuntime() {
|
|
2231
|
-
if (refCount === 0) {
|
|
2232
|
-
registrationId = session2.defaultSession.registerPreloadScript({
|
|
2233
|
-
type: "frame",
|
|
2234
|
-
filePath: hostToolbarRuntimePreloadPath
|
|
2235
|
-
});
|
|
2236
|
-
}
|
|
2237
|
-
refCount++;
|
|
2238
|
-
}
|
|
2239
|
-
function releaseHostToolbarSessionRuntime() {
|
|
2240
|
-
if (refCount === 0) return;
|
|
2241
|
-
refCount--;
|
|
2242
|
-
if (refCount === 0 && registrationId !== null) {
|
|
2243
|
-
session2.defaultSession.unregisterPreloadScript(registrationId);
|
|
2244
|
-
registrationId = null;
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
|
-
|
|
2248
|
-
// src/main/services/views/host-toolbar-port-channel.ts
|
|
2249
|
-
import { MessageChannelMain } from "electron";
|
|
2250
|
-
function createHostToolbarPortChannel(opts) {
|
|
2251
|
-
let activePort = null;
|
|
2252
|
-
let activeWc = null;
|
|
2253
|
-
let state = "absent";
|
|
2254
|
-
let generation = 0;
|
|
2255
|
-
const handlers2 = [];
|
|
2256
|
-
const readyHandlers = [];
|
|
2257
|
-
function dispatch(data) {
|
|
2258
|
-
if (typeof data !== "object" || data === null) return;
|
|
2259
|
-
const { channel, payload } = data;
|
|
2260
|
-
if (typeof channel !== "string") return;
|
|
2261
|
-
for (const entry of [...handlers2]) {
|
|
2262
|
-
if (entry.channel === channel) entry.handler(payload);
|
|
2527
|
+
stopServiceConsole = null;
|
|
2528
|
+
if (!source || source.isDestroyed()) return;
|
|
2529
|
+
try {
|
|
2530
|
+
if (source.isDevToolsOpened()) {
|
|
2531
|
+
source.closeDevTools();
|
|
2532
|
+
}
|
|
2533
|
+
} catch {
|
|
2263
2534
|
}
|
|
2264
2535
|
}
|
|
2265
|
-
function
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
activeWc = null;
|
|
2269
|
-
if (state !== "disposed") state = next;
|
|
2270
|
-
if (close && port) {
|
|
2536
|
+
function stopFollowingNativeServiceHost() {
|
|
2537
|
+
clearNativeDevtoolsRetry();
|
|
2538
|
+
if (unsubscribeNativeRenderEvents) {
|
|
2271
2539
|
try {
|
|
2272
|
-
|
|
2540
|
+
unsubscribeNativeRenderEvents();
|
|
2273
2541
|
} catch {
|
|
2274
2542
|
}
|
|
2543
|
+
unsubscribeNativeRenderEvents = null;
|
|
2275
2544
|
}
|
|
2545
|
+
closeNativeDevtoolsSource();
|
|
2276
2546
|
}
|
|
2277
|
-
function
|
|
2547
|
+
function injectOpenResourceHandler(serviceWc, devtoolsWc) {
|
|
2548
|
+
if (serviceWc.isDestroyed() || devtoolsWc.isDestroyed()) return;
|
|
2278
2549
|
try {
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2550
|
+
const sourceContext = projectSourceContextFromServiceHostUrl(
|
|
2551
|
+
serviceWc.getURL(),
|
|
2552
|
+
ctx.workspace?.getProjectPath?.()
|
|
2553
|
+
);
|
|
2554
|
+
if (!sourceContext) return;
|
|
2555
|
+
devtoolsWc.executeJavaScript(buildDevtoolsProjectSourceLinksScript(sourceContext)).catch(() => {
|
|
2556
|
+
});
|
|
2557
|
+
} catch {
|
|
2282
2558
|
}
|
|
2283
2559
|
}
|
|
2284
|
-
function
|
|
2285
|
-
|
|
2286
|
-
if (
|
|
2560
|
+
function customizeDevtoolsTabs(devtoolsWc) {
|
|
2561
|
+
try {
|
|
2562
|
+
if (devtoolsWc.isDestroyed()) return;
|
|
2563
|
+
const inject = () => {
|
|
2564
|
+
if (devtoolsWc.isDestroyed()) return;
|
|
2565
|
+
try {
|
|
2566
|
+
void devtoolsWc.executeJavaScript(buildCustomizeTabsScript()).catch(() => {
|
|
2567
|
+
});
|
|
2568
|
+
} catch {
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
injectWhenReady(devtoolsWc, "customize-tabs", inject);
|
|
2572
|
+
} catch {
|
|
2287
2573
|
}
|
|
2288
2574
|
}
|
|
2289
|
-
function
|
|
2290
|
-
if (
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2575
|
+
function wireOpenInEditor(serviceWc, devtoolsWc) {
|
|
2576
|
+
if (!devtoolsWc.isDestroyed()) {
|
|
2577
|
+
injectWhenReady(devtoolsWc, "open-in-editor", () => injectOpenResourceHandler(serviceWc, devtoolsWc));
|
|
2578
|
+
}
|
|
2579
|
+
if (openInEditorWiredWcIds.has(serviceWc.id)) return;
|
|
2580
|
+
openInEditorWiredWcIds.add(serviceWc.id);
|
|
2581
|
+
const onOpenUrl = (_event, url) => {
|
|
2582
|
+
const req = decodeOpenInEditorUrl(url);
|
|
2583
|
+
if (!req) return;
|
|
2584
|
+
const target = resolveProjectEditorTarget(
|
|
2585
|
+
serviceWc.getURL(),
|
|
2586
|
+
ctx.workspace?.getProjectPath?.(),
|
|
2587
|
+
req
|
|
2588
|
+
);
|
|
2589
|
+
if (!target) return;
|
|
2590
|
+
deps.openFileInWorkbench(target.path, target.line ?? 1, target.column ?? 1);
|
|
2591
|
+
ctx.notify.editorOpenFile(target);
|
|
2592
|
+
};
|
|
2593
|
+
serviceWc.on("devtools-open-url", onOpenUrl);
|
|
2594
|
+
const conn = ctx.connections.acquire(serviceWc);
|
|
2595
|
+
conn.on("closed", () => {
|
|
2596
|
+
openInEditorWiredWcIds.delete(serviceWc.id);
|
|
2597
|
+
try {
|
|
2598
|
+
serviceWc.removeListener("devtools-open-url", onOpenUrl);
|
|
2599
|
+
} catch {
|
|
2600
|
+
}
|
|
2601
|
+
});
|
|
2602
|
+
}
|
|
2603
|
+
function pointNativeDevtoolsAtServiceWc(next) {
|
|
2604
|
+
if (!simulatorView || simulatorView.webContents.isDestroyed()) return true;
|
|
2605
|
+
if (nativeDevtoolsSourceWc?.id === next.id && !nativeDevtoolsSourceWc.isDestroyed()) {
|
|
2606
|
+
return true;
|
|
2607
|
+
}
|
|
2608
|
+
closeNativeDevtoolsSource();
|
|
2609
|
+
nativeDevtoolsSourceWc = next;
|
|
2610
|
+
if (devtoolsHostUsed) {
|
|
2611
|
+
rebuildDevtoolsHostView();
|
|
2612
|
+
}
|
|
2613
|
+
if (!simulatorView || simulatorView.webContents.isDestroyed()) return true;
|
|
2614
|
+
try {
|
|
2615
|
+
next.setDevToolsWebContents(simulatorView.webContents);
|
|
2616
|
+
next.openDevTools({ mode: "detach", activate: false });
|
|
2617
|
+
devtoolsHostUsed = true;
|
|
2618
|
+
wireOpenInEditor(next, simulatorView.webContents);
|
|
2619
|
+
customizeDevtoolsTabs(simulatorView.webContents);
|
|
2620
|
+
try {
|
|
2621
|
+
stopServiceConsole?.();
|
|
2622
|
+
} catch {
|
|
2623
|
+
}
|
|
2624
|
+
stopServiceConsole = installServiceConsoleForward({
|
|
2625
|
+
serviceWc: next,
|
|
2626
|
+
connections: ctx.connections,
|
|
2627
|
+
emit: (entry) => ctx.consoleForwarder?.emit(entry)
|
|
2628
|
+
}).stop;
|
|
2629
|
+
return true;
|
|
2630
|
+
} catch (err) {
|
|
2631
|
+
console.warn("[devtools-host] point-at-service-wc failed; retry will rebuild:", err);
|
|
2632
|
+
if (nativeDevtoolsSourceWc?.id === next.id) {
|
|
2633
|
+
nativeDevtoolsSourceWc = null;
|
|
2634
|
+
}
|
|
2635
|
+
return false;
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
function pointNativeDevtoolsAtActiveServiceHost(appId) {
|
|
2639
|
+
if (!ctx.bridge?.isNativeHost()) return true;
|
|
2640
|
+
if (!simulatorView || simulatorView.webContents.isDestroyed()) return true;
|
|
2641
|
+
const wc = ctx.bridge.getServiceWc(appId);
|
|
2642
|
+
if (!wc || wc.isDestroyed()) return false;
|
|
2643
|
+
return pointNativeDevtoolsAtServiceWc(wc);
|
|
2644
|
+
}
|
|
2645
|
+
function scheduleNativeDevtoolsFollow(appId, attempt = 0) {
|
|
2646
|
+
if (attempt >= 20) return;
|
|
2647
|
+
if (!ctx.bridge?.isNativeHost()) return;
|
|
2648
|
+
const token = nativeDevtoolsRetryToken;
|
|
2649
|
+
if (nativeDevtoolsRetryTimer) clearTimeout(nativeDevtoolsRetryTimer);
|
|
2650
|
+
nativeDevtoolsRetryTimer = setTimeout(() => {
|
|
2651
|
+
nativeDevtoolsRetryTimer = null;
|
|
2652
|
+
if (token !== nativeDevtoolsRetryToken) return;
|
|
2653
|
+
if (pointNativeDevtoolsAtActiveServiceHost(appId)) return;
|
|
2654
|
+
scheduleNativeDevtoolsFollow(appId, attempt + 1);
|
|
2655
|
+
}, 50);
|
|
2656
|
+
}
|
|
2657
|
+
function followNativeDevtoolsServiceHost(appId) {
|
|
2658
|
+
clearNativeDevtoolsRetry();
|
|
2659
|
+
if (pointNativeDevtoolsAtActiveServiceHost(appId)) return;
|
|
2660
|
+
scheduleNativeDevtoolsFollow(appId);
|
|
2661
|
+
}
|
|
2662
|
+
function onNativeRenderEvent(event) {
|
|
2663
|
+
if (event.kind !== "activePage" && event.kind !== "domReady") return;
|
|
2664
|
+
followNativeDevtoolsServiceHost(event.appId);
|
|
2665
|
+
}
|
|
2666
|
+
function rebuildDevtoolsHostView() {
|
|
2667
|
+
if (simulatorView) {
|
|
2668
|
+
removeSimulatorDevtoolsView();
|
|
2669
|
+
try {
|
|
2670
|
+
if (!simulatorView.webContents.isDestroyed()) {
|
|
2671
|
+
simulatorView.webContents.close();
|
|
2672
|
+
}
|
|
2673
|
+
} catch {
|
|
2674
|
+
}
|
|
2675
|
+
simulatorView = null;
|
|
2676
|
+
}
|
|
2677
|
+
simulatorView = new WebContentsView3();
|
|
2678
|
+
const devtoolsWc = simulatorView.webContents;
|
|
2679
|
+
raiseExecuteJavaScriptListenerCeiling(devtoolsWc);
|
|
2680
|
+
ctx.networkForward?.setDevtoolsHost(devtoolsWc);
|
|
2681
|
+
if (ctx.bridge) {
|
|
2682
|
+
try {
|
|
2683
|
+
stopElementsForward?.();
|
|
2684
|
+
} catch {
|
|
2685
|
+
}
|
|
2686
|
+
const thisForward = installElementsForward({ devtoolsWc, bridge: ctx.bridge, connections: ctx.connections });
|
|
2687
|
+
stopElementsForward = thisForward;
|
|
2688
|
+
devtoolsWc.once("destroyed", () => {
|
|
2689
|
+
try {
|
|
2690
|
+
thisForward();
|
|
2691
|
+
} catch {
|
|
2692
|
+
}
|
|
2693
|
+
if (stopElementsForward === thisForward) stopElementsForward = null;
|
|
2694
|
+
});
|
|
2695
|
+
}
|
|
2696
|
+
injectWhenReady(devtoolsWc, "console-default", () => {
|
|
2697
|
+
devtoolsWc.executeJavaScript(`
|
|
2698
|
+
(function() {
|
|
2699
|
+
try { localStorage.setItem('panel-selectedTab', '"console"') } catch {}
|
|
2700
|
+
let tries = 0
|
|
2701
|
+
const timer = setInterval(() => {
|
|
2702
|
+
tries++
|
|
2703
|
+
try {
|
|
2704
|
+
const UI = globalThis.UI
|
|
2705
|
+
const vm = UI && UI.ViewManager && typeof UI.ViewManager.instance === 'function'
|
|
2706
|
+
? UI.ViewManager.instance()
|
|
2707
|
+
: null
|
|
2708
|
+
if (vm && typeof vm.showView === 'function') {
|
|
2709
|
+
vm.showView('console')
|
|
2710
|
+
clearInterval(timer)
|
|
2711
|
+
return
|
|
2712
|
+
}
|
|
2713
|
+
} catch {}
|
|
2714
|
+
if (tries > 80) clearInterval(timer)
|
|
2715
|
+
}, 50)
|
|
2716
|
+
})()
|
|
2717
|
+
`).catch(() => {
|
|
2718
|
+
});
|
|
2719
|
+
});
|
|
2720
|
+
reconciler.reconcileNow();
|
|
2721
|
+
devtoolsHostUsed = false;
|
|
2722
|
+
}
|
|
2723
|
+
function attachNativeSimulatorDevtoolsHost() {
|
|
2724
|
+
stopFollowingNativeServiceHost();
|
|
2725
|
+
rebuildDevtoolsHostView();
|
|
2726
|
+
if (ctx.bridge?.isNativeHost()) {
|
|
2727
|
+
unsubscribeNativeRenderEvents = ctx.bridge.onRenderEvent(onNativeRenderEvent);
|
|
2728
|
+
followNativeDevtoolsServiceHost();
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
function removeSimulatorDevtoolsView() {
|
|
2732
|
+
if (simulatorView && simulatorViewAdded) {
|
|
2733
|
+
try {
|
|
2734
|
+
ctx.windows.mainWindow.contentView.removeChildView(simulatorView);
|
|
2735
|
+
} catch (e) {
|
|
2736
|
+
console.error("[workbench] removeSimulatorDevtoolsView error", e);
|
|
2737
|
+
}
|
|
2738
|
+
simulatorViewAdded = false;
|
|
2739
|
+
}
|
|
2740
|
+
reconciler.forgetActual(VIEW_ID.simulatorDevtools);
|
|
2741
|
+
}
|
|
2742
|
+
reconciler.registerView(VIEW_ID.simulatorDevtools, {
|
|
2743
|
+
getView: () => simulatorView,
|
|
2744
|
+
setAdded: (added) => {
|
|
2745
|
+
simulatorViewAdded = added;
|
|
2746
|
+
},
|
|
2747
|
+
gateHidden: () => !simulatorView
|
|
2748
|
+
});
|
|
2749
|
+
return {
|
|
2750
|
+
attach: attachNativeSimulatorDevtoolsHost,
|
|
2751
|
+
followServiceHost: followNativeDevtoolsServiceHost,
|
|
2752
|
+
stopFollowing: stopFollowingNativeServiceHost,
|
|
2753
|
+
stopElementsForwarding: () => {
|
|
2754
|
+
try {
|
|
2755
|
+
stopElementsForward?.();
|
|
2756
|
+
} catch {
|
|
2757
|
+
}
|
|
2758
|
+
stopElementsForward = null;
|
|
2759
|
+
},
|
|
2760
|
+
destroyHostView: () => {
|
|
2761
|
+
destroyChildView(ctx.windows.mainWindow, simulatorView);
|
|
2762
|
+
simulatorView = null;
|
|
2763
|
+
simulatorViewAdded = false;
|
|
2764
|
+
}
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
// src/main/services/views/host-toolbar-view.ts
|
|
2769
|
+
import { WebContentsView as WebContentsView4 } from "electron";
|
|
2770
|
+
|
|
2771
|
+
// src/main/services/views/host-toolbar-session-runtime.ts
|
|
2772
|
+
import { session } from "electron";
|
|
2773
|
+
var refCount = 0;
|
|
2774
|
+
var registrationId = null;
|
|
2775
|
+
function acquireHostToolbarSessionRuntime() {
|
|
2776
|
+
if (refCount === 0) {
|
|
2777
|
+
registrationId = session.defaultSession.registerPreloadScript({
|
|
2778
|
+
type: "frame",
|
|
2779
|
+
filePath: hostToolbarRuntimePreloadPath
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
refCount++;
|
|
2783
|
+
}
|
|
2784
|
+
function releaseHostToolbarSessionRuntime() {
|
|
2785
|
+
if (refCount === 0) return;
|
|
2786
|
+
refCount--;
|
|
2787
|
+
if (refCount === 0 && registrationId !== null) {
|
|
2788
|
+
session.defaultSession.unregisterPreloadScript(registrationId);
|
|
2789
|
+
registrationId = null;
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
|
|
2793
|
+
// src/main/services/views/host-toolbar-port-channel.ts
|
|
2794
|
+
import { MessageChannelMain } from "electron";
|
|
2795
|
+
function createHostToolbarPortChannel(opts) {
|
|
2796
|
+
let activePort = null;
|
|
2797
|
+
let activeWc = null;
|
|
2798
|
+
let state = "absent";
|
|
2799
|
+
let generation = 0;
|
|
2800
|
+
const handlers2 = [];
|
|
2801
|
+
const readyHandlers = [];
|
|
2802
|
+
function dispatch(data) {
|
|
2803
|
+
if (typeof data !== "object" || data === null) return;
|
|
2804
|
+
const { channel, payload } = data;
|
|
2805
|
+
if (typeof channel !== "string") return;
|
|
2806
|
+
for (const entry of [...handlers2]) {
|
|
2807
|
+
if (entry.channel === channel) entry.handler(payload);
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
function dropActivePort(close, next) {
|
|
2811
|
+
const port = activePort;
|
|
2812
|
+
activePort = null;
|
|
2813
|
+
activeWc = null;
|
|
2814
|
+
if (state !== "disposed") state = next;
|
|
2815
|
+
if (close && port) {
|
|
2816
|
+
try {
|
|
2817
|
+
port.close();
|
|
2818
|
+
} catch {
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
function invokeReadyHandler(handler) {
|
|
2823
|
+
try {
|
|
2824
|
+
handler();
|
|
2825
|
+
} catch (err) {
|
|
2826
|
+
console.error("[host-toolbar] onReady handler threw:", err);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
function fireReadyHandlers() {
|
|
2830
|
+
for (const entry of [...readyHandlers]) {
|
|
2831
|
+
if (readyHandlers.includes(entry)) invokeReadyHandler(entry.handler);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
function handshake(wc) {
|
|
2835
|
+
if (state === "disposed") return;
|
|
2836
|
+
if (!opts.isCurrent(wc)) return;
|
|
2837
|
+
dropActivePort(true, "awaitingHandshake");
|
|
2838
|
+
const { port1, port2 } = new MessageChannelMain();
|
|
2294
2839
|
port1.on("message", (event) => {
|
|
2295
2840
|
dispatch(event.data);
|
|
2296
2841
|
});
|
|
@@ -2376,90 +2921,8 @@ function createHostToolbarPortChannel(opts) {
|
|
|
2376
2921
|
};
|
|
2377
2922
|
}
|
|
2378
2923
|
|
|
2379
|
-
// src/
|
|
2380
|
-
function
|
|
2381
|
-
const qIdx = value.indexOf("?");
|
|
2382
|
-
if (qIdx < 0) return { pagePath: value, query: {} };
|
|
2383
|
-
const pagePath = value.slice(0, qIdx);
|
|
2384
|
-
const query = {};
|
|
2385
|
-
for (const pair of value.slice(qIdx + 1).split("&")) {
|
|
2386
|
-
if (!pair) continue;
|
|
2387
|
-
const eqIdx = pair.indexOf("=");
|
|
2388
|
-
const k = eqIdx >= 0 ? pair.slice(0, eqIdx) : pair;
|
|
2389
|
-
const v = eqIdx >= 0 ? pair.slice(eqIdx + 1) : "";
|
|
2390
|
-
if (k) query[decodeURIComponent(k)] = decodeURIComponent(v);
|
|
2391
|
-
}
|
|
2392
|
-
return { pagePath, query };
|
|
2393
|
-
}
|
|
2394
|
-
function parseLocationRoute(search) {
|
|
2395
|
-
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
|
2396
|
-
const appId = params.get("appId");
|
|
2397
|
-
const entryRaw = params.get("entry");
|
|
2398
|
-
if (!appId || !entryRaw) return null;
|
|
2399
|
-
const entry = decodePageSpec(entryRaw);
|
|
2400
|
-
const pageRaw = params.get("page");
|
|
2401
|
-
const current = pageRaw && pageRaw !== entryRaw ? decodePageSpec(pageRaw) : entry;
|
|
2402
|
-
return { appId, entry, current };
|
|
2403
|
-
}
|
|
2404
|
-
function parseRoute(url) {
|
|
2405
|
-
if (!url) return null;
|
|
2406
|
-
try {
|
|
2407
|
-
const u = new URL(url);
|
|
2408
|
-
return parseLocationRoute(u.search);
|
|
2409
|
-
} catch {
|
|
2410
|
-
return null;
|
|
2411
|
-
}
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
// src/main/services/views/view-manager.ts
|
|
2415
|
-
function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFile = (absolutePath) => fs4.statSync(absolutePath).isFile()) {
|
|
2416
|
-
const sourceContext = projectSourceContextFromServiceHostUrl(
|
|
2417
|
-
serviceHostUrl,
|
|
2418
|
-
activeProjectRoot
|
|
2419
|
-
);
|
|
2420
|
-
if (!sourceContext) return null;
|
|
2421
|
-
const rel = resourceUrlToProjectRelativePath(req.url, sourceContext);
|
|
2422
|
-
if (!rel) return null;
|
|
2423
|
-
const absolute = path7.resolve(sourceContext.projectRoot, ...rel.split("/"));
|
|
2424
|
-
const fromRoot = path7.relative(path7.resolve(sourceContext.projectRoot), absolute);
|
|
2425
|
-
if (!fromRoot || fromRoot.startsWith("..") || path7.isAbsolute(fromRoot)) return null;
|
|
2426
|
-
try {
|
|
2427
|
-
if (!isFile(absolute)) return null;
|
|
2428
|
-
} catch {
|
|
2429
|
-
return null;
|
|
2430
|
-
}
|
|
2431
|
-
return {
|
|
2432
|
-
path: rel,
|
|
2433
|
-
line: typeof req.line === "number" ? req.line + 1 : void 0,
|
|
2434
|
-
column: typeof req.column === "number" ? req.column + 1 : void 0
|
|
2435
|
-
};
|
|
2436
|
-
}
|
|
2437
|
-
function createViewManager(ctx) {
|
|
2438
|
-
const safeArea = createSafeAreaController({ connections: ctx.connections });
|
|
2439
|
-
let simulatorView = null;
|
|
2440
|
-
let simulatorViewAdded = false;
|
|
2441
|
-
let nativeSimulatorView = null;
|
|
2442
|
-
let nativeSimulatorViewAdded = false;
|
|
2443
|
-
let nativeSimulatorProjectPath = null;
|
|
2444
|
-
let settleNativeSimulatorReady = null;
|
|
2445
|
-
let lastRendererRect = null;
|
|
2446
|
-
let nativeCustomApiBridgeHandler = null;
|
|
2447
|
-
let currentZoomFactor = 1;
|
|
2448
|
-
let settingsView = null;
|
|
2449
|
-
let settingsViewAdded = false;
|
|
2450
|
-
let popoverView = null;
|
|
2451
|
-
let simulatorWebContentsId = null;
|
|
2452
|
-
let nativeDevtoolsSourceWc = null;
|
|
2453
|
-
let unsubscribeNativeRenderEvents = null;
|
|
2454
|
-
let stopElementsForward = null;
|
|
2455
|
-
let stopServiceConsole = null;
|
|
2456
|
-
let nativeDevtoolsRetryTimer = null;
|
|
2457
|
-
let nativeDevtoolsRetryToken = 0;
|
|
2458
|
-
let simulatorBoundsOverride = null;
|
|
2459
|
-
let workbenchView = null;
|
|
2460
|
-
let workbenchViewAdded = false;
|
|
2461
|
-
let workbenchThemeSyncBound = false;
|
|
2462
|
-
let workbenchUrl = null;
|
|
2924
|
+
// src/main/services/views/host-toolbar-view.ts
|
|
2925
|
+
function createHostToolbarView(ctx, reconciler, deps) {
|
|
2463
2926
|
let hostToolbarView = null;
|
|
2464
2927
|
let hostToolbarPreloadOverride = null;
|
|
2465
2928
|
let hostToolbarViewAdded = false;
|
|
@@ -2469,153 +2932,6 @@ function createViewManager(ctx) {
|
|
|
2469
2932
|
const hostToolbarPort = createHostToolbarPortChannel({
|
|
2470
2933
|
isCurrent: (wc) => liveHostToolbarWebContents() === wc
|
|
2471
2934
|
});
|
|
2472
|
-
function destroyViewInternal(view) {
|
|
2473
|
-
if (!view) return;
|
|
2474
|
-
if (!ctx.windows.mainWindow.isDestroyed()) {
|
|
2475
|
-
try {
|
|
2476
|
-
ctx.windows.mainWindow.contentView.removeChildView(view);
|
|
2477
|
-
} catch {
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
try {
|
|
2481
|
-
if (!view.webContents.isDestroyed()) {
|
|
2482
|
-
view.webContents.close();
|
|
2483
|
-
}
|
|
2484
|
-
} catch {
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
function isHidden(b) {
|
|
2488
|
-
return b.width <= 0 || b.height <= 0;
|
|
2489
|
-
}
|
|
2490
|
-
function setSimulatorDevtoolsBounds(bounds) {
|
|
2491
|
-
simulatorBoundsOverride = bounds;
|
|
2492
|
-
if (!simulatorView || simulatorView.webContents.isDestroyed()) return;
|
|
2493
|
-
if (ctx.windows.mainWindow.isDestroyed()) return;
|
|
2494
|
-
if (isHidden(bounds)) {
|
|
2495
|
-
if (simulatorViewAdded) {
|
|
2496
|
-
try {
|
|
2497
|
-
ctx.windows.mainWindow.contentView.removeChildView(simulatorView);
|
|
2498
|
-
} catch {
|
|
2499
|
-
}
|
|
2500
|
-
simulatorViewAdded = false;
|
|
2501
|
-
}
|
|
2502
|
-
return;
|
|
2503
|
-
}
|
|
2504
|
-
if (!simulatorViewAdded) {
|
|
2505
|
-
ctx.windows.mainWindow.contentView.addChildView(simulatorView);
|
|
2506
|
-
simulatorViewAdded = true;
|
|
2507
|
-
raiseTopOverlays();
|
|
2508
|
-
}
|
|
2509
|
-
simulatorView.setBounds(bounds);
|
|
2510
|
-
}
|
|
2511
|
-
function workbenchThemeScheme() {
|
|
2512
|
-
return nativeTheme3.shouldUseDarkColors ? "dark" : "light";
|
|
2513
|
-
}
|
|
2514
|
-
function pushWorkbenchTheme() {
|
|
2515
|
-
if (!workbenchView || workbenchView.webContents.isDestroyed()) return;
|
|
2516
|
-
const wc = workbenchView.webContents;
|
|
2517
|
-
if (typeof wc.executeJavaScript !== "function") return;
|
|
2518
|
-
const script = `window.__WB_SET_THEME && window.__WB_SET_THEME(${JSON.stringify(workbenchThemeScheme())})`;
|
|
2519
|
-
wc.executeJavaScript(script, true).catch(() => {
|
|
2520
|
-
});
|
|
2521
|
-
}
|
|
2522
|
-
async function attachWorkbench(url) {
|
|
2523
|
-
if (workbenchView) return;
|
|
2524
|
-
const view = new WebContentsView2({
|
|
2525
|
-
webPreferences: {
|
|
2526
|
-
nodeIntegration: false,
|
|
2527
|
-
contextIsolation: true,
|
|
2528
|
-
sandbox: false
|
|
2529
|
-
}
|
|
2530
|
-
});
|
|
2531
|
-
workbenchView = view;
|
|
2532
|
-
if (!workbenchThemeSyncBound) {
|
|
2533
|
-
nativeTheme3.on("updated", pushWorkbenchTheme);
|
|
2534
|
-
workbenchThemeSyncBound = true;
|
|
2535
|
-
}
|
|
2536
|
-
try {
|
|
2537
|
-
view.webContents.setWindowOpenHandler(({ url: target }) => handleWindowOpenExternal(target));
|
|
2538
|
-
} catch {
|
|
2539
|
-
}
|
|
2540
|
-
ctx.windows.mainWindow.contentView.addChildView(view);
|
|
2541
|
-
workbenchViewAdded = true;
|
|
2542
|
-
raiseTopOverlays();
|
|
2543
|
-
const loadUrl = `${url}index.html?theme=${workbenchThemeScheme()}`;
|
|
2544
|
-
await view.webContents.loadURL(loadUrl).catch((err) => {
|
|
2545
|
-
console.error("[workbench] attachWorkbench \u2014 loadURL failed", err);
|
|
2546
|
-
});
|
|
2547
|
-
}
|
|
2548
|
-
function setWorkbenchSource(url) {
|
|
2549
|
-
workbenchUrl = url;
|
|
2550
|
-
}
|
|
2551
|
-
function setWorkbenchBounds(bounds) {
|
|
2552
|
-
if (ctx.windows.mainWindow.isDestroyed()) return;
|
|
2553
|
-
if (isHidden(bounds)) {
|
|
2554
|
-
if (workbenchView && workbenchViewAdded && !workbenchView.webContents.isDestroyed()) {
|
|
2555
|
-
try {
|
|
2556
|
-
ctx.windows.mainWindow.contentView.removeChildView(workbenchView);
|
|
2557
|
-
} catch {
|
|
2558
|
-
}
|
|
2559
|
-
workbenchViewAdded = false;
|
|
2560
|
-
}
|
|
2561
|
-
return;
|
|
2562
|
-
}
|
|
2563
|
-
if (!workbenchView && workbenchUrl) {
|
|
2564
|
-
void attachWorkbench(workbenchUrl);
|
|
2565
|
-
}
|
|
2566
|
-
if (!workbenchView || workbenchView.webContents.isDestroyed()) return;
|
|
2567
|
-
if (!workbenchViewAdded) {
|
|
2568
|
-
ctx.windows.mainWindow.contentView.addChildView(workbenchView);
|
|
2569
|
-
workbenchViewAdded = true;
|
|
2570
|
-
raiseTopOverlays();
|
|
2571
|
-
}
|
|
2572
|
-
workbenchView.setBounds(bounds);
|
|
2573
|
-
}
|
|
2574
|
-
function detachWorkbench() {
|
|
2575
|
-
if (workbenchThemeSyncBound) {
|
|
2576
|
-
nativeTheme3.removeListener("updated", pushWorkbenchTheme);
|
|
2577
|
-
workbenchThemeSyncBound = false;
|
|
2578
|
-
}
|
|
2579
|
-
destroyViewInternal(workbenchView);
|
|
2580
|
-
workbenchView = null;
|
|
2581
|
-
workbenchViewAdded = false;
|
|
2582
|
-
}
|
|
2583
|
-
function workspaceUriFor(rel) {
|
|
2584
|
-
const encoded = rel.split("/").map(encodeURIComponent).join("/");
|
|
2585
|
-
return `file:///workspace/${encoded}`;
|
|
2586
|
-
}
|
|
2587
|
-
function tryRevealInWorkbench(uri, zeroLine, zeroCol) {
|
|
2588
|
-
if (!workbenchView || workbenchView.webContents.isDestroyed()) {
|
|
2589
|
-
return Promise.resolve(false);
|
|
2590
|
-
}
|
|
2591
|
-
const script = `(async () => {
|
|
2592
|
-
try {
|
|
2593
|
-
const P = window.__WB_PROBE; if (!P) return false
|
|
2594
|
-
const vscode = P.vscode
|
|
2595
|
-
const uri = vscode.Uri.parse(${JSON.stringify(uri)})
|
|
2596
|
-
const doc = await vscode.workspace.openTextDocument(uri)
|
|
2597
|
-
const pos = new vscode.Position(${zeroLine}, ${zeroCol})
|
|
2598
|
-
await vscode.window.showTextDocument(doc, { selection: new vscode.Range(pos, pos) })
|
|
2599
|
-
return true
|
|
2600
|
-
} catch (e) { return false }
|
|
2601
|
-
})()`;
|
|
2602
|
-
return workbenchView.webContents.executeJavaScript(script, true).then((ok) => ok === true).catch(() => false);
|
|
2603
|
-
}
|
|
2604
|
-
function openFileInWorkbench(relPath, line, column) {
|
|
2605
|
-
if (!workbenchView || workbenchView.webContents.isDestroyed()) return false;
|
|
2606
|
-
const uri = workspaceUriFor(relPath.replace(/^\/+/, ""));
|
|
2607
|
-
const zeroLine = Math.max(0, Math.floor(line) - 1);
|
|
2608
|
-
const zeroCol = Math.max(0, Math.floor(column) - 1);
|
|
2609
|
-
void (async () => {
|
|
2610
|
-
for (let attempt = 0; attempt < 10; attempt++) {
|
|
2611
|
-
if (!workbenchView || workbenchView.webContents.isDestroyed()) return;
|
|
2612
|
-
if (await tryRevealInWorkbench(uri, zeroLine, zeroCol)) return;
|
|
2613
|
-
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
2614
|
-
}
|
|
2615
|
-
console.error("[workbench] openFileInWorkbench: workbench never became ready for", uri);
|
|
2616
|
-
})();
|
|
2617
|
-
return true;
|
|
2618
|
-
}
|
|
2619
2935
|
function liveHostToolbarWebContents() {
|
|
2620
2936
|
const wc = hostToolbarView?.webContents;
|
|
2621
2937
|
if (!wc || wc.isDestroyed()) return null;
|
|
@@ -2632,6 +2948,7 @@ function createViewManager(ctx) {
|
|
|
2632
2948
|
}
|
|
2633
2949
|
hostToolbarViewAdded = false;
|
|
2634
2950
|
}
|
|
2951
|
+
reconciler.forgetActual(VIEW_ID.hostToolbar);
|
|
2635
2952
|
if (!hostToolbarRuntimeAcquired) {
|
|
2636
2953
|
acquireHostToolbarSessionRuntime();
|
|
2637
2954
|
hostToolbarRuntimeAcquired = true;
|
|
@@ -2645,7 +2962,7 @@ function createViewManager(ctx) {
|
|
|
2645
2962
|
if (hostToolbarPreloadOverride !== null) {
|
|
2646
2963
|
webPreferences.preload = hostToolbarPreloadOverride;
|
|
2647
2964
|
}
|
|
2648
|
-
const view = new
|
|
2965
|
+
const view = new WebContentsView4({ webPreferences });
|
|
2649
2966
|
hostToolbarView = view;
|
|
2650
2967
|
hostToolbarPort.attach(view.webContents);
|
|
2651
2968
|
try {
|
|
@@ -2658,46 +2975,25 @@ function createViewManager(ctx) {
|
|
|
2658
2975
|
}
|
|
2659
2976
|
return view;
|
|
2660
2977
|
}
|
|
2661
|
-
function setHostToolbarBounds(bounds) {
|
|
2662
|
-
if (ctx.windows.mainWindow.isDestroyed()) return;
|
|
2663
|
-
if (isHidden(bounds)) {
|
|
2664
|
-
if (hostToolbarView && hostToolbarViewAdded && liveHostToolbarWebContents()) {
|
|
2665
|
-
try {
|
|
2666
|
-
ctx.windows.mainWindow.contentView.removeChildView(hostToolbarView);
|
|
2667
|
-
} catch {
|
|
2668
|
-
}
|
|
2669
|
-
}
|
|
2670
|
-
hostToolbarViewAdded = false;
|
|
2671
|
-
return;
|
|
2672
|
-
}
|
|
2673
|
-
const view = ensureHostToolbarView();
|
|
2674
|
-
if (!hostToolbarViewAdded) {
|
|
2675
|
-
ctx.windows.mainWindow.contentView.addChildView(view);
|
|
2676
|
-
hostToolbarViewAdded = true;
|
|
2677
|
-
}
|
|
2678
|
-
view.setBounds(bounds);
|
|
2679
|
-
}
|
|
2680
2978
|
function notifyHostToolbarHeight(height) {
|
|
2681
2979
|
hostToolbarLastHeight = height;
|
|
2682
2980
|
ctx.notify.hostToolbarHeightChanged(height);
|
|
2683
|
-
|
|
2684
|
-
if (popoverView) applyPopoverBounds();
|
|
2981
|
+
deps.reapplyPresentOverlays();
|
|
2685
2982
|
}
|
|
2686
2983
|
function setHostToolbarHeight(extent) {
|
|
2687
2984
|
if (hostToolbarHeightMode !== "auto") return;
|
|
2688
2985
|
notifyHostToolbarHeight(extent);
|
|
2689
2986
|
}
|
|
2690
2987
|
function hideHostToolbar() {
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
hostToolbarViewAdded = false;
|
|
2988
|
+
reconciler.setBaseDesired(VIEW_ID.hostToolbar, {
|
|
2989
|
+
viewId: VIEW_ID.hostToolbar,
|
|
2990
|
+
placement: { visible: false },
|
|
2991
|
+
layer: VIEW_LAYER.hostToolbar
|
|
2992
|
+
});
|
|
2993
|
+
reconciler.reconcileNow();
|
|
2698
2994
|
notifyHostToolbarHeight(0);
|
|
2699
2995
|
}
|
|
2700
|
-
const
|
|
2996
|
+
const control = {
|
|
2701
2997
|
async loadURL(url) {
|
|
2702
2998
|
const view = ensureHostToolbarView();
|
|
2703
2999
|
hostToolbarPort.invalidate();
|
|
@@ -2714,8 +3010,8 @@ function createViewManager(ctx) {
|
|
|
2714
3010
|
hide() {
|
|
2715
3011
|
hideHostToolbar();
|
|
2716
3012
|
},
|
|
2717
|
-
setPreloadPath(
|
|
2718
|
-
hostToolbarPreloadOverride =
|
|
3013
|
+
setPreloadPath(path24) {
|
|
3014
|
+
hostToolbarPreloadOverride = path24;
|
|
2719
3015
|
},
|
|
2720
3016
|
setHeightMode(mode) {
|
|
2721
3017
|
if (mode !== "auto" && !(Number.isFinite(mode.fixed) && mode.fixed >= 0)) {
|
|
@@ -2738,243 +3034,417 @@ function createViewManager(ctx) {
|
|
|
2738
3034
|
return hostToolbarPort.send(channel, payload);
|
|
2739
3035
|
}
|
|
2740
3036
|
};
|
|
3037
|
+
reconciler.registerView(VIEW_ID.hostToolbar, {
|
|
3038
|
+
getView: () => hostToolbarView,
|
|
3039
|
+
ensureView: () => ensureHostToolbarView(),
|
|
3040
|
+
setAdded: (added) => {
|
|
3041
|
+
hostToolbarViewAdded = added;
|
|
3042
|
+
},
|
|
3043
|
+
ensureLazy: (desired) => {
|
|
3044
|
+
if (desired?.placement.visible && !liveHostToolbarWebContents()) ensureHostToolbarView();
|
|
3045
|
+
}
|
|
3046
|
+
});
|
|
3047
|
+
function dispose() {
|
|
3048
|
+
hostToolbarPort.dispose();
|
|
3049
|
+
destroyChildView(ctx.windows.mainWindow, hostToolbarView);
|
|
3050
|
+
hostToolbarView = null;
|
|
3051
|
+
hostToolbarViewAdded = false;
|
|
3052
|
+
if (hostToolbarRuntimeAcquired) {
|
|
3053
|
+
releaseHostToolbarSessionRuntime();
|
|
3054
|
+
hostToolbarRuntimeAcquired = false;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
return {
|
|
3058
|
+
control,
|
|
3059
|
+
setHostToolbarHeight,
|
|
3060
|
+
getHostToolbarHeight: () => hostToolbarLastHeight,
|
|
3061
|
+
getHostToolbarWebContentsId: () => liveHostToolbarWebContents()?.id ?? null,
|
|
3062
|
+
dispose
|
|
3063
|
+
};
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
// src/main/services/views/overlay-panels-view.ts
|
|
3067
|
+
import { WebContentsView as WebContentsView5 } from "electron";
|
|
3068
|
+
import path8 from "path";
|
|
3069
|
+
|
|
3070
|
+
// src/main/services/layout/index.ts
|
|
3071
|
+
function computeNativeSimulatorViewParams(rect, zoomPercent) {
|
|
3072
|
+
const zoomFactor = zoomPercent / 100;
|
|
3073
|
+
return {
|
|
3074
|
+
bounds: {
|
|
3075
|
+
x: Math.round(rect.x),
|
|
3076
|
+
y: Math.round(rect.y),
|
|
3077
|
+
width: Math.max(0, Math.round(rect.width)),
|
|
3078
|
+
height: Math.max(0, Math.round(rect.height))
|
|
3079
|
+
},
|
|
3080
|
+
zoomFactor
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
function computeSettingsBounds(contentWidth, contentHeight, headerHeight) {
|
|
3084
|
+
return {
|
|
3085
|
+
x: 0,
|
|
3086
|
+
y: headerHeight,
|
|
3087
|
+
width: Math.max(1, contentWidth),
|
|
3088
|
+
height: Math.max(1, contentHeight - headerHeight)
|
|
3089
|
+
};
|
|
3090
|
+
}
|
|
3091
|
+
function computePopoverBounds(contentWidth, contentHeight, headerHeight) {
|
|
3092
|
+
return {
|
|
3093
|
+
x: 0,
|
|
3094
|
+
y: headerHeight,
|
|
3095
|
+
width: Math.max(1, contentWidth),
|
|
3096
|
+
height: contentHeight - headerHeight
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
// src/main/services/views/overlay-panels-view.ts
|
|
3101
|
+
function createOverlayPanelsView(ctx, reconciler, deps) {
|
|
3102
|
+
let settingsView = null;
|
|
3103
|
+
let popoverView = null;
|
|
2741
3104
|
function overlayHeaderHeight() {
|
|
2742
|
-
return HEADER_H +
|
|
3105
|
+
return HEADER_H + deps.getHostToolbarHeight();
|
|
2743
3106
|
}
|
|
2744
3107
|
function applySettingsBounds() {
|
|
2745
3108
|
if (!settingsView || ctx.windows.mainWindow.isDestroyed()) return;
|
|
2746
3109
|
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
2747
|
-
|
|
3110
|
+
reconciler.setOverlayDesired(VIEW_ID.settings, {
|
|
3111
|
+
viewId: VIEW_ID.settings,
|
|
3112
|
+
placement: {
|
|
3113
|
+
visible: true,
|
|
3114
|
+
bounds: computeSettingsBounds(w, h, overlayHeaderHeight())
|
|
3115
|
+
},
|
|
3116
|
+
layer: VIEW_LAYER.settings
|
|
3117
|
+
});
|
|
3118
|
+
reconciler.reconcileNow();
|
|
2748
3119
|
}
|
|
2749
3120
|
function applyPopoverBounds() {
|
|
2750
3121
|
if (!popoverView || ctx.windows.mainWindow.isDestroyed()) return;
|
|
2751
3122
|
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
}
|
|
3123
|
+
reconciler.setOverlayDesired(VIEW_ID.popover, {
|
|
3124
|
+
viewId: VIEW_ID.popover,
|
|
3125
|
+
placement: {
|
|
3126
|
+
visible: true,
|
|
3127
|
+
bounds: computePopoverBounds(w, h, overlayHeaderHeight())
|
|
3128
|
+
},
|
|
3129
|
+
layer: VIEW_LAYER.popover
|
|
3130
|
+
});
|
|
3131
|
+
reconciler.reconcileNow();
|
|
2760
3132
|
}
|
|
2761
|
-
function
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
3133
|
+
async function showSettings() {
|
|
3134
|
+
if (!settingsView) {
|
|
3135
|
+
settingsView = new WebContentsView5({
|
|
3136
|
+
webPreferences: {
|
|
3137
|
+
nodeIntegration: false,
|
|
3138
|
+
contextIsolation: true,
|
|
3139
|
+
sandbox: false,
|
|
3140
|
+
preload: mainPreloadPath
|
|
3141
|
+
}
|
|
3142
|
+
});
|
|
3143
|
+
applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
|
|
3144
|
+
settingsView.setBackgroundColor("#00000000");
|
|
3145
|
+
await settingsView.webContents.loadFile(
|
|
3146
|
+
path8.join(ctx.rendererDir, "entries/settings/index.html")
|
|
3147
|
+
);
|
|
2775
3148
|
}
|
|
3149
|
+
applySettingsBounds();
|
|
2776
3150
|
}
|
|
2777
|
-
function
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
3151
|
+
function hideSettings() {
|
|
3152
|
+
reconciler.deleteOverlayDesired(VIEW_ID.settings);
|
|
3153
|
+
reconciler.reconcileNow();
|
|
3154
|
+
}
|
|
3155
|
+
function showPopover(data) {
|
|
3156
|
+
hidePopover();
|
|
3157
|
+
const popover = new WebContentsView5({
|
|
3158
|
+
webPreferences: {
|
|
3159
|
+
nodeIntegration: false,
|
|
3160
|
+
contextIsolation: true,
|
|
3161
|
+
sandbox: false,
|
|
3162
|
+
preload: mainPreloadPath
|
|
2783
3163
|
}
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
3164
|
+
});
|
|
3165
|
+
applyNavigationHardening(popover.webContents, ctx.rendererDir);
|
|
3166
|
+
popoverView = popover;
|
|
3167
|
+
popover.setBackgroundColor("#00000000");
|
|
3168
|
+
applyPopoverBounds();
|
|
3169
|
+
popover.webContents.once("did-finish-load", () => {
|
|
3170
|
+
ctx.notify.popoverInit(popover, data);
|
|
3171
|
+
});
|
|
3172
|
+
popover.webContents.loadFile(
|
|
3173
|
+
path8.join(ctx.rendererDir, "entries/popover/index.html")
|
|
3174
|
+
);
|
|
2787
3175
|
}
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
3176
|
+
function hidePopover() {
|
|
3177
|
+
if (!popoverView) return;
|
|
3178
|
+
reconciler.deleteOverlayDesired(VIEW_ID.popover);
|
|
3179
|
+
destroyChildView(ctx.windows.mainWindow, popoverView);
|
|
3180
|
+
popoverView = null;
|
|
3181
|
+
reconciler.reconcileNow();
|
|
3182
|
+
ctx.notify.popoverClosed();
|
|
3183
|
+
}
|
|
3184
|
+
function reapplyPresentOverlays() {
|
|
3185
|
+
if (reconciler.hasOverlayDesired(VIEW_ID.settings)) applySettingsBounds();
|
|
3186
|
+
if (reconciler.hasOverlayDesired(VIEW_ID.popover)) applyPopoverBounds();
|
|
3187
|
+
}
|
|
3188
|
+
function applySettingsBoundsIfPresent() {
|
|
3189
|
+
if (reconciler.hasOverlayDesired(VIEW_ID.settings)) applySettingsBounds();
|
|
3190
|
+
}
|
|
3191
|
+
function destroySettings() {
|
|
3192
|
+
destroyChildView(ctx.windows.mainWindow, settingsView);
|
|
3193
|
+
settingsView = null;
|
|
3194
|
+
}
|
|
3195
|
+
reconciler.registerView(VIEW_ID.settings, { getView: () => settingsView });
|
|
3196
|
+
reconciler.registerView(VIEW_ID.popover, { getView: () => popoverView });
|
|
3197
|
+
return {
|
|
3198
|
+
showSettings,
|
|
3199
|
+
hideSettings,
|
|
3200
|
+
showPopover,
|
|
3201
|
+
hidePopover,
|
|
3202
|
+
reapplyPresentOverlays,
|
|
3203
|
+
applySettingsBoundsIfPresent,
|
|
3204
|
+
destroySettings,
|
|
3205
|
+
getSettingsWebContents: () => {
|
|
3206
|
+
if (!settingsView) return null;
|
|
3207
|
+
if (settingsView.webContents.isDestroyed()) return null;
|
|
3208
|
+
return settingsView.webContents;
|
|
3209
|
+
},
|
|
3210
|
+
getSettingsWebContentsId: () => {
|
|
3211
|
+
if (!settingsView) return null;
|
|
3212
|
+
if (settingsView.webContents.isDestroyed()) return null;
|
|
3213
|
+
return settingsView.webContents.id;
|
|
3214
|
+
},
|
|
3215
|
+
getPopoverWebContentsId: () => {
|
|
3216
|
+
if (!popoverView) return null;
|
|
3217
|
+
if (popoverView.webContents.isDestroyed()) return null;
|
|
3218
|
+
return popoverView.webContents.id;
|
|
2800
3219
|
}
|
|
3220
|
+
};
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
// src/main/services/views/native-simulator-view.ts
|
|
3224
|
+
import { ipcMain as ipcMain2, nativeTheme as nativeTheme4, shell as shell2, WebContentsView as WebContentsView6, webContents } from "electron";
|
|
3225
|
+
|
|
3226
|
+
// src/main/services/simulator/custom-apis.ts
|
|
3227
|
+
async function handleCustomApiBridgeRequest(apis, req) {
|
|
3228
|
+
try {
|
|
3229
|
+
const result = req.op === "list" ? apis.list() : await apis.invoke(req.name, req.params);
|
|
3230
|
+
return { id: req.id, result };
|
|
3231
|
+
} catch (err) {
|
|
3232
|
+
return { id: req.id, error: err instanceof Error ? err.message : String(err) };
|
|
2801
3233
|
}
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
} catch {
|
|
2811
|
-
}
|
|
3234
|
+
}
|
|
3235
|
+
function createSimulatorApiRegistry() {
|
|
3236
|
+
const handlers2 = /* @__PURE__ */ new Map();
|
|
3237
|
+
return {
|
|
3238
|
+
register(name, handler) {
|
|
3239
|
+
handlers2.set(name, handler);
|
|
3240
|
+
return () => {
|
|
3241
|
+
if (handlers2.get(name) === handler) handlers2.delete(name);
|
|
2812
3242
|
};
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
3243
|
+
},
|
|
3244
|
+
list() {
|
|
3245
|
+
return Array.from(handlers2.keys());
|
|
3246
|
+
},
|
|
3247
|
+
has(name) {
|
|
3248
|
+
return handlers2.has(name);
|
|
3249
|
+
},
|
|
3250
|
+
async invoke(name, params) {
|
|
3251
|
+
const handler = handlers2.get(name);
|
|
3252
|
+
if (!handler) throw new Error(`Simulator API "${name}" is not registered`);
|
|
3253
|
+
return await handler(params);
|
|
3254
|
+
},
|
|
3255
|
+
clear() {
|
|
3256
|
+
handlers2.clear();
|
|
2819
3257
|
}
|
|
3258
|
+
};
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3261
|
+
// src/main/services/views/miniapp-partition.ts
|
|
3262
|
+
import * as electron from "electron";
|
|
3263
|
+
var SHARED_MINIAPP_PARTITION = "persist:simulator";
|
|
3264
|
+
var PARTITION_PREFIX = "persist:miniapp-";
|
|
3265
|
+
function miniappPartitionKey(appId, projectPath) {
|
|
3266
|
+
const safe = appId.replace(/[^A-Za-z0-9_-]/g, "");
|
|
3267
|
+
const base = safe === appId && safe.length > 0 ? safe : safe.length > 0 ? `${safe}-${djb2(appId).toString(36)}` : djb2(appId).toString(36);
|
|
3268
|
+
if (!projectPath) return base;
|
|
3269
|
+
return `${base}-p${djb2(projectPath).toString(36)}`;
|
|
3270
|
+
}
|
|
3271
|
+
function miniappPartition(appId, projectPath) {
|
|
3272
|
+
if (!appId) return SHARED_MINIAPP_PARTITION;
|
|
3273
|
+
return `${PARTITION_PREFIX}${miniappPartitionKey(appId, projectPath)}`;
|
|
3274
|
+
}
|
|
3275
|
+
function djb2(input) {
|
|
3276
|
+
let h = 5381;
|
|
3277
|
+
for (let i = 0; i < input.length; i++) {
|
|
3278
|
+
h = (h << 5) + h + input.charCodeAt(i) >>> 0;
|
|
2820
3279
|
}
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
3280
|
+
return h;
|
|
3281
|
+
}
|
|
3282
|
+
var configurators = /* @__PURE__ */ new Set();
|
|
3283
|
+
var configuredPartitions = /* @__PURE__ */ new Set();
|
|
3284
|
+
function registerMiniappSessionConfigurator(fn) {
|
|
3285
|
+
configurators.add(fn);
|
|
3286
|
+
for (const partition of configuredPartitions) {
|
|
3287
|
+
try {
|
|
3288
|
+
fn(electron.session.fromPartition(partition), partition);
|
|
3289
|
+
} catch (err) {
|
|
3290
|
+
console.warn("[miniapp-partition] configurator failed for", partition, err);
|
|
2828
3291
|
}
|
|
2829
|
-
if (openInEditorWiredWcIds.has(serviceWc.id)) return;
|
|
2830
|
-
openInEditorWiredWcIds.add(serviceWc.id);
|
|
2831
|
-
const onOpenUrl = (_event, url) => {
|
|
2832
|
-
const req = decodeOpenInEditorUrl(url);
|
|
2833
|
-
if (!req) return;
|
|
2834
|
-
const target = resolveProjectEditorTarget(
|
|
2835
|
-
serviceWc.getURL(),
|
|
2836
|
-
ctx.workspace?.getProjectPath?.(),
|
|
2837
|
-
req
|
|
2838
|
-
);
|
|
2839
|
-
if (!target) return;
|
|
2840
|
-
openFileInWorkbench(target.path, target.line ?? 1, target.column ?? 1);
|
|
2841
|
-
ctx.notify.editorOpenFile(target);
|
|
2842
|
-
};
|
|
2843
|
-
serviceWc.on("devtools-open-url", onOpenUrl);
|
|
2844
|
-
const conn = ctx.connections.acquire(serviceWc);
|
|
2845
|
-
conn.on("closed", () => {
|
|
2846
|
-
openInEditorWiredWcIds.delete(serviceWc.id);
|
|
2847
|
-
try {
|
|
2848
|
-
serviceWc.removeListener("devtools-open-url", onOpenUrl);
|
|
2849
|
-
} catch {
|
|
2850
|
-
}
|
|
2851
|
-
});
|
|
2852
3292
|
}
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
3293
|
+
return () => {
|
|
3294
|
+
configurators.delete(fn);
|
|
3295
|
+
};
|
|
3296
|
+
}
|
|
3297
|
+
function configureMiniappSession(partition) {
|
|
3298
|
+
const alreadyConfigured = configuredPartitions.has(partition);
|
|
3299
|
+
configuredPartitions.add(partition);
|
|
3300
|
+
if (configurators.size === 0) return null;
|
|
3301
|
+
const sess = electron.session.fromPartition(partition);
|
|
3302
|
+
if (alreadyConfigured) return sess;
|
|
3303
|
+
for (const fn of configurators) {
|
|
3304
|
+
try {
|
|
3305
|
+
fn(sess, partition);
|
|
3306
|
+
} catch (err) {
|
|
3307
|
+
console.warn("[miniapp-partition] configurator failed for", partition, err);
|
|
2857
3308
|
}
|
|
2858
|
-
|
|
2859
|
-
|
|
3309
|
+
}
|
|
3310
|
+
return sess;
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
// src/shared/simulator-route.ts
|
|
3314
|
+
function decodePageSpec(value) {
|
|
3315
|
+
const qIdx = value.indexOf("?");
|
|
3316
|
+
if (qIdx < 0) return { pagePath: value, query: {} };
|
|
3317
|
+
const pagePath = value.slice(0, qIdx);
|
|
3318
|
+
const query = {};
|
|
3319
|
+
for (const pair of value.slice(qIdx + 1).split("&")) {
|
|
3320
|
+
if (!pair) continue;
|
|
3321
|
+
const eqIdx = pair.indexOf("=");
|
|
3322
|
+
const k = eqIdx >= 0 ? pair.slice(0, eqIdx) : pair;
|
|
3323
|
+
const v = eqIdx >= 0 ? pair.slice(eqIdx + 1) : "";
|
|
3324
|
+
if (k) query[decodeURIComponent(k)] = decodeURIComponent(v);
|
|
3325
|
+
}
|
|
3326
|
+
return { pagePath, query };
|
|
3327
|
+
}
|
|
3328
|
+
function parseLocationRoute(search) {
|
|
3329
|
+
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
|
3330
|
+
const appId = params.get("appId");
|
|
3331
|
+
const entryRaw = params.get("entry");
|
|
3332
|
+
if (!appId || !entryRaw) return null;
|
|
3333
|
+
const entry = decodePageSpec(entryRaw);
|
|
3334
|
+
const pageRaw = params.get("page");
|
|
3335
|
+
const current = pageRaw && pageRaw !== entryRaw ? decodePageSpec(pageRaw) : entry;
|
|
3336
|
+
return { appId, entry, current };
|
|
3337
|
+
}
|
|
3338
|
+
function parseRoute(url) {
|
|
3339
|
+
if (!url) return null;
|
|
3340
|
+
try {
|
|
3341
|
+
const u = new URL(url);
|
|
3342
|
+
return parseLocationRoute(u.search);
|
|
3343
|
+
} catch {
|
|
3344
|
+
return null;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
// src/shared/bridge-channels.ts
|
|
3349
|
+
var BRIDGE_CHANNELS = {
|
|
3350
|
+
SPAWN: "dmb:spawn",
|
|
3351
|
+
DISPOSE: "dmb:dispose",
|
|
3352
|
+
PAGE_OPEN: "dmb:page:open",
|
|
3353
|
+
PAGE_CLOSE: "dmb:page:close",
|
|
3354
|
+
PAGE_LIFECYCLE: "dmb:page:lifecycle",
|
|
3355
|
+
NAV_CALLBACK: "dmb:nav:callback",
|
|
3356
|
+
SERVICE_INVOKE: "dmb:service:invoke",
|
|
3357
|
+
SERVICE_PUBLISH: "dmb:service:publish",
|
|
3358
|
+
RENDER_INVOKE: "dmb:render:invoke",
|
|
3359
|
+
RENDER_PUBLISH: "dmb:render:publish",
|
|
3360
|
+
TO_SERVICE: "dmb:to-service",
|
|
3361
|
+
TO_RENDER: "dmb:to-render",
|
|
3362
|
+
SIMULATOR_API: "dmb:simulator-api",
|
|
3363
|
+
/** simulator → main: ack of an API_CALL request (carries success/fail args). */
|
|
3364
|
+
API_RESPONSE: "dmb:api:response",
|
|
3365
|
+
/**
|
|
3366
|
+
* simulator webview preload → main (sendSync): "is native-host mode on?".
|
|
3367
|
+
* The guest preload can't read the launch `process.env`, so it asks main
|
|
3368
|
+
* (which can) at install time. Reply is `e.returnValue = boolean`.
|
|
3369
|
+
*/
|
|
3370
|
+
NATIVE_HOST_ENABLED: "dmb:native-host-enabled",
|
|
3371
|
+
/**
|
|
3372
|
+
* simulator (DeviceShell) → main: the visible top-of-stack page bridgeId.
|
|
3373
|
+
* Main has no z-order concept — the active page lives only in DeviceShell's
|
|
3374
|
+
* ShellState — so devtools panels / automation that must target "the current
|
|
3375
|
+
* page's render webContents" resolve it through this signal. Fire-and-forget.
|
|
3376
|
+
*/
|
|
3377
|
+
ACTIVE_PAGE: "dmb:active-page",
|
|
3378
|
+
/**
|
|
3379
|
+
* simulator (DeviceShell) → main: the FULL ordered page stack (bottom→top)
|
|
3380
|
+
* whenever it changes. Main has no stack of its own (it only learns the
|
|
3381
|
+
* active bridgeId via ACTIVE_PAGE), so automation's `App.getPageStack` needs
|
|
3382
|
+
* this to report multi-page stacks. Fire-and-forget.
|
|
3383
|
+
*/
|
|
3384
|
+
PAGE_STACK: "dmb:page-stack"
|
|
3385
|
+
};
|
|
3386
|
+
var SIMULATOR_EVENTS = {
|
|
3387
|
+
DOM_READY: "simulator:dom-ready",
|
|
3388
|
+
NAV_BAR: "simulator:navigation-bar",
|
|
3389
|
+
NAV_ACTION: "simulator:nav-action",
|
|
3390
|
+
TAB_ACTION: "simulator:tab-action",
|
|
3391
|
+
/** main → simulator: invoke a wx.* API on the simulator-resident MiniApp. */
|
|
3392
|
+
API_CALL: "simulator:api-call",
|
|
3393
|
+
/**
|
|
3394
|
+
* main → simulator: the renderer toolbar picked a different device. Carries a
|
|
3395
|
+
* NativeDeviceInfo; DeviceShell resizes the bezel + re-renders status bar /
|
|
3396
|
+
* notch. The race-free INITIAL device rides NativeHostConfig.device (read
|
|
3397
|
+
* synchronously at preload bridge-install); this event covers live changes.
|
|
3398
|
+
*/
|
|
3399
|
+
DEVICE_CHANGE: "simulator:device-change",
|
|
3400
|
+
/**
|
|
3401
|
+
* main → simulator: a watcher rebuild finished; boot a NEW app session for
|
|
3402
|
+
* the carried url ({@link RelaunchPayload}) IN PLACE, keeping the live
|
|
3403
|
+
* DeviceShell painted, and swap once the new session's root page reports
|
|
3404
|
+
* DOM_READY (ready-then-swap soft reload). Main sends this only when the
|
|
3405
|
+
* shell is live+ready; otherwise the renderer falls back to the hard
|
|
3406
|
+
* attachNativeSimulator rebuild.
|
|
3407
|
+
*/
|
|
3408
|
+
RELAUNCH: "simulator:relaunch"
|
|
3409
|
+
};
|
|
3410
|
+
function deviceInfoToHostEnv(d) {
|
|
3411
|
+
return {
|
|
3412
|
+
brand: d.brand,
|
|
3413
|
+
model: d.model,
|
|
3414
|
+
system: d.system,
|
|
3415
|
+
platform: d.platform,
|
|
3416
|
+
pixelRatio: d.pixelRatio,
|
|
3417
|
+
screenWidth: d.screenWidth,
|
|
3418
|
+
screenHeight: d.screenHeight,
|
|
3419
|
+
windowWidth: d.screenWidth,
|
|
3420
|
+
windowHeight: Math.max(0, d.screenHeight - d.statusBarHeight),
|
|
3421
|
+
statusBarHeight: d.statusBarHeight
|
|
3422
|
+
};
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
// src/main/services/views/native-simulator-view.ts
|
|
3426
|
+
function createNativeSimulatorView(ctx, reconciler, deps) {
|
|
3427
|
+
const { safeArea, devtoolsHost, overlayPanels } = deps;
|
|
3428
|
+
let nativeSimulatorView = null;
|
|
3429
|
+
let nativeSimulatorViewAdded = false;
|
|
3430
|
+
let nativeSimulatorProjectPath = null;
|
|
3431
|
+
let settleNativeSimulatorReady = null;
|
|
3432
|
+
let nativeSimulatorShellReady = false;
|
|
3433
|
+
let nativeCustomApiBridgeHandler = null;
|
|
3434
|
+
let currentZoomFactor = 1;
|
|
3435
|
+
let simulatorWebContentsId = null;
|
|
3436
|
+
function applyNativeSimulatorBounds(view, bounds, zoom) {
|
|
3437
|
+
const p = computeNativeSimulatorViewParams(bounds, zoom);
|
|
3438
|
+
currentZoomFactor = p.zoomFactor;
|
|
3439
|
+
view.setBounds(p.bounds);
|
|
3440
|
+
const simWc = view.webContents;
|
|
3441
|
+
if (!simWc.isDestroyed()) simWc.setZoomFactor(p.zoomFactor);
|
|
2860
3442
|
try {
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
customizeDevtoolsTabs(simulatorView.webContents);
|
|
2865
|
-
try {
|
|
2866
|
-
stopServiceConsole?.();
|
|
2867
|
-
} catch {
|
|
3443
|
+
for (const wc of webContents.getAllWebContents()) {
|
|
3444
|
+
if (wc.isDestroyed()) continue;
|
|
3445
|
+
if (wc.hostWebContents === simWc) wc.setZoomFactor(p.zoomFactor);
|
|
2868
3446
|
}
|
|
2869
|
-
stopServiceConsole = installServiceConsoleForward({
|
|
2870
|
-
serviceWc: next,
|
|
2871
|
-
connections: ctx.connections,
|
|
2872
|
-
emit: (entry) => ctx.consoleForwarder?.emit(entry)
|
|
2873
|
-
}).stop;
|
|
2874
|
-
return true;
|
|
2875
3447
|
} catch {
|
|
2876
|
-
if (nativeDevtoolsSourceWc?.id === next.id) {
|
|
2877
|
-
nativeDevtoolsSourceWc = null;
|
|
2878
|
-
}
|
|
2879
|
-
return false;
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2882
|
-
function pointNativeDevtoolsAtActiveServiceHost(appId) {
|
|
2883
|
-
if (!ctx.bridge?.isNativeHost()) return true;
|
|
2884
|
-
if (!simulatorView || simulatorView.webContents.isDestroyed()) return true;
|
|
2885
|
-
const wc = ctx.bridge.getServiceWc(appId);
|
|
2886
|
-
if (!wc || wc.isDestroyed()) return false;
|
|
2887
|
-
return pointNativeDevtoolsAtServiceWc(wc);
|
|
2888
|
-
}
|
|
2889
|
-
function scheduleNativeDevtoolsFollow(appId, attempt = 0) {
|
|
2890
|
-
if (attempt >= 20) return;
|
|
2891
|
-
if (!ctx.bridge?.isNativeHost()) return;
|
|
2892
|
-
const token = nativeDevtoolsRetryToken;
|
|
2893
|
-
if (nativeDevtoolsRetryTimer) clearTimeout(nativeDevtoolsRetryTimer);
|
|
2894
|
-
nativeDevtoolsRetryTimer = setTimeout(() => {
|
|
2895
|
-
nativeDevtoolsRetryTimer = null;
|
|
2896
|
-
if (token !== nativeDevtoolsRetryToken) return;
|
|
2897
|
-
if (pointNativeDevtoolsAtActiveServiceHost(appId)) return;
|
|
2898
|
-
scheduleNativeDevtoolsFollow(appId, attempt + 1);
|
|
2899
|
-
}, 50);
|
|
2900
|
-
}
|
|
2901
|
-
function followNativeDevtoolsServiceHost(appId) {
|
|
2902
|
-
clearNativeDevtoolsRetry();
|
|
2903
|
-
if (pointNativeDevtoolsAtActiveServiceHost(appId)) return;
|
|
2904
|
-
scheduleNativeDevtoolsFollow(appId);
|
|
2905
|
-
}
|
|
2906
|
-
function onNativeRenderEvent(event) {
|
|
2907
|
-
if (event.kind !== "activePage" && event.kind !== "domReady") return;
|
|
2908
|
-
followNativeDevtoolsServiceHost(event.appId);
|
|
2909
|
-
}
|
|
2910
|
-
function attachNativeSimulatorDevtoolsHost() {
|
|
2911
|
-
stopFollowingNativeServiceHost();
|
|
2912
|
-
if (simulatorView) {
|
|
2913
|
-
removeSimulatorDevtoolsView();
|
|
2914
|
-
try {
|
|
2915
|
-
if (!simulatorView.webContents.isDestroyed()) {
|
|
2916
|
-
simulatorView.webContents.close();
|
|
2917
|
-
}
|
|
2918
|
-
} catch {
|
|
2919
|
-
}
|
|
2920
|
-
simulatorView = null;
|
|
2921
|
-
}
|
|
2922
|
-
simulatorView = new WebContentsView2();
|
|
2923
|
-
const devtoolsWc = simulatorView.webContents;
|
|
2924
|
-
ctx.networkForward?.setDevtoolsHost(devtoolsWc);
|
|
2925
|
-
if (ctx.bridge) {
|
|
2926
|
-
try {
|
|
2927
|
-
stopElementsForward?.();
|
|
2928
|
-
} catch {
|
|
2929
|
-
}
|
|
2930
|
-
const thisForward = installElementsForward({ devtoolsWc, bridge: ctx.bridge, connections: ctx.connections });
|
|
2931
|
-
stopElementsForward = thisForward;
|
|
2932
|
-
devtoolsWc.once("destroyed", () => {
|
|
2933
|
-
try {
|
|
2934
|
-
thisForward();
|
|
2935
|
-
} catch {
|
|
2936
|
-
}
|
|
2937
|
-
if (stopElementsForward === thisForward) stopElementsForward = null;
|
|
2938
|
-
});
|
|
2939
|
-
}
|
|
2940
|
-
devtoolsWc.once("dom-ready", () => {
|
|
2941
|
-
devtoolsWc.executeJavaScript(`
|
|
2942
|
-
(function() {
|
|
2943
|
-
try { localStorage.setItem('panel-selectedTab', '"console"') } catch {}
|
|
2944
|
-
let tries = 0
|
|
2945
|
-
const timer = setInterval(() => {
|
|
2946
|
-
tries++
|
|
2947
|
-
try {
|
|
2948
|
-
const UI = globalThis.UI
|
|
2949
|
-
const vm = UI && UI.ViewManager && typeof UI.ViewManager.instance === 'function'
|
|
2950
|
-
? UI.ViewManager.instance()
|
|
2951
|
-
: null
|
|
2952
|
-
if (vm && typeof vm.showView === 'function') {
|
|
2953
|
-
vm.showView('console')
|
|
2954
|
-
clearInterval(timer)
|
|
2955
|
-
return
|
|
2956
|
-
}
|
|
2957
|
-
} catch {}
|
|
2958
|
-
if (tries > 80) clearInterval(timer)
|
|
2959
|
-
}, 50)
|
|
2960
|
-
})()
|
|
2961
|
-
`).catch(() => {
|
|
2962
|
-
});
|
|
2963
|
-
});
|
|
2964
|
-
if (simulatorBoundsOverride && !isHidden(simulatorBoundsOverride)) {
|
|
2965
|
-
ctx.windows.mainWindow.contentView.addChildView(simulatorView);
|
|
2966
|
-
simulatorViewAdded = true;
|
|
2967
|
-
simulatorView.setBounds(simulatorBoundsOverride);
|
|
2968
|
-
}
|
|
2969
|
-
if (ctx.bridge?.isNativeHost()) {
|
|
2970
|
-
unsubscribeNativeRenderEvents = ctx.bridge.onRenderEvent(onNativeRenderEvent);
|
|
2971
|
-
followNativeDevtoolsServiceHost();
|
|
2972
|
-
}
|
|
2973
|
-
}
|
|
2974
|
-
function detachNativeCustomApiBridge() {
|
|
2975
|
-
if (nativeCustomApiBridgeHandler) {
|
|
2976
|
-
ipcMain2.removeListener(SimulatorCustomApiBridgeChannel.Request, nativeCustomApiBridgeHandler);
|
|
2977
|
-
nativeCustomApiBridgeHandler = null;
|
|
2978
3448
|
}
|
|
2979
3449
|
}
|
|
2980
3450
|
function tearDownNativeSimulatorView(label) {
|
|
@@ -2994,6 +3464,15 @@ function createViewManager(ctx) {
|
|
|
2994
3464
|
}
|
|
2995
3465
|
nativeSimulatorView = null;
|
|
2996
3466
|
nativeSimulatorViewAdded = false;
|
|
3467
|
+
nativeSimulatorShellReady = false;
|
|
3468
|
+
reconciler.forgetActual(VIEW_ID.simulator);
|
|
3469
|
+
reconciler.reconcileNow();
|
|
3470
|
+
}
|
|
3471
|
+
function detachNativeCustomApiBridge() {
|
|
3472
|
+
if (nativeCustomApiBridgeHandler) {
|
|
3473
|
+
ipcMain2.removeListener(SimulatorCustomApiBridgeChannel.Request, nativeCustomApiBridgeHandler);
|
|
3474
|
+
nativeCustomApiBridgeHandler = null;
|
|
3475
|
+
}
|
|
2997
3476
|
}
|
|
2998
3477
|
function attachNativeCustomApiBridge(simWc) {
|
|
2999
3478
|
detachNativeCustomApiBridge();
|
|
@@ -3032,7 +3511,7 @@ function createViewManager(ctx) {
|
|
|
3032
3511
|
const route = parseRoute(simulatorUrl);
|
|
3033
3512
|
const partition = miniappPartition(route?.appId, ctx.workspace?.getProjectPath());
|
|
3034
3513
|
configureMiniappSession(partition);
|
|
3035
|
-
const view = new
|
|
3514
|
+
const view = new WebContentsView6({
|
|
3036
3515
|
webPreferences: {
|
|
3037
3516
|
nodeIntegration: false,
|
|
3038
3517
|
contextIsolation: false,
|
|
@@ -3052,8 +3531,8 @@ function createViewManager(ctx) {
|
|
|
3052
3531
|
} catch {
|
|
3053
3532
|
}
|
|
3054
3533
|
};
|
|
3055
|
-
|
|
3056
|
-
ctx.connections.acquire(simWc).own(() =>
|
|
3534
|
+
nativeTheme4.on("updated", syncDeskBg);
|
|
3535
|
+
ctx.connections.acquire(simWc).own(() => nativeTheme4.removeListener("updated", syncDeskBg));
|
|
3057
3536
|
attachNativeCustomApiBridge(simWc);
|
|
3058
3537
|
const pendingGuestIsTab = [];
|
|
3059
3538
|
simWc.on("will-attach-webview", (_event, webPreferences, params) => {
|
|
@@ -3095,10 +3574,11 @@ function createViewManager(ctx) {
|
|
|
3095
3574
|
});
|
|
3096
3575
|
guestWc.once("did-finish-load", () => {
|
|
3097
3576
|
if (nativeSimulatorView !== view || simWc.isDestroyed()) return;
|
|
3577
|
+
nativeSimulatorShellReady = true;
|
|
3098
3578
|
settleNativeSimulatorReady?.();
|
|
3099
3579
|
settleNativeSimulatorReady = null;
|
|
3100
3580
|
});
|
|
3101
|
-
|
|
3581
|
+
devtoolsHost.followServiceHost();
|
|
3102
3582
|
});
|
|
3103
3583
|
simWc.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
|
|
3104
3584
|
simWc.on("will-navigate", (e, url) => {
|
|
@@ -3106,231 +3586,125 @@ function createViewManager(ctx) {
|
|
|
3106
3586
|
const u = new URL(url);
|
|
3107
3587
|
if (u.protocol === "about:") return;
|
|
3108
3588
|
if (u.protocol === "file:") return;
|
|
3109
|
-
if ((u.protocol === "http:" || u.protocol === "https:") && (u.hostname === "localhost" || u.hostname === "127.0.0.1")) {
|
|
3110
|
-
return;
|
|
3111
|
-
}
|
|
3112
|
-
e.preventDefault();
|
|
3113
|
-
if (u.protocol === "http:" || u.protocol === "https:") {
|
|
3114
|
-
void shell2.openExternal(url);
|
|
3115
|
-
}
|
|
3116
|
-
} catch {
|
|
3117
|
-
e.preventDefault();
|
|
3118
|
-
}
|
|
3119
|
-
});
|
|
3120
|
-
void simWc.loadURL(simulatorUrl).catch((err) => {
|
|
3121
|
-
console.error("[workbench] attachNativeSimulator \u2014 loadURL failed", err);
|
|
3122
|
-
});
|
|
3123
|
-
simulatorWebContentsId = simWc.id;
|
|
3124
|
-
ctx.networkForward?.attachSimulator(simWc);
|
|
3125
|
-
if (lastRendererRect) {
|
|
3126
|
-
setNativeSimulatorViewBounds(lastRendererRect);
|
|
3127
|
-
}
|
|
3128
|
-
attachNativeSimulatorDevtoolsHost();
|
|
3129
|
-
return ready;
|
|
3130
|
-
}
|
|
3131
|
-
function detachSimulator() {
|
|
3132
|
-
settleNativeSimulatorReady?.();
|
|
3133
|
-
settleNativeSimulatorReady = null;
|
|
3134
|
-
stopFollowingNativeServiceHost();
|
|
3135
|
-
detachNativeCustomApiBridge();
|
|
3136
|
-
try {
|
|
3137
|
-
stopElementsForward?.();
|
|
3138
|
-
} catch {
|
|
3139
|
-
}
|
|
3140
|
-
stopElementsForward = null;
|
|
3141
|
-
ctx.networkForward?.detachSimulator();
|
|
3142
|
-
ctx.networkForward?.setDevtoolsHost(null);
|
|
3143
|
-
tearDownNativeSimulatorView("close");
|
|
3144
|
-
hidePopover();
|
|
3145
|
-
destroyViewInternal(settingsView);
|
|
3146
|
-
settingsView = null;
|
|
3147
|
-
settingsViewAdded = false;
|
|
3148
|
-
destroyViewInternal(simulatorView);
|
|
3149
|
-
simulatorView = null;
|
|
3150
|
-
simulatorViewAdded = false;
|
|
3151
|
-
simulatorWebContentsId = null;
|
|
3152
|
-
nativeSimulatorProjectPath = null;
|
|
3153
|
-
simulatorBoundsOverride = null;
|
|
3154
|
-
lastRendererRect = null;
|
|
3155
|
-
}
|
|
3156
|
-
function removeSimulatorDevtoolsView() {
|
|
3157
|
-
if (simulatorView && simulatorViewAdded) {
|
|
3158
|
-
try {
|
|
3159
|
-
ctx.windows.mainWindow.contentView.removeChildView(simulatorView);
|
|
3160
|
-
} catch (e) {
|
|
3161
|
-
console.error("[workbench] removeSimulatorDevtoolsView error", e);
|
|
3162
|
-
}
|
|
3163
|
-
simulatorViewAdded = false;
|
|
3164
|
-
}
|
|
3165
|
-
}
|
|
3166
|
-
async function showSettings() {
|
|
3167
|
-
if (!settingsView) {
|
|
3168
|
-
settingsView = new WebContentsView2({
|
|
3169
|
-
webPreferences: {
|
|
3170
|
-
nodeIntegration: false,
|
|
3171
|
-
contextIsolation: true,
|
|
3172
|
-
sandbox: false,
|
|
3173
|
-
preload: mainPreloadPath
|
|
3174
|
-
}
|
|
3175
|
-
});
|
|
3176
|
-
applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
|
|
3177
|
-
settingsView.setBackgroundColor("#00000000");
|
|
3178
|
-
await settingsView.webContents.loadFile(
|
|
3179
|
-
path7.join(ctx.rendererDir, "entries/settings/index.html")
|
|
3180
|
-
);
|
|
3181
|
-
}
|
|
3182
|
-
if (!settingsViewAdded) {
|
|
3183
|
-
ctx.windows.mainWindow.contentView.addChildView(settingsView);
|
|
3184
|
-
settingsViewAdded = true;
|
|
3185
|
-
}
|
|
3186
|
-
applySettingsBounds();
|
|
3187
|
-
}
|
|
3188
|
-
function hideSettings() {
|
|
3189
|
-
if (settingsView && settingsViewAdded) {
|
|
3190
|
-
try {
|
|
3191
|
-
ctx.windows.mainWindow.contentView.removeChildView(settingsView);
|
|
3192
|
-
} catch {
|
|
3193
|
-
}
|
|
3194
|
-
settingsViewAdded = false;
|
|
3195
|
-
}
|
|
3196
|
-
}
|
|
3197
|
-
function raiseTopOverlays() {
|
|
3198
|
-
if (ctx.windows.mainWindow.isDestroyed()) return;
|
|
3199
|
-
const cv = ctx.windows.mainWindow.contentView;
|
|
3200
|
-
if (settingsView && settingsViewAdded) cv.addChildView(settingsView);
|
|
3201
|
-
if (popoverView) cv.addChildView(popoverView);
|
|
3202
|
-
}
|
|
3203
|
-
function showPopover(data) {
|
|
3204
|
-
hidePopover();
|
|
3205
|
-
const popover = new WebContentsView2({
|
|
3206
|
-
webPreferences: {
|
|
3207
|
-
nodeIntegration: false,
|
|
3208
|
-
contextIsolation: true,
|
|
3209
|
-
sandbox: false,
|
|
3210
|
-
preload: mainPreloadPath
|
|
3211
|
-
}
|
|
3212
|
-
});
|
|
3213
|
-
applyNavigationHardening(popover.webContents, ctx.rendererDir);
|
|
3214
|
-
popoverView = popover;
|
|
3215
|
-
popover.setBackgroundColor("#00000000");
|
|
3216
|
-
ctx.windows.mainWindow.contentView.addChildView(popover);
|
|
3217
|
-
applyPopoverBounds();
|
|
3218
|
-
popover.webContents.once("did-finish-load", () => {
|
|
3219
|
-
ctx.notify.popoverInit(popover, data);
|
|
3220
|
-
});
|
|
3221
|
-
popover.webContents.loadFile(
|
|
3222
|
-
path7.join(ctx.rendererDir, "entries/popover/index.html")
|
|
3223
|
-
);
|
|
3224
|
-
}
|
|
3225
|
-
function hidePopover() {
|
|
3226
|
-
if (popoverView) {
|
|
3227
|
-
destroyViewInternal(popoverView);
|
|
3228
|
-
popoverView = null;
|
|
3229
|
-
ctx.notify.popoverClosed();
|
|
3230
|
-
}
|
|
3231
|
-
}
|
|
3232
|
-
function repositionAll() {
|
|
3233
|
-
if (settingsView && settingsViewAdded)
|
|
3234
|
-
applySettingsBounds();
|
|
3235
|
-
if (popoverView)
|
|
3236
|
-
applyPopoverBounds();
|
|
3237
|
-
}
|
|
3238
|
-
function disposeAll() {
|
|
3239
|
-
detachSimulator();
|
|
3240
|
-
detachWorkbench();
|
|
3241
|
-
hostToolbarPort.dispose();
|
|
3242
|
-
destroyViewInternal(hostToolbarView);
|
|
3243
|
-
hostToolbarView = null;
|
|
3244
|
-
hostToolbarViewAdded = false;
|
|
3245
|
-
if (hostToolbarRuntimeAcquired) {
|
|
3246
|
-
releaseHostToolbarSessionRuntime();
|
|
3247
|
-
hostToolbarRuntimeAcquired = false;
|
|
3248
|
-
}
|
|
3249
|
-
safeArea.dispose();
|
|
3250
|
-
}
|
|
3251
|
-
function setNativeSimulatorViewBounds(params) {
|
|
3252
|
-
lastRendererRect = params;
|
|
3253
|
-
if (ctx.windows.mainWindow.isDestroyed() || !nativeSimulatorView) return;
|
|
3254
|
-
const p = computeNativeSimulatorViewParams(params, params.zoom);
|
|
3255
|
-
currentZoomFactor = p.zoomFactor;
|
|
3256
|
-
if (isHidden(p.bounds)) {
|
|
3257
|
-
if (nativeSimulatorViewAdded) {
|
|
3258
|
-
try {
|
|
3259
|
-
ctx.windows.mainWindow.contentView.removeChildView(nativeSimulatorView);
|
|
3260
|
-
} catch {
|
|
3589
|
+
if ((u.protocol === "http:" || u.protocol === "https:") && (u.hostname === "localhost" || u.hostname === "127.0.0.1")) {
|
|
3590
|
+
return;
|
|
3261
3591
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
}
|
|
3266
|
-
if (!nativeSimulatorViewAdded) {
|
|
3267
|
-
ctx.windows.mainWindow.contentView.addChildView(nativeSimulatorView);
|
|
3268
|
-
nativeSimulatorViewAdded = true;
|
|
3269
|
-
raiseTopOverlays();
|
|
3270
|
-
}
|
|
3271
|
-
nativeSimulatorView.setBounds(p.bounds);
|
|
3272
|
-
const simWc = nativeSimulatorView.webContents;
|
|
3273
|
-
if (!simWc.isDestroyed()) {
|
|
3274
|
-
simWc.setZoomFactor(p.zoomFactor);
|
|
3275
|
-
}
|
|
3276
|
-
try {
|
|
3277
|
-
for (const wc of webContents.getAllWebContents()) {
|
|
3278
|
-
if (wc.isDestroyed()) continue;
|
|
3279
|
-
if (wc.hostWebContents === simWc) {
|
|
3280
|
-
wc.setZoomFactor(p.zoomFactor);
|
|
3592
|
+
e.preventDefault();
|
|
3593
|
+
if (u.protocol === "http:" || u.protocol === "https:") {
|
|
3594
|
+
void shell2.openExternal(url);
|
|
3281
3595
|
}
|
|
3596
|
+
} catch {
|
|
3597
|
+
e.preventDefault();
|
|
3282
3598
|
}
|
|
3283
|
-
}
|
|
3284
|
-
|
|
3599
|
+
});
|
|
3600
|
+
void simWc.loadURL(simulatorUrl).catch((err) => {
|
|
3601
|
+
console.error("[workbench] attachNativeSimulator \u2014 loadURL failed", err);
|
|
3602
|
+
});
|
|
3603
|
+
simulatorWebContentsId = simWc.id;
|
|
3604
|
+
ctx.networkForward?.attachSimulator(simWc);
|
|
3605
|
+
reconciler.reconcileNow();
|
|
3606
|
+
devtoolsHost.attach();
|
|
3607
|
+
return ready;
|
|
3285
3608
|
}
|
|
3286
|
-
function
|
|
3287
|
-
if (
|
|
3609
|
+
function softReloadNativeSimulator(simulatorUrl) {
|
|
3610
|
+
if (!nativeSimulatorView || nativeSimulatorView.webContents.isDestroyed()) return false;
|
|
3611
|
+
if (!nativeSimulatorShellReady) return false;
|
|
3612
|
+
const payload = { url: simulatorUrl };
|
|
3613
|
+
nativeSimulatorView.webContents.send(SIMULATOR_EVENTS.RELAUNCH, payload);
|
|
3614
|
+
return true;
|
|
3615
|
+
}
|
|
3616
|
+
function detachSimulator() {
|
|
3617
|
+
settleNativeSimulatorReady?.();
|
|
3618
|
+
settleNativeSimulatorReady = null;
|
|
3619
|
+
devtoolsHost.stopFollowing();
|
|
3620
|
+
detachNativeCustomApiBridge();
|
|
3621
|
+
devtoolsHost.stopElementsForwarding();
|
|
3622
|
+
ctx.networkForward?.detachSimulator();
|
|
3623
|
+
ctx.networkForward?.setDevtoolsHost(null);
|
|
3624
|
+
tearDownNativeSimulatorView("close");
|
|
3625
|
+
overlayPanels.hidePopover();
|
|
3626
|
+
overlayPanels.destroySettings();
|
|
3627
|
+
devtoolsHost.destroyHostView();
|
|
3628
|
+
simulatorWebContentsId = null;
|
|
3629
|
+
nativeSimulatorProjectPath = null;
|
|
3288
3630
|
}
|
|
3631
|
+
reconciler.registerView(VIEW_ID.simulator, {
|
|
3632
|
+
getView: () => nativeSimulatorView,
|
|
3633
|
+
setAdded: (added) => {
|
|
3634
|
+
nativeSimulatorViewAdded = added;
|
|
3635
|
+
},
|
|
3636
|
+
gateHidden: () => !nativeSimulatorView,
|
|
3637
|
+
applyBounds: (view, bounds, extra) => applyNativeSimulatorBounds(view, bounds, extra?.zoom ?? 1)
|
|
3638
|
+
});
|
|
3289
3639
|
return {
|
|
3290
3640
|
attachNativeSimulator,
|
|
3641
|
+
softReloadNativeSimulator,
|
|
3291
3642
|
detachSimulator,
|
|
3292
|
-
reapplySafeArea: (device) => safeArea.reapplyAll(device),
|
|
3293
|
-
showSettings,
|
|
3294
|
-
hideSettings,
|
|
3295
|
-
showPopover,
|
|
3296
|
-
hidePopover,
|
|
3297
|
-
repositionAll,
|
|
3298
|
-
disposeAll,
|
|
3299
3643
|
getSimulatorWebContentsId: () => simulatorWebContentsId,
|
|
3300
3644
|
getSimulatorWebContents: () => {
|
|
3301
3645
|
if (simulatorWebContentsId == null) return null;
|
|
3302
3646
|
const wc = webContents.fromId(simulatorWebContentsId);
|
|
3303
3647
|
return wc && !wc.isDestroyed() ? wc : null;
|
|
3304
3648
|
},
|
|
3305
|
-
getSimulatorProjectPath: () => nativeSimulatorProjectPath
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3649
|
+
getSimulatorProjectPath: () => nativeSimulatorProjectPath
|
|
3650
|
+
};
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3653
|
+
// src/main/services/views/view-manager.ts
|
|
3654
|
+
function createViewManager(ctx) {
|
|
3655
|
+
const safeArea = createSafeAreaController({ connections: ctx.connections });
|
|
3656
|
+
const reconciler = createPlacementReconciler(ctx);
|
|
3657
|
+
const workbench = createWorkbenchView(ctx, reconciler);
|
|
3658
|
+
const devtoolsHost = createDevtoolsHost(ctx, reconciler, {
|
|
3659
|
+
openFileInWorkbench: workbench.openFileInWorkbench
|
|
3660
|
+
});
|
|
3661
|
+
const hostToolbar = createHostToolbarView(ctx, reconciler, {
|
|
3662
|
+
reapplyPresentOverlays: () => reapplyToolbarDependentOverlays()
|
|
3663
|
+
});
|
|
3664
|
+
const overlayPanels = createOverlayPanelsView(ctx, reconciler, {
|
|
3665
|
+
getHostToolbarHeight: hostToolbar.getHostToolbarHeight
|
|
3666
|
+
});
|
|
3667
|
+
const nativeSimulator = createNativeSimulatorView(ctx, reconciler, {
|
|
3668
|
+
safeArea,
|
|
3669
|
+
devtoolsHost,
|
|
3670
|
+
overlayPanels
|
|
3671
|
+
});
|
|
3672
|
+
function reapplyToolbarDependentOverlays() {
|
|
3673
|
+
overlayPanels.reapplyPresentOverlays();
|
|
3674
|
+
}
|
|
3675
|
+
function disposeAll() {
|
|
3676
|
+
nativeSimulator.detachSimulator();
|
|
3677
|
+
workbench.detachWorkbench();
|
|
3678
|
+
hostToolbar.dispose();
|
|
3679
|
+
safeArea.dispose();
|
|
3680
|
+
}
|
|
3681
|
+
return {
|
|
3682
|
+
attachNativeSimulator: nativeSimulator.attachNativeSimulator,
|
|
3683
|
+
softReloadNativeSimulator: nativeSimulator.softReloadNativeSimulator,
|
|
3684
|
+
detachSimulator: nativeSimulator.detachSimulator,
|
|
3685
|
+
reapplySafeArea: (device) => safeArea.reapplyAll(device),
|
|
3686
|
+
showSettings: overlayPanels.showSettings,
|
|
3687
|
+
hideSettings: overlayPanels.hideSettings,
|
|
3688
|
+
showPopover: overlayPanels.showPopover,
|
|
3689
|
+
hidePopover: overlayPanels.hidePopover,
|
|
3690
|
+
repositionAll: () => overlayPanels.reapplyPresentOverlays(),
|
|
3691
|
+
disposeAll,
|
|
3692
|
+
getSimulatorWebContentsId: nativeSimulator.getSimulatorWebContentsId,
|
|
3693
|
+
getSimulatorWebContents: nativeSimulator.getSimulatorWebContents,
|
|
3694
|
+
getSimulatorProjectPath: nativeSimulator.getSimulatorProjectPath,
|
|
3695
|
+
getSettingsWebContents: overlayPanels.getSettingsWebContents,
|
|
3696
|
+
getSettingsWebContentsId: overlayPanels.getSettingsWebContentsId,
|
|
3697
|
+
getPopoverWebContentsId: overlayPanels.getPopoverWebContentsId,
|
|
3698
|
+
getHostToolbarWebContentsId: hostToolbar.getHostToolbarWebContentsId,
|
|
3699
|
+
getHostToolbarHeight: hostToolbar.getHostToolbarHeight,
|
|
3700
|
+
resize: () => overlayPanels.applySettingsBoundsIfPresent(),
|
|
3701
|
+
setPlacementSnapshot: reconciler.setPlacementSnapshot,
|
|
3702
|
+
attachWorkbench: workbench.attachWorkbench,
|
|
3703
|
+
setWorkbenchSource: workbench.setWorkbenchSource,
|
|
3704
|
+
detachWorkbench: workbench.detachWorkbench,
|
|
3705
|
+
openFileInWorkbench: workbench.openFileInWorkbench,
|
|
3706
|
+
setHostToolbarHeight: hostToolbar.setHostToolbarHeight,
|
|
3707
|
+
hostToolbar: hostToolbar.control
|
|
3334
3708
|
};
|
|
3335
3709
|
}
|
|
3336
3710
|
|
|
@@ -3362,7 +3736,7 @@ function createWindowService(mainWindow) {
|
|
|
3362
3736
|
|
|
3363
3737
|
// src/main/windows/settings-window/create.ts
|
|
3364
3738
|
import { BrowserWindow as BrowserWindow3 } from "electron";
|
|
3365
|
-
import
|
|
3739
|
+
import path9 from "path";
|
|
3366
3740
|
async function createSettingsWindow(parent, rendererDir2) {
|
|
3367
3741
|
const win = new BrowserWindow3({
|
|
3368
3742
|
width: 420,
|
|
@@ -3380,7 +3754,7 @@ async function createSettingsWindow(parent, rendererDir2) {
|
|
|
3380
3754
|
}
|
|
3381
3755
|
});
|
|
3382
3756
|
applyNavigationHardening(win.webContents, rendererDir2);
|
|
3383
|
-
await win.loadFile(
|
|
3757
|
+
await win.loadFile(path9.join(rendererDir2, "entries/workbench-settings/index.html"));
|
|
3384
3758
|
return win;
|
|
3385
3759
|
}
|
|
3386
3760
|
|
|
@@ -3431,11 +3805,11 @@ import { z as z2 } from "zod";
|
|
|
3431
3805
|
|
|
3432
3806
|
// src/main/services/projects/project-repository.ts
|
|
3433
3807
|
import { app as app6 } from "electron";
|
|
3434
|
-
import
|
|
3808
|
+
import path10 from "path";
|
|
3435
3809
|
import fs5 from "fs";
|
|
3436
3810
|
var log2 = createLogger("projects");
|
|
3437
3811
|
function getProjectsFile() {
|
|
3438
|
-
return
|
|
3812
|
+
return path10.join(app6.getPath("userData"), "dimina-projects.json");
|
|
3439
3813
|
}
|
|
3440
3814
|
function load() {
|
|
3441
3815
|
try {
|
|
@@ -3457,13 +3831,13 @@ function validateProjectDir(dirPath) {
|
|
|
3457
3831
|
if (!fs5.existsSync(dirPath)) {
|
|
3458
3832
|
return `\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirPath}`;
|
|
3459
3833
|
}
|
|
3460
|
-
if (!fs5.existsSync(
|
|
3461
|
-
const configPath =
|
|
3834
|
+
if (!fs5.existsSync(path10.join(dirPath, "app.json"))) {
|
|
3835
|
+
const configPath = path10.join(dirPath, "project.config.json");
|
|
3462
3836
|
if (fs5.existsSync(configPath)) {
|
|
3463
3837
|
try {
|
|
3464
3838
|
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
3465
3839
|
if (cfg.miniprogramRoot) {
|
|
3466
|
-
const resolvedRoot =
|
|
3840
|
+
const resolvedRoot = path10.resolve(dirPath, cfg.miniprogramRoot);
|
|
3467
3841
|
return `\u8BE5\u76EE\u5F55\u7F3A\u5C11 app.json\uFF0Cproject.config.json \u4E2D\u6307\u5B9A\u4E86 miniprogramRoot: "${cfg.miniprogramRoot}"\uFF0C\u8BF7\u5BFC\u5165 ${resolvedRoot}`;
|
|
3468
3842
|
}
|
|
3469
3843
|
} catch (err) {
|
|
@@ -3476,9 +3850,9 @@ function validateProjectDir(dirPath) {
|
|
|
3476
3850
|
}
|
|
3477
3851
|
function addProject(dirPath) {
|
|
3478
3852
|
const projects = load();
|
|
3479
|
-
let name =
|
|
3853
|
+
let name = path10.basename(dirPath);
|
|
3480
3854
|
try {
|
|
3481
|
-
const configPath =
|
|
3855
|
+
const configPath = path10.join(dirPath, "project.config.json");
|
|
3482
3856
|
if (fs5.existsSync(configPath)) {
|
|
3483
3857
|
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
3484
3858
|
if (cfg.projectname) name = cfg.projectname;
|
|
@@ -3517,7 +3891,7 @@ function getCompileConfig(dirPath) {
|
|
|
3517
3891
|
};
|
|
3518
3892
|
}
|
|
3519
3893
|
function getProjectPages(dirPath) {
|
|
3520
|
-
const appJsonPath =
|
|
3894
|
+
const appJsonPath = path10.join(dirPath, "app.json");
|
|
3521
3895
|
try {
|
|
3522
3896
|
const appJson = JSON.parse(
|
|
3523
3897
|
fs5.readFileSync(appJsonPath, "utf-8")
|
|
@@ -3543,7 +3917,7 @@ function getProjectSettings(projectPath) {
|
|
|
3543
3917
|
return { uploadWithSourceMap: false };
|
|
3544
3918
|
}
|
|
3545
3919
|
try {
|
|
3546
|
-
const configPath =
|
|
3920
|
+
const configPath = path10.join(projectPath, "project.config.json");
|
|
3547
3921
|
const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
3548
3922
|
return {
|
|
3549
3923
|
uploadWithSourceMap: !!config.setting?.uploadWithSourceMap
|
|
@@ -3554,7 +3928,7 @@ function getProjectSettings(projectPath) {
|
|
|
3554
3928
|
}
|
|
3555
3929
|
function updateProjectSettings(projectPath, patch) {
|
|
3556
3930
|
if (!projectPath) return;
|
|
3557
|
-
const configPath =
|
|
3931
|
+
const configPath = path10.join(projectPath, "project.config.json");
|
|
3558
3932
|
let config = {};
|
|
3559
3933
|
try {
|
|
3560
3934
|
config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
@@ -3859,16 +4233,16 @@ function createWorkspaceService(ctx) {
|
|
|
3859
4233
|
// src/main/services/projects/thumbnail.ts
|
|
3860
4234
|
import { createHash } from "crypto";
|
|
3861
4235
|
import fs6 from "fs";
|
|
3862
|
-
import
|
|
4236
|
+
import path11 from "path";
|
|
3863
4237
|
import { app as app7 } from "electron";
|
|
3864
4238
|
function getThumbnailDir() {
|
|
3865
|
-
return
|
|
4239
|
+
return path11.join(app7.getPath("userData"), "thumbnails");
|
|
3866
4240
|
}
|
|
3867
4241
|
function hashProjectPath(projectPath) {
|
|
3868
4242
|
return createHash("sha256").update(projectPath).digest("hex").slice(0, 16);
|
|
3869
4243
|
}
|
|
3870
4244
|
function getThumbnailPath(projectPath) {
|
|
3871
|
-
return
|
|
4245
|
+
return path11.join(getThumbnailDir(), `${hashProjectPath(projectPath)}.png`);
|
|
3872
4246
|
}
|
|
3873
4247
|
var DATA_URL_PNG_PREFIX = "data:image/png;base64,";
|
|
3874
4248
|
function saveThumbnailFromDataUrl(projectPath, imageDataUrl) {
|
|
@@ -3929,20 +4303,20 @@ function sanitizeTemplates(templates) {
|
|
|
3929
4303
|
}
|
|
3930
4304
|
|
|
3931
4305
|
// src/main/services/projects/builtin-templates.ts
|
|
3932
|
-
import
|
|
3933
|
-
var TEMPLATES_DIR =
|
|
4306
|
+
import path12 from "node:path";
|
|
4307
|
+
var TEMPLATES_DIR = path12.join(devtoolsPackageRoot, "templates");
|
|
3934
4308
|
var BUILTIN_TEMPLATES = [
|
|
3935
4309
|
{
|
|
3936
4310
|
id: "blank",
|
|
3937
4311
|
name: "Blank",
|
|
3938
4312
|
description: "\u6700\u5C0F\u9AA8\u67B6\uFF1Aapp.* + \u4E00\u4E2A index \u9875\u9762",
|
|
3939
|
-
source: { type: "directory", path:
|
|
4313
|
+
source: { type: "directory", path: path12.join(TEMPLATES_DIR, "blank") }
|
|
3940
4314
|
},
|
|
3941
4315
|
{
|
|
3942
4316
|
id: "taro-todo",
|
|
3943
4317
|
name: "Taro Todo",
|
|
3944
4318
|
description: "Taro \u7F16\u8BD1\u4EA7\u7269\u7684 Todo \u793A\u4F8B",
|
|
3945
|
-
source: { type: "directory", path:
|
|
4319
|
+
source: { type: "directory", path: path12.join(TEMPLATES_DIR, "taro-todo") }
|
|
3946
4320
|
}
|
|
3947
4321
|
];
|
|
3948
4322
|
|
|
@@ -4088,13 +4462,9 @@ var SimulatorAttachNativeSchema = z3.tuple([
|
|
|
4088
4462
|
}),
|
|
4089
4463
|
SimWidth
|
|
4090
4464
|
]);
|
|
4091
|
-
var
|
|
4092
|
-
z3.
|
|
4093
|
-
|
|
4094
|
-
y: z3.number().finite(),
|
|
4095
|
-
width: z3.number().finite(),
|
|
4096
|
-
height: z3.number().finite(),
|
|
4097
|
-
zoom: z3.number().finite().positive()
|
|
4465
|
+
var SimulatorSoftReloadSchema = z3.tuple([
|
|
4466
|
+
z3.string().url().refine((u) => u.startsWith("http://") || u.startsWith("https://"), {
|
|
4467
|
+
message: "simulator URL must be http(s)"
|
|
4098
4468
|
})
|
|
4099
4469
|
]);
|
|
4100
4470
|
var SimulatorSetDeviceInfoSchema = z3.tuple([
|
|
@@ -4117,12 +4487,31 @@ var SimulatorSetDeviceInfoSchema = z3.tuple([
|
|
|
4117
4487
|
})
|
|
4118
4488
|
]);
|
|
4119
4489
|
var NonNegInt = z3.number().int().min(0).max(1e5);
|
|
4120
|
-
var
|
|
4490
|
+
var FiniteNum = z3.number().finite();
|
|
4491
|
+
var PlacementSchema = z3.union([
|
|
4492
|
+
z3.object({
|
|
4493
|
+
visible: z3.literal(true),
|
|
4494
|
+
bounds: z3.object({
|
|
4495
|
+
x: FiniteNum,
|
|
4496
|
+
y: FiniteNum,
|
|
4497
|
+
width: FiniteNum,
|
|
4498
|
+
height: FiniteNum
|
|
4499
|
+
})
|
|
4500
|
+
}),
|
|
4501
|
+
z3.object({ visible: z3.literal(false) })
|
|
4502
|
+
]);
|
|
4503
|
+
var PlacementSnapshotSchema = z3.tuple([
|
|
4121
4504
|
z3.object({
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4505
|
+
generation: z3.number().int().min(0),
|
|
4506
|
+
epoch: z3.number().int().min(0),
|
|
4507
|
+
views: z3.array(
|
|
4508
|
+
z3.object({
|
|
4509
|
+
viewId: z3.string().min(1).max(64),
|
|
4510
|
+
placement: PlacementSchema,
|
|
4511
|
+
layer: z3.number().int(),
|
|
4512
|
+
extra: z3.object({ zoom: z3.number().finite().positive().optional() }).optional()
|
|
4513
|
+
})
|
|
4514
|
+
).max(64)
|
|
4126
4515
|
})
|
|
4127
4516
|
]);
|
|
4128
4517
|
var HostToolbarAdvertiseHeightSchema = z3.tuple([
|
|
@@ -4169,84 +4558,16 @@ var SettingsProjectSettingsChangedSchema = z3.tuple([
|
|
|
4169
4558
|
var ProjectCaptureThumbnailSchema = z3.tuple([AbsolutePath]);
|
|
4170
4559
|
var ProjectGetThumbnailSchema = z3.tuple([AbsolutePath]);
|
|
4171
4560
|
|
|
4172
|
-
// src/shared/bridge-channels.ts
|
|
4173
|
-
var BRIDGE_CHANNELS = {
|
|
4174
|
-
SPAWN: "dmb:spawn",
|
|
4175
|
-
DISPOSE: "dmb:dispose",
|
|
4176
|
-
PAGE_OPEN: "dmb:page:open",
|
|
4177
|
-
PAGE_CLOSE: "dmb:page:close",
|
|
4178
|
-
PAGE_LIFECYCLE: "dmb:page:lifecycle",
|
|
4179
|
-
NAV_CALLBACK: "dmb:nav:callback",
|
|
4180
|
-
SERVICE_INVOKE: "dmb:service:invoke",
|
|
4181
|
-
SERVICE_PUBLISH: "dmb:service:publish",
|
|
4182
|
-
RENDER_INVOKE: "dmb:render:invoke",
|
|
4183
|
-
RENDER_PUBLISH: "dmb:render:publish",
|
|
4184
|
-
TO_SERVICE: "dmb:to-service",
|
|
4185
|
-
TO_RENDER: "dmb:to-render",
|
|
4186
|
-
SIMULATOR_API: "dmb:simulator-api",
|
|
4187
|
-
/** simulator → main: ack of an API_CALL request (carries success/fail args). */
|
|
4188
|
-
API_RESPONSE: "dmb:api:response",
|
|
4189
|
-
/**
|
|
4190
|
-
* simulator webview preload → main (sendSync): "is native-host mode on?".
|
|
4191
|
-
* The guest preload can't read the launch `process.env`, so it asks main
|
|
4192
|
-
* (which can) at install time. Reply is `e.returnValue = boolean`.
|
|
4193
|
-
*/
|
|
4194
|
-
NATIVE_HOST_ENABLED: "dmb:native-host-enabled",
|
|
4195
|
-
/**
|
|
4196
|
-
* simulator (DeviceShell) → main: the visible top-of-stack page bridgeId.
|
|
4197
|
-
* Main has no z-order concept — the active page lives only in DeviceShell's
|
|
4198
|
-
* ShellState — so devtools panels / automation that must target "the current
|
|
4199
|
-
* page's render webContents" resolve it through this signal. Fire-and-forget.
|
|
4200
|
-
*/
|
|
4201
|
-
ACTIVE_PAGE: "dmb:active-page",
|
|
4202
|
-
/**
|
|
4203
|
-
* simulator (DeviceShell) → main: the FULL ordered page stack (bottom→top)
|
|
4204
|
-
* whenever it changes. Main has no stack of its own (it only learns the
|
|
4205
|
-
* active bridgeId via ACTIVE_PAGE), so automation's `App.getPageStack` needs
|
|
4206
|
-
* this to report multi-page stacks. Fire-and-forget.
|
|
4207
|
-
*/
|
|
4208
|
-
PAGE_STACK: "dmb:page-stack"
|
|
4209
|
-
};
|
|
4210
|
-
var SIMULATOR_EVENTS = {
|
|
4211
|
-
DOM_READY: "simulator:dom-ready",
|
|
4212
|
-
NAV_BAR: "simulator:navigation-bar",
|
|
4213
|
-
NAV_ACTION: "simulator:nav-action",
|
|
4214
|
-
TAB_ACTION: "simulator:tab-action",
|
|
4215
|
-
/** main → simulator: invoke a wx.* API on the simulator-resident MiniApp. */
|
|
4216
|
-
API_CALL: "simulator:api-call",
|
|
4217
|
-
/**
|
|
4218
|
-
* main → simulator: the renderer toolbar picked a different device. Carries a
|
|
4219
|
-
* NativeDeviceInfo; DeviceShell resizes the bezel + re-renders status bar /
|
|
4220
|
-
* notch. The race-free INITIAL device rides NativeHostConfig.device (read
|
|
4221
|
-
* synchronously at preload bridge-install); this event covers live changes.
|
|
4222
|
-
*/
|
|
4223
|
-
DEVICE_CHANGE: "simulator:device-change"
|
|
4224
|
-
};
|
|
4225
|
-
function deviceInfoToHostEnv(d) {
|
|
4226
|
-
return {
|
|
4227
|
-
brand: d.brand,
|
|
4228
|
-
model: d.model,
|
|
4229
|
-
system: d.system,
|
|
4230
|
-
platform: d.platform,
|
|
4231
|
-
pixelRatio: d.pixelRatio,
|
|
4232
|
-
screenWidth: d.screenWidth,
|
|
4233
|
-
screenHeight: d.screenHeight,
|
|
4234
|
-
windowWidth: d.screenWidth,
|
|
4235
|
-
windowHeight: Math.max(0, d.screenHeight - d.statusBarHeight),
|
|
4236
|
-
statusBarHeight: d.statusBarHeight
|
|
4237
|
-
};
|
|
4238
|
-
}
|
|
4239
|
-
|
|
4240
4561
|
// src/main/ipc/simulator.ts
|
|
4241
4562
|
function registerSimulatorIpc(ctx) {
|
|
4242
4563
|
return new IpcRegistry(ctx.senderPolicy).handle(SimulatorChannel.AttachNative, (_, ...args) => {
|
|
4243
4564
|
const [simulatorUrl, simWidth] = validate(SimulatorChannel.AttachNative, SimulatorAttachNativeSchema, args);
|
|
4244
4565
|
return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
4566
|
+
}).handle(SimulatorChannel.SoftReload, (_, ...args) => {
|
|
4567
|
+
const [simulatorUrl] = validate(SimulatorChannel.SoftReload, SimulatorSoftReloadSchema, args);
|
|
4568
|
+
return ctx.views.softReloadNativeSimulator(simulatorUrl);
|
|
4245
4569
|
}).handle(SimulatorChannel.Detach, () => {
|
|
4246
4570
|
ctx.views.detachSimulator();
|
|
4247
|
-
}).handle(SimulatorChannel.SetNativeBounds, (_, ...args) => {
|
|
4248
|
-
const [p] = validate(SimulatorChannel.SetNativeBounds, SimulatorSetNativeBoundsSchema, args);
|
|
4249
|
-
ctx.views.setNativeSimulatorViewBounds(p);
|
|
4250
4571
|
}).handle(SimulatorChannel.SetDeviceInfo, (_, ...args) => {
|
|
4251
4572
|
const [device] = validate(SimulatorChannel.SetDeviceInfo, SimulatorSetDeviceInfoSchema, args);
|
|
4252
4573
|
ctx.bridge?.setDevice(device);
|
|
@@ -4280,11 +4601,11 @@ var popoverModule = {
|
|
|
4280
4601
|
|
|
4281
4602
|
// src/main/ipc/projects.ts
|
|
4282
4603
|
import { app as app8, dialog } from "electron";
|
|
4283
|
-
import
|
|
4604
|
+
import path14 from "path";
|
|
4284
4605
|
|
|
4285
4606
|
// src/main/services/projects/create-project-service.ts
|
|
4286
4607
|
import fs7 from "node:fs";
|
|
4287
|
-
import
|
|
4608
|
+
import path13 from "node:path";
|
|
4288
4609
|
var DEFAULT_TEMPLATE_ID = "blank";
|
|
4289
4610
|
async function createProject(input, ctx) {
|
|
4290
4611
|
const name = (input.name ?? "").trim();
|
|
@@ -4331,7 +4652,7 @@ async function createProject(input, ctx) {
|
|
|
4331
4652
|
force: true
|
|
4332
4653
|
});
|
|
4333
4654
|
}
|
|
4334
|
-
const cfgPath =
|
|
4655
|
+
const cfgPath = path13.join(target, "project.config.json");
|
|
4335
4656
|
let cfg = {};
|
|
4336
4657
|
if (fs7.existsSync(cfgPath)) {
|
|
4337
4658
|
try {
|
|
@@ -4417,7 +4738,7 @@ function registerProjectsIpc(ctx) {
|
|
|
4417
4738
|
}
|
|
4418
4739
|
try {
|
|
4419
4740
|
const settings = loadWorkbenchSettings();
|
|
4420
|
-
const newBase =
|
|
4741
|
+
const newBase = path14.dirname(input.path);
|
|
4421
4742
|
if (newBase && settings.lastCreateBaseDir !== newBase) {
|
|
4422
4743
|
saveWorkbenchSettings({ ...settings, lastCreateBaseDir: newBase });
|
|
4423
4744
|
}
|
|
@@ -4589,7 +4910,7 @@ import { DisposableRegistry as DisposableRegistry6 } from "@dimina-kit/electron-
|
|
|
4589
4910
|
|
|
4590
4911
|
// src/main/ipc/bridge-router.ts
|
|
4591
4912
|
import { app as app12, ipcMain as ipcMain3, protocol as protocol2, session as electronSession, webContents as webContents2 } from "electron";
|
|
4592
|
-
import
|
|
4913
|
+
import path17 from "node:path";
|
|
4593
4914
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
4594
4915
|
|
|
4595
4916
|
// src/shared/simulator-api-metadata.ts
|
|
@@ -4598,13 +4919,40 @@ function isPersistentSimulatorApi(name) {
|
|
|
4598
4919
|
return PERSISTENT_SIMULATOR_APIS.has(name);
|
|
4599
4920
|
}
|
|
4600
4921
|
|
|
4922
|
+
// src/main/ipc/session-listener-bag.ts
|
|
4923
|
+
function createSessionListenerBag() {
|
|
4924
|
+
const records = [];
|
|
4925
|
+
let disposed = false;
|
|
4926
|
+
return {
|
|
4927
|
+
on(emitter, event, fn) {
|
|
4928
|
+
if (disposed) return;
|
|
4929
|
+
emitter.on(event, fn);
|
|
4930
|
+
records.push({ emitter, event, fn });
|
|
4931
|
+
},
|
|
4932
|
+
once(emitter, event, fn) {
|
|
4933
|
+
if (disposed) return;
|
|
4934
|
+
emitter.once(event, fn);
|
|
4935
|
+
records.push({ emitter, event, fn });
|
|
4936
|
+
},
|
|
4937
|
+
dispose() {
|
|
4938
|
+
if (disposed) return;
|
|
4939
|
+
disposed = true;
|
|
4940
|
+
for (const { emitter, event, fn } of records) {
|
|
4941
|
+
if (emitter.isDestroyed?.()) continue;
|
|
4942
|
+
emitter.removeListener(event, fn);
|
|
4943
|
+
}
|
|
4944
|
+
records.length = 0;
|
|
4945
|
+
}
|
|
4946
|
+
};
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4601
4949
|
// src/main/ipc/bridge-router.ts
|
|
4602
4950
|
import { createDebugTap } from "@dimina-kit/electron-deck/main";
|
|
4603
4951
|
|
|
4604
4952
|
// src/main/services/dimina-resource-server.ts
|
|
4605
4953
|
import http from "node:http";
|
|
4606
4954
|
import fs8 from "node:fs";
|
|
4607
|
-
import
|
|
4955
|
+
import path15 from "node:path";
|
|
4608
4956
|
var MIME_TYPES = {
|
|
4609
4957
|
".css": "text/css; charset=utf-8",
|
|
4610
4958
|
".html": "text/html; charset=utf-8",
|
|
@@ -4620,7 +4968,7 @@ var MIME_TYPES = {
|
|
|
4620
4968
|
".wasm": "application/wasm"
|
|
4621
4969
|
};
|
|
4622
4970
|
async function startDiminaResourceServer(rootDir) {
|
|
4623
|
-
const root =
|
|
4971
|
+
const root = path15.resolve(rootDir);
|
|
4624
4972
|
const server = http.createServer((req, res) => {
|
|
4625
4973
|
void handleRequest(root, req, res);
|
|
4626
4974
|
});
|
|
@@ -4668,7 +5016,7 @@ async function handleRequest(root, req, res) {
|
|
|
4668
5016
|
return;
|
|
4669
5017
|
}
|
|
4670
5018
|
res.writeHead(200, {
|
|
4671
|
-
"content-type": MIME_TYPES[
|
|
5019
|
+
"content-type": MIME_TYPES[path15.extname(filePath)] ?? "application/octet-stream",
|
|
4672
5020
|
"content-length": stat.size,
|
|
4673
5021
|
"cache-control": "no-store"
|
|
4674
5022
|
});
|
|
@@ -4684,8 +5032,8 @@ async function handleRequest(root, req, res) {
|
|
|
4684
5032
|
}
|
|
4685
5033
|
function resolveContainedPath(root, pathname) {
|
|
4686
5034
|
const relative = pathname.replace(/^\/+/, "") || "index.html";
|
|
4687
|
-
const resolved =
|
|
4688
|
-
if (resolved !== root && !resolved.startsWith(root +
|
|
5035
|
+
const resolved = path15.resolve(root, relative);
|
|
5036
|
+
if (resolved !== root && !resolved.startsWith(root + path15.sep)) return null;
|
|
4689
5037
|
return resolved;
|
|
4690
5038
|
}
|
|
4691
5039
|
function setCorsHeaders(res) {
|
|
@@ -4697,11 +5045,11 @@ function setCorsHeaders(res) {
|
|
|
4697
5045
|
|
|
4698
5046
|
// src/main/windows/service-host-window/create.ts
|
|
4699
5047
|
import { app as app10, BrowserWindow as BrowserWindow4 } from "electron";
|
|
4700
|
-
import
|
|
5048
|
+
import path16 from "node:path";
|
|
4701
5049
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
4702
5050
|
var SERVICE_HOST_PARTITION = SHARED_MINIAPP_PARTITION;
|
|
4703
|
-
var serviceHostPreloadPath =
|
|
4704
|
-
var serviceHostHtmlPath =
|
|
5051
|
+
var serviceHostPreloadPath = path16.join(devtoolsPackageRoot, "dist/service-host/preload.cjs");
|
|
5052
|
+
var serviceHostHtmlPath = path16.join(devtoolsPackageRoot, "dist/service-host/service.html");
|
|
4705
5053
|
function constructServiceHostWindow(opts = {}) {
|
|
4706
5054
|
const partition = opts.partition ?? SERVICE_HOST_PARTITION;
|
|
4707
5055
|
configureMiniappSession(partition);
|
|
@@ -5618,7 +5966,22 @@ function setupSimulatorStorage(host, options) {
|
|
|
5618
5966
|
}
|
|
5619
5967
|
}
|
|
5620
5968
|
const storageApi = options.bridge?.isNativeHost() ? { invoke: runtimeInvoke } : null;
|
|
5621
|
-
|
|
5969
|
+
function onSyncStorageChange(appId, change) {
|
|
5970
|
+
if (appId !== getActiveAppId()) return;
|
|
5971
|
+
if (host.isDestroyed()) return;
|
|
5972
|
+
switch (change.op) {
|
|
5973
|
+
case "set":
|
|
5974
|
+
pushSyntheticEvent({ type: "added", key: change.key, newValue: change.value });
|
|
5975
|
+
break;
|
|
5976
|
+
case "remove":
|
|
5977
|
+
pushSyntheticEvent({ type: "removed", key: change.key });
|
|
5978
|
+
break;
|
|
5979
|
+
case "clear":
|
|
5980
|
+
host.send(SimulatorStorageChannel.Event, { type: "cleared" });
|
|
5981
|
+
break;
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
5984
|
+
return { dispose: () => registry.dispose(), storageApi, onSyncStorageChange };
|
|
5622
5985
|
}
|
|
5623
5986
|
function findSimulatorWebContents() {
|
|
5624
5987
|
for (const wc of wcStatic.getAllWebContents()) {
|
|
@@ -5744,7 +6107,8 @@ function installBridgeRouter(ctx) {
|
|
|
5744
6107
|
const state = {
|
|
5745
6108
|
appSessions: /* @__PURE__ */ new Map(),
|
|
5746
6109
|
pageSessions: /* @__PURE__ */ new Map(),
|
|
5747
|
-
|
|
6110
|
+
serviceWcIdToAppSessionId: /* @__PURE__ */ new Map(),
|
|
6111
|
+
simulatorWcIdToAppSessionIds: /* @__PURE__ */ new Map(),
|
|
5748
6112
|
wcIdToBridgeId: /* @__PURE__ */ new Map(),
|
|
5749
6113
|
pendingApiCalls: /* @__PURE__ */ new Map(),
|
|
5750
6114
|
pool: null,
|
|
@@ -5776,8 +6140,8 @@ function installBridgeRouter(ctx) {
|
|
|
5776
6140
|
const onNativeHostQuery = (event) => {
|
|
5777
6141
|
const reply = {
|
|
5778
6142
|
enabled: true,
|
|
5779
|
-
renderHostHtmlUrl: pathToFileURL3(
|
|
5780
|
-
renderPreloadUrl: pathToFileURL3(
|
|
6143
|
+
renderHostHtmlUrl: pathToFileURL3(path17.join(devtoolsPackageRoot, "dist/render-host/pageFrame.html")).toString(),
|
|
6144
|
+
renderPreloadUrl: pathToFileURL3(path17.join(devtoolsPackageRoot, "dist/render-host/preload.cjs")).toString(),
|
|
5781
6145
|
device: currentDevice ?? void 0
|
|
5782
6146
|
};
|
|
5783
6147
|
event.returnValue = reply;
|
|
@@ -5852,9 +6216,34 @@ function installBridgeRouter(ctx) {
|
|
|
5852
6216
|
return Promise.all(ids.map((id) => disposeAppSession(state, id))).then(() => {
|
|
5853
6217
|
});
|
|
5854
6218
|
},
|
|
5855
|
-
debugTap: state.debugTap
|
|
6219
|
+
debugTap: state.debugTap,
|
|
6220
|
+
census: () => {
|
|
6221
|
+
const simulatorDestroyedListeners = {};
|
|
6222
|
+
let simulatorWcBindings = 0;
|
|
6223
|
+
for (const ids of state.simulatorWcIdToAppSessionIds.values()) simulatorWcBindings += ids.size;
|
|
6224
|
+
for (const ap of state.appSessions.values()) {
|
|
6225
|
+
const wc = ap.simulatorWc;
|
|
6226
|
+
if (!wc.isDestroyed() && simulatorDestroyedListeners[wc.id] === void 0) {
|
|
6227
|
+
simulatorDestroyedListeners[wc.id] = wc.listenerCount("destroyed");
|
|
6228
|
+
}
|
|
6229
|
+
}
|
|
6230
|
+
return {
|
|
6231
|
+
appSessions: state.appSessions.size,
|
|
6232
|
+
pageSessions: state.pageSessions.size,
|
|
6233
|
+
serviceWcBindings: state.serviceWcIdToAppSessionId.size,
|
|
6234
|
+
simulatorWcs: state.simulatorWcIdToAppSessionIds.size,
|
|
6235
|
+
simulatorWcBindings,
|
|
6236
|
+
renderWcBindings: state.wcIdToBridgeId.size,
|
|
6237
|
+
pendingApiCalls: state.pendingApiCalls.size,
|
|
6238
|
+
simulatorDestroyedListeners
|
|
6239
|
+
};
|
|
6240
|
+
}
|
|
5856
6241
|
};
|
|
5857
6242
|
ctx.bridge = bridgeHandle;
|
|
6243
|
+
if (process.env.NODE_ENV === "test") {
|
|
6244
|
+
;
|
|
6245
|
+
globalThis.__diminaResourceCensus = () => bridgeHandle.census?.();
|
|
6246
|
+
}
|
|
5858
6247
|
const consoleForwarder = createConsoleForwarder(bridgeHandle);
|
|
5859
6248
|
ctx.consoleForwarder = consoleForwarder;
|
|
5860
6249
|
ctx.guestConsole = consoleForwarder;
|
|
@@ -5866,8 +6255,7 @@ function installBridgeRouter(ctx) {
|
|
|
5866
6255
|
const onActivePage = (event, payload) => {
|
|
5867
6256
|
const ap = state.appSessions.get(payload.appSessionId);
|
|
5868
6257
|
if (!ap) return;
|
|
5869
|
-
|
|
5870
|
-
if (!senderApp || senderApp.appSessionId !== ap.appSessionId) return;
|
|
6258
|
+
if (!senderBoundToSession(state, event.sender, ap)) return;
|
|
5871
6259
|
if (ap.pages.has(payload.bridgeId)) {
|
|
5872
6260
|
ap.activeBridgeId = payload.bridgeId;
|
|
5873
6261
|
const pagePath = state.pageSessions.get(payload.bridgeId)?.pagePath;
|
|
@@ -5881,8 +6269,7 @@ function installBridgeRouter(ctx) {
|
|
|
5881
6269
|
const onPageStack = (event, payload) => {
|
|
5882
6270
|
const ap = state.appSessions.get(payload.appSessionId);
|
|
5883
6271
|
if (!ap) return;
|
|
5884
|
-
|
|
5885
|
-
if (!senderApp || senderApp.appSessionId !== ap.appSessionId) return;
|
|
6272
|
+
if (!senderBoundToSession(state, event.sender, ap)) return;
|
|
5886
6273
|
ap.pageStack = payload.stack;
|
|
5887
6274
|
};
|
|
5888
6275
|
ipcMain3.on(BRIDGE_CHANNELS.PAGE_STACK, onPageStack);
|
|
@@ -5912,8 +6299,7 @@ function installBridgeRouter(ctx) {
|
|
|
5912
6299
|
handlePageLifecycle(state, event.sender, payload);
|
|
5913
6300
|
if (payload.event === "pageUnload" && ctx.appData) {
|
|
5914
6301
|
const ap = state.appSessions.get(payload.appSessionId);
|
|
5915
|
-
|
|
5916
|
-
if (ap && senderApp && senderApp.appSessionId === ap.appSessionId) {
|
|
6302
|
+
if (ap && senderBoundToSession(state, event.sender, ap)) {
|
|
5917
6303
|
ctx.appData.evictBridge(ap.appId, payload.bridgeId);
|
|
5918
6304
|
}
|
|
5919
6305
|
}
|
|
@@ -5932,9 +6318,8 @@ function installBridgeRouter(ctx) {
|
|
|
5932
6318
|
const onDispose = (event, payload) => {
|
|
5933
6319
|
const target = resolveAppByBridgeId(state, payload.bridgeId);
|
|
5934
6320
|
if (!target) return;
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
console.warn(`[bridge-router] DISPOSE rejected: sender belongs to ${senderApp.appSessionId}, target ${target.appSessionId}`);
|
|
6321
|
+
if (!senderBoundToSession(state, event.sender, target) && appByWc(state, event.sender)) {
|
|
6322
|
+
console.warn(`[bridge-router] DISPOSE rejected: sender not bound to target ${target.appSessionId}`);
|
|
5938
6323
|
return;
|
|
5939
6324
|
}
|
|
5940
6325
|
void disposeAppSession(state, target.appSessionId);
|
|
@@ -6033,7 +6418,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
6033
6418
|
const simulatorWc = resolveSimulatorWebContents(ctx, opts.simulatorWcId, event.sender);
|
|
6034
6419
|
const pagePath = normalizePagePath(opts.pagePath || "pages/index/index");
|
|
6035
6420
|
const workspaceProjectPath = typeof ctx.workspace.getProjectPath === "function" ? ctx.workspace.getProjectPath() : "";
|
|
6036
|
-
const pkgRoot =
|
|
6421
|
+
const pkgRoot = path17.resolve(opts.pkgRoot || workspaceProjectPath || process.cwd());
|
|
6037
6422
|
const root = opts.root || "main";
|
|
6038
6423
|
const apiNamespaces = ctx.apiNamespaces ?? [];
|
|
6039
6424
|
let resourceServer = null;
|
|
@@ -6041,7 +6426,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
6041
6426
|
if (opts.resourceBaseUrl) {
|
|
6042
6427
|
resourceBaseUrl = opts.resourceBaseUrl.endsWith("/") ? opts.resourceBaseUrl : `${opts.resourceBaseUrl}/`;
|
|
6043
6428
|
} else {
|
|
6044
|
-
resourceServer = await startDiminaResourceServer(
|
|
6429
|
+
resourceServer = await startDiminaResourceServer(path17.resolve(pkgRoot, root));
|
|
6045
6430
|
resourceBaseUrl = resourceServer.baseUrl;
|
|
6046
6431
|
}
|
|
6047
6432
|
const selectedDevice = ctx.bridge?.getDevice?.() ?? null;
|
|
@@ -6100,8 +6485,9 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
6100
6485
|
pages: /* @__PURE__ */ new Map(),
|
|
6101
6486
|
activeBridgeId: null,
|
|
6102
6487
|
poolEntryId,
|
|
6103
|
-
|
|
6104
|
-
|
|
6488
|
+
onServiceBoot: null,
|
|
6489
|
+
listenerBag: createSessionListenerBag(),
|
|
6490
|
+
registryHandle: null
|
|
6105
6491
|
};
|
|
6106
6492
|
const rootPage = {
|
|
6107
6493
|
bridgeId,
|
|
@@ -6119,23 +6505,22 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
6119
6505
|
state.appSessions.set(appSessionId, appSession);
|
|
6120
6506
|
state.pageSessions.set(bridgeId, rootPage);
|
|
6121
6507
|
appSession.pages.set(bridgeId, rootPage);
|
|
6122
|
-
bindWc(state.
|
|
6123
|
-
|
|
6508
|
+
bindWc(state.serviceWcIdToAppSessionId, serviceWindow.webContents, appSessionId);
|
|
6509
|
+
bindSimulatorWc(state.simulatorWcIdToAppSessionIds, simulatorWc, appSessionId);
|
|
6124
6510
|
state.connections.acquire(serviceWindow.webContents).own(() => {
|
|
6125
|
-
if (state.
|
|
6126
|
-
state.
|
|
6511
|
+
if (state.serviceWcIdToAppSessionId.get(appSession.serviceWc.id) === appSessionId) {
|
|
6512
|
+
state.serviceWcIdToAppSessionId.delete(appSession.serviceWc.id);
|
|
6127
6513
|
}
|
|
6128
6514
|
});
|
|
6129
|
-
ctx.registry.add(() => disposeAppSession(state, appSessionId));
|
|
6515
|
+
appSession.registryHandle = ctx.registry.add(() => disposeAppSession(state, appSessionId));
|
|
6130
6516
|
const onServiceClosed = () => {
|
|
6131
6517
|
void disposeAppSession(state, appSessionId, { serviceAlreadyClosed: true });
|
|
6132
6518
|
};
|
|
6133
|
-
appSession.
|
|
6134
|
-
serviceWindow.once("closed", onServiceClosed);
|
|
6519
|
+
appSession.listenerBag.once(serviceWindow, "closed", onServiceClosed);
|
|
6135
6520
|
const onSimulatorDestroyed = () => {
|
|
6136
6521
|
void disposeAppSession(state, appSessionId);
|
|
6137
6522
|
};
|
|
6138
|
-
|
|
6523
|
+
appSession.listenerBag.once(simulatorWc, "destroyed", onSimulatorDestroyed);
|
|
6139
6524
|
if (simulatorWc.isDestroyed()) {
|
|
6140
6525
|
void disposeAppSession(state, appSessionId);
|
|
6141
6526
|
}
|
|
@@ -6183,8 +6568,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
6183
6568
|
async function handlePageOpen(state, event, opts) {
|
|
6184
6569
|
const ap = state.appSessions.get(opts.appSessionId);
|
|
6185
6570
|
if (!ap) throw new Error(`[bridge-router] PAGE_OPEN unknown appSession ${opts.appSessionId}`);
|
|
6186
|
-
|
|
6187
|
-
if (!senderApp || senderApp.appSessionId !== opts.appSessionId) {
|
|
6571
|
+
if (!senderBoundToSession(state, event.sender, ap)) {
|
|
6188
6572
|
throw new Error("[bridge-router] PAGE_OPEN rejected: caller not bound to app session");
|
|
6189
6573
|
}
|
|
6190
6574
|
const pagePath = normalizePagePath(opts.pagePath);
|
|
@@ -6217,8 +6601,7 @@ function handlePageClose(state, sender, payload) {
|
|
|
6217
6601
|
}
|
|
6218
6602
|
const ap = state.appSessions.get(page.appSessionId);
|
|
6219
6603
|
if (!ap) return;
|
|
6220
|
-
|
|
6221
|
-
if (!senderApp || senderApp.appSessionId !== ap.appSessionId) {
|
|
6604
|
+
if (!senderBoundToSession(state, sender, ap)) {
|
|
6222
6605
|
console.warn("[bridge-router] PAGE_CLOSE rejected: caller not bound to app session");
|
|
6223
6606
|
return;
|
|
6224
6607
|
}
|
|
@@ -6227,8 +6610,7 @@ function handlePageClose(state, sender, payload) {
|
|
|
6227
6610
|
function handlePageLifecycle(state, sender, payload) {
|
|
6228
6611
|
const ap = state.appSessions.get(payload.appSessionId);
|
|
6229
6612
|
if (!ap) return;
|
|
6230
|
-
|
|
6231
|
-
if (!senderApp || senderApp.appSessionId !== ap.appSessionId) return;
|
|
6613
|
+
if (!senderBoundToSession(state, sender, ap)) return;
|
|
6232
6614
|
forwardToService(ap, {
|
|
6233
6615
|
type: payload.event,
|
|
6234
6616
|
target: "service",
|
|
@@ -6238,8 +6620,7 @@ function handlePageLifecycle(state, sender, payload) {
|
|
|
6238
6620
|
function handleNavCallback(state, sender, payload) {
|
|
6239
6621
|
const ap = state.appSessions.get(payload.appSessionId);
|
|
6240
6622
|
if (!ap) return;
|
|
6241
|
-
|
|
6242
|
-
if (!senderApp || senderApp.appSessionId !== ap.appSessionId) return;
|
|
6623
|
+
if (!senderBoundToSession(state, sender, ap)) return;
|
|
6243
6624
|
const result = { errMsg: payload.errMsg };
|
|
6244
6625
|
if (payload.ok) {
|
|
6245
6626
|
sendCallback(ap, payload.callbacks.success, result);
|
|
@@ -6255,18 +6636,23 @@ async function bootServiceHost(state, ap, ctx) {
|
|
|
6255
6636
|
reportLogicLoadFailure(ap, ctx);
|
|
6256
6637
|
return;
|
|
6257
6638
|
}
|
|
6258
|
-
|
|
6639
|
+
const rootPage = ap.pages.get(ap.appSessionId);
|
|
6640
|
+
const rootMissing = !!rootPage && !pageInManifest(ap, rootPage.pagePath);
|
|
6641
|
+
if (rootMissing) {
|
|
6642
|
+
reportPageNotFound(ap, ctx, rootPage.pagePath);
|
|
6643
|
+
} else if (rootPage) {
|
|
6644
|
+
forwardToService(ap, makeLoadResource(ap, rootPage, "service"));
|
|
6645
|
+
}
|
|
6259
6646
|
for (const page of ap.pages.values()) {
|
|
6260
|
-
if (page.renderLoadPending)
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
}
|
|
6647
|
+
if (!page.renderLoadPending) continue;
|
|
6648
|
+
page.renderLoadPending = false;
|
|
6649
|
+
sendRenderLoadResource(ap, page);
|
|
6264
6650
|
}
|
|
6265
6651
|
}
|
|
6266
6652
|
function sendRenderLoadResource(ap, page) {
|
|
6267
|
-
if (page.renderWc
|
|
6268
|
-
|
|
6269
|
-
}
|
|
6653
|
+
if (!page.renderWc || page.renderWc.isDestroyed()) return;
|
|
6654
|
+
if (!pageInManifest(ap, page.pagePath)) return;
|
|
6655
|
+
page.renderWc.send(BRIDGE_CHANNELS.TO_RENDER, { msg: makeLoadResource(ap, page, "render") });
|
|
6270
6656
|
}
|
|
6271
6657
|
function logicBundleUrl(ap) {
|
|
6272
6658
|
return ap.resourceServer ? new URL("logic.js", ap.resourceBaseUrl).toString() : new URL(`${ap.appId}/${ap.root}/logic.js`, ap.resourceBaseUrl).toString();
|
|
@@ -6291,6 +6677,14 @@ function reportLogicLoadFailure(ap, ctx) {
|
|
|
6291
6677
|
console.error(message);
|
|
6292
6678
|
ctx.guestConsole?.emit({ source: "service", level: "error", args: [message] });
|
|
6293
6679
|
}
|
|
6680
|
+
function pageInManifest(ap, pagePath) {
|
|
6681
|
+
return ap.manifest.pages.includes(normalizePagePath(pagePath));
|
|
6682
|
+
}
|
|
6683
|
+
function reportPageNotFound(ap, ctx, pagePath) {
|
|
6684
|
+
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.`;
|
|
6685
|
+
console.error(`[bridge-router] ${message}`);
|
|
6686
|
+
ctx.guestConsole?.emit({ source: "service", level: "error", args: [message] });
|
|
6687
|
+
}
|
|
6294
6688
|
function maybeSendResourceLoaded(ap, page) {
|
|
6295
6689
|
if (page.resourceLoadedSent || !ap.serviceLoaded || !page.renderLoaded) return;
|
|
6296
6690
|
page.resourceLoadedSent = true;
|
|
@@ -6379,6 +6773,12 @@ function handleContainerMsg(ap, page, msg, ctx, state) {
|
|
|
6379
6773
|
case "consoleLog":
|
|
6380
6774
|
ctx.guestConsole?.emit(msg.body);
|
|
6381
6775
|
break;
|
|
6776
|
+
case "storageChanged":
|
|
6777
|
+
ctx.onServiceStorageChanged?.(ap.appId, msg.body);
|
|
6778
|
+
break;
|
|
6779
|
+
case "wxmlChanged":
|
|
6780
|
+
state.emitRenderEvent({ kind: "domMutated", appId: ap.appId, bridgeId: page.bridgeId });
|
|
6781
|
+
break;
|
|
6382
6782
|
default:
|
|
6383
6783
|
break;
|
|
6384
6784
|
}
|
|
@@ -6590,8 +6990,7 @@ function handleApiResponse(state, sender, payload) {
|
|
|
6590
6990
|
clearTimeout(pending.timer);
|
|
6591
6991
|
return;
|
|
6592
6992
|
}
|
|
6593
|
-
|
|
6594
|
-
if (!senderApp || senderApp.appSessionId !== ap.appSessionId) {
|
|
6993
|
+
if (!senderBoundToSession(state, sender, ap)) {
|
|
6595
6994
|
console.warn("[bridge-router] API_RESPONSE rejected: sender not bound to app session");
|
|
6596
6995
|
return;
|
|
6597
6996
|
}
|
|
@@ -6696,8 +7095,14 @@ function pageFromMsg(state, ap, msg) {
|
|
|
6696
7095
|
}
|
|
6697
7096
|
function appByWc(state, wc) {
|
|
6698
7097
|
if (wc.isDestroyed()) return void 0;
|
|
6699
|
-
const appSessionId = state.
|
|
7098
|
+
const appSessionId = state.serviceWcIdToAppSessionId.get(wc.id);
|
|
6700
7099
|
if (appSessionId) return state.appSessions.get(appSessionId);
|
|
7100
|
+
const hosted = state.simulatorWcIdToAppSessionIds.get(wc.id);
|
|
7101
|
+
if (hosted) {
|
|
7102
|
+
let latest;
|
|
7103
|
+
for (const id of hosted) latest = state.appSessions.get(id) ?? latest;
|
|
7104
|
+
if (latest) return latest;
|
|
7105
|
+
}
|
|
6701
7106
|
const bridgeId = state.wcIdToBridgeId.get(wc.id);
|
|
6702
7107
|
if (bridgeId) {
|
|
6703
7108
|
const page = state.pageSessions.get(bridgeId);
|
|
@@ -6705,6 +7110,12 @@ function appByWc(state, wc) {
|
|
|
6705
7110
|
}
|
|
6706
7111
|
return void 0;
|
|
6707
7112
|
}
|
|
7113
|
+
function senderBoundToSession(state, sender, ap) {
|
|
7114
|
+
if (sender.isDestroyed()) return false;
|
|
7115
|
+
const hosted = state.simulatorWcIdToAppSessionIds.get(sender.id);
|
|
7116
|
+
if (hosted) return hosted.has(ap.appSessionId);
|
|
7117
|
+
return appByWc(state, sender)?.appSessionId === ap.appSessionId;
|
|
7118
|
+
}
|
|
6708
7119
|
function resolveAppByBridgeId(state, bridgeId) {
|
|
6709
7120
|
if (state.appSessions.has(bridgeId)) return state.appSessions.get(bridgeId);
|
|
6710
7121
|
const page = state.pageSessions.get(bridgeId);
|
|
@@ -6715,6 +7126,15 @@ function bindWc(map, wc, id) {
|
|
|
6715
7126
|
if (wc.isDestroyed()) return;
|
|
6716
7127
|
map.set(wc.id, id);
|
|
6717
7128
|
}
|
|
7129
|
+
function bindSimulatorWc(map, wc, id) {
|
|
7130
|
+
if (wc.isDestroyed()) return;
|
|
7131
|
+
let hosted = map.get(wc.id);
|
|
7132
|
+
if (!hosted) {
|
|
7133
|
+
hosted = /* @__PURE__ */ new Set();
|
|
7134
|
+
map.set(wc.id, hosted);
|
|
7135
|
+
}
|
|
7136
|
+
hosted.add(id);
|
|
7137
|
+
}
|
|
6718
7138
|
function readBridgeId(msg) {
|
|
6719
7139
|
return typeof msg.body?.bridgeId === "string" ? msg.body.bridgeId : void 0;
|
|
6720
7140
|
}
|
|
@@ -6736,6 +7156,9 @@ async function disposeAppSession(state, appSessionId, opts = {}) {
|
|
|
6736
7156
|
const ap = state.appSessions.get(appSessionId);
|
|
6737
7157
|
if (!ap) return;
|
|
6738
7158
|
state.appSessions.delete(appSessionId);
|
|
7159
|
+
const registryHandle = ap.registryHandle;
|
|
7160
|
+
ap.registryHandle = null;
|
|
7161
|
+
void registryHandle?.dispose();
|
|
6739
7162
|
state.appLifecycle.dispose(appSessionId);
|
|
6740
7163
|
state.evictAppDataBridges(ap);
|
|
6741
7164
|
for (const [requestId, pending] of state.pendingApiCalls) {
|
|
@@ -6754,11 +7177,9 @@ async function disposeAppSession(state, appSessionId, opts = {}) {
|
|
|
6754
7177
|
state.pageSessions.delete(page.bridgeId);
|
|
6755
7178
|
}
|
|
6756
7179
|
ap.pages.clear();
|
|
7180
|
+
ap.listenerBag.dispose();
|
|
6757
7181
|
if (ap.poolEntryId !== null && state.pool && !opts.serviceAlreadyClosed) {
|
|
6758
7182
|
state.connections.reset(ap.serviceWc.id);
|
|
6759
|
-
if (ap.onServiceClosed && !ap.serviceWindow.isDestroyed()) {
|
|
6760
|
-
ap.serviceWindow.removeListener("closed", ap.onServiceClosed);
|
|
6761
|
-
}
|
|
6762
7183
|
if (ap.onServiceBoot && !ap.serviceWindow.isDestroyed()) {
|
|
6763
7184
|
ap.serviceWindow.webContents.removeListener("did-finish-load", ap.onServiceBoot);
|
|
6764
7185
|
}
|
|
@@ -6770,8 +7191,14 @@ async function disposeAppSession(state, appSessionId, opts = {}) {
|
|
|
6770
7191
|
} else if (!opts.serviceAlreadyClosed && !ap.serviceWindow.isDestroyed()) {
|
|
6771
7192
|
ap.serviceWindow.close();
|
|
6772
7193
|
}
|
|
6773
|
-
state.
|
|
6774
|
-
|
|
7194
|
+
if (state.serviceWcIdToAppSessionId.get(ap.serviceWc.id) === appSessionId) {
|
|
7195
|
+
state.serviceWcIdToAppSessionId.delete(ap.serviceWc.id);
|
|
7196
|
+
}
|
|
7197
|
+
const hosted = state.simulatorWcIdToAppSessionIds.get(ap.simulatorWc.id);
|
|
7198
|
+
if (hosted) {
|
|
7199
|
+
hosted.delete(appSessionId);
|
|
7200
|
+
if (hosted.size === 0) state.simulatorWcIdToAppSessionIds.delete(ap.simulatorWc.id);
|
|
7201
|
+
}
|
|
6775
7202
|
if (ap.resourceServer) {
|
|
6776
7203
|
await ap.resourceServer.close().catch((error) => {
|
|
6777
7204
|
console.warn("[bridge-router] resource server close failed:", error);
|
|
@@ -6893,27 +7320,13 @@ function makeHostEnv(snapshot) {
|
|
|
6893
7320
|
// src/main/ipc/views.ts
|
|
6894
7321
|
import { ipcMain as ipcMain4 } from "electron";
|
|
6895
7322
|
function registerViewsIpc(ctx) {
|
|
6896
|
-
const registry = new IpcRegistry(ctx.senderPolicy).handle(ViewChannel.
|
|
6897
|
-
const [
|
|
6898
|
-
ViewChannel.
|
|
6899
|
-
|
|
6900
|
-
args
|
|
6901
|
-
);
|
|
6902
|
-
ctx.views.setSimulatorDevtoolsBounds(bounds);
|
|
6903
|
-
}).handle(ViewChannel.WorkbenchBounds, (_event, ...args) => {
|
|
6904
|
-
const [bounds] = validate(
|
|
6905
|
-
ViewChannel.WorkbenchBounds,
|
|
6906
|
-
ViewBoundsSchema,
|
|
6907
|
-
args
|
|
6908
|
-
);
|
|
6909
|
-
ctx.views.setWorkbenchBounds(bounds);
|
|
6910
|
-
}).handle(ViewChannel.HostToolbarBounds, (_event, ...args) => {
|
|
6911
|
-
const [bounds] = validate(
|
|
6912
|
-
ViewChannel.HostToolbarBounds,
|
|
6913
|
-
ViewBoundsSchema,
|
|
7323
|
+
const registry = new IpcRegistry(ctx.senderPolicy).handle(ViewChannel.PlacementSnapshot, (_event, ...args) => {
|
|
7324
|
+
const [snapshot] = validate(
|
|
7325
|
+
ViewChannel.PlacementSnapshot,
|
|
7326
|
+
PlacementSnapshotSchema,
|
|
6914
7327
|
args
|
|
6915
7328
|
);
|
|
6916
|
-
ctx.views.
|
|
7329
|
+
ctx.views.setPlacementSnapshot(snapshot);
|
|
6917
7330
|
}).handle(ViewChannel.HostToolbarGetHeight, () => ctx.views.getHostToolbarHeight());
|
|
6918
7331
|
const onAdvertiseHeight = (event, ...args) => {
|
|
6919
7332
|
if (event.sender.id !== ctx.views.getHostToolbarWebContentsId()) return;
|
|
@@ -8503,6 +8916,11 @@ function createNetworkForwarder(bridge) {
|
|
|
8503
8916
|
trimQueue();
|
|
8504
8917
|
return;
|
|
8505
8918
|
}
|
|
8919
|
+
if (!isFrontendSettled(wc)) {
|
|
8920
|
+
trimQueue();
|
|
8921
|
+
scheduleReadyRetry();
|
|
8922
|
+
return;
|
|
8923
|
+
}
|
|
8506
8924
|
if (sink === "idle") beginProbing();
|
|
8507
8925
|
const batch = [];
|
|
8508
8926
|
let batchChars = 0;
|
|
@@ -8813,21 +9231,87 @@ import { DisposableRegistry as DisposableRegistry8 } from "@dimina-kit/electron-
|
|
|
8813
9231
|
function setupSimulatorWxml(host, options) {
|
|
8814
9232
|
const { bridge, inspector, getActiveAppId } = options;
|
|
8815
9233
|
const registry = new DisposableRegistry8();
|
|
8816
|
-
|
|
8817
|
-
|
|
9234
|
+
let active = false;
|
|
9235
|
+
let seq = 0;
|
|
9236
|
+
let pulling = false;
|
|
9237
|
+
let again = false;
|
|
9238
|
+
let observedWc = null;
|
|
9239
|
+
function activeWc() {
|
|
9240
|
+
return bridge.getActiveRenderWc(getActiveAppId() ?? void 0);
|
|
9241
|
+
}
|
|
9242
|
+
async function pull(wc) {
|
|
8818
9243
|
if (!wc) return null;
|
|
8819
9244
|
return inspector.getWxml(wc);
|
|
8820
9245
|
}
|
|
9246
|
+
function schedulePull() {
|
|
9247
|
+
if (!active) return;
|
|
9248
|
+
const mySeq = ++seq;
|
|
9249
|
+
if (pulling) {
|
|
9250
|
+
again = true;
|
|
9251
|
+
return;
|
|
9252
|
+
}
|
|
9253
|
+
pulling = true;
|
|
9254
|
+
void pull(activeWc()).then((tree) => {
|
|
9255
|
+
if (mySeq === seq && active && !host.isDestroyed()) {
|
|
9256
|
+
host.send(SimulatorWxmlChannel.Event, tree);
|
|
9257
|
+
}
|
|
9258
|
+
}).finally(() => {
|
|
9259
|
+
pulling = false;
|
|
9260
|
+
if (again) {
|
|
9261
|
+
again = false;
|
|
9262
|
+
schedulePull();
|
|
9263
|
+
}
|
|
9264
|
+
});
|
|
9265
|
+
}
|
|
9266
|
+
function startObserving(wc) {
|
|
9267
|
+
if (!wc) return;
|
|
9268
|
+
observedWc = wc;
|
|
9269
|
+
void inspector.setWxmlObserving(wc, true);
|
|
9270
|
+
}
|
|
9271
|
+
function stopObserving() {
|
|
9272
|
+
const wc = observedWc;
|
|
9273
|
+
observedWc = null;
|
|
9274
|
+
if (wc) void inspector.setWxmlObserving(wc, false);
|
|
9275
|
+
}
|
|
9276
|
+
function reconcileObserving() {
|
|
9277
|
+
if (!active) return;
|
|
9278
|
+
const wc = activeWc();
|
|
9279
|
+
if (wc !== observedWc) {
|
|
9280
|
+
stopObserving();
|
|
9281
|
+
startObserving(wc);
|
|
9282
|
+
}
|
|
9283
|
+
}
|
|
9284
|
+
function cancelPending() {
|
|
9285
|
+
seq++;
|
|
9286
|
+
again = false;
|
|
9287
|
+
}
|
|
8821
9288
|
const ipc = new IpcRegistry(options.senderPolicy);
|
|
8822
|
-
ipc.handle(SimulatorWxmlChannel.GetSnapshot, () => pull());
|
|
9289
|
+
ipc.handle(SimulatorWxmlChannel.GetSnapshot, () => pull(activeWc()));
|
|
9290
|
+
ipc.handle(SimulatorWxmlChannel.SetActive, (_event, on) => {
|
|
9291
|
+
if (on) {
|
|
9292
|
+
active = true;
|
|
9293
|
+
reconcileObserving();
|
|
9294
|
+
schedulePull();
|
|
9295
|
+
} else {
|
|
9296
|
+
active = false;
|
|
9297
|
+
cancelPending();
|
|
9298
|
+
stopObserving();
|
|
9299
|
+
}
|
|
9300
|
+
});
|
|
8823
9301
|
registry.add(ipc);
|
|
8824
|
-
const unsubscribe = bridge.onRenderEvent(() => {
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
9302
|
+
const unsubscribe = bridge.onRenderEvent((event) => {
|
|
9303
|
+
if (!active) return;
|
|
9304
|
+
const appId = getActiveAppId();
|
|
9305
|
+
if (appId && event.appId !== appId) return;
|
|
9306
|
+
reconcileObserving();
|
|
9307
|
+
schedulePull();
|
|
8829
9308
|
});
|
|
8830
9309
|
registry.add(unsubscribe);
|
|
9310
|
+
registry.add(() => {
|
|
9311
|
+
active = false;
|
|
9312
|
+
cancelPending();
|
|
9313
|
+
stopObserving();
|
|
9314
|
+
});
|
|
8831
9315
|
return registry;
|
|
8832
9316
|
}
|
|
8833
9317
|
|
|
@@ -9037,7 +9521,7 @@ function setupSimulatorCurrentPage(host, options) {
|
|
|
9037
9521
|
|
|
9038
9522
|
// src/main/services/render-inspect/index.ts
|
|
9039
9523
|
import { readFileSync } from "node:fs";
|
|
9040
|
-
import
|
|
9524
|
+
import path18 from "node:path";
|
|
9041
9525
|
var DEFAULT_SOURCE_PATH = "dist/render-host/render-inspect.js";
|
|
9042
9526
|
var HIGHLIGHT_CONFIG = {
|
|
9043
9527
|
showInfo: true,
|
|
@@ -9063,7 +9547,7 @@ function withTimeout(p, ms) {
|
|
|
9063
9547
|
});
|
|
9064
9548
|
}
|
|
9065
9549
|
function createRenderInspector(options = {}) {
|
|
9066
|
-
const loadSource = options.loadSource ?? (() => readFileSync(
|
|
9550
|
+
const loadSource = options.loadSource ?? (() => readFileSync(path18.join(devtoolsPackageRoot, DEFAULT_SOURCE_PATH), "utf8"));
|
|
9067
9551
|
let cachedSource = null;
|
|
9068
9552
|
const injected = /* @__PURE__ */ new Set();
|
|
9069
9553
|
const selfAttached = /* @__PURE__ */ new Set();
|
|
@@ -9209,20 +9693,30 @@ function createRenderInspector(options = {}) {
|
|
|
9209
9693
|
} catch {
|
|
9210
9694
|
}
|
|
9211
9695
|
}
|
|
9212
|
-
|
|
9696
|
+
async function setWxmlObserving(wc, on) {
|
|
9697
|
+
if (wc.isDestroyed()) return;
|
|
9698
|
+
if (!await ensureInjected(wc)) return;
|
|
9699
|
+
try {
|
|
9700
|
+
await wc.executeJavaScript(
|
|
9701
|
+
`window.__diminaRenderInspect && window.__diminaRenderInspect.setWxmlObserving(${on ? "true" : "false"})`
|
|
9702
|
+
);
|
|
9703
|
+
} catch {
|
|
9704
|
+
}
|
|
9705
|
+
}
|
|
9706
|
+
return { getWxml, highlight, unhighlight, setWxmlObserving };
|
|
9213
9707
|
}
|
|
9214
9708
|
|
|
9215
9709
|
// src/main/services/simulator-temp-files/index.ts
|
|
9216
9710
|
import { toDisposable as toDisposable6 } from "@dimina-kit/electron-deck/main";
|
|
9217
9711
|
|
|
9218
9712
|
// src/main/services/simulator-temp-files/store.ts
|
|
9219
|
-
function registerTempFile(store,
|
|
9713
|
+
function registerTempFile(store, path24, mime, bytes) {
|
|
9220
9714
|
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
|
|
9221
|
-
store.delete(
|
|
9222
|
-
store.set(
|
|
9715
|
+
store.delete(path24);
|
|
9716
|
+
store.set(path24, { bytes: buf, mime });
|
|
9223
9717
|
}
|
|
9224
|
-
function revokeTempFile(store,
|
|
9225
|
-
store.delete(
|
|
9718
|
+
function revokeTempFile(store, path24) {
|
|
9719
|
+
store.delete(path24);
|
|
9226
9720
|
}
|
|
9227
9721
|
function revokeAllTempFiles(store) {
|
|
9228
9722
|
store.clear();
|
|
@@ -9230,14 +9724,14 @@ function revokeAllTempFiles(store) {
|
|
|
9230
9724
|
|
|
9231
9725
|
// src/shared/vpath.ts
|
|
9232
9726
|
import os from "node:os";
|
|
9233
|
-
import
|
|
9727
|
+
import path19 from "node:path";
|
|
9234
9728
|
var DIFILE_PREFIX = "difile://";
|
|
9235
9729
|
function sandboxBase() {
|
|
9236
9730
|
const env = typeof process !== "undefined" && process.env && process.env.DIMINA_HOME || "";
|
|
9237
9731
|
if (env) {
|
|
9238
|
-
return
|
|
9732
|
+
return path19.join(env, "files");
|
|
9239
9733
|
}
|
|
9240
|
-
return
|
|
9734
|
+
return path19.join(os.homedir(), ".dimina", "files");
|
|
9241
9735
|
}
|
|
9242
9736
|
function resolveVPath(url) {
|
|
9243
9737
|
if (typeof url !== "string") return null;
|
|
@@ -9271,15 +9765,15 @@ function resolveVPath(url) {
|
|
|
9271
9765
|
return { kind, writable };
|
|
9272
9766
|
}
|
|
9273
9767
|
const base = sandboxBase();
|
|
9274
|
-
const joined =
|
|
9275
|
-
const normalized =
|
|
9276
|
-
if (normalized !== base && !normalized.startsWith(base +
|
|
9768
|
+
const joined = path19.join(base, decoded);
|
|
9769
|
+
const normalized = path19.normalize(joined);
|
|
9770
|
+
if (normalized !== base && !normalized.startsWith(base + path19.sep)) return null;
|
|
9277
9771
|
return { kind, writable, realPath: normalized };
|
|
9278
9772
|
}
|
|
9279
9773
|
|
|
9280
9774
|
// src/main/services/simulator-temp-files/disk.ts
|
|
9281
9775
|
import fs9 from "node:fs/promises";
|
|
9282
|
-
import
|
|
9776
|
+
import path20 from "node:path";
|
|
9283
9777
|
var EXT_MIME = {
|
|
9284
9778
|
".txt": "text/plain",
|
|
9285
9779
|
".log": "text/plain",
|
|
@@ -9344,7 +9838,7 @@ function sniffMime(head) {
|
|
|
9344
9838
|
return null;
|
|
9345
9839
|
}
|
|
9346
9840
|
function extMime(realPath) {
|
|
9347
|
-
const ext =
|
|
9841
|
+
const ext = path20.extname(realPath).toLowerCase();
|
|
9348
9842
|
if (!ext) return null;
|
|
9349
9843
|
return EXT_MIME[ext] ?? null;
|
|
9350
9844
|
}
|
|
@@ -9414,7 +9908,7 @@ async function readDiskFile(realPath, opts) {
|
|
|
9414
9908
|
}
|
|
9415
9909
|
async function writeDiskFile(realPath, bytes) {
|
|
9416
9910
|
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
|
|
9417
|
-
await fs9.mkdir(
|
|
9911
|
+
await fs9.mkdir(path20.dirname(realPath), { recursive: true });
|
|
9418
9912
|
await fs9.writeFile(realPath, buf);
|
|
9419
9913
|
}
|
|
9420
9914
|
async function readDiskDir(realPath) {
|
|
@@ -9556,28 +10050,28 @@ async function handleDifileRequest(ctx, req) {
|
|
|
9556
10050
|
|
|
9557
10051
|
// src/main/services/simulator-temp-files/fs-channels.ts
|
|
9558
10052
|
import fs10 from "node:fs/promises";
|
|
9559
|
-
import
|
|
10053
|
+
import path21 from "node:path";
|
|
9560
10054
|
async function enforceSandbox(realPath) {
|
|
9561
10055
|
if (typeof realPath !== "string" || realPath.length === 0) {
|
|
9562
10056
|
throw new Error("sandbox: realPath must be a non-empty string");
|
|
9563
10057
|
}
|
|
9564
10058
|
const base = sandboxBase();
|
|
9565
10059
|
const baseReal = await fs10.realpath(base).catch(() => base);
|
|
9566
|
-
const normalized =
|
|
9567
|
-
if (normalized !== base && !normalized.startsWith(base +
|
|
10060
|
+
const normalized = path21.normalize(realPath);
|
|
10061
|
+
if (normalized !== base && !normalized.startsWith(base + path21.sep)) {
|
|
9568
10062
|
throw new Error("sandbox: realPath escapes the user-data base");
|
|
9569
10063
|
}
|
|
9570
10064
|
let probe = normalized;
|
|
9571
|
-
while (probe !==
|
|
10065
|
+
while (probe !== path21.parse(probe).root) {
|
|
9572
10066
|
try {
|
|
9573
10067
|
const resolved = await fs10.realpath(probe);
|
|
9574
|
-
if (resolved !== baseReal && !resolved.startsWith(baseReal +
|
|
10068
|
+
if (resolved !== baseReal && !resolved.startsWith(baseReal + path21.sep)) {
|
|
9575
10069
|
throw new Error("sandbox: realPath escapes the user-data base via symlink");
|
|
9576
10070
|
}
|
|
9577
10071
|
break;
|
|
9578
10072
|
} catch (err) {
|
|
9579
10073
|
if (err.code === "ENOENT") {
|
|
9580
|
-
probe =
|
|
10074
|
+
probe = path21.dirname(probe);
|
|
9581
10075
|
continue;
|
|
9582
10076
|
}
|
|
9583
10077
|
throw err;
|
|
@@ -9633,10 +10127,10 @@ function setupSimulatorTempFiles(simSession) {
|
|
|
9633
10127
|
const store = /* @__PURE__ */ new Map();
|
|
9634
10128
|
const pendingWaiters = /* @__PURE__ */ new Map();
|
|
9635
10129
|
let disposed = false;
|
|
9636
|
-
function drainWaiters(
|
|
9637
|
-
const list = pendingWaiters.get(
|
|
10130
|
+
function drainWaiters(path24) {
|
|
10131
|
+
const list = pendingWaiters.get(path24);
|
|
9638
10132
|
if (!list) return;
|
|
9639
|
-
pendingWaiters.delete(
|
|
10133
|
+
pendingWaiters.delete(path24);
|
|
9640
10134
|
for (const fn of list) fn();
|
|
9641
10135
|
}
|
|
9642
10136
|
function drainAllWaiters() {
|
|
@@ -9649,15 +10143,15 @@ function setupSimulatorTempFiles(simSession) {
|
|
|
9649
10143
|
const registry = new IpcRegistry(simulatorOnlyPolicy);
|
|
9650
10144
|
registry.on("simulator:temp-file:write", (_event, payload) => {
|
|
9651
10145
|
if (disposed) return;
|
|
9652
|
-
const { path:
|
|
9653
|
-
registerTempFile(store,
|
|
10146
|
+
const { path: path24, mime, bytes } = payload;
|
|
10147
|
+
registerTempFile(store, path24, mime, bytes);
|
|
9654
10148
|
enforceStoreCap(store);
|
|
9655
|
-
drainWaiters(
|
|
10149
|
+
drainWaiters(path24);
|
|
9656
10150
|
});
|
|
9657
10151
|
registry.on("simulator:temp-file:revoke", (_event, payload) => {
|
|
9658
10152
|
if (disposed) return;
|
|
9659
|
-
const { path:
|
|
9660
|
-
revokeTempFile(store,
|
|
10153
|
+
const { path: path24 } = payload;
|
|
10154
|
+
revokeTempFile(store, path24);
|
|
9661
10155
|
});
|
|
9662
10156
|
registry.on("simulator:temp-file:revoke-all", () => {
|
|
9663
10157
|
if (disposed) return;
|
|
@@ -9795,7 +10289,7 @@ function setupSimulatorSessionPolicy() {
|
|
|
9795
10289
|
import http2 from "node:http";
|
|
9796
10290
|
import nodeFs2 from "node:fs";
|
|
9797
10291
|
import fs11 from "node:fs/promises";
|
|
9798
|
-
import
|
|
10292
|
+
import path22 from "node:path";
|
|
9799
10293
|
var MAX_FS_WRITE_BYTES = 32 * 1024 * 1024;
|
|
9800
10294
|
var MIME = {
|
|
9801
10295
|
".html": "text/html; charset=utf-8",
|
|
@@ -9819,8 +10313,8 @@ function setIsolationHeaders(res) {
|
|
|
9819
10313
|
}
|
|
9820
10314
|
function containedStaticPath(root, pathname) {
|
|
9821
10315
|
const rel = pathname.replace(/^\/+/, "") || "index.html";
|
|
9822
|
-
const resolved =
|
|
9823
|
-
if (resolved !== root && !resolved.startsWith(root +
|
|
10316
|
+
const resolved = path22.resolve(root, rel);
|
|
10317
|
+
if (resolved !== root && !resolved.startsWith(root + path22.sep)) return null;
|
|
9824
10318
|
return resolved;
|
|
9825
10319
|
}
|
|
9826
10320
|
function serveStaticFile(res, root, pathname) {
|
|
@@ -9831,7 +10325,7 @@ function serveStaticFile(res, root, pathname) {
|
|
|
9831
10325
|
return;
|
|
9832
10326
|
}
|
|
9833
10327
|
Promise.all([fs11.realpath(root), fs11.realpath(candidate)]).then(([realRoot, realFile]) => {
|
|
9834
|
-
if (realFile !== realRoot && !realFile.startsWith(realRoot +
|
|
10328
|
+
if (realFile !== realRoot && !realFile.startsWith(realRoot + path22.sep)) {
|
|
9835
10329
|
res.writeHead(403);
|
|
9836
10330
|
res.end("Forbidden");
|
|
9837
10331
|
return;
|
|
@@ -9843,7 +10337,7 @@ function serveStaticFile(res, root, pathname) {
|
|
|
9843
10337
|
return;
|
|
9844
10338
|
}
|
|
9845
10339
|
res.writeHead(200, {
|
|
9846
|
-
"Content-Type": MIME[
|
|
10340
|
+
"Content-Type": MIME[path22.extname(realFile)] ?? "application/octet-stream",
|
|
9847
10341
|
"Content-Length": stat.size,
|
|
9848
10342
|
"Cache-Control": "no-store"
|
|
9849
10343
|
});
|
|
@@ -9985,7 +10479,7 @@ async function listFilesRecursive(dir, base = "") {
|
|
|
9985
10479
|
for (const e of entries) {
|
|
9986
10480
|
const rel = base ? `${base}/${e.name}` : e.name;
|
|
9987
10481
|
if (e.isDirectory()) {
|
|
9988
|
-
out.push(...await listFilesRecursive(
|
|
10482
|
+
out.push(...await listFilesRecursive(path22.join(dir, e.name), rel));
|
|
9989
10483
|
} else if (e.isFile()) {
|
|
9990
10484
|
out.push(rel);
|
|
9991
10485
|
}
|
|
@@ -10002,9 +10496,9 @@ async function readContributedExtensions(extensionsDir) {
|
|
|
10002
10496
|
}
|
|
10003
10497
|
for (const e of entries) {
|
|
10004
10498
|
if (!e.isDirectory()) continue;
|
|
10005
|
-
const extDir =
|
|
10499
|
+
const extDir = path22.join(extensionsDir, e.name);
|
|
10006
10500
|
try {
|
|
10007
|
-
const pkgRaw = await fs11.readFile(
|
|
10501
|
+
const pkgRaw = await fs11.readFile(path22.join(extDir, "package.json"), "utf8");
|
|
10008
10502
|
const files = await listFilesRecursive(extDir);
|
|
10009
10503
|
out.push({ dir: e.name, packageJson: JSON.parse(pkgRaw), files });
|
|
10010
10504
|
} catch {
|
|
@@ -10013,8 +10507,8 @@ async function readContributedExtensions(extensionsDir) {
|
|
|
10013
10507
|
return out;
|
|
10014
10508
|
}
|
|
10015
10509
|
async function startWorkbenchCoiServer(options) {
|
|
10016
|
-
const root =
|
|
10017
|
-
const contribRoot = options.extensionsDir ?
|
|
10510
|
+
const root = path22.resolve(options.rootDir);
|
|
10511
|
+
const contribRoot = options.extensionsDir ? path22.resolve(options.extensionsDir) : null;
|
|
10018
10512
|
const server = http2.createServer((req, res) => {
|
|
10019
10513
|
setIsolationHeaders(res);
|
|
10020
10514
|
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
@@ -10232,7 +10726,7 @@ async function disposeContext(ctx) {
|
|
|
10232
10726
|
function createConfiguredMainWindow(config, rendererDir2) {
|
|
10233
10727
|
const mainWindow = createMainWindow({
|
|
10234
10728
|
title: config.appName ?? "Dimina DevTools",
|
|
10235
|
-
indexHtml:
|
|
10729
|
+
indexHtml: path23.join(rendererDir2, "entries/main/index.html"),
|
|
10236
10730
|
width: config.window?.width,
|
|
10237
10731
|
height: config.window?.height,
|
|
10238
10732
|
minWidth: config.window?.minWidth,
|
|
@@ -10368,6 +10862,7 @@ function runDevtoolsBootstrap(config = {}) {
|
|
|
10368
10862
|
}
|
|
10369
10863
|
setupCdpPort();
|
|
10370
10864
|
suppressInsecureCspWarnings();
|
|
10865
|
+
if (!app15.isPackaged) installMaxListenersWarningDiagnostic();
|
|
10371
10866
|
registerDifileScheme();
|
|
10372
10867
|
try {
|
|
10373
10868
|
app15.commandLine.appendSwitch("enable-features", "SharedArrayBuffer");
|
|
@@ -10492,6 +10987,10 @@ async function createDevtoolsRuntime(config = {}) {
|
|
|
10492
10987
|
context.registry.add(() => {
|
|
10493
10988
|
context.storageApi = void 0;
|
|
10494
10989
|
});
|
|
10990
|
+
context.onServiceStorageChanged = storage.onSyncStorageChange;
|
|
10991
|
+
context.registry.add(() => {
|
|
10992
|
+
context.onServiceStorageChanged = void 0;
|
|
10993
|
+
});
|
|
10495
10994
|
}
|
|
10496
10995
|
if (context.bridge?.isNativeHost()) {
|
|
10497
10996
|
const networkForward = createNetworkForwarder({
|
|
@@ -10522,8 +11021,8 @@ async function createDevtoolsRuntime(config = {}) {
|
|
|
10522
11021
|
bridge: context.bridge
|
|
10523
11022
|
}));
|
|
10524
11023
|
}
|
|
10525
|
-
const bundleDir = config.editorViewConfig?.bundleDir ??
|
|
10526
|
-
if (!fs12.existsSync(
|
|
11024
|
+
const bundleDir = config.editorViewConfig?.bundleDir ?? path23.join(devtoolsPackageRoot, "dist/vscode-workbench");
|
|
11025
|
+
if (!fs12.existsSync(path23.join(bundleDir, "index.html"))) {
|
|
10527
11026
|
console.warn(
|
|
10528
11027
|
`[workbench] editor bundle not found at ${bundleDir} \u2014 skipping embedded editor assembly`
|
|
10529
11028
|
);
|