@dimina-kit/devtools 0.4.0-dev.20260618090552 → 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 +5 -1
- package/dist/main/app/app.js +14 -2
- package/dist/main/index.bundle.js +347 -99
- 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 +5 -5
- 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/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/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 +67 -41
- 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/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 +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-DmgWoK8N.js +0 -50
|
@@ -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) {
|
|
@@ -2022,12 +2238,36 @@ function parseRoute(url) {
|
|
|
2022
2238
|
}
|
|
2023
2239
|
|
|
2024
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
|
+
}
|
|
2025
2263
|
function createViewManager(ctx) {
|
|
2026
2264
|
const safeArea = createSafeAreaController({ connections: ctx.connections });
|
|
2027
2265
|
let simulatorView = null;
|
|
2028
2266
|
let simulatorViewAdded = false;
|
|
2029
2267
|
let nativeSimulatorView = null;
|
|
2030
2268
|
let nativeSimulatorViewAdded = false;
|
|
2269
|
+
let nativeSimulatorProjectPath = null;
|
|
2270
|
+
let settleNativeSimulatorReady = null;
|
|
2031
2271
|
let lastRendererRect = null;
|
|
2032
2272
|
let nativeCustomApiBridgeHandler = null;
|
|
2033
2273
|
let currentZoomFactor = 1;
|
|
@@ -2260,37 +2500,13 @@ function createViewManager(ctx) {
|
|
|
2260
2500
|
closeNativeDevtoolsSource();
|
|
2261
2501
|
}
|
|
2262
2502
|
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(() => {
|
|
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(() => {
|
|
2294
2510
|
});
|
|
2295
2511
|
}
|
|
2296
2512
|
function customizeDevtoolsTabs(devtoolsWc) {
|
|
@@ -2315,9 +2531,9 @@ function createViewManager(ctx) {
|
|
|
2315
2531
|
function wireOpenInEditor(serviceWc, devtoolsWc) {
|
|
2316
2532
|
if (!devtoolsWc.isDestroyed()) {
|
|
2317
2533
|
if (devtoolsWc.isLoading()) {
|
|
2318
|
-
devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(devtoolsWc));
|
|
2534
|
+
devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(serviceWc, devtoolsWc));
|
|
2319
2535
|
} else {
|
|
2320
|
-
injectOpenResourceHandler(devtoolsWc);
|
|
2536
|
+
injectOpenResourceHandler(serviceWc, devtoolsWc);
|
|
2321
2537
|
}
|
|
2322
2538
|
}
|
|
2323
2539
|
if (openInEditorWiredWcIds.has(serviceWc.id)) return;
|
|
@@ -2325,11 +2541,13 @@ function createViewManager(ctx) {
|
|
|
2325
2541
|
const onOpenUrl = (_event, url) => {
|
|
2326
2542
|
const req = decodeOpenInEditorUrl(url);
|
|
2327
2543
|
if (!req) return;
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2544
|
+
const target = resolveProjectEditorTarget(
|
|
2545
|
+
serviceWc.getURL(),
|
|
2546
|
+
ctx.workspace?.getProjectPath?.(),
|
|
2547
|
+
req
|
|
2548
|
+
);
|
|
2549
|
+
if (!target) return;
|
|
2550
|
+
ctx.notify.editorOpenFile(target);
|
|
2333
2551
|
};
|
|
2334
2552
|
serviceWc.on("devtools-open-url", onOpenUrl);
|
|
2335
2553
|
const conn = ctx.connections.acquire(serviceWc);
|
|
@@ -2489,8 +2707,10 @@ function createViewManager(ctx) {
|
|
|
2489
2707
|
function attachNativeSimulator(simulatorUrl, _simWidth) {
|
|
2490
2708
|
if (!ctx.preloadPath) {
|
|
2491
2709
|
console.error("[workbench] attachNativeSimulator \u2014 preloadPath unset; cannot mount native simulator");
|
|
2492
|
-
return;
|
|
2710
|
+
return Promise.resolve();
|
|
2493
2711
|
}
|
|
2712
|
+
settleNativeSimulatorReady?.();
|
|
2713
|
+
settleNativeSimulatorReady = null;
|
|
2494
2714
|
if (nativeSimulatorView) {
|
|
2495
2715
|
detachNativeCustomApiBridge();
|
|
2496
2716
|
if (nativeSimulatorViewAdded) {
|
|
@@ -2508,6 +2728,10 @@ function createViewManager(ctx) {
|
|
|
2508
2728
|
}
|
|
2509
2729
|
nativeSimulatorView = null;
|
|
2510
2730
|
}
|
|
2731
|
+
nativeSimulatorProjectPath = null;
|
|
2732
|
+
const ready = new Promise((resolve) => {
|
|
2733
|
+
settleNativeSimulatorReady = resolve;
|
|
2734
|
+
});
|
|
2511
2735
|
const route = parseRoute(simulatorUrl);
|
|
2512
2736
|
const partition = miniappPartition(route?.appId);
|
|
2513
2737
|
configureMiniappSession(partition);
|
|
@@ -2522,6 +2746,7 @@ function createViewManager(ctx) {
|
|
|
2522
2746
|
}
|
|
2523
2747
|
});
|
|
2524
2748
|
nativeSimulatorView = view;
|
|
2749
|
+
nativeSimulatorProjectPath = ctx.workspace?.getProjectPath() || null;
|
|
2525
2750
|
view.setBackgroundColor(simDeskBg());
|
|
2526
2751
|
const simWc = view.webContents;
|
|
2527
2752
|
const syncDeskBg = () => {
|
|
@@ -2571,6 +2796,11 @@ function createViewManager(ctx) {
|
|
|
2571
2796
|
e.preventDefault();
|
|
2572
2797
|
}
|
|
2573
2798
|
});
|
|
2799
|
+
guestWc.once("did-finish-load", () => {
|
|
2800
|
+
if (nativeSimulatorView !== view || simWc.isDestroyed()) return;
|
|
2801
|
+
settleNativeSimulatorReady?.();
|
|
2802
|
+
settleNativeSimulatorReady = null;
|
|
2803
|
+
});
|
|
2574
2804
|
followNativeDevtoolsServiceHost();
|
|
2575
2805
|
});
|
|
2576
2806
|
simWc.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
|
|
@@ -2599,8 +2829,11 @@ function createViewManager(ctx) {
|
|
|
2599
2829
|
setNativeSimulatorViewBounds(lastRendererRect);
|
|
2600
2830
|
}
|
|
2601
2831
|
attachNativeSimulatorDevtoolsHost();
|
|
2832
|
+
return ready;
|
|
2602
2833
|
}
|
|
2603
2834
|
function detachSimulator() {
|
|
2835
|
+
settleNativeSimulatorReady?.();
|
|
2836
|
+
settleNativeSimulatorReady = null;
|
|
2604
2837
|
stopFollowingNativeServiceHost();
|
|
2605
2838
|
detachNativeCustomApiBridge();
|
|
2606
2839
|
try {
|
|
@@ -2634,6 +2867,7 @@ function createViewManager(ctx) {
|
|
|
2634
2867
|
simulatorView = null;
|
|
2635
2868
|
simulatorViewAdded = false;
|
|
2636
2869
|
simulatorWebContentsId = null;
|
|
2870
|
+
nativeSimulatorProjectPath = null;
|
|
2637
2871
|
simulatorBoundsOverride = null;
|
|
2638
2872
|
lastRendererRect = null;
|
|
2639
2873
|
}
|
|
@@ -2785,6 +3019,7 @@ function createViewManager(ctx) {
|
|
|
2785
3019
|
const wc = webContents.fromId(simulatorWebContentsId);
|
|
2786
3020
|
return wc && !wc.isDestroyed() ? wc : null;
|
|
2787
3021
|
},
|
|
3022
|
+
getSimulatorProjectPath: () => nativeSimulatorProjectPath,
|
|
2788
3023
|
getSettingsWebContents: () => {
|
|
2789
3024
|
if (!settingsView) return null;
|
|
2790
3025
|
if (settingsView.webContents.isDestroyed()) return null;
|
|
@@ -2909,20 +3144,20 @@ import { z as z2 } from "zod";
|
|
|
2909
3144
|
// src/main/services/projects/project-repository.ts
|
|
2910
3145
|
import { app as app6 } from "electron";
|
|
2911
3146
|
import path9 from "path";
|
|
2912
|
-
import
|
|
3147
|
+
import fs5 from "fs";
|
|
2913
3148
|
var log2 = createLogger("projects");
|
|
2914
3149
|
function getProjectsFile() {
|
|
2915
3150
|
return path9.join(app6.getPath("userData"), "dimina-projects.json");
|
|
2916
3151
|
}
|
|
2917
3152
|
function load() {
|
|
2918
3153
|
try {
|
|
2919
|
-
return JSON.parse(
|
|
3154
|
+
return JSON.parse(fs5.readFileSync(getProjectsFile(), "utf-8"));
|
|
2920
3155
|
} catch {
|
|
2921
3156
|
return [];
|
|
2922
3157
|
}
|
|
2923
3158
|
}
|
|
2924
3159
|
function save(projects) {
|
|
2925
|
-
|
|
3160
|
+
fs5.writeFileSync(getProjectsFile(), JSON.stringify(projects, null, 2));
|
|
2926
3161
|
}
|
|
2927
3162
|
function listProjects() {
|
|
2928
3163
|
return load();
|
|
@@ -2931,14 +3166,14 @@ function validateProjectDir(dirPath) {
|
|
|
2931
3166
|
if (!dirPath) {
|
|
2932
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";
|
|
2933
3168
|
}
|
|
2934
|
-
if (!
|
|
3169
|
+
if (!fs5.existsSync(dirPath)) {
|
|
2935
3170
|
return `\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirPath}`;
|
|
2936
3171
|
}
|
|
2937
|
-
if (!
|
|
3172
|
+
if (!fs5.existsSync(path9.join(dirPath, "app.json"))) {
|
|
2938
3173
|
const configPath = path9.join(dirPath, "project.config.json");
|
|
2939
|
-
if (
|
|
3174
|
+
if (fs5.existsSync(configPath)) {
|
|
2940
3175
|
try {
|
|
2941
|
-
const cfg = JSON.parse(
|
|
3176
|
+
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2942
3177
|
if (cfg.miniprogramRoot) {
|
|
2943
3178
|
const resolvedRoot = path9.resolve(dirPath, cfg.miniprogramRoot);
|
|
2944
3179
|
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 +3191,8 @@ function addProject(dirPath) {
|
|
|
2956
3191
|
let name = path9.basename(dirPath);
|
|
2957
3192
|
try {
|
|
2958
3193
|
const configPath = path9.join(dirPath, "project.config.json");
|
|
2959
|
-
if (
|
|
2960
|
-
const cfg = JSON.parse(
|
|
3194
|
+
if (fs5.existsSync(configPath)) {
|
|
3195
|
+
const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
2961
3196
|
if (cfg.projectname) name = cfg.projectname;
|
|
2962
3197
|
}
|
|
2963
3198
|
} catch (err) {
|
|
@@ -2997,7 +3232,7 @@ function getProjectPages(dirPath) {
|
|
|
2997
3232
|
const appJsonPath = path9.join(dirPath, "app.json");
|
|
2998
3233
|
try {
|
|
2999
3234
|
const appJson = JSON.parse(
|
|
3000
|
-
|
|
3235
|
+
fs5.readFileSync(appJsonPath, "utf-8")
|
|
3001
3236
|
);
|
|
3002
3237
|
return {
|
|
3003
3238
|
pages: appJson.pages || [],
|
|
@@ -3021,7 +3256,7 @@ function getProjectSettings(projectPath) {
|
|
|
3021
3256
|
}
|
|
3022
3257
|
try {
|
|
3023
3258
|
const configPath = path9.join(projectPath, "project.config.json");
|
|
3024
|
-
const config = JSON.parse(
|
|
3259
|
+
const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
3025
3260
|
return {
|
|
3026
3261
|
uploadWithSourceMap: !!config.setting?.uploadWithSourceMap
|
|
3027
3262
|
};
|
|
@@ -3034,14 +3269,14 @@ function updateProjectSettings(projectPath, patch) {
|
|
|
3034
3269
|
const configPath = path9.join(projectPath, "project.config.json");
|
|
3035
3270
|
let config = {};
|
|
3036
3271
|
try {
|
|
3037
|
-
config = JSON.parse(
|
|
3272
|
+
config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
3038
3273
|
} catch {
|
|
3039
3274
|
}
|
|
3040
3275
|
const nextSetting = {
|
|
3041
3276
|
...config.setting ?? {},
|
|
3042
3277
|
...patch.uploadWithSourceMap === void 0 ? {} : { uploadWithSourceMap: patch.uploadWithSourceMap }
|
|
3043
3278
|
};
|
|
3044
|
-
|
|
3279
|
+
fs5.writeFileSync(
|
|
3045
3280
|
configPath,
|
|
3046
3281
|
JSON.stringify({ ...config, setting: nextSetting }, null, 2)
|
|
3047
3282
|
);
|
|
@@ -3216,10 +3451,16 @@ function createWorkspaceService(ctx) {
|
|
|
3216
3451
|
getLastClosedProjectPath: () => lastClosedProjectPath,
|
|
3217
3452
|
hasActiveSession: () => currentSession !== null,
|
|
3218
3453
|
async captureThumbnail(projectPath) {
|
|
3454
|
+
if (!currentSession || projectPath !== currentProjectPath) return null;
|
|
3219
3455
|
const wc = ctx.views.getSimulatorWebContents();
|
|
3220
3456
|
if (!wc) return null;
|
|
3457
|
+
if (ctx.views.getSimulatorProjectPath() !== projectPath) return null;
|
|
3458
|
+
const session5 = currentSession;
|
|
3221
3459
|
try {
|
|
3222
3460
|
const image = await wc.capturePage();
|
|
3461
|
+
if (currentSession !== session5 || currentProjectPath !== projectPath || ctx.views.getSimulatorWebContents() !== wc || ctx.views.getSimulatorProjectPath() !== projectPath) {
|
|
3462
|
+
return null;
|
|
3463
|
+
}
|
|
3223
3464
|
const dataUrl = `data:image/png;base64,${image.toPNG().toString("base64")}`;
|
|
3224
3465
|
if (provider.saveThumbnail) {
|
|
3225
3466
|
await provider.saveThumbnail(projectPath, dataUrl);
|
|
@@ -3253,7 +3494,7 @@ function createWorkspaceService(ctx) {
|
|
|
3253
3494
|
|
|
3254
3495
|
// src/main/services/projects/thumbnail.ts
|
|
3255
3496
|
import { createHash } from "crypto";
|
|
3256
|
-
import
|
|
3497
|
+
import fs6 from "fs";
|
|
3257
3498
|
import path10 from "path";
|
|
3258
3499
|
import { app as app7 } from "electron";
|
|
3259
3500
|
function getThumbnailDir() {
|
|
@@ -3269,13 +3510,13 @@ var DATA_URL_PNG_PREFIX = "data:image/png;base64,";
|
|
|
3269
3510
|
function saveThumbnailFromDataUrl(projectPath, imageDataUrl) {
|
|
3270
3511
|
if (!imageDataUrl.startsWith(DATA_URL_PNG_PREFIX)) return;
|
|
3271
3512
|
const png = Buffer.from(imageDataUrl.slice(DATA_URL_PNG_PREFIX.length), "base64");
|
|
3272
|
-
|
|
3273
|
-
|
|
3513
|
+
fs6.mkdirSync(getThumbnailDir(), { recursive: true });
|
|
3514
|
+
fs6.writeFileSync(getThumbnailPath(projectPath), png);
|
|
3274
3515
|
}
|
|
3275
3516
|
function loadThumbnail(projectPath) {
|
|
3276
3517
|
const filePath = getThumbnailPath(projectPath);
|
|
3277
3518
|
try {
|
|
3278
|
-
const buf =
|
|
3519
|
+
const buf = fs6.readFileSync(filePath);
|
|
3279
3520
|
return `${DATA_URL_PNG_PREFIX}${buf.toString("base64")}`;
|
|
3280
3521
|
} catch {
|
|
3281
3522
|
return null;
|
|
@@ -3635,7 +3876,7 @@ function deviceInfoToHostEnv(d) {
|
|
|
3635
3876
|
function registerSimulatorIpc(ctx) {
|
|
3636
3877
|
return new IpcRegistry(ctx.senderPolicy).handle(SimulatorChannel.AttachNative, (_, ...args) => {
|
|
3637
3878
|
const [simulatorUrl, simWidth] = validate(SimulatorChannel.AttachNative, SimulatorAttachNativeSchema, args);
|
|
3638
|
-
ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
3879
|
+
return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
3639
3880
|
}).handle(SimulatorChannel.Detach, () => {
|
|
3640
3881
|
ctx.views.detachSimulator();
|
|
3641
3882
|
}).handle(SimulatorChannel.SetNativeBounds, (_, ...args) => {
|
|
@@ -3677,7 +3918,7 @@ import { app as app8, dialog } from "electron";
|
|
|
3677
3918
|
import path13 from "path";
|
|
3678
3919
|
|
|
3679
3920
|
// src/main/services/projects/create-project-service.ts
|
|
3680
|
-
import
|
|
3921
|
+
import fs7 from "node:fs";
|
|
3681
3922
|
import path12 from "node:path";
|
|
3682
3923
|
var DEFAULT_TEMPLATE_ID = "blank";
|
|
3683
3924
|
async function createProject(input, ctx) {
|
|
@@ -3689,12 +3930,12 @@ async function createProject(input, ctx) {
|
|
|
3689
3930
|
if (!target || typeof target !== "string") {
|
|
3690
3931
|
throw new Error("Project path is required");
|
|
3691
3932
|
}
|
|
3692
|
-
if (
|
|
3693
|
-
const stat =
|
|
3933
|
+
if (fs7.existsSync(target)) {
|
|
3934
|
+
const stat = fs7.statSync(target);
|
|
3694
3935
|
if (!stat.isDirectory()) {
|
|
3695
3936
|
throw new Error(`Project path exists and is not a directory: ${target}`);
|
|
3696
3937
|
}
|
|
3697
|
-
const entries =
|
|
3938
|
+
const entries = fs7.readdirSync(target);
|
|
3698
3939
|
if (entries.length > 0) {
|
|
3699
3940
|
throw new Error(
|
|
3700
3941
|
`Project path is not empty (refusing to overwrite): ${target}`
|
|
@@ -3711,31 +3952,31 @@ async function createProject(input, ctx) {
|
|
|
3711
3952
|
`Template '${templateId}' has neither a source directory nor a generate function`
|
|
3712
3953
|
);
|
|
3713
3954
|
}
|
|
3714
|
-
|
|
3955
|
+
fs7.mkdirSync(target, { recursive: true });
|
|
3715
3956
|
if (template.generate) {
|
|
3716
3957
|
await template.generate(target, { name });
|
|
3717
3958
|
} else if (template.source) {
|
|
3718
|
-
if (!
|
|
3959
|
+
if (!fs7.existsSync(template.source.path)) {
|
|
3719
3960
|
throw new Error(
|
|
3720
3961
|
`Template source missing on disk: ${template.source.path}`
|
|
3721
3962
|
);
|
|
3722
3963
|
}
|
|
3723
|
-
|
|
3964
|
+
fs7.cpSync(template.source.path, target, {
|
|
3724
3965
|
recursive: true,
|
|
3725
3966
|
force: true
|
|
3726
3967
|
});
|
|
3727
3968
|
}
|
|
3728
3969
|
const cfgPath = path12.join(target, "project.config.json");
|
|
3729
3970
|
let cfg = {};
|
|
3730
|
-
if (
|
|
3971
|
+
if (fs7.existsSync(cfgPath)) {
|
|
3731
3972
|
try {
|
|
3732
|
-
cfg = JSON.parse(
|
|
3973
|
+
cfg = JSON.parse(fs7.readFileSync(cfgPath, "utf-8"));
|
|
3733
3974
|
} catch {
|
|
3734
3975
|
cfg = {};
|
|
3735
3976
|
}
|
|
3736
3977
|
}
|
|
3737
3978
|
cfg.projectname = name;
|
|
3738
|
-
|
|
3979
|
+
fs7.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
|
|
3739
3980
|
const created = await ctx.projectsProvider.addProject(target);
|
|
3740
3981
|
return created;
|
|
3741
3982
|
}
|
|
@@ -3997,7 +4238,7 @@ import { createDebugTap } from "@dimina-kit/electron-deck/main";
|
|
|
3997
4238
|
|
|
3998
4239
|
// src/main/services/dimina-resource-server.ts
|
|
3999
4240
|
import http from "node:http";
|
|
4000
|
-
import
|
|
4241
|
+
import fs8 from "node:fs";
|
|
4001
4242
|
import path14 from "node:path";
|
|
4002
4243
|
var MIME_TYPES = {
|
|
4003
4244
|
".css": "text/css; charset=utf-8",
|
|
@@ -4055,7 +4296,7 @@ async function handleRequest(root, req, res) {
|
|
|
4055
4296
|
return;
|
|
4056
4297
|
}
|
|
4057
4298
|
try {
|
|
4058
|
-
const stat = await
|
|
4299
|
+
const stat = await fs8.promises.stat(filePath);
|
|
4059
4300
|
if (!stat.isFile()) {
|
|
4060
4301
|
res.writeHead(404);
|
|
4061
4302
|
res.end("Not Found");
|
|
@@ -4070,7 +4311,7 @@ async function handleRequest(root, req, res) {
|
|
|
4070
4311
|
res.end();
|
|
4071
4312
|
return;
|
|
4072
4313
|
}
|
|
4073
|
-
|
|
4314
|
+
fs8.createReadStream(filePath).pipe(res);
|
|
4074
4315
|
} catch {
|
|
4075
4316
|
res.writeHead(404);
|
|
4076
4317
|
res.end("Not Found");
|
|
@@ -4120,6 +4361,7 @@ function buildServiceHostSpawnUrl(opts) {
|
|
|
4120
4361
|
url.searchParams.set("appId", opts.appId);
|
|
4121
4362
|
url.searchParams.set("pagePath", opts.pagePath);
|
|
4122
4363
|
url.searchParams.set("pkgRoot", opts.pkgRoot);
|
|
4364
|
+
url.searchParams.set("root", opts.root || "main");
|
|
4123
4365
|
url.searchParams.set("resourceBaseUrl", opts.resourceBaseUrl);
|
|
4124
4366
|
if (opts.hostEnvSnapshot) {
|
|
4125
4367
|
url.searchParams.set("hostEnv", encodeURIComponent(JSON.stringify(opts.hostEnvSnapshot)));
|
|
@@ -5358,7 +5600,8 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5358
5600
|
const appSessionId = bridgeId;
|
|
5359
5601
|
const simulatorWc = resolveSimulatorWebContents(ctx, opts.simulatorWcId, event.sender);
|
|
5360
5602
|
const pagePath = normalizePagePath(opts.pagePath || "pages/index/index");
|
|
5361
|
-
const
|
|
5603
|
+
const workspaceProjectPath = typeof ctx.workspace.getProjectPath === "function" ? ctx.workspace.getProjectPath() : "";
|
|
5604
|
+
const pkgRoot = path16.resolve(opts.pkgRoot || workspaceProjectPath || process.cwd());
|
|
5362
5605
|
const root = opts.root || "main";
|
|
5363
5606
|
let resourceServer = null;
|
|
5364
5607
|
let resourceBaseUrl;
|
|
@@ -5392,6 +5635,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5392
5635
|
appId,
|
|
5393
5636
|
pagePath,
|
|
5394
5637
|
pkgRoot,
|
|
5638
|
+
root,
|
|
5395
5639
|
resourceBaseUrl,
|
|
5396
5640
|
hostEnvSnapshot: hostEnv
|
|
5397
5641
|
});
|
|
@@ -5469,6 +5713,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
5469
5713
|
appId,
|
|
5470
5714
|
pagePath,
|
|
5471
5715
|
pkgRoot,
|
|
5716
|
+
root,
|
|
5472
5717
|
resourceBaseUrl,
|
|
5473
5718
|
hostEnvSnapshot: hostEnv
|
|
5474
5719
|
})
|
|
@@ -5860,13 +6105,13 @@ function makeLoadResource(ap, page, target) {
|
|
|
5860
6105
|
// dimina's service runtime reads hostEnv as `{ systemInfo, menuRect }`
|
|
5861
6106
|
// (core/host-env.js init → getSystemInfo/getMenuRect; invokeAPI resolves
|
|
5862
6107
|
// getSystemInfoSync/getWindowInfo/getDeviceInfo from hostEnv.systemInfo).
|
|
5863
|
-
//
|
|
5864
|
-
// `wx.getSystemInfoSync()`
|
|
5865
|
-
// `.screenWidth`
|
|
5866
|
-
//
|
|
5867
|
-
//
|
|
5868
|
-
// menuRect stays null
|
|
5869
|
-
//
|
|
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.
|
|
5870
6115
|
hostEnv: { systemInfo: ap.hostEnv, menuRect: null }
|
|
5871
6116
|
}
|
|
5872
6117
|
};
|
|
@@ -8096,7 +8341,7 @@ var AppDataAccumulator = class {
|
|
|
8096
8341
|
}
|
|
8097
8342
|
/**
|
|
8098
8343
|
* Apply one entry. Returns true if it was accepted (a mutation worth
|
|
8099
|
-
* republishing), false if dropped (missing ids, or the
|
|
8344
|
+
* republishing), false if dropped (missing ids, or the init-gate).
|
|
8100
8345
|
*/
|
|
8101
8346
|
apply(input) {
|
|
8102
8347
|
if (!input.bridgeId || !input.moduleId) return false;
|
|
@@ -8379,7 +8624,7 @@ function resolveVPath(url) {
|
|
|
8379
8624
|
}
|
|
8380
8625
|
|
|
8381
8626
|
// src/main/services/simulator-temp-files/disk.ts
|
|
8382
|
-
import
|
|
8627
|
+
import fs9 from "node:fs/promises";
|
|
8383
8628
|
import path19 from "node:path";
|
|
8384
8629
|
var EXT_MIME = {
|
|
8385
8630
|
".txt": "text/plain",
|
|
@@ -8460,7 +8705,7 @@ function etagOf(mtimeMs, size) {
|
|
|
8460
8705
|
return `W/"${Math.floor(mtimeMs)}-${size}"`;
|
|
8461
8706
|
}
|
|
8462
8707
|
async function readDiskFile(realPath, opts) {
|
|
8463
|
-
const handle = await
|
|
8708
|
+
const handle = await fs9.open(realPath, "r");
|
|
8464
8709
|
try {
|
|
8465
8710
|
const st = await handle.stat();
|
|
8466
8711
|
const totalSize = st.size;
|
|
@@ -8515,15 +8760,15 @@ async function readDiskFile(realPath, opts) {
|
|
|
8515
8760
|
}
|
|
8516
8761
|
async function writeDiskFile(realPath, bytes) {
|
|
8517
8762
|
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
|
|
8518
|
-
await
|
|
8519
|
-
await
|
|
8763
|
+
await fs9.mkdir(path19.dirname(realPath), { recursive: true });
|
|
8764
|
+
await fs9.writeFile(realPath, buf);
|
|
8520
8765
|
}
|
|
8521
8766
|
async function readDiskDir(realPath) {
|
|
8522
|
-
const entries = await
|
|
8767
|
+
const entries = await fs9.readdir(realPath);
|
|
8523
8768
|
return entries;
|
|
8524
8769
|
}
|
|
8525
8770
|
async function statDiskFile(realPath) {
|
|
8526
|
-
const st = await
|
|
8771
|
+
const st = await fs9.stat(realPath);
|
|
8527
8772
|
return {
|
|
8528
8773
|
size: st.size,
|
|
8529
8774
|
mtime: Math.floor(st.mtimeMs),
|
|
@@ -8656,14 +8901,14 @@ async function handleDifileRequest(ctx, req) {
|
|
|
8656
8901
|
}
|
|
8657
8902
|
|
|
8658
8903
|
// src/main/services/simulator-temp-files/fs-channels.ts
|
|
8659
|
-
import
|
|
8904
|
+
import fs10 from "node:fs/promises";
|
|
8660
8905
|
import path20 from "node:path";
|
|
8661
8906
|
async function enforceSandbox(realPath) {
|
|
8662
8907
|
if (typeof realPath !== "string" || realPath.length === 0) {
|
|
8663
8908
|
throw new Error("sandbox: realPath must be a non-empty string");
|
|
8664
8909
|
}
|
|
8665
8910
|
const base = sandboxBase();
|
|
8666
|
-
const baseReal = await
|
|
8911
|
+
const baseReal = await fs10.realpath(base).catch(() => base);
|
|
8667
8912
|
const normalized = path20.normalize(realPath);
|
|
8668
8913
|
if (normalized !== base && !normalized.startsWith(base + path20.sep)) {
|
|
8669
8914
|
throw new Error("sandbox: realPath escapes the user-data base");
|
|
@@ -8671,7 +8916,7 @@ async function enforceSandbox(realPath) {
|
|
|
8671
8916
|
let probe = normalized;
|
|
8672
8917
|
while (probe !== path20.parse(probe).root) {
|
|
8673
8918
|
try {
|
|
8674
|
-
const resolved = await
|
|
8919
|
+
const resolved = await fs10.realpath(probe);
|
|
8675
8920
|
if (resolved !== baseReal && !resolved.startsWith(baseReal + path20.sep)) {
|
|
8676
8921
|
throw new Error("sandbox: realPath escapes the user-data base via symlink");
|
|
8677
8922
|
}
|
|
@@ -8711,12 +8956,12 @@ async function handleFsReaddir(req) {
|
|
|
8711
8956
|
}
|
|
8712
8957
|
async function handleFsUnlink(req) {
|
|
8713
8958
|
const safe = await enforceSandbox(req.realPath);
|
|
8714
|
-
await
|
|
8959
|
+
await fs10.unlink(safe);
|
|
8715
8960
|
return { ok: true };
|
|
8716
8961
|
}
|
|
8717
8962
|
async function handleFsMkdir(req) {
|
|
8718
8963
|
const safe = await enforceSandbox(req.realPath);
|
|
8719
|
-
await
|
|
8964
|
+
await fs10.mkdir(safe, { recursive: !!req.recursive });
|
|
8720
8965
|
return { ok: true };
|
|
8721
8966
|
}
|
|
8722
8967
|
|
|
@@ -9149,9 +9394,12 @@ function wireAppWindowEvents(config, instance) {
|
|
|
9149
9394
|
onResize: () => context.views.repositionAll(),
|
|
9150
9395
|
onClose: async (e) => {
|
|
9151
9396
|
if (isAppQuitting()) return;
|
|
9397
|
+
if (closing) {
|
|
9398
|
+
e.preventDefault();
|
|
9399
|
+
return;
|
|
9400
|
+
}
|
|
9152
9401
|
if (!context.workspace.hasActiveSession()) return;
|
|
9153
9402
|
e.preventDefault();
|
|
9154
|
-
if (closing) return;
|
|
9155
9403
|
closing = true;
|
|
9156
9404
|
try {
|
|
9157
9405
|
if (config.onBeforeClose) {
|
|
@@ -9171,7 +9419,7 @@ function enableDevRendererAutoReload(rendererDir2) {
|
|
|
9171
9419
|
});
|
|
9172
9420
|
}
|
|
9173
9421
|
let reloadTimer = null;
|
|
9174
|
-
const watcher =
|
|
9422
|
+
const watcher = fs11.watch(rendererDir2, { recursive: true }, () => {
|
|
9175
9423
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
9176
9424
|
reloadTimer = setTimeout(() => {
|
|
9177
9425
|
for (const win of BrowserWindow8.getAllWindows()) {
|