@dimina-kit/devtools 0.4.0-dev.20260618090552 → 0.4.0-dev.20260624084417
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/README.md +5 -1
- package/dist/main/app/app.js +14 -2
- package/dist/main/index.bundle.js +596 -112
- package/dist/main/ipc/bridge-router.js +13 -8
- package/dist/main/ipc/projects.js +1 -1
- package/dist/main/ipc/simulator.js +1 -1
- package/dist/main/runtime/miniapp-runtime.d.ts +3 -3
- package/dist/main/services/elements-forward/index.js +42 -8
- package/dist/main/services/network-forward/index.d.ts +5 -6
- package/dist/main/services/network-forward/index.js +9 -10
- package/dist/main/services/notifications/renderer-notifier.d.ts +3 -4
- package/dist/main/services/projects/index.js +1 -1
- package/dist/main/services/render-inspect/index.js +182 -6
- package/dist/main/services/service-console/console-api.d.ts +5 -6
- package/dist/main/services/service-console/console-api.js +5 -6
- package/dist/main/services/service-host-pool/pool.d.ts +2 -3
- package/dist/main/services/simulator-storage/index.d.ts +2 -4
- package/dist/main/services/simulator-storage/index.js +2 -4
- package/dist/main/services/simulator-temp-files/index.js +2 -2
- package/dist/main/services/views/devtools-tabs.d.ts +4 -1
- package/dist/main/services/views/devtools-tabs.js +21 -3
- package/dist/main/services/views/host-toolbar-session-runtime.d.ts +4 -4
- package/dist/main/services/views/host-toolbar-session-runtime.js +4 -4
- package/dist/main/services/views/view-manager.d.ts +17 -1
- package/dist/main/services/views/view-manager.js +74 -47
- package/dist/main/services/workspace/workspace-service.js +11 -0
- package/dist/main/windows/service-host-window/create.d.ts +1 -0
- package/dist/main/windows/service-host-window/create.js +1 -0
- package/dist/preload/instrumentation/wxml-extract.js +53 -7
- package/dist/preload/runtime/host-toolbar-port.d.ts +1 -1
- package/dist/preload/runtime/host-toolbar-port.js +1 -1
- package/dist/preload/runtime/host-toolbar-runtime.d.ts +8 -7
- package/dist/preload/runtime/host-toolbar-runtime.js +8 -7
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs +1 -1
- package/dist/preload/windows/simulator.cjs.map +1 -1
- package/dist/preload/windows/simulator.js +1 -1
- package/dist/render-host/render-inspect.js +24 -23
- package/dist/renderer/assets/index-BMqriQNr.js +50 -0
- package/dist/renderer/entries/main/index.html +1 -1
- package/dist/shared/appdata-accumulator.d.ts +2 -2
- package/dist/shared/appdata-accumulator.js +3 -3
- package/dist/shared/constants.d.ts +1 -1
- package/dist/shared/constants.js +1 -1
- package/dist/shared/ipc-channels.d.ts +3 -3
- package/dist/shared/ipc-channels.js +3 -3
- package/dist/shared/open-in-editor.d.ts +27 -1
- package/dist/shared/open-in-editor.js +369 -3
- package/dist/shared/vpath.d.ts +2 -2
- package/dist/shared/vpath.js +2 -2
- package/dist/simulator/assets/device-shell-CPCnCp1L.js +2 -0
- package/dist/simulator/assets/{simulator-sf-D0mhw.js → simulator-gMBWKDeO.js} +3 -3
- package/dist/simulator/simulator.html +1 -1
- package/package.json +6 -4
- package/dist/renderer/assets/index-DmgWoK8N.js +0 -50
- package/dist/simulator/assets/device-shell-BWX7Yopg.js +0 -2
|
@@ -410,11 +410,11 @@ var ProjectsChannel = {
|
|
|
410
410
|
List: "projects:list",
|
|
411
411
|
Add: "projects:add",
|
|
412
412
|
Remove: "projects:remove",
|
|
413
|
-
/**
|
|
413
|
+
/** Merged + sanitized template catalog for the create-project dialog. */
|
|
414
414
|
ListTemplates: "projects:listTemplates",
|
|
415
|
-
/**
|
|
415
|
+
/** Host-supplied create-project dialog hook (returns input or null). */
|
|
416
416
|
OpenCreateDialog: "projects:openCreateDialog",
|
|
417
|
-
/**
|
|
417
|
+
/** Server-side scaffold + register (delegates to create-project-service). */
|
|
418
418
|
Create: "projects:create",
|
|
419
419
|
/** Default values used to pre-fill the create-project dialog (baseDir). */
|
|
420
420
|
GetCreateDefaults: "projects:getCreateDefaults"
|
|
@@ -762,7 +762,7 @@ function registerProjectFsIpc(ctx) {
|
|
|
762
762
|
|
|
763
763
|
// src/main/app/app.ts
|
|
764
764
|
import { app as app15, BrowserWindow as BrowserWindow8, nativeImage, session as session4 } from "electron";
|
|
765
|
-
import
|
|
765
|
+
import fs11 from "fs";
|
|
766
766
|
import path21 from "path";
|
|
767
767
|
|
|
768
768
|
// src/main/utils/paths.ts
|
|
@@ -1052,6 +1052,7 @@ function createRendererNotifier(ctx) {
|
|
|
1052
1052
|
|
|
1053
1053
|
// src/main/services/views/view-manager.ts
|
|
1054
1054
|
import { ipcMain as ipcMain2, nativeTheme as nativeTheme3, shell as shell2, WebContentsView as WebContentsView2, webContents } from "electron";
|
|
1055
|
+
import fs4 from "node:fs";
|
|
1055
1056
|
import path7 from "path";
|
|
1056
1057
|
|
|
1057
1058
|
// src/shared/open-in-editor.ts
|
|
@@ -1078,8 +1079,11 @@ function decodeOpenInEditorUrl(raw) {
|
|
|
1078
1079
|
}
|
|
1079
1080
|
return out;
|
|
1080
1081
|
}
|
|
1081
|
-
function resourceUrlToProjectRelativePath(resourceUrl,
|
|
1082
|
+
function resourceUrlToProjectRelativePath(resourceUrl, expectedOriginOrContext) {
|
|
1082
1083
|
if (typeof resourceUrl !== "string" || !resourceUrl) return null;
|
|
1084
|
+
if (expectedOriginOrContext && typeof expectedOriginOrContext === "object") {
|
|
1085
|
+
return projectAwareResourcePath(resourceUrl, expectedOriginOrContext);
|
|
1086
|
+
}
|
|
1083
1087
|
let resource;
|
|
1084
1088
|
try {
|
|
1085
1089
|
resource = new URL(resourceUrl);
|
|
@@ -1087,10 +1091,10 @@ function resourceUrlToProjectRelativePath(resourceUrl, expectedOrigin) {
|
|
|
1087
1091
|
return null;
|
|
1088
1092
|
}
|
|
1089
1093
|
if (resource.protocol !== "http:" && resource.protocol !== "https:") return null;
|
|
1090
|
-
if (
|
|
1094
|
+
if (expectedOriginOrContext) {
|
|
1091
1095
|
let base;
|
|
1092
1096
|
try {
|
|
1093
|
-
base = new URL(
|
|
1097
|
+
base = new URL(expectedOriginOrContext);
|
|
1094
1098
|
} catch {
|
|
1095
1099
|
return null;
|
|
1096
1100
|
}
|
|
@@ -1106,6 +1110,322 @@ function resourceUrlToProjectRelativePath(resourceUrl, expectedOrigin) {
|
|
|
1106
1110
|
if (segments.length < 2) return null;
|
|
1107
1111
|
return segments.slice(1).join("/");
|
|
1108
1112
|
}
|
|
1113
|
+
function decodePathname(pathname) {
|
|
1114
|
+
return pathname.split("/").map((segment) => {
|
|
1115
|
+
try {
|
|
1116
|
+
return decodeURIComponent(segment);
|
|
1117
|
+
} catch {
|
|
1118
|
+
return segment;
|
|
1119
|
+
}
|
|
1120
|
+
}).join("/");
|
|
1121
|
+
}
|
|
1122
|
+
function normalizeSlashPath(value) {
|
|
1123
|
+
return decodePathname(value.replace(/\\/g, "/")).replace(/\/+/g, "/");
|
|
1124
|
+
}
|
|
1125
|
+
function safeRelativePath(segments) {
|
|
1126
|
+
if (segments.length === 0 || segments.some((segment) => !segment || segment === "." || segment === "..")) {
|
|
1127
|
+
return null;
|
|
1128
|
+
}
|
|
1129
|
+
return segments.join("/");
|
|
1130
|
+
}
|
|
1131
|
+
function projectAwareResourcePath(resourceUrl, context) {
|
|
1132
|
+
let base;
|
|
1133
|
+
try {
|
|
1134
|
+
base = new URL(context.resourceBaseUrl);
|
|
1135
|
+
} catch {
|
|
1136
|
+
return null;
|
|
1137
|
+
}
|
|
1138
|
+
const projectRoot = normalizeSlashPath(context.projectRoot).replace(/\/$/, "");
|
|
1139
|
+
const raw = resourceUrl.trim();
|
|
1140
|
+
if (!raw) return null;
|
|
1141
|
+
const excludeBuildChunk = (rel) => {
|
|
1142
|
+
if (!rel) return rel;
|
|
1143
|
+
const base2 = rel.split("/").pop();
|
|
1144
|
+
return base2 === "common.js" || base2 === "vendors.js" || base2 === "runtime.js" || base2 === "taro.js" || base2 === "babelHelpers.js" ? null : rel;
|
|
1145
|
+
};
|
|
1146
|
+
const normalizedRaw = normalizeSlashPath(raw);
|
|
1147
|
+
if (projectRoot && (normalizedRaw === projectRoot || normalizedRaw.startsWith(`${projectRoot}/`))) {
|
|
1148
|
+
const relative = normalizedRaw.slice(projectRoot.length).replace(/^\/+/, "");
|
|
1149
|
+
return excludeBuildChunk(safeRelativePath(relative.split("/").filter(Boolean)));
|
|
1150
|
+
}
|
|
1151
|
+
if (/^\/(?:Volumes|Users|home|private|tmp|var|opt|Applications)\//.test(normalizedRaw)) {
|
|
1152
|
+
return null;
|
|
1153
|
+
}
|
|
1154
|
+
if (!raw.startsWith("/") && !/^[a-z][a-z0-9+.-]*:/i.test(raw)) return null;
|
|
1155
|
+
let resource;
|
|
1156
|
+
try {
|
|
1157
|
+
resource = raw.startsWith("/") && !raw.startsWith("//") ? new URL(raw, base.origin) : new URL(raw);
|
|
1158
|
+
} catch {
|
|
1159
|
+
return null;
|
|
1160
|
+
}
|
|
1161
|
+
if (resource.protocol === "file:") {
|
|
1162
|
+
const filePath = normalizeSlashPath(resource.pathname);
|
|
1163
|
+
if (!projectRoot || filePath !== projectRoot && !filePath.startsWith(`${projectRoot}/`)) return null;
|
|
1164
|
+
return excludeBuildChunk(safeRelativePath(
|
|
1165
|
+
filePath.slice(projectRoot.length).replace(/^\/+/, "").split("/").filter(Boolean)
|
|
1166
|
+
));
|
|
1167
|
+
}
|
|
1168
|
+
if (resource.protocol !== "http:" && resource.protocol !== "https:") return null;
|
|
1169
|
+
if (resource.origin !== base.origin) return null;
|
|
1170
|
+
let segments = decodePathname(resource.pathname).split("/").filter(Boolean);
|
|
1171
|
+
if (context.appId && segments[0] === context.appId) {
|
|
1172
|
+
segments = segments.slice(1);
|
|
1173
|
+
if (context.outputRoot && segments[0] === context.outputRoot) segments = segments.slice(1);
|
|
1174
|
+
}
|
|
1175
|
+
return excludeBuildChunk(safeRelativePath(segments));
|
|
1176
|
+
}
|
|
1177
|
+
function projectSourceContextFromServiceHostUrl(serviceHostUrl, activeProjectRoot) {
|
|
1178
|
+
let url;
|
|
1179
|
+
try {
|
|
1180
|
+
url = new URL(serviceHostUrl);
|
|
1181
|
+
} catch {
|
|
1182
|
+
return null;
|
|
1183
|
+
}
|
|
1184
|
+
const projectRoot = url.searchParams.get("pkgRoot") || "";
|
|
1185
|
+
const resourceBaseUrl = url.searchParams.get("resourceBaseUrl") ?? "";
|
|
1186
|
+
const appId = url.searchParams.get("appId") ?? "";
|
|
1187
|
+
const outputRoot = url.searchParams.get("root") ?? "main";
|
|
1188
|
+
if (!projectRoot || !resourceBaseUrl || !appId) return null;
|
|
1189
|
+
if (activeProjectRoot) {
|
|
1190
|
+
const authoritativeRoot = normalizeSlashPath(projectRoot).replace(/\/+$/, "");
|
|
1191
|
+
const currentRoot = normalizeSlashPath(activeProjectRoot).replace(/\/+$/, "");
|
|
1192
|
+
if (!authoritativeRoot || authoritativeRoot !== currentRoot) return null;
|
|
1193
|
+
}
|
|
1194
|
+
try {
|
|
1195
|
+
new URL(resourceBaseUrl);
|
|
1196
|
+
} catch {
|
|
1197
|
+
return null;
|
|
1198
|
+
}
|
|
1199
|
+
return { projectRoot, resourceBaseUrl, appId, outputRoot };
|
|
1200
|
+
}
|
|
1201
|
+
function buildDevtoolsProjectSourceLinksScript(context) {
|
|
1202
|
+
const config = JSON.stringify(context);
|
|
1203
|
+
const scheme = JSON.stringify(OPEN_IN_EDITOR_SCHEME);
|
|
1204
|
+
return `
|
|
1205
|
+
(function() {
|
|
1206
|
+
try {
|
|
1207
|
+
const stateKey = '__diminaProjectSourceLinksState__'
|
|
1208
|
+
const previousState = globalThis[stateKey]
|
|
1209
|
+
if (previousState && typeof previousState.dispose === 'function') {
|
|
1210
|
+
try { previousState.dispose() } catch (_) {}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
const cfg = ${config}
|
|
1214
|
+
const diminaProjectSourcePath = ${projectAwareResourcePath.toString()}
|
|
1215
|
+
const decodePathname = ${decodePathname.toString()}
|
|
1216
|
+
const normalizeSlashPath = ${normalizeSlashPath.toString()}
|
|
1217
|
+
const safeRelativePath = ${safeRelativePath.toString()}
|
|
1218
|
+
const observedRoots = new Set()
|
|
1219
|
+
const observers = []
|
|
1220
|
+
const clickBindings = []
|
|
1221
|
+
let timer = null
|
|
1222
|
+
const state = {
|
|
1223
|
+
dispose() {
|
|
1224
|
+
if (timer !== null) {
|
|
1225
|
+
clearInterval(timer)
|
|
1226
|
+
timer = null
|
|
1227
|
+
}
|
|
1228
|
+
for (const observer of observers.splice(0)) {
|
|
1229
|
+
try { observer.disconnect() } catch (_) {}
|
|
1230
|
+
}
|
|
1231
|
+
for (const binding of clickBindings.splice(0)) {
|
|
1232
|
+
try { binding.target.removeEventListener('click', binding.fn, true) } catch (_) {}
|
|
1233
|
+
}
|
|
1234
|
+
observedRoots.clear()
|
|
1235
|
+
},
|
|
1236
|
+
}
|
|
1237
|
+
globalThis[stateKey] = state
|
|
1238
|
+
|
|
1239
|
+
// The InspectorFrontendHost that owns openInNewTab. Across DevTools
|
|
1240
|
+
// versions it lives on the top-level \`InspectorFrontendHost\` global, the
|
|
1241
|
+
// legacy \`Host.InspectorFrontendHost\`, or \`DevToolsHost\`; resolve at call
|
|
1242
|
+
// time so a late-bootstrapped host is still found.
|
|
1243
|
+
function resolveOpenInNewTabHost() {
|
|
1244
|
+
const candidates = [
|
|
1245
|
+
globalThis.InspectorFrontendHost,
|
|
1246
|
+
globalThis.Host && globalThis.Host.InspectorFrontendHost,
|
|
1247
|
+
globalThis.DevToolsHost,
|
|
1248
|
+
]
|
|
1249
|
+
for (const host of candidates) {
|
|
1250
|
+
if (host && typeof host.openInNewTab === 'function') return host
|
|
1251
|
+
}
|
|
1252
|
+
return null
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// Encode (url, 0-based line, 0-based column) as the sentinel the main
|
|
1256
|
+
// process decodes from \`devtools-open-url\` and routes to Monaco.
|
|
1257
|
+
function openInEditor(url, line, column) {
|
|
1258
|
+
const host = resolveOpenInNewTabHost()
|
|
1259
|
+
if (!host) return false
|
|
1260
|
+
const p = new URLSearchParams()
|
|
1261
|
+
p.set('u', String(url))
|
|
1262
|
+
if (typeof line === 'number' && isFinite(line)) p.set('l', String(line))
|
|
1263
|
+
if (typeof column === 'number' && isFinite(column)) p.set('c', String(column))
|
|
1264
|
+
try { host.openInNewTab(${scheme} + ':?' + p.toString()) } catch (_) { return false }
|
|
1265
|
+
return true
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// Resolve a clicked link element to a project source location. Returns
|
|
1269
|
+
// the FULL resource url (the main process re-maps it against the active
|
|
1270
|
+
// project) plus its display line/column when present.
|
|
1271
|
+
function projectLocationForLink(link) {
|
|
1272
|
+
if (!link) return null
|
|
1273
|
+
const candidates = [
|
|
1274
|
+
link.getAttribute && link.getAttribute('data-url'),
|
|
1275
|
+
link.getAttribute && link.getAttribute('href'),
|
|
1276
|
+
link.getAttribute && link.getAttribute('title'),
|
|
1277
|
+
]
|
|
1278
|
+
for (const candidate of candidates) {
|
|
1279
|
+
if (!candidate) continue
|
|
1280
|
+
const location = splitLocation(candidate)
|
|
1281
|
+
if (!diminaProjectSourcePath(location.url, cfg)) continue
|
|
1282
|
+
const suffix = location.suffix
|
|
1283
|
+
|| ((String(link.textContent || '').match(/(:\\d+(?::\\d+)?)$/) || [])[1] || '')
|
|
1284
|
+
return { url: location.url, suffix }
|
|
1285
|
+
}
|
|
1286
|
+
return null
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// DevTools shows 1-based line:column in link text; the main process
|
|
1290
|
+
// contract expects 0-based (it re-adds 1). Convert here.
|
|
1291
|
+
function parseSuffix(suffix) {
|
|
1292
|
+
const m = String(suffix || '').match(/^:(\\d+)(?::(\\d+))?$/)
|
|
1293
|
+
if (!m) return { line: undefined, column: undefined }
|
|
1294
|
+
const line = Math.max(0, parseInt(m[1], 10) - 1)
|
|
1295
|
+
const column = m[2] != null ? Math.max(0, parseInt(m[2], 10) - 1) : undefined
|
|
1296
|
+
return { line, column }
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Capture-phase click handler: route a project-source link click to
|
|
1300
|
+
// Monaco instead of the DevTools Sources panel. Plain primary clicks only
|
|
1301
|
+
// \u2014 modified clicks (cmd/ctrl/shift/alt, middle button) fall through to
|
|
1302
|
+
// DevTools so its own "open in new tab" / multi-select still work.
|
|
1303
|
+
function onLinkClick(event) {
|
|
1304
|
+
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return
|
|
1305
|
+
const path = typeof event.composedPath === 'function' ? event.composedPath() : []
|
|
1306
|
+
let link = null
|
|
1307
|
+
for (const node of path) {
|
|
1308
|
+
if (node && node.nodeType === 1 && node.classList && node.classList.contains('devtools-link')) {
|
|
1309
|
+
link = node
|
|
1310
|
+
break
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
if (!link) return
|
|
1314
|
+
const location = projectLocationForLink(link)
|
|
1315
|
+
if (!location) return
|
|
1316
|
+
const { line, column } = parseSuffix(location.suffix)
|
|
1317
|
+
if (!openInEditor(location.url, line, column)) return
|
|
1318
|
+
event.preventDefault()
|
|
1319
|
+
event.stopImmediatePropagation()
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
function bindClicks(target) {
|
|
1323
|
+
if (!target || !target.addEventListener) return
|
|
1324
|
+
for (const binding of clickBindings) {
|
|
1325
|
+
if (binding.target === target) return
|
|
1326
|
+
}
|
|
1327
|
+
target.addEventListener('click', onLinkClick, true)
|
|
1328
|
+
clickBindings.push({ target, fn: onLinkClick })
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
function splitLocation(value) {
|
|
1332
|
+
const raw = String(value || '')
|
|
1333
|
+
const match = raw.match(/^(.*?)(?::(\\d+))(?::(\\d+))?$/)
|
|
1334
|
+
return match
|
|
1335
|
+
? { url: match[1], suffix: ':' + match[2] + (match[3] ? ':' + match[3] : '') }
|
|
1336
|
+
: { url: raw, suffix: '' }
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
function rewriteLink(link) {
|
|
1340
|
+
if (!link || link.dataset.diminaProjectSourcePath) return
|
|
1341
|
+
const candidates = [
|
|
1342
|
+
link.getAttribute && link.getAttribute('title'),
|
|
1343
|
+
link.getAttribute && link.getAttribute('href'),
|
|
1344
|
+
link.getAttribute && link.getAttribute('data-url'),
|
|
1345
|
+
]
|
|
1346
|
+
for (const candidate of candidates) {
|
|
1347
|
+
if (!candidate) continue
|
|
1348
|
+
const location = splitLocation(candidate)
|
|
1349
|
+
const relative = diminaProjectSourcePath(location.url, cfg)
|
|
1350
|
+
if (!relative) continue
|
|
1351
|
+
const textSuffix = location.suffix || ((String(link.textContent || '').match(/(:\\d+(?::\\d+)?)$/) || [])[1] || '')
|
|
1352
|
+
link.textContent = relative + textSuffix
|
|
1353
|
+
link.dataset.diminaProjectSourcePath = relative
|
|
1354
|
+
return
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
function observeRoot(root) {
|
|
1359
|
+
if (!root || !root.querySelectorAll || observedRoots.has(root)) return
|
|
1360
|
+
observedRoots.add(root)
|
|
1361
|
+
bindClicks(root)
|
|
1362
|
+
|
|
1363
|
+
const observer = new MutationObserver((records) => {
|
|
1364
|
+
for (const record of records) {
|
|
1365
|
+
if (record.type === 'attributes') rewriteLink(record.target)
|
|
1366
|
+
for (const node of record.addedNodes || []) visitNode(node)
|
|
1367
|
+
}
|
|
1368
|
+
})
|
|
1369
|
+
observer.observe(root, {
|
|
1370
|
+
subtree: true,
|
|
1371
|
+
childList: true,
|
|
1372
|
+
attributes: true,
|
|
1373
|
+
attributeFilter: ['title', 'href', 'data-url'],
|
|
1374
|
+
})
|
|
1375
|
+
observers.push(observer)
|
|
1376
|
+
|
|
1377
|
+
for (const link of root.querySelectorAll('.devtools-link')) rewriteLink(link)
|
|
1378
|
+
for (const element of root.querySelectorAll('*')) {
|
|
1379
|
+
if (element.shadowRoot) observeRoot(element.shadowRoot)
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
function visitNode(node) {
|
|
1384
|
+
if (!node) return
|
|
1385
|
+
if (node.matches && node.matches('.devtools-link')) rewriteLink(node)
|
|
1386
|
+
if (node.shadowRoot) observeRoot(node.shadowRoot)
|
|
1387
|
+
if (!node.querySelectorAll) return
|
|
1388
|
+
for (const link of node.querySelectorAll('.devtools-link')) rewriteLink(link)
|
|
1389
|
+
for (const element of node.querySelectorAll('*')) {
|
|
1390
|
+
if (element.shadowRoot) observeRoot(element.shadowRoot)
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
observeRoot(document)
|
|
1395
|
+
|
|
1396
|
+
// Fallback for older DevTools fronts that still expose the
|
|
1397
|
+
// setOpenResourceHandler hook. On current Chromium the method is gone,
|
|
1398
|
+
// so this poll simply times out and the capture-phase click interceptor
|
|
1399
|
+
// is the only live path. When the hook IS present the interceptor still
|
|
1400
|
+
// wins (it runs in capture and stops propagation), so the two never
|
|
1401
|
+
// double-open the same click.
|
|
1402
|
+
let tries = 0
|
|
1403
|
+
timer = setInterval(() => {
|
|
1404
|
+
tries++
|
|
1405
|
+
try {
|
|
1406
|
+
const host = resolveOpenInNewTabHost()
|
|
1407
|
+
if (host && typeof host.setOpenResourceHandler === 'function') {
|
|
1408
|
+
host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
|
|
1409
|
+
if (!diminaProjectSourcePath(String(url), cfg)) return
|
|
1410
|
+
openInEditor(
|
|
1411
|
+
String(url),
|
|
1412
|
+
typeof lineNumber === 'number' ? lineNumber : undefined,
|
|
1413
|
+
typeof columnNumber === 'number' ? columnNumber : undefined,
|
|
1414
|
+
)
|
|
1415
|
+
})
|
|
1416
|
+
clearInterval(timer)
|
|
1417
|
+
timer = null
|
|
1418
|
+
}
|
|
1419
|
+
} catch (_) {}
|
|
1420
|
+
if (tries > 80 && timer !== null) {
|
|
1421
|
+
clearInterval(timer)
|
|
1422
|
+
timer = null
|
|
1423
|
+
}
|
|
1424
|
+
}, 50)
|
|
1425
|
+
} catch (_) {}
|
|
1426
|
+
})()
|
|
1427
|
+
`;
|
|
1428
|
+
}
|
|
1109
1429
|
|
|
1110
1430
|
// src/main/services/safe-area/index.ts
|
|
1111
1431
|
function guestInsets(device, isTabPage2) {
|
|
@@ -1157,19 +1477,25 @@ function createSafeAreaController(options = {}) {
|
|
|
1157
1477
|
}
|
|
1158
1478
|
|
|
1159
1479
|
// src/main/services/views/devtools-tabs.ts
|
|
1160
|
-
var DEVTOOLS_KEPT_VIEW_IDS = ["elements", "console", "network"];
|
|
1480
|
+
var DEVTOOLS_KEPT_VIEW_IDS = ["elements", "console", "network", "sources"];
|
|
1161
1481
|
function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
|
|
1162
1482
|
const NAME_MAP = {
|
|
1163
1483
|
elements: ["Elements", "\u5143\u7D20"],
|
|
1164
1484
|
console: ["Console", "\u63A7\u5236\u53F0"],
|
|
1165
|
-
network: ["Network", "\u7F51\u7EDC"]
|
|
1485
|
+
network: ["Network", "\u7F51\u7EDC"],
|
|
1486
|
+
sources: ["Sources", "\u6765\u6E90", "\u6E90\u4EE3\u7801"]
|
|
1166
1487
|
};
|
|
1167
1488
|
const keepNames = keptIds.flatMap((id) => NAME_MAP[id] ?? [id]);
|
|
1168
1489
|
const keepIdsJson = JSON.stringify(JSON.stringify([...keptIds]));
|
|
1169
1490
|
const keepNamesJson = JSON.stringify(JSON.stringify(keepNames));
|
|
1491
|
+
const srcNamesJson = JSON.stringify(JSON.stringify(NAME_MAP.sources));
|
|
1492
|
+
const netNamesJson = JSON.stringify(JSON.stringify(NAME_MAP.network));
|
|
1170
1493
|
return `(function(){try{
|
|
1171
1494
|
var KEEPID = new Set(JSON.parse(${keepIdsJson}));
|
|
1172
1495
|
var KEEPNAME = new Set(JSON.parse(${keepNamesJson}));
|
|
1496
|
+
var SRCNAME = new Set(JSON.parse(${srcNamesJson}));
|
|
1497
|
+
var NETNAME = new Set(JSON.parse(${netNamesJson}));
|
|
1498
|
+
var WANT_SOURCES_LAST = KEEPID.has('sources');
|
|
1173
1499
|
// (1) Locale infobar \u2014 official host-preference suppression (NOT localStorage).
|
|
1174
1500
|
try { var IFH=globalThis.InspectorFrontendHost; if(IFH&&typeof IFH.setPreference==='function'){ IFH.setPreference('disable-locale-info-bar','true'); } }catch(_){}
|
|
1175
1501
|
function deepCollect(sel,cap){ var out=[],seen=0,stack=[document]; while(stack.length&&seen<(cap||40000)){ var root=stack.pop(); try{var m=root.querySelectorAll?root.querySelectorAll(sel):[];for(var i=0;i<m.length;i++)out.push(m[i]);}catch(_){} try{var all=root.querySelectorAll?root.querySelectorAll('*'):[];for(var j=0;j<all.length;j++){seen++;if(all[j].shadowRoot)stack.push(all[j].shadowRoot);}}catch(_){} } return out; }
|
|
@@ -1197,9 +1523,18 @@ function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
|
|
|
1197
1523
|
handled=true;
|
|
1198
1524
|
}catch(_){} }
|
|
1199
1525
|
// fallback: registrations not enumerable -> at least clear the bar by id
|
|
1200
|
-
if(!handled){ var FALL=['timeline','resources','heap-profiler','
|
|
1526
|
+
if(!handled){ var FALL=['timeline','resources','heap-profiler','security','lighthouse','chrome-recorder','coverage','linear-memory-inspector','sensors','rendering','animations','autofill-view','medias','issues-pane']; for(var fr=0;fr<FALL.length;fr++){ try{ if(!KEEPID.has(FALL[fr])) maybeRemove(FALL[fr]); }catch(_){} } }
|
|
1201
1527
|
} else { domFallback(); }
|
|
1202
1528
|
})();
|
|
1529
|
+
// Keep Sources LAST in the bar (after Network). Default DevTools order puts
|
|
1530
|
+
// Sources between Console and Network; nudge it to just after Network. Runs in
|
|
1531
|
+
// BOTH paths (registry removal leaves the kept tabs in default order). Self-
|
|
1532
|
+
// stable: once Sources follows Network the condition no longer holds.
|
|
1533
|
+
if(WANT_SOURCES_LAST){ var ro=0,rt=setInterval(function(){ ro++; try{
|
|
1534
|
+
var tabs=deepCollect('[role="tab"]'),src=null,net=null;
|
|
1535
|
+
for(var i=0;i<tabs.length;i++){ var n=txt(tabs[i]); if(SRCNAME.has(n))src=tabs[i]; else if(NETNAME.has(n))net=tabs[i]; }
|
|
1536
|
+
if(src&&net&&src.parentElement&&src.parentElement===net.parentElement&&(src.compareDocumentPosition(net)&Node.DOCUMENT_POSITION_FOLLOWING)){ net.parentElement.insertBefore(src,net.nextSibling); }
|
|
1537
|
+
}catch(_){} if(ro>120)clearInterval(rt); },60); }
|
|
1203
1538
|
// DOM fallback: only if the ESM module couldn't be resolved at all.
|
|
1204
1539
|
function domFallback(){ var cachedBar=null;
|
|
1205
1540
|
function findBar(){ if(cachedBar&&cachedBar.isConnected)return cachedBar; cachedBar=null; var tabs=deepCollect('[role="tab"]'); var a=null; for(var i=0;i<tabs.length;i++){if(KEEPNAME.has(txt(tabs[i]))){a=tabs[i];break;}} if(!a)return null; var p=a.parentElement; while(p){try{if(p.querySelectorAll('[role="tab"]').length>1){cachedBar=p;return p;}}catch(_){} p=p.parentElement;} cachedBar=a.parentElement; return cachedBar; }
|
|
@@ -1454,10 +1789,19 @@ function installElementsForward(deps) {
|
|
|
1454
1789
|
function primeGuest(wc) {
|
|
1455
1790
|
if (!ensureGuestDebugger(wc)) return;
|
|
1456
1791
|
wireGuestEvents(wc);
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1792
|
+
void enableGuestDomains(wc);
|
|
1793
|
+
}
|
|
1794
|
+
async function enableGuestDomains(wc) {
|
|
1795
|
+
wc.debugger.sendCommand("CSS.enable").catch(() => {
|
|
1796
|
+
});
|
|
1797
|
+
try {
|
|
1798
|
+
await wc.debugger.sendCommand("DOM.enable");
|
|
1799
|
+
} catch {
|
|
1800
|
+
return;
|
|
1460
1801
|
}
|
|
1802
|
+
if (disposed || !isActiveWcId(wc.id)) return;
|
|
1803
|
+
wc.debugger.sendCommand("Overlay.enable").catch(() => {
|
|
1804
|
+
});
|
|
1461
1805
|
}
|
|
1462
1806
|
function routeCommand(cmd) {
|
|
1463
1807
|
const wc = activeRenderWc();
|
|
@@ -1477,6 +1821,10 @@ function installElementsForward(deps) {
|
|
|
1477
1821
|
replyError(cmd, "stale render generation");
|
|
1478
1822
|
return;
|
|
1479
1823
|
}
|
|
1824
|
+
if (cmd.method === "Overlay.disable" && isActiveWcId(cmdWcId)) {
|
|
1825
|
+
wc.debugger.sendCommand("Overlay.enable").catch(() => {
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1480
1828
|
replyResult(cmd, result);
|
|
1481
1829
|
}).catch((err) => {
|
|
1482
1830
|
if (disposed) return;
|
|
@@ -2022,12 +2370,36 @@ function parseRoute(url) {
|
|
|
2022
2370
|
}
|
|
2023
2371
|
|
|
2024
2372
|
// src/main/services/views/view-manager.ts
|
|
2373
|
+
function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFile = (absolutePath) => fs4.statSync(absolutePath).isFile()) {
|
|
2374
|
+
const sourceContext = projectSourceContextFromServiceHostUrl(
|
|
2375
|
+
serviceHostUrl,
|
|
2376
|
+
activeProjectRoot
|
|
2377
|
+
);
|
|
2378
|
+
if (!sourceContext) return null;
|
|
2379
|
+
const rel = resourceUrlToProjectRelativePath(req.url, sourceContext);
|
|
2380
|
+
if (!rel) return null;
|
|
2381
|
+
const absolute = path7.resolve(sourceContext.projectRoot, ...rel.split("/"));
|
|
2382
|
+
const fromRoot = path7.relative(path7.resolve(sourceContext.projectRoot), absolute);
|
|
2383
|
+
if (!fromRoot || fromRoot.startsWith("..") || path7.isAbsolute(fromRoot)) return null;
|
|
2384
|
+
try {
|
|
2385
|
+
if (!isFile(absolute)) return null;
|
|
2386
|
+
} catch {
|
|
2387
|
+
return null;
|
|
2388
|
+
}
|
|
2389
|
+
return {
|
|
2390
|
+
path: rel,
|
|
2391
|
+
line: typeof req.line === "number" ? req.line + 1 : void 0,
|
|
2392
|
+
column: typeof req.column === "number" ? req.column + 1 : void 0
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2025
2395
|
function createViewManager(ctx) {
|
|
2026
2396
|
const safeArea = createSafeAreaController({ connections: ctx.connections });
|
|
2027
2397
|
let simulatorView = null;
|
|
2028
2398
|
let simulatorViewAdded = false;
|
|
2029
2399
|
let nativeSimulatorView = null;
|
|
2030
2400
|
let nativeSimulatorViewAdded = false;
|
|
2401
|
+
let nativeSimulatorProjectPath = null;
|
|
2402
|
+
let settleNativeSimulatorReady = null;
|
|
2031
2403
|
let lastRendererRect = null;
|
|
2032
2404
|
let nativeCustomApiBridgeHandler = null;
|
|
2033
2405
|
let currentZoomFactor = 1;
|
|
@@ -2260,37 +2632,13 @@ function createViewManager(ctx) {
|
|
|
2260
2632
|
closeNativeDevtoolsSource();
|
|
2261
2633
|
}
|
|
2262
2634
|
const openInEditorWiredWcIds = /* @__PURE__ */ new Set();
|
|
2263
|
-
function injectOpenResourceHandler(devtoolsWc) {
|
|
2264
|
-
const
|
|
2265
|
-
|
|
2266
|
-
(
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
tries++
|
|
2271
|
-
try {
|
|
2272
|
-
const Host = globalThis.Host
|
|
2273
|
-
const host = Host && Host.InspectorFrontendHost
|
|
2274
|
-
if (host && typeof host.setOpenResourceHandler === 'function'
|
|
2275
|
-
&& typeof host.openInNewTab === 'function') {
|
|
2276
|
-
host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
|
|
2277
|
-
try {
|
|
2278
|
-
const p = new URLSearchParams()
|
|
2279
|
-
p.set('u', String(url))
|
|
2280
|
-
if (typeof lineNumber === 'number') p.set('l', String(lineNumber))
|
|
2281
|
-
if (typeof columnNumber === 'number') p.set('c', String(columnNumber))
|
|
2282
|
-
host.openInNewTab(${scheme} + ':?' + p.toString())
|
|
2283
|
-
} catch (_) {}
|
|
2284
|
-
})
|
|
2285
|
-
clearInterval(timer)
|
|
2286
|
-
return
|
|
2287
|
-
}
|
|
2288
|
-
} catch (_) {}
|
|
2289
|
-
if (tries > 80) clearInterval(timer)
|
|
2290
|
-
}, 50)
|
|
2291
|
-
} catch (_) {}
|
|
2292
|
-
})()
|
|
2293
|
-
`).catch(() => {
|
|
2635
|
+
function injectOpenResourceHandler(serviceWc, devtoolsWc) {
|
|
2636
|
+
const sourceContext = projectSourceContextFromServiceHostUrl(
|
|
2637
|
+
serviceWc.getURL(),
|
|
2638
|
+
ctx.workspace?.getProjectPath?.()
|
|
2639
|
+
);
|
|
2640
|
+
if (!sourceContext) return;
|
|
2641
|
+
devtoolsWc.executeJavaScript(buildDevtoolsProjectSourceLinksScript(sourceContext)).catch(() => {
|
|
2294
2642
|
});
|
|
2295
2643
|
}
|
|
2296
2644
|
function customizeDevtoolsTabs(devtoolsWc) {
|
|
@@ -2315,9 +2663,9 @@ function createViewManager(ctx) {
|
|
|
2315
2663
|
function wireOpenInEditor(serviceWc, devtoolsWc) {
|
|
2316
2664
|
if (!devtoolsWc.isDestroyed()) {
|
|
2317
2665
|
if (devtoolsWc.isLoading()) {
|
|
2318
|
-
devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(devtoolsWc));
|
|
2666
|
+
devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(serviceWc, devtoolsWc));
|
|
2319
2667
|
} else {
|
|
2320
|
-
injectOpenResourceHandler(devtoolsWc);
|
|
2668
|
+
injectOpenResourceHandler(serviceWc, devtoolsWc);
|
|
2321
2669
|
}
|
|
2322
2670
|
}
|
|
2323
2671
|
if (openInEditorWiredWcIds.has(serviceWc.id)) return;
|
|
@@ -2325,11 +2673,13 @@ function createViewManager(ctx) {
|
|
|
2325
2673
|
const onOpenUrl = (_event, url) => {
|
|
2326
2674
|
const req = decodeOpenInEditorUrl(url);
|
|
2327
2675
|
if (!req) return;
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2676
|
+
const target = resolveProjectEditorTarget(
|
|
2677
|
+
serviceWc.getURL(),
|
|
2678
|
+
ctx.workspace?.getProjectPath?.(),
|
|
2679
|
+
req
|
|
2680
|
+
);
|
|
2681
|
+
if (!target) return;
|
|
2682
|
+
ctx.notify.editorOpenFile(target);
|
|
2333
2683
|
};
|
|
2334
2684
|
serviceWc.on("devtools-open-url", onOpenUrl);
|
|
2335
2685
|
const conn = ctx.connections.acquire(serviceWc);
|
|
@@ -2489,8 +2839,10 @@ function createViewManager(ctx) {
|
|
|
2489
2839
|
function attachNativeSimulator(simulatorUrl, _simWidth) {
|
|
2490
2840
|
if (!ctx.preloadPath) {
|
|
2491
2841
|
console.error("[workbench] attachNativeSimulator \u2014 preloadPath unset; cannot mount native simulator");
|
|
2492
|
-
return;
|
|
2842
|
+
return Promise.resolve();
|
|
2493
2843
|
}
|
|
2844
|
+
settleNativeSimulatorReady?.();
|
|
2845
|
+
settleNativeSimulatorReady = null;
|
|
2494
2846
|
if (nativeSimulatorView) {
|
|
2495
2847
|
detachNativeCustomApiBridge();
|
|
2496
2848
|
if (nativeSimulatorViewAdded) {
|
|
@@ -2508,6 +2860,10 @@ function createViewManager(ctx) {
|
|
|
2508
2860
|
}
|
|
2509
2861
|
nativeSimulatorView = null;
|
|
2510
2862
|
}
|
|
2863
|
+
nativeSimulatorProjectPath = null;
|
|
2864
|
+
const ready = new Promise((resolve) => {
|
|
2865
|
+
settleNativeSimulatorReady = resolve;
|
|
2866
|
+
});
|
|
2511
2867
|
const route = parseRoute(simulatorUrl);
|
|
2512
2868
|
const partition = miniappPartition(route?.appId);
|
|
2513
2869
|
configureMiniappSession(partition);
|
|
@@ -2522,6 +2878,7 @@ function createViewManager(ctx) {
|
|
|
2522
2878
|
}
|
|
2523
2879
|
});
|
|
2524
2880
|
nativeSimulatorView = view;
|
|
2881
|
+
nativeSimulatorProjectPath = ctx.workspace?.getProjectPath() || null;
|
|
2525
2882
|
view.setBackgroundColor(simDeskBg());
|
|
2526
2883
|
const simWc = view.webContents;
|
|
2527
2884
|
const syncDeskBg = () => {
|
|
@@ -2571,6 +2928,11 @@ function createViewManager(ctx) {
|
|
|
2571
2928
|
e.preventDefault();
|
|
2572
2929
|
}
|
|
2573
2930
|
});
|
|
2931
|
+
guestWc.once("did-finish-load", () => {
|
|
2932
|
+
if (nativeSimulatorView !== view || simWc.isDestroyed()) return;
|
|
2933
|
+
settleNativeSimulatorReady?.();
|
|
2934
|
+
settleNativeSimulatorReady = null;
|
|
2935
|
+
});
|
|
2574
2936
|
followNativeDevtoolsServiceHost();
|
|
2575
2937
|
});
|
|
2576
2938
|
simWc.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
|
|
@@ -2599,8 +2961,11 @@ function createViewManager(ctx) {
|
|
|
2599
2961
|
setNativeSimulatorViewBounds(lastRendererRect);
|
|
2600
2962
|
}
|
|
2601
2963
|
attachNativeSimulatorDevtoolsHost();
|
|
2964
|
+
return ready;
|
|
2602
2965
|
}
|
|
2603
2966
|
function detachSimulator() {
|
|
2967
|
+
settleNativeSimulatorReady?.();
|
|
2968
|
+
settleNativeSimulatorReady = null;
|
|
2604
2969
|
stopFollowingNativeServiceHost();
|
|
2605
2970
|
detachNativeCustomApiBridge();
|
|
2606
2971
|
try {
|
|
@@ -2634,6 +2999,7 @@ function createViewManager(ctx) {
|
|
|
2634
2999
|
simulatorView = null;
|
|
2635
3000
|
simulatorViewAdded = false;
|
|
2636
3001
|
simulatorWebContentsId = null;
|
|
3002
|
+
nativeSimulatorProjectPath = null;
|
|
2637
3003
|
simulatorBoundsOverride = null;
|
|
2638
3004
|
lastRendererRect = null;
|
|
2639
3005
|
}
|
|
@@ -2785,6 +3151,7 @@ function createViewManager(ctx) {
|
|
|
2785
3151
|
const wc = webContents.fromId(simulatorWebContentsId);
|
|
2786
3152
|
return wc && !wc.isDestroyed() ? wc : null;
|
|
2787
3153
|
},
|
|
3154
|
+
getSimulatorProjectPath: () => nativeSimulatorProjectPath,
|
|
2788
3155
|
getSettingsWebContents: () => {
|
|
2789
3156
|
if (!settingsView) return null;
|
|
2790
3157
|
if (settingsView.webContents.isDestroyed()) return null;
|
|
@@ -2909,20 +3276,20 @@ import { z as z2 } from "zod";
|
|
|
2909
3276
|
// src/main/services/projects/project-repository.ts
|
|
2910
3277
|
import { app as app6 } from "electron";
|
|
2911
3278
|
import path9 from "path";
|
|
2912
|
-
import
|
|
3279
|
+
import fs5 from "fs";
|
|
2913
3280
|
var log2 = createLogger("projects");
|
|
2914
3281
|
function getProjectsFile() {
|
|
2915
3282
|
return path9.join(app6.getPath("userData"), "dimina-projects.json");
|
|
2916
3283
|
}
|
|
2917
3284
|
function load() {
|
|
2918
3285
|
try {
|
|
2919
|
-
return JSON.parse(
|
|
3286
|
+
return JSON.parse(fs5.readFileSync(getProjectsFile(), "utf-8"));
|
|
2920
3287
|
} catch {
|
|
2921
3288
|
return [];
|
|
2922
3289
|
}
|
|
2923
3290
|
}
|
|
2924
3291
|
function save(projects) {
|
|
2925
|
-
|
|
3292
|
+
fs5.writeFileSync(getProjectsFile(), JSON.stringify(projects, null, 2));
|
|
2926
3293
|
}
|
|
2927
3294
|
function listProjects() {
|
|
2928
3295
|
return load();
|
|
@@ -2931,14 +3298,14 @@ function validateProjectDir(dirPath) {
|
|
|
2931
3298
|
if (!dirPath) {
|
|
2932
3299
|
return "\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u8DEF\u5F84\u4E3A\u7A7A\uFF0C\u8BF7\u9009\u62E9\u5305\u542B\u5C0F\u7A0B\u5E8F\u6E90\u7801\u7684\u76EE\u5F55";
|
|
2933
3300
|
}
|
|
2934
|
-
if (!
|
|
3301
|
+
if (!fs5.existsSync(dirPath)) {
|
|
2935
3302
|
return `\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirPath}`;
|
|
2936
3303
|
}
|
|
2937
|
-
if (!
|
|
3304
|
+
if (!fs5.existsSync(path9.join(dirPath, "app.json"))) {
|
|
2938
3305
|
const configPath = path9.join(dirPath, "project.config.json");
|
|
2939
|
-
if (
|
|
3306
|
+
if (fs5.existsSync(configPath)) {
|
|
2940
3307
|
try {
|
|
2941
|
-
const cfg = JSON.parse(
|
|
3308
|
+
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2942
3309
|
if (cfg.miniprogramRoot) {
|
|
2943
3310
|
const resolvedRoot = path9.resolve(dirPath, cfg.miniprogramRoot);
|
|
2944
3311
|
return `\u8BE5\u76EE\u5F55\u7F3A\u5C11 app.json\uFF0Cproject.config.json \u4E2D\u6307\u5B9A\u4E86 miniprogramRoot: "${cfg.miniprogramRoot}"\uFF0C\u8BF7\u5BFC\u5165 ${resolvedRoot}`;
|
|
@@ -2956,8 +3323,8 @@ function addProject(dirPath) {
|
|
|
2956
3323
|
let name = path9.basename(dirPath);
|
|
2957
3324
|
try {
|
|
2958
3325
|
const configPath = path9.join(dirPath, "project.config.json");
|
|
2959
|
-
if (
|
|
2960
|
-
const cfg = JSON.parse(
|
|
3326
|
+
if (fs5.existsSync(configPath)) {
|
|
3327
|
+
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2961
3328
|
if (cfg.projectname) name = cfg.projectname;
|
|
2962
3329
|
}
|
|
2963
3330
|
} catch (err) {
|
|
@@ -2997,7 +3364,7 @@ function getProjectPages(dirPath) {
|
|
|
2997
3364
|
const appJsonPath = path9.join(dirPath, "app.json");
|
|
2998
3365
|
try {
|
|
2999
3366
|
const appJson = JSON.parse(
|
|
3000
|
-
|
|
3367
|
+
fs5.readFileSync(appJsonPath, "utf-8")
|
|
3001
3368
|
);
|
|
3002
3369
|
return {
|
|
3003
3370
|
pages: appJson.pages || [],
|
|
@@ -3021,7 +3388,7 @@ function getProjectSettings(projectPath) {
|
|
|
3021
3388
|
}
|
|
3022
3389
|
try {
|
|
3023
3390
|
const configPath = path9.join(projectPath, "project.config.json");
|
|
3024
|
-
const config = JSON.parse(
|
|
3391
|
+
const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
3025
3392
|
return {
|
|
3026
3393
|
uploadWithSourceMap: !!config.setting?.uploadWithSourceMap
|
|
3027
3394
|
};
|
|
@@ -3034,14 +3401,14 @@ function updateProjectSettings(projectPath, patch) {
|
|
|
3034
3401
|
const configPath = path9.join(projectPath, "project.config.json");
|
|
3035
3402
|
let config = {};
|
|
3036
3403
|
try {
|
|
3037
|
-
config = JSON.parse(
|
|
3404
|
+
config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
3038
3405
|
} catch {
|
|
3039
3406
|
}
|
|
3040
3407
|
const nextSetting = {
|
|
3041
3408
|
...config.setting ?? {},
|
|
3042
3409
|
...patch.uploadWithSourceMap === void 0 ? {} : { uploadWithSourceMap: patch.uploadWithSourceMap }
|
|
3043
3410
|
};
|
|
3044
|
-
|
|
3411
|
+
fs5.writeFileSync(
|
|
3045
3412
|
configPath,
|
|
3046
3413
|
JSON.stringify({ ...config, setting: nextSetting }, null, 2)
|
|
3047
3414
|
);
|
|
@@ -3216,10 +3583,16 @@ function createWorkspaceService(ctx) {
|
|
|
3216
3583
|
getLastClosedProjectPath: () => lastClosedProjectPath,
|
|
3217
3584
|
hasActiveSession: () => currentSession !== null,
|
|
3218
3585
|
async captureThumbnail(projectPath) {
|
|
3586
|
+
if (!currentSession || projectPath !== currentProjectPath) return null;
|
|
3219
3587
|
const wc = ctx.views.getSimulatorWebContents();
|
|
3220
3588
|
if (!wc) return null;
|
|
3589
|
+
if (ctx.views.getSimulatorProjectPath() !== projectPath) return null;
|
|
3590
|
+
const session5 = currentSession;
|
|
3221
3591
|
try {
|
|
3222
3592
|
const image = await wc.capturePage();
|
|
3593
|
+
if (currentSession !== session5 || currentProjectPath !== projectPath || ctx.views.getSimulatorWebContents() !== wc || ctx.views.getSimulatorProjectPath() !== projectPath) {
|
|
3594
|
+
return null;
|
|
3595
|
+
}
|
|
3223
3596
|
const dataUrl = `data:image/png;base64,${image.toPNG().toString("base64")}`;
|
|
3224
3597
|
if (provider.saveThumbnail) {
|
|
3225
3598
|
await provider.saveThumbnail(projectPath, dataUrl);
|
|
@@ -3253,7 +3626,7 @@ function createWorkspaceService(ctx) {
|
|
|
3253
3626
|
|
|
3254
3627
|
// src/main/services/projects/thumbnail.ts
|
|
3255
3628
|
import { createHash } from "crypto";
|
|
3256
|
-
import
|
|
3629
|
+
import fs6 from "fs";
|
|
3257
3630
|
import path10 from "path";
|
|
3258
3631
|
import { app as app7 } from "electron";
|
|
3259
3632
|
function getThumbnailDir() {
|
|
@@ -3269,13 +3642,13 @@ var DATA_URL_PNG_PREFIX = "data:image/png;base64,";
|
|
|
3269
3642
|
function saveThumbnailFromDataUrl(projectPath, imageDataUrl) {
|
|
3270
3643
|
if (!imageDataUrl.startsWith(DATA_URL_PNG_PREFIX)) return;
|
|
3271
3644
|
const png = Buffer.from(imageDataUrl.slice(DATA_URL_PNG_PREFIX.length), "base64");
|
|
3272
|
-
|
|
3273
|
-
|
|
3645
|
+
fs6.mkdirSync(getThumbnailDir(), { recursive: true });
|
|
3646
|
+
fs6.writeFileSync(getThumbnailPath(projectPath), png);
|
|
3274
3647
|
}
|
|
3275
3648
|
function loadThumbnail(projectPath) {
|
|
3276
3649
|
const filePath = getThumbnailPath(projectPath);
|
|
3277
3650
|
try {
|
|
3278
|
-
const buf =
|
|
3651
|
+
const buf = fs6.readFileSync(filePath);
|
|
3279
3652
|
return `${DATA_URL_PNG_PREFIX}${buf.toString("base64")}`;
|
|
3280
3653
|
} catch {
|
|
3281
3654
|
return null;
|
|
@@ -3635,7 +4008,7 @@ function deviceInfoToHostEnv(d) {
|
|
|
3635
4008
|
function registerSimulatorIpc(ctx) {
|
|
3636
4009
|
return new IpcRegistry(ctx.senderPolicy).handle(SimulatorChannel.AttachNative, (_, ...args) => {
|
|
3637
4010
|
const [simulatorUrl, simWidth] = validate(SimulatorChannel.AttachNative, SimulatorAttachNativeSchema, args);
|
|
3638
|
-
ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
4011
|
+
return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
3639
4012
|
}).handle(SimulatorChannel.Detach, () => {
|
|
3640
4013
|
ctx.views.detachSimulator();
|
|
3641
4014
|
}).handle(SimulatorChannel.SetNativeBounds, (_, ...args) => {
|
|
@@ -3677,7 +4050,7 @@ import { app as app8, dialog } from "electron";
|
|
|
3677
4050
|
import path13 from "path";
|
|
3678
4051
|
|
|
3679
4052
|
// src/main/services/projects/create-project-service.ts
|
|
3680
|
-
import
|
|
4053
|
+
import fs7 from "node:fs";
|
|
3681
4054
|
import path12 from "node:path";
|
|
3682
4055
|
var DEFAULT_TEMPLATE_ID = "blank";
|
|
3683
4056
|
async function createProject(input, ctx) {
|
|
@@ -3689,12 +4062,12 @@ async function createProject(input, ctx) {
|
|
|
3689
4062
|
if (!target || typeof target !== "string") {
|
|
3690
4063
|
throw new Error("Project path is required");
|
|
3691
4064
|
}
|
|
3692
|
-
if (
|
|
3693
|
-
const stat =
|
|
4065
|
+
if (fs7.existsSync(target)) {
|
|
4066
|
+
const stat = fs7.statSync(target);
|
|
3694
4067
|
if (!stat.isDirectory()) {
|
|
3695
4068
|
throw new Error(`Project path exists and is not a directory: ${target}`);
|
|
3696
4069
|
}
|
|
3697
|
-
const entries =
|
|
4070
|
+
const entries = fs7.readdirSync(target);
|
|
3698
4071
|
if (entries.length > 0) {
|
|
3699
4072
|
throw new Error(
|
|
3700
4073
|
`Project path is not empty (refusing to overwrite): ${target}`
|
|
@@ -3711,31 +4084,31 @@ async function createProject(input, ctx) {
|
|
|
3711
4084
|
`Template '${templateId}' has neither a source directory nor a generate function`
|
|
3712
4085
|
);
|
|
3713
4086
|
}
|
|
3714
|
-
|
|
4087
|
+
fs7.mkdirSync(target, { recursive: true });
|
|
3715
4088
|
if (template.generate) {
|
|
3716
4089
|
await template.generate(target, { name });
|
|
3717
4090
|
} else if (template.source) {
|
|
3718
|
-
if (!
|
|
4091
|
+
if (!fs7.existsSync(template.source.path)) {
|
|
3719
4092
|
throw new Error(
|
|
3720
4093
|
`Template source missing on disk: ${template.source.path}`
|
|
3721
4094
|
);
|
|
3722
4095
|
}
|
|
3723
|
-
|
|
4096
|
+
fs7.cpSync(template.source.path, target, {
|
|
3724
4097
|
recursive: true,
|
|
3725
4098
|
force: true
|
|
3726
4099
|
});
|
|
3727
4100
|
}
|
|
3728
4101
|
const cfgPath = path12.join(target, "project.config.json");
|
|
3729
4102
|
let cfg = {};
|
|
3730
|
-
if (
|
|
4103
|
+
if (fs7.existsSync(cfgPath)) {
|
|
3731
4104
|
try {
|
|
3732
|
-
cfg = JSON.parse(
|
|
4105
|
+
cfg = JSON.parse(fs7.readFileSync(cfgPath, "utf-8"));
|
|
3733
4106
|
} catch {
|
|
3734
4107
|
cfg = {};
|
|
3735
4108
|
}
|
|
3736
4109
|
}
|
|
3737
4110
|
cfg.projectname = name;
|
|
3738
|
-
|
|
4111
|
+
fs7.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
|
|
3739
4112
|
const created = await ctx.projectsProvider.addProject(target);
|
|
3740
4113
|
return created;
|
|
3741
4114
|
}
|
|
@@ -3997,7 +4370,7 @@ import { createDebugTap } from "@dimina-kit/electron-deck/main";
|
|
|
3997
4370
|
|
|
3998
4371
|
// src/main/services/dimina-resource-server.ts
|
|
3999
4372
|
import http from "node:http";
|
|
4000
|
-
import
|
|
4373
|
+
import fs8 from "node:fs";
|
|
4001
4374
|
import path14 from "node:path";
|
|
4002
4375
|
var MIME_TYPES = {
|
|
4003
4376
|
".css": "text/css; charset=utf-8",
|
|
@@ -4055,7 +4428,7 @@ async function handleRequest(root, req, res) {
|
|
|
4055
4428
|
return;
|
|
4056
4429
|
}
|
|
4057
4430
|
try {
|
|
4058
|
-
const stat = await
|
|
4431
|
+
const stat = await fs8.promises.stat(filePath);
|
|
4059
4432
|
if (!stat.isFile()) {
|
|
4060
4433
|
res.writeHead(404);
|
|
4061
4434
|
res.end("Not Found");
|
|
@@ -4070,7 +4443,7 @@ async function handleRequest(root, req, res) {
|
|
|
4070
4443
|
res.end();
|
|
4071
4444
|
return;
|
|
4072
4445
|
}
|
|
4073
|
-
|
|
4446
|
+
fs8.createReadStream(filePath).pipe(res);
|
|
4074
4447
|
} catch {
|
|
4075
4448
|
res.writeHead(404);
|
|
4076
4449
|
res.end("Not Found");
|
|
@@ -4120,6 +4493,7 @@ function buildServiceHostSpawnUrl(opts) {
|
|
|
4120
4493
|
url.searchParams.set("appId", opts.appId);
|
|
4121
4494
|
url.searchParams.set("pagePath", opts.pagePath);
|
|
4122
4495
|
url.searchParams.set("pkgRoot", opts.pkgRoot);
|
|
4496
|
+
url.searchParams.set("root", opts.root || "main");
|
|
4123
4497
|
url.searchParams.set("resourceBaseUrl", opts.resourceBaseUrl);
|
|
4124
4498
|
if (opts.hostEnvSnapshot) {
|
|
4125
4499
|
url.searchParams.set("hostEnv", encodeURIComponent(JSON.stringify(opts.hostEnvSnapshot)));
|
|
@@ -5358,7 +5732,8 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5358
5732
|
const appSessionId = bridgeId;
|
|
5359
5733
|
const simulatorWc = resolveSimulatorWebContents(ctx, opts.simulatorWcId, event.sender);
|
|
5360
5734
|
const pagePath = normalizePagePath(opts.pagePath || "pages/index/index");
|
|
5361
|
-
const
|
|
5735
|
+
const workspaceProjectPath = typeof ctx.workspace.getProjectPath === "function" ? ctx.workspace.getProjectPath() : "";
|
|
5736
|
+
const pkgRoot = path16.resolve(opts.pkgRoot || workspaceProjectPath || process.cwd());
|
|
5362
5737
|
const root = opts.root || "main";
|
|
5363
5738
|
let resourceServer = null;
|
|
5364
5739
|
let resourceBaseUrl;
|
|
@@ -5392,6 +5767,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5392
5767
|
appId,
|
|
5393
5768
|
pagePath,
|
|
5394
5769
|
pkgRoot,
|
|
5770
|
+
root,
|
|
5395
5771
|
resourceBaseUrl,
|
|
5396
5772
|
hostEnvSnapshot: hostEnv
|
|
5397
5773
|
});
|
|
@@ -5469,6 +5845,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5469
5845
|
appId,
|
|
5470
5846
|
pagePath,
|
|
5471
5847
|
pkgRoot,
|
|
5848
|
+
root,
|
|
5472
5849
|
resourceBaseUrl,
|
|
5473
5850
|
hostEnvSnapshot: hostEnv
|
|
5474
5851
|
})
|
|
@@ -5860,13 +6237,13 @@ function makeLoadResource(ap, page, target) {
|
|
|
5860
6237
|
// dimina's service runtime reads hostEnv as `{ systemInfo, menuRect }`
|
|
5861
6238
|
// (core/host-env.js init → getSystemInfo/getMenuRect; invokeAPI resolves
|
|
5862
6239
|
// getSystemInfoSync/getWindowInfo/getDeviceInfo from hostEnv.systemInfo).
|
|
5863
|
-
//
|
|
5864
|
-
// `wx.getSystemInfoSync()`
|
|
5865
|
-
// `.screenWidth`
|
|
5866
|
-
//
|
|
5867
|
-
//
|
|
5868
|
-
// menuRect stays null
|
|
5869
|
-
//
|
|
6240
|
+
// The snapshot must be nested under `systemInfo`: a FLAT HostEnvSnapshot
|
|
6241
|
+
// leaves `systemInfo` null → `wx.getSystemInfoSync()` returns null and
|
|
6242
|
+
// pages reading `.screenWidth` throw. (render does NOT read hostEnv, so
|
|
6243
|
+
// this is service-only; the devtools sync-api-patch reads the separate
|
|
6244
|
+
// __diminaSpawnContext.hostEnvSnapshot and is unaffected.)
|
|
6245
|
+
// menuRect stays null — getMenuButtonBoundingClientRect is served by the
|
|
6246
|
+
// sync-api-patch / DeviceShell capsule, not this path.
|
|
5870
6247
|
hostEnv: { systemInfo: ap.hostEnv, menuRect: null }
|
|
5871
6248
|
}
|
|
5872
6249
|
};
|
|
@@ -8096,7 +8473,7 @@ var AppDataAccumulator = class {
|
|
|
8096
8473
|
}
|
|
8097
8474
|
/**
|
|
8098
8475
|
* Apply one entry. Returns true if it was accepted (a mutation worth
|
|
8099
|
-
* republishing), false if dropped (missing ids, or the
|
|
8476
|
+
* republishing), false if dropped (missing ids, or the init-gate).
|
|
8100
8477
|
*/
|
|
8101
8478
|
apply(input) {
|
|
8102
8479
|
if (!input.bridgeId || !input.moduleId) return false;
|
|
@@ -8244,10 +8621,35 @@ function setupSimulatorCurrentPage(host, options) {
|
|
|
8244
8621
|
import { readFileSync } from "node:fs";
|
|
8245
8622
|
import path17 from "node:path";
|
|
8246
8623
|
var DEFAULT_SOURCE_PATH = "dist/render-host/render-inspect.js";
|
|
8624
|
+
var HIGHLIGHT_CONFIG = {
|
|
8625
|
+
showInfo: true,
|
|
8626
|
+
showRulers: false,
|
|
8627
|
+
showExtensionLines: false,
|
|
8628
|
+
contentColor: { r: 111, g: 168, b: 220, a: 0.66 },
|
|
8629
|
+
paddingColor: { r: 147, g: 196, b: 125, a: 0.55 },
|
|
8630
|
+
borderColor: { r: 255, g: 229, b: 153, a: 0.66 },
|
|
8631
|
+
marginColor: { r: 246, g: 178, b: 107, a: 0.66 }
|
|
8632
|
+
};
|
|
8633
|
+
var HOVER_OBJECT_GROUP = "render-inspect-hover";
|
|
8634
|
+
var ENABLE_HANDSHAKE_TIMEOUT_MS = 500;
|
|
8635
|
+
function withTimeout(p, ms) {
|
|
8636
|
+
return new Promise((resolve) => {
|
|
8637
|
+
const timer = setTimeout(resolve, ms);
|
|
8638
|
+
p.then(() => {
|
|
8639
|
+
clearTimeout(timer);
|
|
8640
|
+
resolve();
|
|
8641
|
+
}, () => {
|
|
8642
|
+
clearTimeout(timer);
|
|
8643
|
+
resolve();
|
|
8644
|
+
});
|
|
8645
|
+
});
|
|
8646
|
+
}
|
|
8247
8647
|
function createRenderInspector(options = {}) {
|
|
8248
8648
|
const loadSource = options.loadSource ?? (() => readFileSync(path17.join(devtoolsPackageRoot, DEFAULT_SOURCE_PATH), "utf8"));
|
|
8249
8649
|
let cachedSource = null;
|
|
8250
8650
|
const injected = /* @__PURE__ */ new Set();
|
|
8651
|
+
const selfAttached = /* @__PURE__ */ new Set();
|
|
8652
|
+
const enablePromises = /* @__PURE__ */ new Map();
|
|
8251
8653
|
function source() {
|
|
8252
8654
|
if (cachedSource === null) cachedSource = loadSource();
|
|
8253
8655
|
return cachedSource;
|
|
@@ -8269,10 +8671,14 @@ function createRenderInspector(options = {}) {
|
|
|
8269
8671
|
return false;
|
|
8270
8672
|
}
|
|
8271
8673
|
injected.add(wc.id);
|
|
8674
|
+
const forget = () => {
|
|
8675
|
+
injected.delete(wc.id);
|
|
8676
|
+
enablePromises.delete(wc.id);
|
|
8677
|
+
};
|
|
8272
8678
|
if (options.connections) {
|
|
8273
|
-
options.connections.acquire(wc).own(
|
|
8679
|
+
options.connections.acquire(wc).own(forget);
|
|
8274
8680
|
} else {
|
|
8275
|
-
wc.once("destroyed",
|
|
8681
|
+
wc.once("destroyed", forget);
|
|
8276
8682
|
}
|
|
8277
8683
|
return true;
|
|
8278
8684
|
}
|
|
@@ -8291,22 +8697,97 @@ function createRenderInspector(options = {}) {
|
|
|
8291
8697
|
async function highlight(wc, sid) {
|
|
8292
8698
|
if (wc.isDestroyed()) return null;
|
|
8293
8699
|
if (!await ensureInjected(wc)) return null;
|
|
8700
|
+
let inspection;
|
|
8294
8701
|
try {
|
|
8295
8702
|
const result = await wc.executeJavaScript(
|
|
8296
8703
|
`window.__diminaRenderInspect ? window.__diminaRenderInspect.highlightElement(${JSON.stringify(sid)}) : null`
|
|
8297
8704
|
);
|
|
8298
|
-
|
|
8705
|
+
inspection = result ?? null;
|
|
8299
8706
|
} catch {
|
|
8300
8707
|
return null;
|
|
8301
8708
|
}
|
|
8709
|
+
if (!inspection) return null;
|
|
8710
|
+
await drawNativeHighlight(wc, sid).catch(() => {
|
|
8711
|
+
});
|
|
8712
|
+
return inspection;
|
|
8713
|
+
}
|
|
8714
|
+
async function drawNativeHighlight(wc, sid) {
|
|
8715
|
+
if (wc.isDestroyed()) return;
|
|
8716
|
+
if (!ensureGuestDebugger(wc)) return;
|
|
8717
|
+
await withTimeout(ensureDomainsEnabled(wc), ENABLE_HANDSHAKE_TIMEOUT_MS);
|
|
8718
|
+
if (wc.isDestroyed()) return;
|
|
8719
|
+
const expression = `window.__diminaRenderInspect && window.__diminaRenderInspect.elementFor(${JSON.stringify(sid)})`;
|
|
8720
|
+
try {
|
|
8721
|
+
const evaluated = await wc.debugger.sendCommand("Runtime.evaluate", {
|
|
8722
|
+
expression,
|
|
8723
|
+
returnByValue: false,
|
|
8724
|
+
objectGroup: HOVER_OBJECT_GROUP
|
|
8725
|
+
});
|
|
8726
|
+
const objectId = evaluated?.result?.objectId;
|
|
8727
|
+
if (!objectId) return;
|
|
8728
|
+
await wc.debugger.sendCommand("Overlay.highlightNode", {
|
|
8729
|
+
objectId,
|
|
8730
|
+
highlightConfig: HIGHLIGHT_CONFIG
|
|
8731
|
+
});
|
|
8732
|
+
} finally {
|
|
8733
|
+
wc.debugger.sendCommand("Runtime.releaseObjectGroup", { objectGroup: HOVER_OBJECT_GROUP }).catch(() => {
|
|
8734
|
+
});
|
|
8735
|
+
}
|
|
8736
|
+
}
|
|
8737
|
+
function ensureGuestDebugger(wc) {
|
|
8738
|
+
try {
|
|
8739
|
+
if (wc.debugger.isAttached()) return true;
|
|
8740
|
+
} catch {
|
|
8741
|
+
return false;
|
|
8742
|
+
}
|
|
8743
|
+
try {
|
|
8744
|
+
wc.debugger.attach("1.3");
|
|
8745
|
+
trackSelfAttached(wc);
|
|
8746
|
+
return true;
|
|
8747
|
+
} catch {
|
|
8748
|
+
try {
|
|
8749
|
+
return wc.debugger.isAttached();
|
|
8750
|
+
} catch {
|
|
8751
|
+
return false;
|
|
8752
|
+
}
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8755
|
+
function trackSelfAttached(wc) {
|
|
8756
|
+
if (selfAttached.has(wc.id)) return;
|
|
8757
|
+
selfAttached.add(wc.id);
|
|
8758
|
+
const detach = () => {
|
|
8759
|
+
selfAttached.delete(wc.id);
|
|
8760
|
+
try {
|
|
8761
|
+
if (!wc.isDestroyed() && wc.debugger.isAttached()) wc.debugger.detach();
|
|
8762
|
+
} catch {
|
|
8763
|
+
}
|
|
8764
|
+
};
|
|
8765
|
+
if (options.connections) options.connections.acquire(wc).own(detach);
|
|
8766
|
+
else {
|
|
8767
|
+
try {
|
|
8768
|
+
wc.once("destroyed", () => selfAttached.delete(wc.id));
|
|
8769
|
+
} catch {
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
}
|
|
8773
|
+
function ensureDomainsEnabled(wc) {
|
|
8774
|
+
const cached = enablePromises.get(wc.id);
|
|
8775
|
+
if (cached) return cached;
|
|
8776
|
+
wc.debugger.sendCommand("CSS.enable").catch(() => {
|
|
8777
|
+
});
|
|
8778
|
+
const handshake = wc.debugger.sendCommand("DOM.enable").then(() => {
|
|
8779
|
+
if (wc.isDestroyed()) return;
|
|
8780
|
+
return wc.debugger.sendCommand("Overlay.enable");
|
|
8781
|
+
}).then(() => void 0).catch(() => {
|
|
8782
|
+
enablePromises.delete(wc.id);
|
|
8783
|
+
});
|
|
8784
|
+
enablePromises.set(wc.id, handshake);
|
|
8785
|
+
return handshake;
|
|
8302
8786
|
}
|
|
8303
8787
|
async function unhighlight(wc) {
|
|
8304
8788
|
if (wc.isDestroyed()) return;
|
|
8305
|
-
if (!await ensureInjected(wc)) return;
|
|
8306
8789
|
try {
|
|
8307
|
-
await wc.
|
|
8308
|
-
"window.__diminaRenderInspect && window.__diminaRenderInspect.unhighlightElement && window.__diminaRenderInspect.unhighlightElement()"
|
|
8309
|
-
);
|
|
8790
|
+
await wc.debugger.sendCommand("Overlay.hideHighlight");
|
|
8310
8791
|
} catch {
|
|
8311
8792
|
}
|
|
8312
8793
|
}
|
|
@@ -8379,7 +8860,7 @@ function resolveVPath(url) {
|
|
|
8379
8860
|
}
|
|
8380
8861
|
|
|
8381
8862
|
// src/main/services/simulator-temp-files/disk.ts
|
|
8382
|
-
import
|
|
8863
|
+
import fs9 from "node:fs/promises";
|
|
8383
8864
|
import path19 from "node:path";
|
|
8384
8865
|
var EXT_MIME = {
|
|
8385
8866
|
".txt": "text/plain",
|
|
@@ -8460,7 +8941,7 @@ function etagOf(mtimeMs, size) {
|
|
|
8460
8941
|
return `W/"${Math.floor(mtimeMs)}-${size}"`;
|
|
8461
8942
|
}
|
|
8462
8943
|
async function readDiskFile(realPath, opts) {
|
|
8463
|
-
const handle = await
|
|
8944
|
+
const handle = await fs9.open(realPath, "r");
|
|
8464
8945
|
try {
|
|
8465
8946
|
const st = await handle.stat();
|
|
8466
8947
|
const totalSize = st.size;
|
|
@@ -8515,15 +8996,15 @@ async function readDiskFile(realPath, opts) {
|
|
|
8515
8996
|
}
|
|
8516
8997
|
async function writeDiskFile(realPath, bytes) {
|
|
8517
8998
|
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
|
|
8518
|
-
await
|
|
8519
|
-
await
|
|
8999
|
+
await fs9.mkdir(path19.dirname(realPath), { recursive: true });
|
|
9000
|
+
await fs9.writeFile(realPath, buf);
|
|
8520
9001
|
}
|
|
8521
9002
|
async function readDiskDir(realPath) {
|
|
8522
|
-
const entries = await
|
|
9003
|
+
const entries = await fs9.readdir(realPath);
|
|
8523
9004
|
return entries;
|
|
8524
9005
|
}
|
|
8525
9006
|
async function statDiskFile(realPath) {
|
|
8526
|
-
const st = await
|
|
9007
|
+
const st = await fs9.stat(realPath);
|
|
8527
9008
|
return {
|
|
8528
9009
|
size: st.size,
|
|
8529
9010
|
mtime: Math.floor(st.mtimeMs),
|
|
@@ -8656,14 +9137,14 @@ async function handleDifileRequest(ctx, req) {
|
|
|
8656
9137
|
}
|
|
8657
9138
|
|
|
8658
9139
|
// src/main/services/simulator-temp-files/fs-channels.ts
|
|
8659
|
-
import
|
|
9140
|
+
import fs10 from "node:fs/promises";
|
|
8660
9141
|
import path20 from "node:path";
|
|
8661
9142
|
async function enforceSandbox(realPath) {
|
|
8662
9143
|
if (typeof realPath !== "string" || realPath.length === 0) {
|
|
8663
9144
|
throw new Error("sandbox: realPath must be a non-empty string");
|
|
8664
9145
|
}
|
|
8665
9146
|
const base = sandboxBase();
|
|
8666
|
-
const baseReal = await
|
|
9147
|
+
const baseReal = await fs10.realpath(base).catch(() => base);
|
|
8667
9148
|
const normalized = path20.normalize(realPath);
|
|
8668
9149
|
if (normalized !== base && !normalized.startsWith(base + path20.sep)) {
|
|
8669
9150
|
throw new Error("sandbox: realPath escapes the user-data base");
|
|
@@ -8671,7 +9152,7 @@ async function enforceSandbox(realPath) {
|
|
|
8671
9152
|
let probe = normalized;
|
|
8672
9153
|
while (probe !== path20.parse(probe).root) {
|
|
8673
9154
|
try {
|
|
8674
|
-
const resolved = await
|
|
9155
|
+
const resolved = await fs10.realpath(probe);
|
|
8675
9156
|
if (resolved !== baseReal && !resolved.startsWith(baseReal + path20.sep)) {
|
|
8676
9157
|
throw new Error("sandbox: realPath escapes the user-data base via symlink");
|
|
8677
9158
|
}
|
|
@@ -8711,12 +9192,12 @@ async function handleFsReaddir(req) {
|
|
|
8711
9192
|
}
|
|
8712
9193
|
async function handleFsUnlink(req) {
|
|
8713
9194
|
const safe = await enforceSandbox(req.realPath);
|
|
8714
|
-
await
|
|
9195
|
+
await fs10.unlink(safe);
|
|
8715
9196
|
return { ok: true };
|
|
8716
9197
|
}
|
|
8717
9198
|
async function handleFsMkdir(req) {
|
|
8718
9199
|
const safe = await enforceSandbox(req.realPath);
|
|
8719
|
-
await
|
|
9200
|
+
await fs10.mkdir(safe, { recursive: !!req.recursive });
|
|
8720
9201
|
return { ok: true };
|
|
8721
9202
|
}
|
|
8722
9203
|
|
|
@@ -9149,9 +9630,12 @@ function wireAppWindowEvents(config, instance) {
|
|
|
9149
9630
|
onResize: () => context.views.repositionAll(),
|
|
9150
9631
|
onClose: async (e) => {
|
|
9151
9632
|
if (isAppQuitting()) return;
|
|
9633
|
+
if (closing) {
|
|
9634
|
+
e.preventDefault();
|
|
9635
|
+
return;
|
|
9636
|
+
}
|
|
9152
9637
|
if (!context.workspace.hasActiveSession()) return;
|
|
9153
9638
|
e.preventDefault();
|
|
9154
|
-
if (closing) return;
|
|
9155
9639
|
closing = true;
|
|
9156
9640
|
try {
|
|
9157
9641
|
if (config.onBeforeClose) {
|
|
@@ -9171,7 +9655,7 @@ function enableDevRendererAutoReload(rendererDir2) {
|
|
|
9171
9655
|
});
|
|
9172
9656
|
}
|
|
9173
9657
|
let reloadTimer = null;
|
|
9174
|
-
const watcher =
|
|
9658
|
+
const watcher = fs11.watch(rendererDir2, { recursive: true }, () => {
|
|
9175
9659
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
9176
9660
|
reloadTimer = setTimeout(() => {
|
|
9177
9661
|
for (const win of BrowserWindow8.getAllWindows()) {
|