@dimina-kit/devtools 0.3.2-dev.20260524104239 → 0.3.2-dev.20260525152421
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main/app/app.js +13 -2
- package/dist/main/app/bootstrap.d.ts +9 -0
- package/dist/main/app/bootstrap.js +28 -1
- package/dist/main/index.bundle.js +570 -20
- package/dist/main/services/simulator-temp-files/disk.d.ts +55 -0
- package/dist/main/services/simulator-temp-files/disk.js +215 -0
- package/dist/main/services/simulator-temp-files/fs-channels.d.ts +69 -0
- package/dist/main/services/simulator-temp-files/fs-channels.js +108 -0
- package/dist/main/services/simulator-temp-files/index.d.ts +33 -0
- package/dist/main/services/simulator-temp-files/index.js +160 -0
- package/dist/main/services/simulator-temp-files/request-handler.d.ts +30 -0
- package/dist/main/services/simulator-temp-files/request-handler.js +178 -0
- package/dist/main/services/simulator-temp-files/resolver.d.ts +22 -0
- package/dist/main/services/simulator-temp-files/resolver.js +22 -0
- package/dist/main/services/simulator-temp-files/store.d.ts +14 -0
- package/dist/main/services/simulator-temp-files/store.js +24 -0
- package/dist/preload/runtime/temp-files.d.ts +8 -0
- package/dist/preload/runtime/temp-files.js +34 -0
- package/dist/preload/windows/simulator.js +38 -6
- package/dist/simulator/assets/simulator-CVOFTpSj.js +9 -0
- package/dist/simulator/simulator.html +1 -1
- package/package.json +4 -4
- package/dist/simulator/assets/simulator-DDRBJ6Wa.js +0 -9
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/main/app/bootstrap.ts
|
|
2
|
-
import { app as app2 } from "electron";
|
|
9
|
+
import { app as app2, protocol } from "electron";
|
|
3
10
|
|
|
4
11
|
// src/shared/constants.ts
|
|
5
12
|
var DEFAULT_CDP_PORT = 9222;
|
|
@@ -63,6 +70,24 @@ function applyTheme(theme) {
|
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
// src/main/app/bootstrap.ts
|
|
73
|
+
var difileSchemeRegistered = false;
|
|
74
|
+
function registerDifileScheme() {
|
|
75
|
+
if (difileSchemeRegistered) return;
|
|
76
|
+
difileSchemeRegistered = true;
|
|
77
|
+
protocol.registerSchemesAsPrivileged([
|
|
78
|
+
{
|
|
79
|
+
scheme: "difile",
|
|
80
|
+
privileges: {
|
|
81
|
+
standard: true,
|
|
82
|
+
secure: true,
|
|
83
|
+
supportFetchAPI: true,
|
|
84
|
+
stream: true,
|
|
85
|
+
bypassCSP: true,
|
|
86
|
+
corsEnabled: true
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
66
91
|
function setupCdpPort() {
|
|
67
92
|
if (app2.commandLine.getSwitchValue("remote-debugging-port")) return;
|
|
68
93
|
const envPort = process.env.DIMINA_DEBUG_PORT;
|
|
@@ -79,9 +104,9 @@ function setupCdpPort() {
|
|
|
79
104
|
}
|
|
80
105
|
|
|
81
106
|
// src/main/app/app.ts
|
|
82
|
-
import { app as app13, BrowserWindow as BrowserWindow4, nativeImage } from "electron";
|
|
83
|
-
import
|
|
84
|
-
import
|
|
107
|
+
import { app as app13, BrowserWindow as BrowserWindow4, nativeImage, session as session2 } from "electron";
|
|
108
|
+
import fs9 from "fs";
|
|
109
|
+
import path14 from "path";
|
|
85
110
|
|
|
86
111
|
// src/main/utils/paths.ts
|
|
87
112
|
import fs2 from "fs";
|
|
@@ -1094,11 +1119,11 @@ function createWorkspaceService(ctx) {
|
|
|
1094
1119
|
}
|
|
1095
1120
|
async function disposeSession() {
|
|
1096
1121
|
if (!currentSession) return;
|
|
1097
|
-
const
|
|
1122
|
+
const session3 = currentSession;
|
|
1098
1123
|
currentSession = null;
|
|
1099
1124
|
try {
|
|
1100
1125
|
await Promise.race([
|
|
1101
|
-
|
|
1126
|
+
session3.close(),
|
|
1102
1127
|
new Promise(
|
|
1103
1128
|
(_, reject) => setTimeout(() => reject(new Error("session close timed out")), 5e3)
|
|
1104
1129
|
)
|
|
@@ -1107,8 +1132,8 @@ function createWorkspaceService(ctx) {
|
|
|
1107
1132
|
console.error("[workspace] session close failed:", err);
|
|
1108
1133
|
}
|
|
1109
1134
|
}
|
|
1110
|
-
function applyRefererFromSession(
|
|
1111
|
-
const appInfo =
|
|
1135
|
+
function applyRefererFromSession(session3) {
|
|
1136
|
+
const appInfo = session3.appInfo;
|
|
1112
1137
|
if (appInfo && typeof appInfo.appId === "string" && appInfo.appId.length > 0) {
|
|
1113
1138
|
setSimulatorServicewechatReferer(
|
|
1114
1139
|
appInfo.appId,
|
|
@@ -1139,9 +1164,9 @@ function createWorkspaceService(ctx) {
|
|
|
1139
1164
|
}
|
|
1140
1165
|
sendStatus("compiling", "\u6B63\u5728\u7F16\u8BD1...");
|
|
1141
1166
|
const { compile } = loadWorkbenchSettings();
|
|
1142
|
-
let
|
|
1167
|
+
let session3;
|
|
1143
1168
|
try {
|
|
1144
|
-
|
|
1169
|
+
session3 = await ctx.adapter.openProject({
|
|
1145
1170
|
projectPath,
|
|
1146
1171
|
sourcemap: true,
|
|
1147
1172
|
watch: compile.watch,
|
|
@@ -1153,17 +1178,17 @@ function createWorkspaceService(ctx) {
|
|
|
1153
1178
|
sendStatus("error", String(err));
|
|
1154
1179
|
return { success: false, error: String(err) };
|
|
1155
1180
|
}
|
|
1156
|
-
currentSession =
|
|
1181
|
+
currentSession = session3;
|
|
1157
1182
|
currentProjectPath = projectPath;
|
|
1158
1183
|
bestEffort("updateLastOpened", () => {
|
|
1159
1184
|
if (provider.updateLastOpened) provider.updateLastOpened(projectPath);
|
|
1160
1185
|
});
|
|
1161
1186
|
bestEffort("sendStatus", () => sendStatus("ready", "\u7F16\u8BD1\u5B8C\u6210"));
|
|
1162
|
-
bestEffort("applyReferer", () => applyRefererFromSession(
|
|
1187
|
+
bestEffort("applyReferer", () => applyRefererFromSession(session3));
|
|
1163
1188
|
return {
|
|
1164
1189
|
success: true,
|
|
1165
|
-
port:
|
|
1166
|
-
appInfo:
|
|
1190
|
+
port: session3.port,
|
|
1191
|
+
appInfo: session3.appInfo
|
|
1167
1192
|
};
|
|
1168
1193
|
},
|
|
1169
1194
|
async closeProject() {
|
|
@@ -3532,6 +3557,528 @@ async function clearElementInspection() {
|
|
|
3532
3557
|
}
|
|
3533
3558
|
}
|
|
3534
3559
|
|
|
3560
|
+
// src/main/services/simulator-temp-files/store.ts
|
|
3561
|
+
function registerTempFile(store, path16, mime, bytes) {
|
|
3562
|
+
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
|
|
3563
|
+
store.delete(path16);
|
|
3564
|
+
store.set(path16, { bytes: buf, mime });
|
|
3565
|
+
}
|
|
3566
|
+
function revokeTempFile(store, path16) {
|
|
3567
|
+
store.delete(path16);
|
|
3568
|
+
}
|
|
3569
|
+
function revokeAllTempFiles(store) {
|
|
3570
|
+
store.clear();
|
|
3571
|
+
}
|
|
3572
|
+
|
|
3573
|
+
// src/simulator/vpath.ts
|
|
3574
|
+
var _os = typeof __require !== "undefined" ? __require("os") : null;
|
|
3575
|
+
var _path = typeof __require !== "undefined" ? __require("path") : null;
|
|
3576
|
+
var DIFILE_PREFIX = "difile://";
|
|
3577
|
+
function sandboxBase() {
|
|
3578
|
+
const env = typeof process !== "undefined" && process.env && process.env.DIMINA_HOME || "";
|
|
3579
|
+
if (env) {
|
|
3580
|
+
return _path.join(env, "files");
|
|
3581
|
+
}
|
|
3582
|
+
const home = _os ? _os.homedir() : "/tmp";
|
|
3583
|
+
return _path.join(home, ".dimina", "files");
|
|
3584
|
+
}
|
|
3585
|
+
function resolveVPath(url) {
|
|
3586
|
+
if (typeof url !== "string") return null;
|
|
3587
|
+
if (!url.startsWith(DIFILE_PREFIX)) return null;
|
|
3588
|
+
const raw = url.slice(DIFILE_PREFIX.length);
|
|
3589
|
+
if (raw.length === 0) return null;
|
|
3590
|
+
let decoded;
|
|
3591
|
+
try {
|
|
3592
|
+
decoded = decodeURIComponent(raw);
|
|
3593
|
+
} catch {
|
|
3594
|
+
return null;
|
|
3595
|
+
}
|
|
3596
|
+
if (decoded.includes("\0")) return null;
|
|
3597
|
+
decoded = decoded.replace(/^[/\\]+/, "");
|
|
3598
|
+
if (decoded.length === 0) return null;
|
|
3599
|
+
const segments = decoded.split(/[/\\]+/);
|
|
3600
|
+
if (segments.some((s) => s === ".." || s === ".")) return null;
|
|
3601
|
+
let kind;
|
|
3602
|
+
let writable;
|
|
3603
|
+
if (decoded.startsWith("_tmp/")) {
|
|
3604
|
+
kind = "tmp";
|
|
3605
|
+
writable = false;
|
|
3606
|
+
} else if (decoded.startsWith("_store/")) {
|
|
3607
|
+
kind = "store";
|
|
3608
|
+
writable = false;
|
|
3609
|
+
} else {
|
|
3610
|
+
kind = "usr";
|
|
3611
|
+
writable = true;
|
|
3612
|
+
}
|
|
3613
|
+
if (kind === "tmp") {
|
|
3614
|
+
return { kind, writable };
|
|
3615
|
+
}
|
|
3616
|
+
const base = sandboxBase();
|
|
3617
|
+
const joined = _path.join(base, decoded);
|
|
3618
|
+
const normalized = _path.normalize(joined);
|
|
3619
|
+
if (normalized !== base && !normalized.startsWith(base + _path.sep)) return null;
|
|
3620
|
+
return { kind, writable, realPath: normalized };
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
// src/main/services/simulator-temp-files/disk.ts
|
|
3624
|
+
import fs7 from "node:fs/promises";
|
|
3625
|
+
import path12 from "node:path";
|
|
3626
|
+
var EXT_MIME = {
|
|
3627
|
+
".txt": "text/plain",
|
|
3628
|
+
".log": "text/plain",
|
|
3629
|
+
".md": "text/markdown",
|
|
3630
|
+
".html": "text/html",
|
|
3631
|
+
".htm": "text/html",
|
|
3632
|
+
".css": "text/css",
|
|
3633
|
+
".csv": "text/csv",
|
|
3634
|
+
".json": "application/json",
|
|
3635
|
+
".xml": "application/xml",
|
|
3636
|
+
".js": "application/javascript",
|
|
3637
|
+
".mjs": "application/javascript",
|
|
3638
|
+
".svg": "image/svg+xml",
|
|
3639
|
+
".png": "image/png",
|
|
3640
|
+
".jpg": "image/jpeg",
|
|
3641
|
+
".jpeg": "image/jpeg",
|
|
3642
|
+
".gif": "image/gif",
|
|
3643
|
+
".webp": "image/webp",
|
|
3644
|
+
".bmp": "image/bmp",
|
|
3645
|
+
".ico": "image/x-icon",
|
|
3646
|
+
".mp4": "video/mp4",
|
|
3647
|
+
".m4v": "video/mp4",
|
|
3648
|
+
".webm": "video/webm",
|
|
3649
|
+
".mov": "video/quicktime",
|
|
3650
|
+
".mp3": "audio/mpeg",
|
|
3651
|
+
".wav": "audio/wav",
|
|
3652
|
+
".ogg": "audio/ogg",
|
|
3653
|
+
".pdf": "application/pdf",
|
|
3654
|
+
".zip": "application/zip"
|
|
3655
|
+
};
|
|
3656
|
+
function sniffMime(head) {
|
|
3657
|
+
if (head.length >= 8 && head[0] === 137 && head[1] === 80 && head[2] === 78 && head[3] === 71 && head[4] === 13 && head[5] === 10 && head[6] === 26 && head[7] === 10) {
|
|
3658
|
+
return "image/png";
|
|
3659
|
+
}
|
|
3660
|
+
if (head.length >= 3 && head[0] === 255 && head[1] === 216 && head[2] === 255) {
|
|
3661
|
+
return "image/jpeg";
|
|
3662
|
+
}
|
|
3663
|
+
if (head.length >= 6 && head[0] === 71 && head[1] === 73 && head[2] === 70 && head[3] === 56 && (head[4] === 55 || head[4] === 57) && head[5] === 97) {
|
|
3664
|
+
return "image/gif";
|
|
3665
|
+
}
|
|
3666
|
+
if (head.length >= 12 && head[0] === 82 && head[1] === 73 && head[2] === 70 && head[3] === 70 && head[8] === 87 && head[9] === 69 && head[10] === 66 && head[11] === 80) {
|
|
3667
|
+
return "image/webp";
|
|
3668
|
+
}
|
|
3669
|
+
if (head.length >= 12 && head[4] === 102 && head[5] === 116 && head[6] === 121 && head[7] === 112) {
|
|
3670
|
+
return "video/mp4";
|
|
3671
|
+
}
|
|
3672
|
+
if (head.length >= 4 && head[0] === 37 && head[1] === 80 && head[2] === 68 && head[3] === 70) {
|
|
3673
|
+
return "application/pdf";
|
|
3674
|
+
}
|
|
3675
|
+
if (head.length >= 2 && head[0] === 66 && head[1] === 77) {
|
|
3676
|
+
return "image/bmp";
|
|
3677
|
+
}
|
|
3678
|
+
if (head.length >= 4 && head[0] === 80 && head[1] === 75 && head[2] === 3 && head[3] === 4) {
|
|
3679
|
+
return "application/zip";
|
|
3680
|
+
}
|
|
3681
|
+
if (head.length >= 3 && head[0] === 73 && head[1] === 68 && head[2] === 51) {
|
|
3682
|
+
return "audio/mpeg";
|
|
3683
|
+
}
|
|
3684
|
+
if (head.length >= 4 && head[0] === 79 && head[1] === 103 && head[2] === 103 && head[3] === 83) {
|
|
3685
|
+
return "audio/ogg";
|
|
3686
|
+
}
|
|
3687
|
+
return null;
|
|
3688
|
+
}
|
|
3689
|
+
function extMime(realPath) {
|
|
3690
|
+
const ext = path12.extname(realPath).toLowerCase();
|
|
3691
|
+
if (!ext) return null;
|
|
3692
|
+
return EXT_MIME[ext] ?? null;
|
|
3693
|
+
}
|
|
3694
|
+
function detectMime(realPath, head) {
|
|
3695
|
+
const sniffed = sniffMime(head);
|
|
3696
|
+
if (sniffed) return sniffed;
|
|
3697
|
+
const byExt = extMime(realPath);
|
|
3698
|
+
if (byExt) return byExt;
|
|
3699
|
+
return "application/octet-stream";
|
|
3700
|
+
}
|
|
3701
|
+
function etagOf(mtimeMs, size) {
|
|
3702
|
+
return `W/"${Math.floor(mtimeMs)}-${size}"`;
|
|
3703
|
+
}
|
|
3704
|
+
async function readDiskFile(realPath, opts) {
|
|
3705
|
+
const handle = await fs7.open(realPath, "r");
|
|
3706
|
+
try {
|
|
3707
|
+
const st = await handle.stat();
|
|
3708
|
+
const totalSize = st.size;
|
|
3709
|
+
const mtimeMs = st.mtimeMs;
|
|
3710
|
+
const range = opts?.range;
|
|
3711
|
+
let sliceStart = 0;
|
|
3712
|
+
let sliceLen = totalSize;
|
|
3713
|
+
if (range) {
|
|
3714
|
+
const { start, end } = range;
|
|
3715
|
+
if (!Number.isFinite(start) || !Number.isFinite(end)) {
|
|
3716
|
+
throw new RangeError(`invalid range: ${start}-${end}`);
|
|
3717
|
+
}
|
|
3718
|
+
if (start < 0) throw new RangeError(`range start out of bounds: ${start}`);
|
|
3719
|
+
if (start > end) throw new RangeError(`range start > end: ${start} > ${end}`);
|
|
3720
|
+
if (start >= totalSize) {
|
|
3721
|
+
throw new RangeError(`range start beyond file size: ${start} >= ${totalSize}`);
|
|
3722
|
+
}
|
|
3723
|
+
const clampedEnd = Math.min(end, totalSize - 1);
|
|
3724
|
+
sliceStart = start;
|
|
3725
|
+
sliceLen = clampedEnd - start + 1;
|
|
3726
|
+
}
|
|
3727
|
+
const head = Buffer.alloc(Math.min(12, totalSize));
|
|
3728
|
+
if (head.length > 0) {
|
|
3729
|
+
await handle.read(head, 0, head.length, 0);
|
|
3730
|
+
}
|
|
3731
|
+
let bytes;
|
|
3732
|
+
if (!range) {
|
|
3733
|
+
bytes = Buffer.alloc(totalSize);
|
|
3734
|
+
if (totalSize > 0) {
|
|
3735
|
+
if (totalSize <= head.length) {
|
|
3736
|
+
head.copy(bytes, 0, 0, totalSize);
|
|
3737
|
+
} else {
|
|
3738
|
+
head.copy(bytes, 0, 0, head.length);
|
|
3739
|
+
await handle.read(bytes, head.length, totalSize - head.length, head.length);
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
} else {
|
|
3743
|
+
bytes = Buffer.alloc(sliceLen);
|
|
3744
|
+
if (sliceLen > 0) {
|
|
3745
|
+
await handle.read(bytes, 0, sliceLen, sliceStart);
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
return {
|
|
3749
|
+
bytes,
|
|
3750
|
+
mime: detectMime(realPath, head),
|
|
3751
|
+
etag: etagOf(mtimeMs, totalSize),
|
|
3752
|
+
totalSize
|
|
3753
|
+
};
|
|
3754
|
+
} finally {
|
|
3755
|
+
await handle.close();
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
async function writeDiskFile(realPath, bytes) {
|
|
3759
|
+
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
|
|
3760
|
+
await fs7.mkdir(path12.dirname(realPath), { recursive: true });
|
|
3761
|
+
await fs7.writeFile(realPath, buf);
|
|
3762
|
+
}
|
|
3763
|
+
async function readDiskDir(realPath) {
|
|
3764
|
+
const entries = await fs7.readdir(realPath);
|
|
3765
|
+
return entries;
|
|
3766
|
+
}
|
|
3767
|
+
async function statDiskFile(realPath) {
|
|
3768
|
+
const st = await fs7.stat(realPath);
|
|
3769
|
+
return {
|
|
3770
|
+
size: st.size,
|
|
3771
|
+
mtime: Math.floor(st.mtimeMs),
|
|
3772
|
+
mode: st.mode,
|
|
3773
|
+
isFile: st.isFile(),
|
|
3774
|
+
isDirectory: st.isDirectory()
|
|
3775
|
+
};
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
// src/main/services/simulator-temp-files/request-handler.ts
|
|
3779
|
+
var CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
3780
|
+
function getHeader(headers, name) {
|
|
3781
|
+
if (!headers) return void 0;
|
|
3782
|
+
const lc = name.toLowerCase();
|
|
3783
|
+
for (const k of Object.keys(headers)) {
|
|
3784
|
+
if (k.toLowerCase() === lc) return headers[k];
|
|
3785
|
+
}
|
|
3786
|
+
return void 0;
|
|
3787
|
+
}
|
|
3788
|
+
function etagsMatch(a, b) {
|
|
3789
|
+
if (!a) return false;
|
|
3790
|
+
const stripped = (s) => s.startsWith("W/") ? s.slice(2) : s;
|
|
3791
|
+
return stripped(a.trim()) === stripped(b);
|
|
3792
|
+
}
|
|
3793
|
+
function parseRange(header, totalSize) {
|
|
3794
|
+
if (!header) return null;
|
|
3795
|
+
const m = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
|
|
3796
|
+
if (!m) return null;
|
|
3797
|
+
const startStr = m[1];
|
|
3798
|
+
const endStr = m[2];
|
|
3799
|
+
if (startStr === "" && endStr === "") return null;
|
|
3800
|
+
if (startStr === "") {
|
|
3801
|
+
const n = Number(endStr);
|
|
3802
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
3803
|
+
const start2 = Math.max(0, totalSize - n);
|
|
3804
|
+
return { start: start2, end: totalSize - 1 };
|
|
3805
|
+
}
|
|
3806
|
+
const start = Number(startStr);
|
|
3807
|
+
if (!Number.isFinite(start) || start < 0) return null;
|
|
3808
|
+
const end = endStr === "" ? totalSize - 1 : Number(endStr);
|
|
3809
|
+
if (!Number.isFinite(end)) return null;
|
|
3810
|
+
return { start, end };
|
|
3811
|
+
}
|
|
3812
|
+
function notFound() {
|
|
3813
|
+
return new Response(null, { status: 404 });
|
|
3814
|
+
}
|
|
3815
|
+
function notModified(etag) {
|
|
3816
|
+
return new Response(null, {
|
|
3817
|
+
status: 304,
|
|
3818
|
+
headers: {
|
|
3819
|
+
ETag: etag,
|
|
3820
|
+
"Cache-Control": CACHE_CONTROL,
|
|
3821
|
+
"Access-Control-Allow-Origin": "*"
|
|
3822
|
+
}
|
|
3823
|
+
});
|
|
3824
|
+
}
|
|
3825
|
+
function bufferToBody(bytes) {
|
|
3826
|
+
const out = new ArrayBuffer(bytes.byteLength);
|
|
3827
|
+
new Uint8Array(out).set(bytes);
|
|
3828
|
+
return out;
|
|
3829
|
+
}
|
|
3830
|
+
function tempBody(bytes, mime) {
|
|
3831
|
+
return new Response(bufferToBody(bytes), {
|
|
3832
|
+
status: 200,
|
|
3833
|
+
headers: {
|
|
3834
|
+
"Content-Type": mime,
|
|
3835
|
+
"Cache-Control": CACHE_CONTROL,
|
|
3836
|
+
"Access-Control-Allow-Origin": "*"
|
|
3837
|
+
}
|
|
3838
|
+
});
|
|
3839
|
+
}
|
|
3840
|
+
async function handleDifileRequest(ctx, req) {
|
|
3841
|
+
const v = resolveVPath(req.url);
|
|
3842
|
+
if (!v) return notFound();
|
|
3843
|
+
if (v.kind === "tmp") {
|
|
3844
|
+
const record = ctx.tempStore.get(req.url);
|
|
3845
|
+
if (!record) return notFound();
|
|
3846
|
+
return tempBody(record.bytes, record.mime || "application/octet-stream");
|
|
3847
|
+
}
|
|
3848
|
+
if (!v.realPath) return notFound();
|
|
3849
|
+
try {
|
|
3850
|
+
const probe = await readDiskFile(v.realPath);
|
|
3851
|
+
const etag = probe.etag;
|
|
3852
|
+
const totalSize = probe.totalSize;
|
|
3853
|
+
const mime = probe.mime;
|
|
3854
|
+
const ifNoneMatch = getHeader(req.headers, "If-None-Match");
|
|
3855
|
+
if (etagsMatch(ifNoneMatch, etag)) {
|
|
3856
|
+
return notModified(etag);
|
|
3857
|
+
}
|
|
3858
|
+
const rangeHeader = getHeader(req.headers, "Range");
|
|
3859
|
+
const range = parseRange(rangeHeader, totalSize);
|
|
3860
|
+
if (range) {
|
|
3861
|
+
if (range.start < 0 || range.start >= totalSize || range.end < range.start) {
|
|
3862
|
+
return new Response(null, {
|
|
3863
|
+
status: 416,
|
|
3864
|
+
headers: {
|
|
3865
|
+
"Content-Range": `bytes */${totalSize}`,
|
|
3866
|
+
"Access-Control-Allow-Origin": "*"
|
|
3867
|
+
}
|
|
3868
|
+
});
|
|
3869
|
+
}
|
|
3870
|
+
const clampedEnd = Math.min(range.end, totalSize - 1);
|
|
3871
|
+
const sliced = await readDiskFile(v.realPath, { range: { start: range.start, end: clampedEnd } });
|
|
3872
|
+
const { bytes } = sliced;
|
|
3873
|
+
const lastByte = range.start + bytes.length - 1;
|
|
3874
|
+
return new Response(bufferToBody(bytes), {
|
|
3875
|
+
status: 206,
|
|
3876
|
+
headers: {
|
|
3877
|
+
"Content-Type": mime,
|
|
3878
|
+
"Content-Length": String(bytes.length),
|
|
3879
|
+
"Content-Range": `bytes ${range.start}-${lastByte}/${totalSize}`,
|
|
3880
|
+
"Cache-Control": CACHE_CONTROL,
|
|
3881
|
+
ETag: etag,
|
|
3882
|
+
"Access-Control-Allow-Origin": "*"
|
|
3883
|
+
}
|
|
3884
|
+
});
|
|
3885
|
+
}
|
|
3886
|
+
return new Response(bufferToBody(probe.bytes), {
|
|
3887
|
+
status: 200,
|
|
3888
|
+
headers: {
|
|
3889
|
+
"Content-Type": mime,
|
|
3890
|
+
"Cache-Control": CACHE_CONTROL,
|
|
3891
|
+
ETag: etag,
|
|
3892
|
+
"Access-Control-Allow-Origin": "*"
|
|
3893
|
+
}
|
|
3894
|
+
});
|
|
3895
|
+
} catch {
|
|
3896
|
+
return notFound();
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
// src/main/services/simulator-temp-files/fs-channels.ts
|
|
3901
|
+
import fs8 from "node:fs/promises";
|
|
3902
|
+
import path13 from "node:path";
|
|
3903
|
+
async function enforceSandbox(realPath) {
|
|
3904
|
+
if (typeof realPath !== "string" || realPath.length === 0) {
|
|
3905
|
+
throw new Error("sandbox: realPath must be a non-empty string");
|
|
3906
|
+
}
|
|
3907
|
+
const base = sandboxBase();
|
|
3908
|
+
const baseReal = await fs8.realpath(base).catch(() => base);
|
|
3909
|
+
const normalized = path13.normalize(realPath);
|
|
3910
|
+
if (normalized !== base && !normalized.startsWith(base + path13.sep)) {
|
|
3911
|
+
throw new Error("sandbox: realPath escapes the user-data base");
|
|
3912
|
+
}
|
|
3913
|
+
let probe = normalized;
|
|
3914
|
+
while (probe !== path13.parse(probe).root) {
|
|
3915
|
+
try {
|
|
3916
|
+
const resolved = await fs8.realpath(probe);
|
|
3917
|
+
if (resolved !== baseReal && !resolved.startsWith(baseReal + path13.sep)) {
|
|
3918
|
+
throw new Error("sandbox: realPath escapes the user-data base via symlink");
|
|
3919
|
+
}
|
|
3920
|
+
break;
|
|
3921
|
+
} catch (err) {
|
|
3922
|
+
if (err.code === "ENOENT") {
|
|
3923
|
+
probe = path13.dirname(probe);
|
|
3924
|
+
continue;
|
|
3925
|
+
}
|
|
3926
|
+
throw err;
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
return normalized;
|
|
3930
|
+
}
|
|
3931
|
+
async function handleFsRead(req) {
|
|
3932
|
+
const safe = await enforceSandbox(req.realPath);
|
|
3933
|
+
const result = await readDiskFile(safe, req.range ? { range: req.range } : void 0);
|
|
3934
|
+
return {
|
|
3935
|
+
bytes: result.bytes,
|
|
3936
|
+
mime: result.mime,
|
|
3937
|
+
etag: result.etag,
|
|
3938
|
+
totalSize: result.totalSize
|
|
3939
|
+
};
|
|
3940
|
+
}
|
|
3941
|
+
async function handleFsWrite(req) {
|
|
3942
|
+
const safe = await enforceSandbox(req.realPath);
|
|
3943
|
+
await writeDiskFile(safe, req.bytes);
|
|
3944
|
+
return { ok: true };
|
|
3945
|
+
}
|
|
3946
|
+
async function handleFsStat(req) {
|
|
3947
|
+
const safe = await enforceSandbox(req.realPath);
|
|
3948
|
+
return statDiskFile(safe);
|
|
3949
|
+
}
|
|
3950
|
+
async function handleFsReaddir(req) {
|
|
3951
|
+
const safe = await enforceSandbox(req.realPath);
|
|
3952
|
+
return readDiskDir(safe);
|
|
3953
|
+
}
|
|
3954
|
+
async function handleFsUnlink(req) {
|
|
3955
|
+
const safe = await enforceSandbox(req.realPath);
|
|
3956
|
+
await fs8.unlink(safe);
|
|
3957
|
+
return { ok: true };
|
|
3958
|
+
}
|
|
3959
|
+
async function handleFsMkdir(req) {
|
|
3960
|
+
const safe = await enforceSandbox(req.realPath);
|
|
3961
|
+
await fs8.mkdir(safe, { recursive: !!req.recursive });
|
|
3962
|
+
return { ok: true };
|
|
3963
|
+
}
|
|
3964
|
+
|
|
3965
|
+
// src/main/services/simulator-temp-files/index.ts
|
|
3966
|
+
var MAX_STORE_ENTRIES = 200;
|
|
3967
|
+
var PENDING_TIMEOUT_MS = 500;
|
|
3968
|
+
function enforceStoreCap(store) {
|
|
3969
|
+
while (store.size > MAX_STORE_ENTRIES) {
|
|
3970
|
+
const next = store.keys().next();
|
|
3971
|
+
if (next.done) break;
|
|
3972
|
+
store.delete(next.value);
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
function setupSimulatorTempFiles(simSession) {
|
|
3976
|
+
const store = /* @__PURE__ */ new Map();
|
|
3977
|
+
const pendingWaiters = /* @__PURE__ */ new Map();
|
|
3978
|
+
let disposed = false;
|
|
3979
|
+
function drainWaiters(path16) {
|
|
3980
|
+
const list = pendingWaiters.get(path16);
|
|
3981
|
+
if (!list) return;
|
|
3982
|
+
pendingWaiters.delete(path16);
|
|
3983
|
+
for (const fn of list) fn();
|
|
3984
|
+
}
|
|
3985
|
+
function drainAllWaiters() {
|
|
3986
|
+
const lists = Array.from(pendingWaiters.values());
|
|
3987
|
+
pendingWaiters.clear();
|
|
3988
|
+
for (const list of lists) for (const fn of list) fn();
|
|
3989
|
+
}
|
|
3990
|
+
const simulatorOnlyPolicy = (sender) => !sender.isDestroyed() && sender.session === simSession;
|
|
3991
|
+
const registry = new IpcRegistry(simulatorOnlyPolicy);
|
|
3992
|
+
registry.on("simulator:temp-file:write", (_event, payload) => {
|
|
3993
|
+
if (disposed) return;
|
|
3994
|
+
const { path: path16, mime, bytes } = payload;
|
|
3995
|
+
registerTempFile(store, path16, mime, bytes);
|
|
3996
|
+
enforceStoreCap(store);
|
|
3997
|
+
drainWaiters(path16);
|
|
3998
|
+
});
|
|
3999
|
+
registry.on("simulator:temp-file:revoke", (_event, payload) => {
|
|
4000
|
+
if (disposed) return;
|
|
4001
|
+
const { path: path16 } = payload;
|
|
4002
|
+
revokeTempFile(store, path16);
|
|
4003
|
+
});
|
|
4004
|
+
registry.on("simulator:temp-file:revoke-all", () => {
|
|
4005
|
+
if (disposed) return;
|
|
4006
|
+
revokeAllTempFiles(store);
|
|
4007
|
+
});
|
|
4008
|
+
try {
|
|
4009
|
+
simSession.protocol.unhandle("difile");
|
|
4010
|
+
} catch {
|
|
4011
|
+
}
|
|
4012
|
+
simSession.protocol.handle("difile", async (req) => {
|
|
4013
|
+
const url = req.url;
|
|
4014
|
+
const headers = {};
|
|
4015
|
+
try {
|
|
4016
|
+
req.headers.forEach((v, k) => {
|
|
4017
|
+
headers[k] = v;
|
|
4018
|
+
});
|
|
4019
|
+
} catch {
|
|
4020
|
+
}
|
|
4021
|
+
const ctx = { tempStore: store };
|
|
4022
|
+
let res = await handleDifileRequest(ctx, { url, headers });
|
|
4023
|
+
if (res.status === 404 && !disposed && url.startsWith("difile://_tmp/")) {
|
|
4024
|
+
await new Promise((resolve) => {
|
|
4025
|
+
let timer = null;
|
|
4026
|
+
const notify = () => {
|
|
4027
|
+
if (timer) clearTimeout(timer);
|
|
4028
|
+
resolve();
|
|
4029
|
+
};
|
|
4030
|
+
const list = pendingWaiters.get(url) ?? /* @__PURE__ */ new Set();
|
|
4031
|
+
list.add(notify);
|
|
4032
|
+
pendingWaiters.set(url, list);
|
|
4033
|
+
timer = setTimeout(() => {
|
|
4034
|
+
const cur = pendingWaiters.get(url);
|
|
4035
|
+
if (cur) {
|
|
4036
|
+
cur.delete(notify);
|
|
4037
|
+
if (cur.size === 0) pendingWaiters.delete(url);
|
|
4038
|
+
}
|
|
4039
|
+
resolve();
|
|
4040
|
+
}, PENDING_TIMEOUT_MS);
|
|
4041
|
+
});
|
|
4042
|
+
res = await handleDifileRequest(ctx, { url, headers });
|
|
4043
|
+
}
|
|
4044
|
+
return res;
|
|
4045
|
+
});
|
|
4046
|
+
registry.handle(
|
|
4047
|
+
"simulator:fs:read",
|
|
4048
|
+
(_event, payload) => handleFsRead(payload)
|
|
4049
|
+
);
|
|
4050
|
+
registry.handle(
|
|
4051
|
+
"simulator:fs:write",
|
|
4052
|
+
(_event, payload) => handleFsWrite(payload)
|
|
4053
|
+
);
|
|
4054
|
+
registry.handle(
|
|
4055
|
+
"simulator:fs:stat",
|
|
4056
|
+
(_event, payload) => handleFsStat(payload)
|
|
4057
|
+
);
|
|
4058
|
+
registry.handle(
|
|
4059
|
+
"simulator:fs:readdir",
|
|
4060
|
+
(_event, payload) => handleFsReaddir(payload)
|
|
4061
|
+
);
|
|
4062
|
+
registry.handle(
|
|
4063
|
+
"simulator:fs:unlink",
|
|
4064
|
+
(_event, payload) => handleFsUnlink(payload)
|
|
4065
|
+
);
|
|
4066
|
+
registry.handle(
|
|
4067
|
+
"simulator:fs:mkdir",
|
|
4068
|
+
(_event, payload) => handleFsMkdir(payload)
|
|
4069
|
+
);
|
|
4070
|
+
return toDisposable(async () => {
|
|
4071
|
+
disposed = true;
|
|
4072
|
+
drainAllWaiters();
|
|
4073
|
+
store.clear();
|
|
4074
|
+
try {
|
|
4075
|
+
simSession.protocol.unhandle("difile");
|
|
4076
|
+
} catch {
|
|
4077
|
+
}
|
|
4078
|
+
await registry.dispose();
|
|
4079
|
+
});
|
|
4080
|
+
}
|
|
4081
|
+
|
|
3535
4082
|
// src/main/services/update/update-manager.ts
|
|
3536
4083
|
import { app as app11, shell as shell3 } from "electron";
|
|
3537
4084
|
var UpdateManager = class {
|
|
@@ -3690,7 +4237,7 @@ async function disposeContext(ctx) {
|
|
|
3690
4237
|
function createConfiguredMainWindow(config, rendererDir2) {
|
|
3691
4238
|
const mainWindow = createMainWindow({
|
|
3692
4239
|
title: config.appName ?? "Dimina DevTools",
|
|
3693
|
-
indexHtml:
|
|
4240
|
+
indexHtml: path14.join(rendererDir2, "entries/main/index.html"),
|
|
3694
4241
|
width: config.window?.width,
|
|
3695
4242
|
height: config.window?.height,
|
|
3696
4243
|
minWidth: config.window?.minWidth,
|
|
@@ -3788,7 +4335,7 @@ function enableDevRendererAutoReload(rendererDir2) {
|
|
|
3788
4335
|
});
|
|
3789
4336
|
}
|
|
3790
4337
|
let reloadTimer = null;
|
|
3791
|
-
const watcher =
|
|
4338
|
+
const watcher = fs9.watch(rendererDir2, { recursive: true }, () => {
|
|
3792
4339
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
3793
4340
|
reloadTimer = setTimeout(() => {
|
|
3794
4341
|
for (const win of BrowserWindow4.getAllWindows()) {
|
|
@@ -3808,6 +4355,7 @@ function createWorkbenchApp(config = {}) {
|
|
|
3808
4355
|
let setupPromise = null;
|
|
3809
4356
|
let appEventsRegistered = false;
|
|
3810
4357
|
setupCdpPort();
|
|
4358
|
+
registerDifileScheme();
|
|
3811
4359
|
async function setup() {
|
|
3812
4360
|
if (setupPromise) return setupPromise;
|
|
3813
4361
|
setupPromise = app13.whenReady().then(async () => {
|
|
@@ -3818,6 +4366,8 @@ function createWorkbenchApp(config = {}) {
|
|
|
3818
4366
|
context.registry.add(registerAppIpc(context));
|
|
3819
4367
|
context.registry.add(installThemeBackgroundSync());
|
|
3820
4368
|
registerBuiltinModules(config, context);
|
|
4369
|
+
const simSession = session2.fromPartition("persist:simulator");
|
|
4370
|
+
context.registry.add(setupSimulatorTempFiles(simSession));
|
|
3821
4371
|
installMenu(config, mainWindow, context);
|
|
3822
4372
|
const hostIpc = new IpcRegistry(context.senderPolicy);
|
|
3823
4373
|
context.registry.add(hostIpc);
|
|
@@ -3864,8 +4414,8 @@ function createWorkbenchApp(config = {}) {
|
|
|
3864
4414
|
// prefixes; this callback lets the storage panel filter the CDP
|
|
3865
4415
|
// snapshot/event stream to the active appId.
|
|
3866
4416
|
getActiveAppId: () => {
|
|
3867
|
-
const
|
|
3868
|
-
const appInfo =
|
|
4417
|
+
const session3 = context.workspace.getSession();
|
|
4418
|
+
const appInfo = session3?.appInfo;
|
|
3869
4419
|
return appInfo?.appId ?? null;
|
|
3870
4420
|
}
|
|
3871
4421
|
}));
|
|
@@ -3890,7 +4440,7 @@ function createWorkbenchApp(config = {}) {
|
|
|
3890
4440
|
|
|
3891
4441
|
// src/main/windows/settings-window/create.ts
|
|
3892
4442
|
import { BrowserWindow as BrowserWindow5 } from "electron";
|
|
3893
|
-
import
|
|
4443
|
+
import path15 from "path";
|
|
3894
4444
|
async function createSettingsWindow(parent, rendererDir2) {
|
|
3895
4445
|
const win = new BrowserWindow5({
|
|
3896
4446
|
width: 420,
|
|
@@ -3908,7 +4458,7 @@ async function createSettingsWindow(parent, rendererDir2) {
|
|
|
3908
4458
|
}
|
|
3909
4459
|
});
|
|
3910
4460
|
applyNavigationHardening(win.webContents, rendererDir2);
|
|
3911
|
-
await win.loadFile(
|
|
4461
|
+
await win.loadFile(path15.join(rendererDir2, "entries/workbench-settings/index.html"));
|
|
3912
4462
|
return win;
|
|
3913
4463
|
}
|
|
3914
4464
|
|