@dimina-kit/devtools 0.4.0-dev.20260616102751 → 0.4.0-dev.20260624040247
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 +30 -25
- package/dist/main/app/app.js +14 -2
- package/dist/main/index.bundle.js +559 -111
- package/dist/main/ipc/bridge-router.js +57 -9
- package/dist/main/ipc/projects.js +1 -1
- package/dist/main/ipc/simulator.js +1 -1
- package/dist/main/runtime/devtools-backend.d.ts +1 -1
- package/dist/main/runtime/devtools-backend.js +1 -1
- package/dist/main/runtime/miniapp-runtime.d.ts +5 -5
- package/dist/main/services/console-forward/index.js +8 -1
- package/dist/main/services/elements-forward/index.js +36 -12
- package/dist/main/services/layout/index.d.ts +12 -0
- package/dist/main/services/layout/index.js +14 -2
- 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/projects/types.d.ts +1 -1
- package/dist/main/services/projects/types.js +1 -1
- package/dist/main/services/service-console/console-api.d.ts +77 -0
- package/dist/main/services/service-console/console-api.js +103 -0
- package/dist/main/services/service-console/index.d.ts +47 -0
- package/dist/main/services/service-console/index.js +139 -0
- 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/update/update-manager.d.ts +1 -1
- package/dist/main/services/update/update-manager.js +1 -1
- 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 +24 -1
- package/dist/main/services/views/view-manager.js +120 -41
- package/dist/main/services/workbench-context.d.ts +7 -6
- 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/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/renderer/assets/index-PtsdWlGu.js +50 -0
- package/dist/renderer/assets/{input-B8NDCYv3.js → input-DiCxYlqY.js} +2 -2
- package/dist/renderer/assets/{ipc-transport-DhrajiC5.js → ipc-transport-DSBmaWpJ.js} +1 -1
- package/dist/renderer/assets/ipc-transport-DZxf2YoM.css +1 -0
- package/dist/renderer/assets/{popover-DbZOg03s.js → popover-CyL_uffj.js} +2 -2
- package/dist/renderer/assets/{select-pW3Ysc9T.js → select-BSwvDMtA.js} +2 -2
- package/dist/renderer/assets/settings-Ch8XbFxf.js +2 -0
- package/dist/renderer/assets/{settings-api-BSKzKiWd.js → settings-api-e9ILe2JO.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-BGxjl25x.js → workbenchSettings-DZsHf1g_.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 +11 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/service-host/preload.cjs +13 -15
- package/dist/service-host/sourcemap-rewrite.cjs +21 -12
- 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 +20 -1
- package/dist/shared/open-in-editor.js +246 -3
- package/dist/shared/vpath.d.ts +2 -2
- package/dist/shared/vpath.js +2 -2
- package/dist/simulator/assets/{device-shell-BWX7Yopg.js → device-shell-TtcSXwhb.js} +2 -2
- package/dist/simulator/assets/{simulator-sf-D0mhw.js → simulator-CtyXt_4V.js} +3 -3
- package/dist/simulator/simulator.html +1 -1
- package/package.json +8 -6
- package/dist/renderer/assets/index-Z4Rh52G8.js +0 -50
- package/dist/renderer/assets/ipc-transport-9agi76dX.css +0 -1
- package/dist/renderer/assets/settings-CZJOHt8b.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,218 @@ 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 normalizedRaw = normalizeSlashPath(raw);
|
|
1142
|
+
if (projectRoot && (normalizedRaw === projectRoot || normalizedRaw.startsWith(`${projectRoot}/`))) {
|
|
1143
|
+
const relative = normalizedRaw.slice(projectRoot.length).replace(/^\/+/, "");
|
|
1144
|
+
return safeRelativePath(relative.split("/").filter(Boolean));
|
|
1145
|
+
}
|
|
1146
|
+
if (/^\/(?:Volumes|Users|home|private|tmp|var|opt|Applications)\//.test(normalizedRaw)) {
|
|
1147
|
+
return null;
|
|
1148
|
+
}
|
|
1149
|
+
if (!raw.startsWith("/") && !/^[a-z][a-z0-9+.-]*:/i.test(raw)) return null;
|
|
1150
|
+
let resource;
|
|
1151
|
+
try {
|
|
1152
|
+
resource = raw.startsWith("/") && !raw.startsWith("//") ? new URL(raw, base.origin) : new URL(raw);
|
|
1153
|
+
} catch {
|
|
1154
|
+
return null;
|
|
1155
|
+
}
|
|
1156
|
+
if (resource.protocol === "file:") {
|
|
1157
|
+
const filePath = normalizeSlashPath(resource.pathname);
|
|
1158
|
+
if (!projectRoot || filePath !== projectRoot && !filePath.startsWith(`${projectRoot}/`)) return null;
|
|
1159
|
+
return safeRelativePath(
|
|
1160
|
+
filePath.slice(projectRoot.length).replace(/^\/+/, "").split("/").filter(Boolean)
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
if (resource.protocol !== "http:" && resource.protocol !== "https:") return null;
|
|
1164
|
+
if (resource.origin !== base.origin) return null;
|
|
1165
|
+
let segments = decodePathname(resource.pathname).split("/").filter(Boolean);
|
|
1166
|
+
if (context.appId && segments[0] === context.appId) {
|
|
1167
|
+
segments = segments.slice(1);
|
|
1168
|
+
if (context.outputRoot && segments[0] === context.outputRoot) segments = segments.slice(1);
|
|
1169
|
+
}
|
|
1170
|
+
return safeRelativePath(segments);
|
|
1171
|
+
}
|
|
1172
|
+
function projectSourceContextFromServiceHostUrl(serviceHostUrl, activeProjectRoot) {
|
|
1173
|
+
let url;
|
|
1174
|
+
try {
|
|
1175
|
+
url = new URL(serviceHostUrl);
|
|
1176
|
+
} catch {
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1179
|
+
const projectRoot = url.searchParams.get("pkgRoot") || "";
|
|
1180
|
+
const resourceBaseUrl = url.searchParams.get("resourceBaseUrl") ?? "";
|
|
1181
|
+
const appId = url.searchParams.get("appId") ?? "";
|
|
1182
|
+
const outputRoot = url.searchParams.get("root") ?? "main";
|
|
1183
|
+
if (!projectRoot || !resourceBaseUrl || !appId) return null;
|
|
1184
|
+
if (activeProjectRoot) {
|
|
1185
|
+
const authoritativeRoot = normalizeSlashPath(projectRoot).replace(/\/+$/, "");
|
|
1186
|
+
const currentRoot = normalizeSlashPath(activeProjectRoot).replace(/\/+$/, "");
|
|
1187
|
+
if (!authoritativeRoot || authoritativeRoot !== currentRoot) return null;
|
|
1188
|
+
}
|
|
1189
|
+
try {
|
|
1190
|
+
new URL(resourceBaseUrl);
|
|
1191
|
+
} catch {
|
|
1192
|
+
return null;
|
|
1193
|
+
}
|
|
1194
|
+
return { projectRoot, resourceBaseUrl, appId, outputRoot };
|
|
1195
|
+
}
|
|
1196
|
+
function buildDevtoolsProjectSourceLinksScript(context) {
|
|
1197
|
+
const config = JSON.stringify(context);
|
|
1198
|
+
const scheme = JSON.stringify(OPEN_IN_EDITOR_SCHEME);
|
|
1199
|
+
return `
|
|
1200
|
+
(function() {
|
|
1201
|
+
try {
|
|
1202
|
+
const stateKey = '__diminaProjectSourceLinksState__'
|
|
1203
|
+
const previousState = globalThis[stateKey]
|
|
1204
|
+
if (previousState && typeof previousState.dispose === 'function') {
|
|
1205
|
+
try { previousState.dispose() } catch (_) {}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
const cfg = ${config}
|
|
1209
|
+
const diminaProjectSourcePath = ${projectAwareResourcePath.toString()}
|
|
1210
|
+
const decodePathname = ${decodePathname.toString()}
|
|
1211
|
+
const normalizeSlashPath = ${normalizeSlashPath.toString()}
|
|
1212
|
+
const safeRelativePath = ${safeRelativePath.toString()}
|
|
1213
|
+
const observedRoots = new Set()
|
|
1214
|
+
const observers = []
|
|
1215
|
+
let timer = null
|
|
1216
|
+
const state = {
|
|
1217
|
+
dispose() {
|
|
1218
|
+
if (timer !== null) {
|
|
1219
|
+
clearInterval(timer)
|
|
1220
|
+
timer = null
|
|
1221
|
+
}
|
|
1222
|
+
for (const observer of observers.splice(0)) {
|
|
1223
|
+
try { observer.disconnect() } catch (_) {}
|
|
1224
|
+
}
|
|
1225
|
+
observedRoots.clear()
|
|
1226
|
+
},
|
|
1227
|
+
}
|
|
1228
|
+
globalThis[stateKey] = state
|
|
1229
|
+
|
|
1230
|
+
function splitLocation(value) {
|
|
1231
|
+
const raw = String(value || '')
|
|
1232
|
+
const match = raw.match(/^(.*?)(?::(\\d+))(?::(\\d+))?$/)
|
|
1233
|
+
return match
|
|
1234
|
+
? { url: match[1], suffix: ':' + match[2] + (match[3] ? ':' + match[3] : '') }
|
|
1235
|
+
: { url: raw, suffix: '' }
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
function rewriteLink(link) {
|
|
1239
|
+
if (!link || link.dataset.diminaProjectSourcePath) return
|
|
1240
|
+
const candidates = [
|
|
1241
|
+
link.getAttribute && link.getAttribute('title'),
|
|
1242
|
+
link.getAttribute && link.getAttribute('href'),
|
|
1243
|
+
link.getAttribute && link.getAttribute('data-url'),
|
|
1244
|
+
]
|
|
1245
|
+
for (const candidate of candidates) {
|
|
1246
|
+
if (!candidate) continue
|
|
1247
|
+
const location = splitLocation(candidate)
|
|
1248
|
+
const relative = diminaProjectSourcePath(location.url, cfg)
|
|
1249
|
+
if (!relative) continue
|
|
1250
|
+
const textSuffix = location.suffix || ((String(link.textContent || '').match(/(:\\d+(?::\\d+)?)$/) || [])[1] || '')
|
|
1251
|
+
link.textContent = relative + textSuffix
|
|
1252
|
+
link.dataset.diminaProjectSourcePath = relative
|
|
1253
|
+
return
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
function observeRoot(root) {
|
|
1258
|
+
if (!root || !root.querySelectorAll || observedRoots.has(root)) return
|
|
1259
|
+
observedRoots.add(root)
|
|
1260
|
+
|
|
1261
|
+
const observer = new MutationObserver((records) => {
|
|
1262
|
+
for (const record of records) {
|
|
1263
|
+
if (record.type === 'attributes') rewriteLink(record.target)
|
|
1264
|
+
for (const node of record.addedNodes || []) visitNode(node)
|
|
1265
|
+
}
|
|
1266
|
+
})
|
|
1267
|
+
observer.observe(root, {
|
|
1268
|
+
subtree: true,
|
|
1269
|
+
childList: true,
|
|
1270
|
+
attributes: true,
|
|
1271
|
+
attributeFilter: ['title', 'href', 'data-url'],
|
|
1272
|
+
})
|
|
1273
|
+
observers.push(observer)
|
|
1274
|
+
|
|
1275
|
+
for (const link of root.querySelectorAll('.devtools-link')) rewriteLink(link)
|
|
1276
|
+
for (const element of root.querySelectorAll('*')) {
|
|
1277
|
+
if (element.shadowRoot) observeRoot(element.shadowRoot)
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
function visitNode(node) {
|
|
1282
|
+
if (!node) return
|
|
1283
|
+
if (node.matches && node.matches('.devtools-link')) rewriteLink(node)
|
|
1284
|
+
if (node.shadowRoot) observeRoot(node.shadowRoot)
|
|
1285
|
+
if (!node.querySelectorAll) return
|
|
1286
|
+
for (const link of node.querySelectorAll('.devtools-link')) rewriteLink(link)
|
|
1287
|
+
for (const element of node.querySelectorAll('*')) {
|
|
1288
|
+
if (element.shadowRoot) observeRoot(element.shadowRoot)
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
observeRoot(document)
|
|
1293
|
+
|
|
1294
|
+
let tries = 0
|
|
1295
|
+
timer = setInterval(() => {
|
|
1296
|
+
tries++
|
|
1297
|
+
try {
|
|
1298
|
+
const Host = globalThis.Host
|
|
1299
|
+
const host = Host && Host.InspectorFrontendHost
|
|
1300
|
+
if (host && typeof host.setOpenResourceHandler === 'function'
|
|
1301
|
+
&& typeof host.openInNewTab === 'function') {
|
|
1302
|
+
host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
|
|
1303
|
+
try {
|
|
1304
|
+
if (!diminaProjectSourcePath(String(url), cfg)) return
|
|
1305
|
+
const p = new URLSearchParams()
|
|
1306
|
+
p.set('u', String(url))
|
|
1307
|
+
if (typeof lineNumber === 'number') p.set('l', String(lineNumber))
|
|
1308
|
+
if (typeof columnNumber === 'number') p.set('c', String(columnNumber))
|
|
1309
|
+
host.openInNewTab(${scheme} + ':?' + p.toString())
|
|
1310
|
+
} catch (_) {}
|
|
1311
|
+
})
|
|
1312
|
+
clearInterval(timer)
|
|
1313
|
+
timer = null
|
|
1314
|
+
}
|
|
1315
|
+
} catch (_) {}
|
|
1316
|
+
if (tries > 80 && timer !== null) {
|
|
1317
|
+
clearInterval(timer)
|
|
1318
|
+
timer = null
|
|
1319
|
+
}
|
|
1320
|
+
}, 50)
|
|
1321
|
+
} catch (_) {}
|
|
1322
|
+
})()
|
|
1323
|
+
`;
|
|
1324
|
+
}
|
|
1109
1325
|
|
|
1110
1326
|
// src/main/services/safe-area/index.ts
|
|
1111
1327
|
function guestInsets(device, isTabPage2) {
|
|
@@ -1276,7 +1492,7 @@ function buildDocumentUpdatedScript() {
|
|
|
1276
1492
|
return buildDispatchScript(msg);
|
|
1277
1493
|
}
|
|
1278
1494
|
var DRAIN_INTERVAL_MS = 150;
|
|
1279
|
-
var INSTALL_POLL_TRIES =
|
|
1495
|
+
var INSTALL_POLL_TRIES = 200;
|
|
1280
1496
|
var INSTALL_POLL_INTERVAL_MS = 50;
|
|
1281
1497
|
function installElementsForward(deps) {
|
|
1282
1498
|
const { devtoolsWc, bridge } = deps;
|
|
@@ -1503,6 +1719,14 @@ function installElementsForward(deps) {
|
|
|
1503
1719
|
const unsubscribeRenderEvents = bridge.onRenderEvent(onRenderEvent);
|
|
1504
1720
|
const onReady = () => {
|
|
1505
1721
|
if (disposed) return;
|
|
1722
|
+
if (installTimer) {
|
|
1723
|
+
clearInterval(installTimer);
|
|
1724
|
+
installTimer = null;
|
|
1725
|
+
}
|
|
1726
|
+
if (drainTimer) {
|
|
1727
|
+
clearInterval(drainTimer);
|
|
1728
|
+
drainTimer = null;
|
|
1729
|
+
}
|
|
1506
1730
|
let tries = 0;
|
|
1507
1731
|
installTimer = setInterval(() => {
|
|
1508
1732
|
tries++;
|
|
@@ -1537,11 +1761,8 @@ function installElementsForward(deps) {
|
|
|
1537
1761
|
});
|
|
1538
1762
|
}, DRAIN_INTERVAL_MS);
|
|
1539
1763
|
};
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
} else {
|
|
1543
|
-
onReady();
|
|
1544
|
-
}
|
|
1764
|
+
devtoolsWc.on("dom-ready", onReady);
|
|
1765
|
+
onReady();
|
|
1545
1766
|
let devtoolsClosedSub;
|
|
1546
1767
|
try {
|
|
1547
1768
|
if (deps.connections) devtoolsClosedSub = deps.connections.acquire(devtoolsWc).on("closed", stop);
|
|
@@ -1557,10 +1778,160 @@ function installElementsForward(deps) {
|
|
|
1557
1778
|
devtoolsClosedSub?.dispose();
|
|
1558
1779
|
} catch {
|
|
1559
1780
|
}
|
|
1781
|
+
try {
|
|
1782
|
+
devtoolsWc.removeListener("dom-ready", onReady);
|
|
1783
|
+
} catch {
|
|
1784
|
+
}
|
|
1560
1785
|
stop();
|
|
1561
1786
|
};
|
|
1562
1787
|
}
|
|
1563
1788
|
|
|
1789
|
+
// src/main/services/service-console/console-api.ts
|
|
1790
|
+
var RENDER_FORWARD_SOURCE_URL = "dimina://render-console-forward";
|
|
1791
|
+
var KNOWN_LEVELS = /* @__PURE__ */ new Set(["log", "warn", "error", "info", "debug"]);
|
|
1792
|
+
function mapConsoleApiType(type) {
|
|
1793
|
+
if (type === "warning") return "warn";
|
|
1794
|
+
if (type && KNOWN_LEVELS.has(type)) return type;
|
|
1795
|
+
return "log";
|
|
1796
|
+
}
|
|
1797
|
+
var BIGINT_LITERAL = /^-?\d+n$/;
|
|
1798
|
+
function remoteObjectToValue(ro) {
|
|
1799
|
+
if (!ro) return ro;
|
|
1800
|
+
if ("value" in ro) return ro.value;
|
|
1801
|
+
if (typeof ro.unserializableValue === "string") {
|
|
1802
|
+
const u = ro.unserializableValue;
|
|
1803
|
+
if (u === "Infinity") return Infinity;
|
|
1804
|
+
if (u === "-Infinity") return -Infinity;
|
|
1805
|
+
if (u === "NaN") return NaN;
|
|
1806
|
+
if (u === "-0") return -0;
|
|
1807
|
+
if (BIGINT_LITERAL.test(u)) return u;
|
|
1808
|
+
return u;
|
|
1809
|
+
}
|
|
1810
|
+
switch (ro.type) {
|
|
1811
|
+
case "undefined":
|
|
1812
|
+
return void 0;
|
|
1813
|
+
case "function":
|
|
1814
|
+
return ro.description ?? "[Function]";
|
|
1815
|
+
case "symbol":
|
|
1816
|
+
return ro.description ?? "[Symbol]";
|
|
1817
|
+
case "object":
|
|
1818
|
+
if (ro.subtype === "null") return null;
|
|
1819
|
+
return ro.description ?? "[Object]";
|
|
1820
|
+
default:
|
|
1821
|
+
return ro.description ?? "[Unknown]";
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
function needsDeepFetch(ro) {
|
|
1825
|
+
if (!ro) return false;
|
|
1826
|
+
if ("value" in ro) return false;
|
|
1827
|
+
return ro.type === "object" && ro.subtype !== "null" && typeof ro.objectId === "string";
|
|
1828
|
+
}
|
|
1829
|
+
function isRenderForwardEvent(params, sentinelUrl) {
|
|
1830
|
+
const top = params?.stackTrace?.callFrames?.[0]?.url;
|
|
1831
|
+
return typeof top === "string" && top === sentinelUrl;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// src/main/services/service-console/index.ts
|
|
1835
|
+
function installServiceConsoleForward(deps) {
|
|
1836
|
+
const { serviceWc, emit, connections } = deps;
|
|
1837
|
+
let disposed = false;
|
|
1838
|
+
let selfAttached = false;
|
|
1839
|
+
let tail = Promise.resolve();
|
|
1840
|
+
let closedSub;
|
|
1841
|
+
function usableDebugger() {
|
|
1842
|
+
try {
|
|
1843
|
+
if (serviceWc.isDestroyed()) return false;
|
|
1844
|
+
if (serviceWc.debugger.isAttached()) return true;
|
|
1845
|
+
} catch {
|
|
1846
|
+
return false;
|
|
1847
|
+
}
|
|
1848
|
+
try {
|
|
1849
|
+
serviceWc.debugger.attach("1.3");
|
|
1850
|
+
selfAttached = true;
|
|
1851
|
+
return true;
|
|
1852
|
+
} catch {
|
|
1853
|
+
try {
|
|
1854
|
+
return serviceWc.debugger.isAttached();
|
|
1855
|
+
} catch {
|
|
1856
|
+
return false;
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
async function resolveArg(ro) {
|
|
1861
|
+
if (!needsDeepFetch(ro)) return remoteObjectToValue(ro);
|
|
1862
|
+
try {
|
|
1863
|
+
const res = await serviceWc.debugger.sendCommand("Runtime.callFunctionOn", {
|
|
1864
|
+
objectId: ro.objectId,
|
|
1865
|
+
functionDeclaration: "function () { return this }",
|
|
1866
|
+
returnByValue: true
|
|
1867
|
+
});
|
|
1868
|
+
if (res && res.result && "value" in res.result) return res.result.value;
|
|
1869
|
+
} catch {
|
|
1870
|
+
}
|
|
1871
|
+
return remoteObjectToValue(ro);
|
|
1872
|
+
}
|
|
1873
|
+
async function handleConsoleApi(params) {
|
|
1874
|
+
if (disposed) return;
|
|
1875
|
+
if (isRenderForwardEvent(params, RENDER_FORWARD_SOURCE_URL)) return;
|
|
1876
|
+
const level = mapConsoleApiType(params.type);
|
|
1877
|
+
const rawArgs = Array.isArray(params.args) ? params.args : [];
|
|
1878
|
+
let args;
|
|
1879
|
+
try {
|
|
1880
|
+
args = await Promise.all(rawArgs.map((a) => resolveArg(a)));
|
|
1881
|
+
} catch {
|
|
1882
|
+
args = rawArgs.map((a) => remoteObjectToValue(a));
|
|
1883
|
+
}
|
|
1884
|
+
if (disposed) return;
|
|
1885
|
+
emit({ source: "service", level, args, ts: Date.now() });
|
|
1886
|
+
}
|
|
1887
|
+
const onMessage = (_event, method, params) => {
|
|
1888
|
+
if (disposed) return;
|
|
1889
|
+
if (method !== "Runtime.consoleAPICalled") return;
|
|
1890
|
+
const p = params;
|
|
1891
|
+
tail = tail.then(() => handleConsoleApi(p)).catch(() => {
|
|
1892
|
+
});
|
|
1893
|
+
};
|
|
1894
|
+
function stop() {
|
|
1895
|
+
if (disposed) return;
|
|
1896
|
+
disposed = true;
|
|
1897
|
+
try {
|
|
1898
|
+
closedSub?.dispose();
|
|
1899
|
+
} catch {
|
|
1900
|
+
}
|
|
1901
|
+
try {
|
|
1902
|
+
serviceWc.debugger.removeListener("message", onMessage);
|
|
1903
|
+
} catch {
|
|
1904
|
+
}
|
|
1905
|
+
if (selfAttached) {
|
|
1906
|
+
try {
|
|
1907
|
+
if (!serviceWc.isDestroyed() && serviceWc.debugger.isAttached()) serviceWc.debugger.detach();
|
|
1908
|
+
} catch {
|
|
1909
|
+
}
|
|
1910
|
+
selfAttached = false;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
if (!usableDebugger()) {
|
|
1914
|
+
disposed = true;
|
|
1915
|
+
return { stop() {
|
|
1916
|
+
} };
|
|
1917
|
+
}
|
|
1918
|
+
try {
|
|
1919
|
+
serviceWc.debugger.on("message", onMessage);
|
|
1920
|
+
} catch {
|
|
1921
|
+
stop();
|
|
1922
|
+
return { stop() {
|
|
1923
|
+
} };
|
|
1924
|
+
}
|
|
1925
|
+
serviceWc.debugger.sendCommand("Runtime.enable").catch(() => {
|
|
1926
|
+
});
|
|
1927
|
+
try {
|
|
1928
|
+
if (connections) closedSub = connections.acquire(serviceWc).on("closed", stop);
|
|
1929
|
+
else serviceWc.once("destroyed", stop);
|
|
1930
|
+
} catch {
|
|
1931
|
+
}
|
|
1932
|
+
return { stop };
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1564
1935
|
// src/main/services/layout/index.ts
|
|
1565
1936
|
function computeNativeSimulatorViewParams(rect, zoomPercent) {
|
|
1566
1937
|
const zoomFactor = zoomPercent / 100;
|
|
@@ -1574,12 +1945,11 @@ function computeNativeSimulatorViewParams(rect, zoomPercent) {
|
|
|
1574
1945
|
zoomFactor
|
|
1575
1946
|
};
|
|
1576
1947
|
}
|
|
1577
|
-
var SETTINGS_W = 320;
|
|
1578
1948
|
function computeSettingsBounds(contentWidth, contentHeight, headerHeight) {
|
|
1579
1949
|
return {
|
|
1580
|
-
x:
|
|
1950
|
+
x: 0,
|
|
1581
1951
|
y: headerHeight,
|
|
1582
|
-
width: Math.
|
|
1952
|
+
width: Math.max(1, contentWidth),
|
|
1583
1953
|
height: Math.max(1, contentHeight - headerHeight)
|
|
1584
1954
|
};
|
|
1585
1955
|
}
|
|
@@ -1868,12 +2238,36 @@ function parseRoute(url) {
|
|
|
1868
2238
|
}
|
|
1869
2239
|
|
|
1870
2240
|
// src/main/services/views/view-manager.ts
|
|
2241
|
+
function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFile = (absolutePath) => fs4.statSync(absolutePath).isFile()) {
|
|
2242
|
+
const sourceContext = projectSourceContextFromServiceHostUrl(
|
|
2243
|
+
serviceHostUrl,
|
|
2244
|
+
activeProjectRoot
|
|
2245
|
+
);
|
|
2246
|
+
if (!sourceContext) return null;
|
|
2247
|
+
const rel = resourceUrlToProjectRelativePath(req.url, sourceContext);
|
|
2248
|
+
if (!rel) return null;
|
|
2249
|
+
const absolute = path7.resolve(sourceContext.projectRoot, ...rel.split("/"));
|
|
2250
|
+
const fromRoot = path7.relative(path7.resolve(sourceContext.projectRoot), absolute);
|
|
2251
|
+
if (!fromRoot || fromRoot.startsWith("..") || path7.isAbsolute(fromRoot)) return null;
|
|
2252
|
+
try {
|
|
2253
|
+
if (!isFile(absolute)) return null;
|
|
2254
|
+
} catch {
|
|
2255
|
+
return null;
|
|
2256
|
+
}
|
|
2257
|
+
return {
|
|
2258
|
+
path: rel,
|
|
2259
|
+
line: typeof req.line === "number" ? req.line + 1 : void 0,
|
|
2260
|
+
column: typeof req.column === "number" ? req.column + 1 : void 0
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
1871
2263
|
function createViewManager(ctx) {
|
|
1872
2264
|
const safeArea = createSafeAreaController({ connections: ctx.connections });
|
|
1873
2265
|
let simulatorView = null;
|
|
1874
2266
|
let simulatorViewAdded = false;
|
|
1875
2267
|
let nativeSimulatorView = null;
|
|
1876
2268
|
let nativeSimulatorViewAdded = false;
|
|
2269
|
+
let nativeSimulatorProjectPath = null;
|
|
2270
|
+
let settleNativeSimulatorReady = null;
|
|
1877
2271
|
let lastRendererRect = null;
|
|
1878
2272
|
let nativeCustomApiBridgeHandler = null;
|
|
1879
2273
|
let currentZoomFactor = 1;
|
|
@@ -1884,6 +2278,7 @@ function createViewManager(ctx) {
|
|
|
1884
2278
|
let nativeDevtoolsSourceWc = null;
|
|
1885
2279
|
let unsubscribeNativeRenderEvents = null;
|
|
1886
2280
|
let stopElementsForward = null;
|
|
2281
|
+
let stopServiceConsole = null;
|
|
1887
2282
|
let nativeDevtoolsRetryTimer = null;
|
|
1888
2283
|
let nativeDevtoolsRetryToken = 0;
|
|
1889
2284
|
let simulatorBoundsOverride = null;
|
|
@@ -1931,6 +2326,7 @@ function createViewManager(ctx) {
|
|
|
1931
2326
|
if (!simulatorViewAdded) {
|
|
1932
2327
|
ctx.windows.mainWindow.contentView.addChildView(simulatorView);
|
|
1933
2328
|
simulatorViewAdded = true;
|
|
2329
|
+
raiseTopOverlays();
|
|
1934
2330
|
}
|
|
1935
2331
|
simulatorView.setBounds(bounds);
|
|
1936
2332
|
}
|
|
@@ -2079,6 +2475,11 @@ function createViewManager(ctx) {
|
|
|
2079
2475
|
function closeNativeDevtoolsSource() {
|
|
2080
2476
|
const source = nativeDevtoolsSourceWc;
|
|
2081
2477
|
nativeDevtoolsSourceWc = null;
|
|
2478
|
+
try {
|
|
2479
|
+
stopServiceConsole?.();
|
|
2480
|
+
} catch {
|
|
2481
|
+
}
|
|
2482
|
+
stopServiceConsole = null;
|
|
2082
2483
|
if (!source || source.isDestroyed()) return;
|
|
2083
2484
|
try {
|
|
2084
2485
|
if (source.isDevToolsOpened()) {
|
|
@@ -2099,37 +2500,13 @@ function createViewManager(ctx) {
|
|
|
2099
2500
|
closeNativeDevtoolsSource();
|
|
2100
2501
|
}
|
|
2101
2502
|
const openInEditorWiredWcIds = /* @__PURE__ */ new Set();
|
|
2102
|
-
function injectOpenResourceHandler(devtoolsWc) {
|
|
2103
|
-
const
|
|
2104
|
-
|
|
2105
|
-
(
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
tries++
|
|
2110
|
-
try {
|
|
2111
|
-
const Host = globalThis.Host
|
|
2112
|
-
const host = Host && Host.InspectorFrontendHost
|
|
2113
|
-
if (host && typeof host.setOpenResourceHandler === 'function'
|
|
2114
|
-
&& typeof host.openInNewTab === 'function') {
|
|
2115
|
-
host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
|
|
2116
|
-
try {
|
|
2117
|
-
const p = new URLSearchParams()
|
|
2118
|
-
p.set('u', String(url))
|
|
2119
|
-
if (typeof lineNumber === 'number') p.set('l', String(lineNumber))
|
|
2120
|
-
if (typeof columnNumber === 'number') p.set('c', String(columnNumber))
|
|
2121
|
-
host.openInNewTab(${scheme} + ':?' + p.toString())
|
|
2122
|
-
} catch (_) {}
|
|
2123
|
-
})
|
|
2124
|
-
clearInterval(timer)
|
|
2125
|
-
return
|
|
2126
|
-
}
|
|
2127
|
-
} catch (_) {}
|
|
2128
|
-
if (tries > 80) clearInterval(timer)
|
|
2129
|
-
}, 50)
|
|
2130
|
-
} catch (_) {}
|
|
2131
|
-
})()
|
|
2132
|
-
`).catch(() => {
|
|
2503
|
+
function injectOpenResourceHandler(serviceWc, devtoolsWc) {
|
|
2504
|
+
const sourceContext = projectSourceContextFromServiceHostUrl(
|
|
2505
|
+
serviceWc.getURL(),
|
|
2506
|
+
ctx.workspace?.getProjectPath?.()
|
|
2507
|
+
);
|
|
2508
|
+
if (!sourceContext) return;
|
|
2509
|
+
devtoolsWc.executeJavaScript(buildDevtoolsProjectSourceLinksScript(sourceContext)).catch(() => {
|
|
2133
2510
|
});
|
|
2134
2511
|
}
|
|
2135
2512
|
function customizeDevtoolsTabs(devtoolsWc) {
|
|
@@ -2154,9 +2531,9 @@ function createViewManager(ctx) {
|
|
|
2154
2531
|
function wireOpenInEditor(serviceWc, devtoolsWc) {
|
|
2155
2532
|
if (!devtoolsWc.isDestroyed()) {
|
|
2156
2533
|
if (devtoolsWc.isLoading()) {
|
|
2157
|
-
devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(devtoolsWc));
|
|
2534
|
+
devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(serviceWc, devtoolsWc));
|
|
2158
2535
|
} else {
|
|
2159
|
-
injectOpenResourceHandler(devtoolsWc);
|
|
2536
|
+
injectOpenResourceHandler(serviceWc, devtoolsWc);
|
|
2160
2537
|
}
|
|
2161
2538
|
}
|
|
2162
2539
|
if (openInEditorWiredWcIds.has(serviceWc.id)) return;
|
|
@@ -2164,11 +2541,13 @@ function createViewManager(ctx) {
|
|
|
2164
2541
|
const onOpenUrl = (_event, url) => {
|
|
2165
2542
|
const req = decodeOpenInEditorUrl(url);
|
|
2166
2543
|
if (!req) return;
|
|
2167
|
-
const
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2544
|
+
const target = resolveProjectEditorTarget(
|
|
2545
|
+
serviceWc.getURL(),
|
|
2546
|
+
ctx.workspace?.getProjectPath?.(),
|
|
2547
|
+
req
|
|
2548
|
+
);
|
|
2549
|
+
if (!target) return;
|
|
2550
|
+
ctx.notify.editorOpenFile(target);
|
|
2172
2551
|
};
|
|
2173
2552
|
serviceWc.on("devtools-open-url", onOpenUrl);
|
|
2174
2553
|
const conn = ctx.connections.acquire(serviceWc);
|
|
@@ -2192,6 +2571,15 @@ function createViewManager(ctx) {
|
|
|
2192
2571
|
next.openDevTools({ mode: "detach", activate: false });
|
|
2193
2572
|
wireOpenInEditor(next, simulatorView.webContents);
|
|
2194
2573
|
customizeDevtoolsTabs(simulatorView.webContents);
|
|
2574
|
+
try {
|
|
2575
|
+
stopServiceConsole?.();
|
|
2576
|
+
} catch {
|
|
2577
|
+
}
|
|
2578
|
+
stopServiceConsole = installServiceConsoleForward({
|
|
2579
|
+
serviceWc: next,
|
|
2580
|
+
connections: ctx.connections,
|
|
2581
|
+
emit: (entry) => ctx.consoleForwarder?.emit(entry)
|
|
2582
|
+
}).stop;
|
|
2195
2583
|
return true;
|
|
2196
2584
|
} catch {
|
|
2197
2585
|
if (nativeDevtoolsSourceWc?.id === next.id) {
|
|
@@ -2319,8 +2707,10 @@ function createViewManager(ctx) {
|
|
|
2319
2707
|
function attachNativeSimulator(simulatorUrl, _simWidth) {
|
|
2320
2708
|
if (!ctx.preloadPath) {
|
|
2321
2709
|
console.error("[workbench] attachNativeSimulator \u2014 preloadPath unset; cannot mount native simulator");
|
|
2322
|
-
return;
|
|
2710
|
+
return Promise.resolve();
|
|
2323
2711
|
}
|
|
2712
|
+
settleNativeSimulatorReady?.();
|
|
2713
|
+
settleNativeSimulatorReady = null;
|
|
2324
2714
|
if (nativeSimulatorView) {
|
|
2325
2715
|
detachNativeCustomApiBridge();
|
|
2326
2716
|
if (nativeSimulatorViewAdded) {
|
|
@@ -2338,6 +2728,10 @@ function createViewManager(ctx) {
|
|
|
2338
2728
|
}
|
|
2339
2729
|
nativeSimulatorView = null;
|
|
2340
2730
|
}
|
|
2731
|
+
nativeSimulatorProjectPath = null;
|
|
2732
|
+
const ready = new Promise((resolve) => {
|
|
2733
|
+
settleNativeSimulatorReady = resolve;
|
|
2734
|
+
});
|
|
2341
2735
|
const route = parseRoute(simulatorUrl);
|
|
2342
2736
|
const partition = miniappPartition(route?.appId);
|
|
2343
2737
|
configureMiniappSession(partition);
|
|
@@ -2352,6 +2746,7 @@ function createViewManager(ctx) {
|
|
|
2352
2746
|
}
|
|
2353
2747
|
});
|
|
2354
2748
|
nativeSimulatorView = view;
|
|
2749
|
+
nativeSimulatorProjectPath = ctx.workspace?.getProjectPath() || null;
|
|
2355
2750
|
view.setBackgroundColor(simDeskBg());
|
|
2356
2751
|
const simWc = view.webContents;
|
|
2357
2752
|
const syncDeskBg = () => {
|
|
@@ -2401,6 +2796,11 @@ function createViewManager(ctx) {
|
|
|
2401
2796
|
e.preventDefault();
|
|
2402
2797
|
}
|
|
2403
2798
|
});
|
|
2799
|
+
guestWc.once("did-finish-load", () => {
|
|
2800
|
+
if (nativeSimulatorView !== view || simWc.isDestroyed()) return;
|
|
2801
|
+
settleNativeSimulatorReady?.();
|
|
2802
|
+
settleNativeSimulatorReady = null;
|
|
2803
|
+
});
|
|
2404
2804
|
followNativeDevtoolsServiceHost();
|
|
2405
2805
|
});
|
|
2406
2806
|
simWc.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
|
|
@@ -2429,8 +2829,11 @@ function createViewManager(ctx) {
|
|
|
2429
2829
|
setNativeSimulatorViewBounds(lastRendererRect);
|
|
2430
2830
|
}
|
|
2431
2831
|
attachNativeSimulatorDevtoolsHost();
|
|
2832
|
+
return ready;
|
|
2432
2833
|
}
|
|
2433
2834
|
function detachSimulator() {
|
|
2835
|
+
settleNativeSimulatorReady?.();
|
|
2836
|
+
settleNativeSimulatorReady = null;
|
|
2434
2837
|
stopFollowingNativeServiceHost();
|
|
2435
2838
|
detachNativeCustomApiBridge();
|
|
2436
2839
|
try {
|
|
@@ -2464,6 +2867,7 @@ function createViewManager(ctx) {
|
|
|
2464
2867
|
simulatorView = null;
|
|
2465
2868
|
simulatorViewAdded = false;
|
|
2466
2869
|
simulatorWebContentsId = null;
|
|
2870
|
+
nativeSimulatorProjectPath = null;
|
|
2467
2871
|
simulatorBoundsOverride = null;
|
|
2468
2872
|
lastRendererRect = null;
|
|
2469
2873
|
}
|
|
@@ -2488,6 +2892,7 @@ function createViewManager(ctx) {
|
|
|
2488
2892
|
}
|
|
2489
2893
|
});
|
|
2490
2894
|
applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
|
|
2895
|
+
settingsView.setBackgroundColor("#00000000");
|
|
2491
2896
|
await settingsView.webContents.loadFile(
|
|
2492
2897
|
path7.join(ctx.rendererDir, "entries/settings/index.html")
|
|
2493
2898
|
);
|
|
@@ -2507,6 +2912,12 @@ function createViewManager(ctx) {
|
|
|
2507
2912
|
settingsViewAdded = false;
|
|
2508
2913
|
}
|
|
2509
2914
|
}
|
|
2915
|
+
function raiseTopOverlays() {
|
|
2916
|
+
if (ctx.windows.mainWindow.isDestroyed()) return;
|
|
2917
|
+
const cv = ctx.windows.mainWindow.contentView;
|
|
2918
|
+
if (settingsView && settingsViewAdded) cv.addChildView(settingsView);
|
|
2919
|
+
if (popoverView) cv.addChildView(popoverView);
|
|
2920
|
+
}
|
|
2510
2921
|
function showPopover(data) {
|
|
2511
2922
|
hidePopover();
|
|
2512
2923
|
const popover = new WebContentsView2({
|
|
@@ -2572,6 +2983,7 @@ function createViewManager(ctx) {
|
|
|
2572
2983
|
if (!nativeSimulatorViewAdded) {
|
|
2573
2984
|
ctx.windows.mainWindow.contentView.addChildView(nativeSimulatorView);
|
|
2574
2985
|
nativeSimulatorViewAdded = true;
|
|
2986
|
+
raiseTopOverlays();
|
|
2575
2987
|
}
|
|
2576
2988
|
nativeSimulatorView.setBounds(p.bounds);
|
|
2577
2989
|
const simWc = nativeSimulatorView.webContents;
|
|
@@ -2607,6 +3019,7 @@ function createViewManager(ctx) {
|
|
|
2607
3019
|
const wc = webContents.fromId(simulatorWebContentsId);
|
|
2608
3020
|
return wc && !wc.isDestroyed() ? wc : null;
|
|
2609
3021
|
},
|
|
3022
|
+
getSimulatorProjectPath: () => nativeSimulatorProjectPath,
|
|
2610
3023
|
getSettingsWebContents: () => {
|
|
2611
3024
|
if (!settingsView) return null;
|
|
2612
3025
|
if (settingsView.webContents.isDestroyed()) return null;
|
|
@@ -2731,20 +3144,20 @@ import { z as z2 } from "zod";
|
|
|
2731
3144
|
// src/main/services/projects/project-repository.ts
|
|
2732
3145
|
import { app as app6 } from "electron";
|
|
2733
3146
|
import path9 from "path";
|
|
2734
|
-
import
|
|
3147
|
+
import fs5 from "fs";
|
|
2735
3148
|
var log2 = createLogger("projects");
|
|
2736
3149
|
function getProjectsFile() {
|
|
2737
3150
|
return path9.join(app6.getPath("userData"), "dimina-projects.json");
|
|
2738
3151
|
}
|
|
2739
3152
|
function load() {
|
|
2740
3153
|
try {
|
|
2741
|
-
return JSON.parse(
|
|
3154
|
+
return JSON.parse(fs5.readFileSync(getProjectsFile(), "utf-8"));
|
|
2742
3155
|
} catch {
|
|
2743
3156
|
return [];
|
|
2744
3157
|
}
|
|
2745
3158
|
}
|
|
2746
3159
|
function save(projects) {
|
|
2747
|
-
|
|
3160
|
+
fs5.writeFileSync(getProjectsFile(), JSON.stringify(projects, null, 2));
|
|
2748
3161
|
}
|
|
2749
3162
|
function listProjects() {
|
|
2750
3163
|
return load();
|
|
@@ -2753,14 +3166,14 @@ function validateProjectDir(dirPath) {
|
|
|
2753
3166
|
if (!dirPath) {
|
|
2754
3167
|
return "\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u8DEF\u5F84\u4E3A\u7A7A\uFF0C\u8BF7\u9009\u62E9\u5305\u542B\u5C0F\u7A0B\u5E8F\u6E90\u7801\u7684\u76EE\u5F55";
|
|
2755
3168
|
}
|
|
2756
|
-
if (!
|
|
3169
|
+
if (!fs5.existsSync(dirPath)) {
|
|
2757
3170
|
return `\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirPath}`;
|
|
2758
3171
|
}
|
|
2759
|
-
if (!
|
|
3172
|
+
if (!fs5.existsSync(path9.join(dirPath, "app.json"))) {
|
|
2760
3173
|
const configPath = path9.join(dirPath, "project.config.json");
|
|
2761
|
-
if (
|
|
3174
|
+
if (fs5.existsSync(configPath)) {
|
|
2762
3175
|
try {
|
|
2763
|
-
const cfg = JSON.parse(
|
|
3176
|
+
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2764
3177
|
if (cfg.miniprogramRoot) {
|
|
2765
3178
|
const resolvedRoot = path9.resolve(dirPath, cfg.miniprogramRoot);
|
|
2766
3179
|
return `\u8BE5\u76EE\u5F55\u7F3A\u5C11 app.json\uFF0Cproject.config.json \u4E2D\u6307\u5B9A\u4E86 miniprogramRoot: "${cfg.miniprogramRoot}"\uFF0C\u8BF7\u5BFC\u5165 ${resolvedRoot}`;
|
|
@@ -2778,8 +3191,8 @@ function addProject(dirPath) {
|
|
|
2778
3191
|
let name = path9.basename(dirPath);
|
|
2779
3192
|
try {
|
|
2780
3193
|
const configPath = path9.join(dirPath, "project.config.json");
|
|
2781
|
-
if (
|
|
2782
|
-
const cfg = JSON.parse(
|
|
3194
|
+
if (fs5.existsSync(configPath)) {
|
|
3195
|
+
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2783
3196
|
if (cfg.projectname) name = cfg.projectname;
|
|
2784
3197
|
}
|
|
2785
3198
|
} catch (err) {
|
|
@@ -2819,7 +3232,7 @@ function getProjectPages(dirPath) {
|
|
|
2819
3232
|
const appJsonPath = path9.join(dirPath, "app.json");
|
|
2820
3233
|
try {
|
|
2821
3234
|
const appJson = JSON.parse(
|
|
2822
|
-
|
|
3235
|
+
fs5.readFileSync(appJsonPath, "utf-8")
|
|
2823
3236
|
);
|
|
2824
3237
|
return {
|
|
2825
3238
|
pages: appJson.pages || [],
|
|
@@ -2843,7 +3256,7 @@ function getProjectSettings(projectPath) {
|
|
|
2843
3256
|
}
|
|
2844
3257
|
try {
|
|
2845
3258
|
const configPath = path9.join(projectPath, "project.config.json");
|
|
2846
|
-
const config = JSON.parse(
|
|
3259
|
+
const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2847
3260
|
return {
|
|
2848
3261
|
uploadWithSourceMap: !!config.setting?.uploadWithSourceMap
|
|
2849
3262
|
};
|
|
@@ -2856,14 +3269,14 @@ function updateProjectSettings(projectPath, patch) {
|
|
|
2856
3269
|
const configPath = path9.join(projectPath, "project.config.json");
|
|
2857
3270
|
let config = {};
|
|
2858
3271
|
try {
|
|
2859
|
-
config = JSON.parse(
|
|
3272
|
+
config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2860
3273
|
} catch {
|
|
2861
3274
|
}
|
|
2862
3275
|
const nextSetting = {
|
|
2863
3276
|
...config.setting ?? {},
|
|
2864
3277
|
...patch.uploadWithSourceMap === void 0 ? {} : { uploadWithSourceMap: patch.uploadWithSourceMap }
|
|
2865
3278
|
};
|
|
2866
|
-
|
|
3279
|
+
fs5.writeFileSync(
|
|
2867
3280
|
configPath,
|
|
2868
3281
|
JSON.stringify({ ...config, setting: nextSetting }, null, 2)
|
|
2869
3282
|
);
|
|
@@ -3038,10 +3451,16 @@ function createWorkspaceService(ctx) {
|
|
|
3038
3451
|
getLastClosedProjectPath: () => lastClosedProjectPath,
|
|
3039
3452
|
hasActiveSession: () => currentSession !== null,
|
|
3040
3453
|
async captureThumbnail(projectPath) {
|
|
3454
|
+
if (!currentSession || projectPath !== currentProjectPath) return null;
|
|
3041
3455
|
const wc = ctx.views.getSimulatorWebContents();
|
|
3042
3456
|
if (!wc) return null;
|
|
3457
|
+
if (ctx.views.getSimulatorProjectPath() !== projectPath) return null;
|
|
3458
|
+
const session5 = currentSession;
|
|
3043
3459
|
try {
|
|
3044
3460
|
const image = await wc.capturePage();
|
|
3461
|
+
if (currentSession !== session5 || currentProjectPath !== projectPath || ctx.views.getSimulatorWebContents() !== wc || ctx.views.getSimulatorProjectPath() !== projectPath) {
|
|
3462
|
+
return null;
|
|
3463
|
+
}
|
|
3045
3464
|
const dataUrl = `data:image/png;base64,${image.toPNG().toString("base64")}`;
|
|
3046
3465
|
if (provider.saveThumbnail) {
|
|
3047
3466
|
await provider.saveThumbnail(projectPath, dataUrl);
|
|
@@ -3075,7 +3494,7 @@ function createWorkspaceService(ctx) {
|
|
|
3075
3494
|
|
|
3076
3495
|
// src/main/services/projects/thumbnail.ts
|
|
3077
3496
|
import { createHash } from "crypto";
|
|
3078
|
-
import
|
|
3497
|
+
import fs6 from "fs";
|
|
3079
3498
|
import path10 from "path";
|
|
3080
3499
|
import { app as app7 } from "electron";
|
|
3081
3500
|
function getThumbnailDir() {
|
|
@@ -3091,13 +3510,13 @@ var DATA_URL_PNG_PREFIX = "data:image/png;base64,";
|
|
|
3091
3510
|
function saveThumbnailFromDataUrl(projectPath, imageDataUrl) {
|
|
3092
3511
|
if (!imageDataUrl.startsWith(DATA_URL_PNG_PREFIX)) return;
|
|
3093
3512
|
const png = Buffer.from(imageDataUrl.slice(DATA_URL_PNG_PREFIX.length), "base64");
|
|
3094
|
-
|
|
3095
|
-
|
|
3513
|
+
fs6.mkdirSync(getThumbnailDir(), { recursive: true });
|
|
3514
|
+
fs6.writeFileSync(getThumbnailPath(projectPath), png);
|
|
3096
3515
|
}
|
|
3097
3516
|
function loadThumbnail(projectPath) {
|
|
3098
3517
|
const filePath = getThumbnailPath(projectPath);
|
|
3099
3518
|
try {
|
|
3100
|
-
const buf =
|
|
3519
|
+
const buf = fs6.readFileSync(filePath);
|
|
3101
3520
|
return `${DATA_URL_PNG_PREFIX}${buf.toString("base64")}`;
|
|
3102
3521
|
} catch {
|
|
3103
3522
|
return null;
|
|
@@ -3457,7 +3876,7 @@ function deviceInfoToHostEnv(d) {
|
|
|
3457
3876
|
function registerSimulatorIpc(ctx) {
|
|
3458
3877
|
return new IpcRegistry(ctx.senderPolicy).handle(SimulatorChannel.AttachNative, (_, ...args) => {
|
|
3459
3878
|
const [simulatorUrl, simWidth] = validate(SimulatorChannel.AttachNative, SimulatorAttachNativeSchema, args);
|
|
3460
|
-
ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
3879
|
+
return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
3461
3880
|
}).handle(SimulatorChannel.Detach, () => {
|
|
3462
3881
|
ctx.views.detachSimulator();
|
|
3463
3882
|
}).handle(SimulatorChannel.SetNativeBounds, (_, ...args) => {
|
|
@@ -3499,7 +3918,7 @@ import { app as app8, dialog } from "electron";
|
|
|
3499
3918
|
import path13 from "path";
|
|
3500
3919
|
|
|
3501
3920
|
// src/main/services/projects/create-project-service.ts
|
|
3502
|
-
import
|
|
3921
|
+
import fs7 from "node:fs";
|
|
3503
3922
|
import path12 from "node:path";
|
|
3504
3923
|
var DEFAULT_TEMPLATE_ID = "blank";
|
|
3505
3924
|
async function createProject(input, ctx) {
|
|
@@ -3511,12 +3930,12 @@ async function createProject(input, ctx) {
|
|
|
3511
3930
|
if (!target || typeof target !== "string") {
|
|
3512
3931
|
throw new Error("Project path is required");
|
|
3513
3932
|
}
|
|
3514
|
-
if (
|
|
3515
|
-
const stat =
|
|
3933
|
+
if (fs7.existsSync(target)) {
|
|
3934
|
+
const stat = fs7.statSync(target);
|
|
3516
3935
|
if (!stat.isDirectory()) {
|
|
3517
3936
|
throw new Error(`Project path exists and is not a directory: ${target}`);
|
|
3518
3937
|
}
|
|
3519
|
-
const entries =
|
|
3938
|
+
const entries = fs7.readdirSync(target);
|
|
3520
3939
|
if (entries.length > 0) {
|
|
3521
3940
|
throw new Error(
|
|
3522
3941
|
`Project path is not empty (refusing to overwrite): ${target}`
|
|
@@ -3533,31 +3952,31 @@ async function createProject(input, ctx) {
|
|
|
3533
3952
|
`Template '${templateId}' has neither a source directory nor a generate function`
|
|
3534
3953
|
);
|
|
3535
3954
|
}
|
|
3536
|
-
|
|
3955
|
+
fs7.mkdirSync(target, { recursive: true });
|
|
3537
3956
|
if (template.generate) {
|
|
3538
3957
|
await template.generate(target, { name });
|
|
3539
3958
|
} else if (template.source) {
|
|
3540
|
-
if (!
|
|
3959
|
+
if (!fs7.existsSync(template.source.path)) {
|
|
3541
3960
|
throw new Error(
|
|
3542
3961
|
`Template source missing on disk: ${template.source.path}`
|
|
3543
3962
|
);
|
|
3544
3963
|
}
|
|
3545
|
-
|
|
3964
|
+
fs7.cpSync(template.source.path, target, {
|
|
3546
3965
|
recursive: true,
|
|
3547
3966
|
force: true
|
|
3548
3967
|
});
|
|
3549
3968
|
}
|
|
3550
3969
|
const cfgPath = path12.join(target, "project.config.json");
|
|
3551
3970
|
let cfg = {};
|
|
3552
|
-
if (
|
|
3971
|
+
if (fs7.existsSync(cfgPath)) {
|
|
3553
3972
|
try {
|
|
3554
|
-
cfg = JSON.parse(
|
|
3973
|
+
cfg = JSON.parse(fs7.readFileSync(cfgPath, "utf-8"));
|
|
3555
3974
|
} catch {
|
|
3556
3975
|
cfg = {};
|
|
3557
3976
|
}
|
|
3558
3977
|
}
|
|
3559
3978
|
cfg.projectname = name;
|
|
3560
|
-
|
|
3979
|
+
fs7.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
|
|
3561
3980
|
const created = await ctx.projectsProvider.addProject(target);
|
|
3562
3981
|
return created;
|
|
3563
3982
|
}
|
|
@@ -3819,7 +4238,7 @@ import { createDebugTap } from "@dimina-kit/electron-deck/main";
|
|
|
3819
4238
|
|
|
3820
4239
|
// src/main/services/dimina-resource-server.ts
|
|
3821
4240
|
import http from "node:http";
|
|
3822
|
-
import
|
|
4241
|
+
import fs8 from "node:fs";
|
|
3823
4242
|
import path14 from "node:path";
|
|
3824
4243
|
var MIME_TYPES = {
|
|
3825
4244
|
".css": "text/css; charset=utf-8",
|
|
@@ -3877,7 +4296,7 @@ async function handleRequest(root, req, res) {
|
|
|
3877
4296
|
return;
|
|
3878
4297
|
}
|
|
3879
4298
|
try {
|
|
3880
|
-
const stat = await
|
|
4299
|
+
const stat = await fs8.promises.stat(filePath);
|
|
3881
4300
|
if (!stat.isFile()) {
|
|
3882
4301
|
res.writeHead(404);
|
|
3883
4302
|
res.end("Not Found");
|
|
@@ -3892,7 +4311,7 @@ async function handleRequest(root, req, res) {
|
|
|
3892
4311
|
res.end();
|
|
3893
4312
|
return;
|
|
3894
4313
|
}
|
|
3895
|
-
|
|
4314
|
+
fs8.createReadStream(filePath).pipe(res);
|
|
3896
4315
|
} catch {
|
|
3897
4316
|
res.writeHead(404);
|
|
3898
4317
|
res.end("Not Found");
|
|
@@ -3942,6 +4361,7 @@ function buildServiceHostSpawnUrl(opts) {
|
|
|
3942
4361
|
url.searchParams.set("appId", opts.appId);
|
|
3943
4362
|
url.searchParams.set("pagePath", opts.pagePath);
|
|
3944
4363
|
url.searchParams.set("pkgRoot", opts.pkgRoot);
|
|
4364
|
+
url.searchParams.set("root", opts.root || "main");
|
|
3945
4365
|
url.searchParams.set("resourceBaseUrl", opts.resourceBaseUrl);
|
|
3946
4366
|
if (opts.hostEnvSnapshot) {
|
|
3947
4367
|
url.searchParams.set("hostEnv", encodeURIComponent(JSON.stringify(opts.hostEnvSnapshot)));
|
|
@@ -4301,7 +4721,8 @@ var FORWARDABLE_LEVELS = /* @__PURE__ */ new Set(["log", "warn", "error", "info"
|
|
|
4301
4721
|
function buildForwardScript(level, args) {
|
|
4302
4722
|
const method = FORWARDABLE_LEVELS.has(level) ? level : "log";
|
|
4303
4723
|
const argsJson = JSON.stringify(args ?? []);
|
|
4304
|
-
return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}]('[\u89C6\u56FE]',...a)}catch(_){}})()
|
|
4724
|
+
return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}]('[\u89C6\u56FE]',...a)}catch(_){}})()
|
|
4725
|
+
//# sourceURL=${RENDER_FORWARD_SOURCE_URL}`;
|
|
4305
4726
|
}
|
|
4306
4727
|
function createConsoleForwarder(bridge) {
|
|
4307
4728
|
const sinks = /* @__PURE__ */ new Set();
|
|
@@ -4836,6 +5257,27 @@ function findSimulatorWebContents() {
|
|
|
4836
5257
|
}
|
|
4837
5258
|
|
|
4838
5259
|
// src/main/ipc/bridge-router.ts
|
|
5260
|
+
function rewriteSourceMappingUrl(source, scriptUrl) {
|
|
5261
|
+
if (typeof source !== "string" || !source) return source;
|
|
5262
|
+
const re = /(^|\n)[ \t]*\/\/[#@][ \t]*sourceMappingURL=([^\n]*)/g;
|
|
5263
|
+
let lastIndex = -1;
|
|
5264
|
+
let lastValue = "";
|
|
5265
|
+
let m;
|
|
5266
|
+
while ((m = re.exec(source)) !== null) {
|
|
5267
|
+
lastIndex = m.index + m[1].length;
|
|
5268
|
+
lastValue = (m[2] || "").trim();
|
|
5269
|
+
}
|
|
5270
|
+
if (lastIndex < 0 || !lastValue) return source;
|
|
5271
|
+
if (/^(?:[a-z][a-z0-9+.-]*:)?\/\//i.test(lastValue) || /^data:/i.test(lastValue)) return source;
|
|
5272
|
+
let absolute;
|
|
5273
|
+
try {
|
|
5274
|
+
absolute = new URL(lastValue, scriptUrl).toString();
|
|
5275
|
+
} catch {
|
|
5276
|
+
return source;
|
|
5277
|
+
}
|
|
5278
|
+
return `${source.slice(0, lastIndex)}
|
|
5279
|
+
//# sourceMappingURL=${absolute}`;
|
|
5280
|
+
}
|
|
4839
5281
|
var STACK_ID = "stack_0";
|
|
4840
5282
|
var PREWARM_MAX_POOL_SIZE = 4;
|
|
4841
5283
|
function resolvePrewarmPoolSize() {
|
|
@@ -5158,7 +5600,8 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5158
5600
|
const appSessionId = bridgeId;
|
|
5159
5601
|
const simulatorWc = resolveSimulatorWebContents(ctx, opts.simulatorWcId, event.sender);
|
|
5160
5602
|
const pagePath = normalizePagePath(opts.pagePath || "pages/index/index");
|
|
5161
|
-
const
|
|
5603
|
+
const workspaceProjectPath = typeof ctx.workspace.getProjectPath === "function" ? ctx.workspace.getProjectPath() : "";
|
|
5604
|
+
const pkgRoot = path16.resolve(opts.pkgRoot || workspaceProjectPath || process.cwd());
|
|
5162
5605
|
const root = opts.root || "main";
|
|
5163
5606
|
let resourceServer = null;
|
|
5164
5607
|
let resourceBaseUrl;
|
|
@@ -5192,6 +5635,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5192
5635
|
appId,
|
|
5193
5636
|
pagePath,
|
|
5194
5637
|
pkgRoot,
|
|
5638
|
+
root,
|
|
5195
5639
|
resourceBaseUrl,
|
|
5196
5640
|
hostEnvSnapshot: hostEnv
|
|
5197
5641
|
});
|
|
@@ -5269,6 +5713,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5269
5713
|
appId,
|
|
5270
5714
|
pagePath,
|
|
5271
5715
|
pkgRoot,
|
|
5716
|
+
root,
|
|
5272
5717
|
resourceBaseUrl,
|
|
5273
5718
|
hostEnvSnapshot: hostEnv
|
|
5274
5719
|
})
|
|
@@ -5365,7 +5810,7 @@ async function injectLogicBundle(ap) {
|
|
|
5365
5810
|
try {
|
|
5366
5811
|
const res = await fetch(logicUrl);
|
|
5367
5812
|
if (!res.ok) throw new Error(`logic.js fetch ${res.status} at ${logicUrl}`);
|
|
5368
|
-
const logicContent = await res.text();
|
|
5813
|
+
const logicContent = rewriteSourceMappingUrl(await res.text(), logicUrl);
|
|
5369
5814
|
await ap.serviceWc.executeJavaScript(`${logicContent}
|
|
5370
5815
|
//# sourceURL=${logicUrl}`, true);
|
|
5371
5816
|
} catch (error) {
|
|
@@ -5660,13 +6105,13 @@ function makeLoadResource(ap, page, target) {
|
|
|
5660
6105
|
// dimina's service runtime reads hostEnv as `{ systemInfo, menuRect }`
|
|
5661
6106
|
// (core/host-env.js init → getSystemInfo/getMenuRect; invokeAPI resolves
|
|
5662
6107
|
// getSystemInfoSync/getWindowInfo/getDeviceInfo from hostEnv.systemInfo).
|
|
5663
|
-
//
|
|
5664
|
-
// `wx.getSystemInfoSync()`
|
|
5665
|
-
// `.screenWidth`
|
|
5666
|
-
//
|
|
5667
|
-
//
|
|
5668
|
-
// menuRect stays null
|
|
5669
|
-
//
|
|
6108
|
+
// The snapshot must be nested under `systemInfo`: a FLAT HostEnvSnapshot
|
|
6109
|
+
// leaves `systemInfo` null → `wx.getSystemInfoSync()` returns null and
|
|
6110
|
+
// pages reading `.screenWidth` throw. (render does NOT read hostEnv, so
|
|
6111
|
+
// this is service-only; the devtools sync-api-patch reads the separate
|
|
6112
|
+
// __diminaSpawnContext.hostEnvSnapshot and is unaffected.)
|
|
6113
|
+
// menuRect stays null — getMenuButtonBoundingClientRect is served by the
|
|
6114
|
+
// sync-api-patch / DeviceShell capsule, not this path.
|
|
5670
6115
|
hostEnv: { systemInfo: ap.hostEnv, menuRect: null }
|
|
5671
6116
|
}
|
|
5672
6117
|
};
|
|
@@ -7896,7 +8341,7 @@ var AppDataAccumulator = class {
|
|
|
7896
8341
|
}
|
|
7897
8342
|
/**
|
|
7898
8343
|
* Apply one entry. Returns true if it was accepted (a mutation worth
|
|
7899
|
-
* republishing), false if dropped (missing ids, or the
|
|
8344
|
+
* republishing), false if dropped (missing ids, or the init-gate).
|
|
7900
8345
|
*/
|
|
7901
8346
|
apply(input) {
|
|
7902
8347
|
if (!input.bridgeId || !input.moduleId) return false;
|
|
@@ -8179,7 +8624,7 @@ function resolveVPath(url) {
|
|
|
8179
8624
|
}
|
|
8180
8625
|
|
|
8181
8626
|
// src/main/services/simulator-temp-files/disk.ts
|
|
8182
|
-
import
|
|
8627
|
+
import fs9 from "node:fs/promises";
|
|
8183
8628
|
import path19 from "node:path";
|
|
8184
8629
|
var EXT_MIME = {
|
|
8185
8630
|
".txt": "text/plain",
|
|
@@ -8260,7 +8705,7 @@ function etagOf(mtimeMs, size) {
|
|
|
8260
8705
|
return `W/"${Math.floor(mtimeMs)}-${size}"`;
|
|
8261
8706
|
}
|
|
8262
8707
|
async function readDiskFile(realPath, opts) {
|
|
8263
|
-
const handle = await
|
|
8708
|
+
const handle = await fs9.open(realPath, "r");
|
|
8264
8709
|
try {
|
|
8265
8710
|
const st = await handle.stat();
|
|
8266
8711
|
const totalSize = st.size;
|
|
@@ -8315,15 +8760,15 @@ async function readDiskFile(realPath, opts) {
|
|
|
8315
8760
|
}
|
|
8316
8761
|
async function writeDiskFile(realPath, bytes) {
|
|
8317
8762
|
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
|
|
8318
|
-
await
|
|
8319
|
-
await
|
|
8763
|
+
await fs9.mkdir(path19.dirname(realPath), { recursive: true });
|
|
8764
|
+
await fs9.writeFile(realPath, buf);
|
|
8320
8765
|
}
|
|
8321
8766
|
async function readDiskDir(realPath) {
|
|
8322
|
-
const entries = await
|
|
8767
|
+
const entries = await fs9.readdir(realPath);
|
|
8323
8768
|
return entries;
|
|
8324
8769
|
}
|
|
8325
8770
|
async function statDiskFile(realPath) {
|
|
8326
|
-
const st = await
|
|
8771
|
+
const st = await fs9.stat(realPath);
|
|
8327
8772
|
return {
|
|
8328
8773
|
size: st.size,
|
|
8329
8774
|
mtime: Math.floor(st.mtimeMs),
|
|
@@ -8456,14 +8901,14 @@ async function handleDifileRequest(ctx, req) {
|
|
|
8456
8901
|
}
|
|
8457
8902
|
|
|
8458
8903
|
// src/main/services/simulator-temp-files/fs-channels.ts
|
|
8459
|
-
import
|
|
8904
|
+
import fs10 from "node:fs/promises";
|
|
8460
8905
|
import path20 from "node:path";
|
|
8461
8906
|
async function enforceSandbox(realPath) {
|
|
8462
8907
|
if (typeof realPath !== "string" || realPath.length === 0) {
|
|
8463
8908
|
throw new Error("sandbox: realPath must be a non-empty string");
|
|
8464
8909
|
}
|
|
8465
8910
|
const base = sandboxBase();
|
|
8466
|
-
const baseReal = await
|
|
8911
|
+
const baseReal = await fs10.realpath(base).catch(() => base);
|
|
8467
8912
|
const normalized = path20.normalize(realPath);
|
|
8468
8913
|
if (normalized !== base && !normalized.startsWith(base + path20.sep)) {
|
|
8469
8914
|
throw new Error("sandbox: realPath escapes the user-data base");
|
|
@@ -8471,7 +8916,7 @@ async function enforceSandbox(realPath) {
|
|
|
8471
8916
|
let probe = normalized;
|
|
8472
8917
|
while (probe !== path20.parse(probe).root) {
|
|
8473
8918
|
try {
|
|
8474
|
-
const resolved = await
|
|
8919
|
+
const resolved = await fs10.realpath(probe);
|
|
8475
8920
|
if (resolved !== baseReal && !resolved.startsWith(baseReal + path20.sep)) {
|
|
8476
8921
|
throw new Error("sandbox: realPath escapes the user-data base via symlink");
|
|
8477
8922
|
}
|
|
@@ -8511,12 +8956,12 @@ async function handleFsReaddir(req) {
|
|
|
8511
8956
|
}
|
|
8512
8957
|
async function handleFsUnlink(req) {
|
|
8513
8958
|
const safe = await enforceSandbox(req.realPath);
|
|
8514
|
-
await
|
|
8959
|
+
await fs10.unlink(safe);
|
|
8515
8960
|
return { ok: true };
|
|
8516
8961
|
}
|
|
8517
8962
|
async function handleFsMkdir(req) {
|
|
8518
8963
|
const safe = await enforceSandbox(req.realPath);
|
|
8519
|
-
await
|
|
8964
|
+
await fs10.mkdir(safe, { recursive: !!req.recursive });
|
|
8520
8965
|
return { ok: true };
|
|
8521
8966
|
}
|
|
8522
8967
|
|
|
@@ -8702,7 +9147,7 @@ var UpdateManager = class {
|
|
|
8702
9147
|
downloadedPath = null;
|
|
8703
9148
|
/**
|
|
8704
9149
|
* Whether this instance has already emitted `Available` once. The periodic
|
|
8705
|
-
* check fires forever (interval default 1h), and downstream UI (
|
|
9150
|
+
* check fires forever (interval default 1h), and downstream UI (a downstream host shell
|
|
8706
9151
|
* renders a native toast / Notification) is not idempotent — every event
|
|
8707
9152
|
* stacks. We dedupe at the source: at most one Available per instance
|
|
8708
9153
|
* lifetime, regardless of how the upstream `info.version` shifts. The user
|
|
@@ -8949,9 +9394,12 @@ function wireAppWindowEvents(config, instance) {
|
|
|
8949
9394
|
onResize: () => context.views.repositionAll(),
|
|
8950
9395
|
onClose: async (e) => {
|
|
8951
9396
|
if (isAppQuitting()) return;
|
|
9397
|
+
if (closing) {
|
|
9398
|
+
e.preventDefault();
|
|
9399
|
+
return;
|
|
9400
|
+
}
|
|
8952
9401
|
if (!context.workspace.hasActiveSession()) return;
|
|
8953
9402
|
e.preventDefault();
|
|
8954
|
-
if (closing) return;
|
|
8955
9403
|
closing = true;
|
|
8956
9404
|
try {
|
|
8957
9405
|
if (config.onBeforeClose) {
|
|
@@ -8971,7 +9419,7 @@ function enableDevRendererAutoReload(rendererDir2) {
|
|
|
8971
9419
|
});
|
|
8972
9420
|
}
|
|
8973
9421
|
let reloadTimer = null;
|
|
8974
|
-
const watcher =
|
|
9422
|
+
const watcher = fs11.watch(rendererDir2, { recursive: true }, () => {
|
|
8975
9423
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
8976
9424
|
reloadTimer = setTimeout(() => {
|
|
8977
9425
|
for (const win of BrowserWindow8.getAllWindows()) {
|