@dimina-kit/devtools 0.4.0-dev.20260615083030 → 0.4.0-dev.20260616085026
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main/app/app.js +11 -0
- package/dist/main/app/lifecycle.d.ts +1 -0
- package/dist/main/app/lifecycle.js +10 -0
- package/dist/main/index.bundle.js +71 -51
- package/dist/main/runtime/devtools-backend.d.ts +5 -0
- package/dist/main/runtime/devtools-backend.js +10 -3
- package/dist/main/runtime/miniapp-runtime.d.ts +4 -2
- package/dist/main/services/workbench-context.d.ts +9 -0
- package/dist/main/services/workbench-context.js +1 -0
- package/dist/main/services/workspace/workspace-service.js +21 -0
- package/dist/main/windows/main-window/create.d.ts +6 -0
- package/dist/main/windows/main-window/create.js +17 -10
- package/dist/renderer/assets/index-BYV0bEvB.js +50 -0
- package/dist/renderer/assets/{input-hGF71bn3.js → input-B8NDCYv3.js} +2 -2
- package/dist/renderer/assets/ipc-transport-9agi76dX.css +1 -0
- package/dist/renderer/assets/{ipc-transport-BKWkvwKK.js → ipc-transport-DhrajiC5.js} +1 -1
- package/dist/renderer/assets/{popover-NNQNyjgI.js → popover-CI5uE9ZZ.js} +2 -2
- package/dist/renderer/assets/{select-Bb1AKeSq.js → select-tInleY0z.js} +2 -2
- package/dist/renderer/assets/{settings-7uwimev-.js → settings-CZJOHt8b.js} +2 -2
- package/dist/renderer/assets/{settings-api-DkrPHroq.js → settings-api-BSKzKiWd.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-EaMYvKHG.js → workbenchSettings-BGxjl25x.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +5 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/shared/types.d.ts +27 -0
- package/package.json +4 -4
- package/dist/renderer/assets/index-BFwsvw4p.js +0 -50
- package/dist/renderer/assets/ipc-transport-Cg1q1gwD.css +0 -1
package/dist/main/app/app.js
CHANGED
|
@@ -6,6 +6,7 @@ import path from 'path';
|
|
|
6
6
|
import { rendererDir as defaultRendererDir, defaultPreloadPath } from '../utils/paths.js';
|
|
7
7
|
import { installThemeBackgroundSync } from '../utils/theme.js';
|
|
8
8
|
import { createMainWindow, wireMainWindowEvents } from '../windows/main-window/index.js';
|
|
9
|
+
import { isAppQuitting } from './lifecycle.js';
|
|
9
10
|
// eslint-disable-next-line no-restricted-syntax -- grandfathered(workbench-context): shrink-only
|
|
10
11
|
import { createWorkbenchContext } from '../services/workbench-context.js';
|
|
11
12
|
import { loadWorkbenchSettings, applyTheme } from '../services/settings/index.js';
|
|
@@ -131,6 +132,7 @@ function createConfiguredMainWindow(config, rendererDir) {
|
|
|
131
132
|
height: config.window?.height,
|
|
132
133
|
minWidth: config.window?.minWidth,
|
|
133
134
|
minHeight: config.window?.minHeight,
|
|
135
|
+
autoShow: config.window?.autoShow,
|
|
134
136
|
});
|
|
135
137
|
// Set window/taskbar icon if provided (Linux/Windows; macOS uses app bundle icon)
|
|
136
138
|
if (config.icon) {
|
|
@@ -157,6 +159,7 @@ function createContext(config, mainWindow, rendererDir) {
|
|
|
157
159
|
projectTemplates: config.projectTemplates,
|
|
158
160
|
builtinTemplates: config.builtinTemplates,
|
|
159
161
|
customCreateProjectDialog: config.customCreateProjectDialog,
|
|
162
|
+
onBeforeOpenProject: config.onBeforeOpenProject,
|
|
160
163
|
});
|
|
161
164
|
}
|
|
162
165
|
function registerBuiltinModules(config, context) {
|
|
@@ -229,6 +232,14 @@ function wireAppWindowEvents(config, instance) {
|
|
|
229
232
|
context,
|
|
230
233
|
onResize: () => context.views.repositionAll(),
|
|
231
234
|
onClose: async (e) => {
|
|
235
|
+
// A real application quit (⌘Q / menu "Quit" / app.quit()) fires
|
|
236
|
+
// `before-quit` first, then this window's `close`. Let it through so the
|
|
237
|
+
// app actually exits — do NOT convert it into "close the project".
|
|
238
|
+
// Without this, `hasActiveSession()` would be true and the quit gets
|
|
239
|
+
// swallowed into closeProject(), so the app can never be quit while a
|
|
240
|
+
// project is open.
|
|
241
|
+
if (isAppQuitting())
|
|
242
|
+
return;
|
|
232
243
|
if (!context.workspace.hasActiveSession())
|
|
233
244
|
return;
|
|
234
245
|
// Close button while a project session is open: stay in the workbench
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { app, globalShortcut } from 'electron';
|
|
2
|
+
// Flips to `true` once Electron's `before-quit` fires — a real application
|
|
3
|
+
// quit (⌘Q / menu "Quit" / app.quit()) is underway. `before-quit` is emitted
|
|
4
|
+
// BEFORE each window's `close` event, so the main-window onClose handler can
|
|
5
|
+
// read this to tell "the whole app is exiting" apart from "the user closed a
|
|
6
|
+
// single project window" and avoid swallowing the quit.
|
|
7
|
+
let appIsQuitting = false;
|
|
8
|
+
export function isAppQuitting() {
|
|
9
|
+
return appIsQuitting;
|
|
10
|
+
}
|
|
2
11
|
export function registerAppLifecycle() {
|
|
3
12
|
app.on('window-all-closed', () => {
|
|
4
13
|
globalShortcut.unregisterAll();
|
|
5
14
|
app.quit();
|
|
6
15
|
});
|
|
7
16
|
app.on('before-quit', () => {
|
|
17
|
+
appIsQuitting = true;
|
|
8
18
|
globalShortcut.unregisterAll();
|
|
9
19
|
});
|
|
10
20
|
}
|
|
@@ -761,7 +761,7 @@ function registerProjectFsIpc(ctx) {
|
|
|
761
761
|
}
|
|
762
762
|
|
|
763
763
|
// src/main/app/app.ts
|
|
764
|
-
import { app as
|
|
764
|
+
import { app as app15, BrowserWindow as BrowserWindow8, nativeImage, session as session4 } from "electron";
|
|
765
765
|
import fs10 from "fs";
|
|
766
766
|
import path21 from "path";
|
|
767
767
|
|
|
@@ -885,13 +885,13 @@ function createMainWindow(opts) {
|
|
|
885
885
|
}
|
|
886
886
|
});
|
|
887
887
|
mainWindow.once("ready-to-show", () => {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
mainWindow.show();
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
}
|
|
888
|
+
const isTest = process.env.NODE_ENV === "test";
|
|
889
|
+
if (opts.autoShow !== false) {
|
|
890
|
+
if (isTest) mainWindow.showInactive();
|
|
891
|
+
else mainWindow.show();
|
|
892
|
+
}
|
|
893
|
+
if (!isTest && !app3.isPackaged && process.env.DIMINA_DEVTOOLS_MAIN_INSPECTOR === "1") {
|
|
894
|
+
mainWindow.webContents.openDevTools({ mode: "detach" });
|
|
895
895
|
}
|
|
896
896
|
});
|
|
897
897
|
const rendererDir2 = path5.dirname(opts.indexHtml);
|
|
@@ -943,6 +943,23 @@ function wireMainWindowEvents(win, state = {}) {
|
|
|
943
943
|
return registry;
|
|
944
944
|
}
|
|
945
945
|
|
|
946
|
+
// src/main/app/lifecycle.ts
|
|
947
|
+
import { app as app4, globalShortcut as globalShortcut2 } from "electron";
|
|
948
|
+
var appIsQuitting = false;
|
|
949
|
+
function isAppQuitting() {
|
|
950
|
+
return appIsQuitting;
|
|
951
|
+
}
|
|
952
|
+
function registerAppLifecycle() {
|
|
953
|
+
app4.on("window-all-closed", () => {
|
|
954
|
+
globalShortcut2.unregisterAll();
|
|
955
|
+
app4.quit();
|
|
956
|
+
});
|
|
957
|
+
app4.on("before-quit", () => {
|
|
958
|
+
appIsQuitting = true;
|
|
959
|
+
globalShortcut2.unregisterAll();
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
|
|
946
963
|
// src/main/services/workbench-context.ts
|
|
947
964
|
import {
|
|
948
965
|
createConnectionRegistry,
|
|
@@ -966,12 +983,12 @@ function createWorkbenchSenderPolicy(ctx) {
|
|
|
966
983
|
|
|
967
984
|
// src/main/services/default-adapter.ts
|
|
968
985
|
import path6 from "path";
|
|
969
|
-
import { app as
|
|
986
|
+
import { app as app5 } from "electron";
|
|
970
987
|
var defaultAdapter = {
|
|
971
988
|
async openProject(opts) {
|
|
972
989
|
const diminaKit = await import("@dimina-kit/devkit");
|
|
973
990
|
const openProjectOpts = {
|
|
974
|
-
outputDir: path6.join(
|
|
991
|
+
outputDir: path6.join(app5.getPath("userData"), "dimina-fe-output"),
|
|
975
992
|
...opts,
|
|
976
993
|
simulatorDir
|
|
977
994
|
};
|
|
@@ -2707,12 +2724,12 @@ async function openSettingsWindow(deps) {
|
|
|
2707
2724
|
import { z as z2 } from "zod";
|
|
2708
2725
|
|
|
2709
2726
|
// src/main/services/projects/project-repository.ts
|
|
2710
|
-
import { app as
|
|
2727
|
+
import { app as app6 } from "electron";
|
|
2711
2728
|
import path9 from "path";
|
|
2712
2729
|
import fs4 from "fs";
|
|
2713
2730
|
var log2 = createLogger("projects");
|
|
2714
2731
|
function getProjectsFile() {
|
|
2715
|
-
return path9.join(
|
|
2732
|
+
return path9.join(app6.getPath("userData"), "dimina-projects.json");
|
|
2716
2733
|
}
|
|
2717
2734
|
function load() {
|
|
2718
2735
|
try {
|
|
@@ -2927,6 +2944,15 @@ function createWorkspaceService(ctx) {
|
|
|
2927
2944
|
},
|
|
2928
2945
|
validateProjectDir: async (dirPath) => provider.validateProjectDir ? provider.validateProjectDir(dirPath) : null,
|
|
2929
2946
|
async openProject(projectPath) {
|
|
2947
|
+
if (ctx.onBeforeOpenProject) {
|
|
2948
|
+
try {
|
|
2949
|
+
await ctx.onBeforeOpenProject(projectPath);
|
|
2950
|
+
} catch (err) {
|
|
2951
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
2952
|
+
sendStatus("error", error);
|
|
2953
|
+
return { success: false, error };
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2930
2956
|
clearSimulatorServicewechatReferer();
|
|
2931
2957
|
logGeneration++;
|
|
2932
2958
|
await disposeSession();
|
|
@@ -3046,9 +3072,9 @@ function createWorkspaceService(ctx) {
|
|
|
3046
3072
|
import { createHash } from "crypto";
|
|
3047
3073
|
import fs5 from "fs";
|
|
3048
3074
|
import path10 from "path";
|
|
3049
|
-
import { app as
|
|
3075
|
+
import { app as app7 } from "electron";
|
|
3050
3076
|
function getThumbnailDir() {
|
|
3051
|
-
return path10.join(
|
|
3077
|
+
return path10.join(app7.getPath("userData"), "thumbnails");
|
|
3052
3078
|
}
|
|
3053
3079
|
function hashProjectPath(projectPath) {
|
|
3054
3080
|
return createHash("sha256").update(projectPath).digest("hex").slice(0, 16);
|
|
@@ -3157,6 +3183,7 @@ function createWorkbenchContext(opts) {
|
|
|
3157
3183
|
opts.builtinTemplates ?? "all"
|
|
3158
3184
|
);
|
|
3159
3185
|
ctx.customCreateProjectDialog = opts.customCreateProjectDialog;
|
|
3186
|
+
ctx.onBeforeOpenProject = opts.onBeforeOpenProject;
|
|
3160
3187
|
ctx.workspace = createWorkspaceService(ctx);
|
|
3161
3188
|
ctx.senderPolicy = createWorkbenchSenderPolicy(ctx);
|
|
3162
3189
|
return ctx;
|
|
@@ -3463,7 +3490,7 @@ var popoverModule = {
|
|
|
3463
3490
|
};
|
|
3464
3491
|
|
|
3465
3492
|
// src/main/ipc/projects.ts
|
|
3466
|
-
import { app as
|
|
3493
|
+
import { app as app8, dialog } from "electron";
|
|
3467
3494
|
import path13 from "path";
|
|
3468
3495
|
|
|
3469
3496
|
// src/main/services/projects/create-project-service.ts
|
|
@@ -3617,7 +3644,7 @@ function registerProjectsIpc(ctx) {
|
|
|
3617
3644
|
}
|
|
3618
3645
|
function safeAppPath(name) {
|
|
3619
3646
|
try {
|
|
3620
|
-
return
|
|
3647
|
+
return app8.getPath(name);
|
|
3621
3648
|
} catch {
|
|
3622
3649
|
return null;
|
|
3623
3650
|
}
|
|
@@ -3671,7 +3698,7 @@ var sessionModule = {
|
|
|
3671
3698
|
};
|
|
3672
3699
|
|
|
3673
3700
|
// src/main/ipc/settings.ts
|
|
3674
|
-
import { app as
|
|
3701
|
+
import { app as app9 } from "electron";
|
|
3675
3702
|
|
|
3676
3703
|
// src/main/services/mcp/status.ts
|
|
3677
3704
|
var status = { running: false, port: null, error: null };
|
|
@@ -3710,8 +3737,8 @@ function registerSettingsIpc(ctx) {
|
|
|
3710
3737
|
applyTheme(theme);
|
|
3711
3738
|
}).handle(WorkbenchSettingsChannel.GetCdpStatus, () => {
|
|
3712
3739
|
const settings = loadWorkbenchSettings();
|
|
3713
|
-
const switchValue =
|
|
3714
|
-
const implicitDevDefault = !
|
|
3740
|
+
const switchValue = app9.commandLine.getSwitchValue("remote-debugging-port");
|
|
3741
|
+
const implicitDevDefault = !app9.isPackaged && !settings.cdp.enabled && switchValue === String(DEFAULT_CDP_PORT);
|
|
3715
3742
|
return {
|
|
3716
3743
|
configured: settings.cdp.enabled,
|
|
3717
3744
|
port: settings.cdp.port,
|
|
@@ -3772,7 +3799,7 @@ var settingsModule = {
|
|
|
3772
3799
|
import { DisposableRegistry as DisposableRegistry6 } from "@dimina-kit/electron-deck/main";
|
|
3773
3800
|
|
|
3774
3801
|
// src/main/ipc/bridge-router.ts
|
|
3775
|
-
import { app as
|
|
3802
|
+
import { app as app12, ipcMain as ipcMain3, protocol as protocol2, session as electronSession, webContents as webContents2 } from "electron";
|
|
3776
3803
|
import path16 from "node:path";
|
|
3777
3804
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
3778
3805
|
|
|
@@ -3880,7 +3907,7 @@ function setCorsHeaders(res) {
|
|
|
3880
3907
|
}
|
|
3881
3908
|
|
|
3882
3909
|
// src/main/windows/service-host-window/create.ts
|
|
3883
|
-
import { app as
|
|
3910
|
+
import { app as app10, BrowserWindow as BrowserWindow4 } from "electron";
|
|
3884
3911
|
import path15 from "node:path";
|
|
3885
3912
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
3886
3913
|
var SERVICE_HOST_PARTITION = SHARED_MINIAPP_PARTITION;
|
|
@@ -3921,7 +3948,7 @@ function navigateServiceHost(win, url) {
|
|
|
3921
3948
|
() => void 0,
|
|
3922
3949
|
() => void 0
|
|
3923
3950
|
);
|
|
3924
|
-
if (!
|
|
3951
|
+
if (!app10.isPackaged && process.env.NODE_ENV !== "test") {
|
|
3925
3952
|
const w = win;
|
|
3926
3953
|
if (w.__diminaDevToolsHook) {
|
|
3927
3954
|
try {
|
|
@@ -4318,7 +4345,7 @@ function createConsoleForwarder(bridge) {
|
|
|
4318
4345
|
}
|
|
4319
4346
|
|
|
4320
4347
|
// src/main/services/simulator-storage/index.ts
|
|
4321
|
-
import { app as
|
|
4348
|
+
import { app as app11, webContents as wcStatic } from "electron";
|
|
4322
4349
|
import { DisposableRegistry as DisposableRegistry5 } from "@dimina-kit/electron-deck/main";
|
|
4323
4350
|
|
|
4324
4351
|
// src/main/services/simulator-storage/service-storage-ops.ts
|
|
@@ -4688,9 +4715,9 @@ function setupSimulatorStorage(host, options) {
|
|
|
4688
4715
|
}
|
|
4689
4716
|
}
|
|
4690
4717
|
};
|
|
4691
|
-
|
|
4718
|
+
app11.on("web-contents-created", onWcCreated);
|
|
4692
4719
|
registry.add(() => {
|
|
4693
|
-
|
|
4720
|
+
app11.removeListener("web-contents-created", onWcCreated);
|
|
4694
4721
|
});
|
|
4695
4722
|
registry.add(async () => {
|
|
4696
4723
|
const subs = Array.from(wcSubs.values());
|
|
@@ -5864,7 +5891,7 @@ function makeHostEnv(snapshot) {
|
|
|
5864
5891
|
windowWidth: 390,
|
|
5865
5892
|
windowHeight: 844,
|
|
5866
5893
|
statusBarHeight: 24,
|
|
5867
|
-
language:
|
|
5894
|
+
language: app12.getLocale(),
|
|
5868
5895
|
theme: "light",
|
|
5869
5896
|
...snapshot
|
|
5870
5897
|
};
|
|
@@ -8661,7 +8688,7 @@ function setupSimulatorSessionPolicy() {
|
|
|
8661
8688
|
}
|
|
8662
8689
|
|
|
8663
8690
|
// src/main/services/update/update-manager.ts
|
|
8664
|
-
import { app as
|
|
8691
|
+
import { app as app13, shell as shell3 } from "electron";
|
|
8665
8692
|
var UpdateManager = class {
|
|
8666
8693
|
checker;
|
|
8667
8694
|
mainWindow;
|
|
@@ -8684,7 +8711,7 @@ var UpdateManager = class {
|
|
|
8684
8711
|
constructor(opts) {
|
|
8685
8712
|
this.checker = opts.checker;
|
|
8686
8713
|
this.mainWindow = opts.mainWindow;
|
|
8687
|
-
this.getCurrentVersion = opts.getCurrentVersion ?? (() =>
|
|
8714
|
+
this.getCurrentVersion = opts.getCurrentVersion ?? (() => app13.getVersion());
|
|
8688
8715
|
this.ipc = new IpcRegistry(opts.senderPolicy);
|
|
8689
8716
|
this.registerIpc();
|
|
8690
8717
|
this.startPeriodicCheck(opts.checkInterval ?? 60 * 60 * 1e3, opts.initialDelay ?? 5e3);
|
|
@@ -8725,7 +8752,7 @@ var UpdateManager = class {
|
|
|
8725
8752
|
install() {
|
|
8726
8753
|
if (this.downloadedPath) {
|
|
8727
8754
|
shell3.openPath(this.downloadedPath);
|
|
8728
|
-
|
|
8755
|
+
app13.quit();
|
|
8729
8756
|
}
|
|
8730
8757
|
}
|
|
8731
8758
|
/**
|
|
@@ -8759,7 +8786,7 @@ var UpdateManager = class {
|
|
|
8759
8786
|
};
|
|
8760
8787
|
|
|
8761
8788
|
// src/main/services/update/github-release-checker.ts
|
|
8762
|
-
import { app as
|
|
8789
|
+
import { app as app14 } from "electron";
|
|
8763
8790
|
|
|
8764
8791
|
// src/main/app/app.ts
|
|
8765
8792
|
import { toDisposable as toDisposable8 } from "@dimina-kit/electron-deck/main";
|
|
@@ -8834,7 +8861,8 @@ function createConfiguredMainWindow(config, rendererDir2) {
|
|
|
8834
8861
|
width: config.window?.width,
|
|
8835
8862
|
height: config.window?.height,
|
|
8836
8863
|
minWidth: config.window?.minWidth,
|
|
8837
|
-
minHeight: config.window?.minHeight
|
|
8864
|
+
minHeight: config.window?.minHeight,
|
|
8865
|
+
autoShow: config.window?.autoShow
|
|
8838
8866
|
});
|
|
8839
8867
|
if (config.icon) {
|
|
8840
8868
|
const icon = nativeImage.createFromPath(config.icon);
|
|
@@ -8858,7 +8886,8 @@ function createContext(config, mainWindow, rendererDir2) {
|
|
|
8858
8886
|
projectsProvider: config.projectsProvider,
|
|
8859
8887
|
projectTemplates: config.projectTemplates,
|
|
8860
8888
|
builtinTemplates: config.builtinTemplates,
|
|
8861
|
-
customCreateProjectDialog: config.customCreateProjectDialog
|
|
8889
|
+
customCreateProjectDialog: config.customCreateProjectDialog,
|
|
8890
|
+
onBeforeOpenProject: config.onBeforeOpenProject
|
|
8862
8891
|
});
|
|
8863
8892
|
}
|
|
8864
8893
|
function registerBuiltinModules(config, context) {
|
|
@@ -8903,7 +8932,7 @@ async function setupAutomation(instance) {
|
|
|
8903
8932
|
function setupMcp() {
|
|
8904
8933
|
const settings = loadWorkbenchSettings();
|
|
8905
8934
|
if (!settings.mcp.enabled) return null;
|
|
8906
|
-
const cdpPortSwitch =
|
|
8935
|
+
const cdpPortSwitch = app15.commandLine.getSwitchValue("remote-debugging-port");
|
|
8907
8936
|
const cdpPort2 = cdpPortSwitch ? parseInt(cdpPortSwitch, 10) : settings.cdp.port;
|
|
8908
8937
|
return startMcpServer(cdpPort2, settings.mcp.port);
|
|
8909
8938
|
}
|
|
@@ -8914,6 +8943,7 @@ function wireAppWindowEvents(config, instance) {
|
|
|
8914
8943
|
context,
|
|
8915
8944
|
onResize: () => context.views.repositionAll(),
|
|
8916
8945
|
onClose: async (e) => {
|
|
8946
|
+
if (isAppQuitting()) return;
|
|
8917
8947
|
if (!context.workspace.hasActiveSession()) return;
|
|
8918
8948
|
e.preventDefault();
|
|
8919
8949
|
if (closing) return;
|
|
@@ -8931,7 +8961,7 @@ function wireAppWindowEvents(config, instance) {
|
|
|
8931
8961
|
});
|
|
8932
8962
|
}
|
|
8933
8963
|
function enableDevRendererAutoReload(rendererDir2) {
|
|
8934
|
-
if (
|
|
8964
|
+
if (app15.isPackaged) {
|
|
8935
8965
|
return toDisposable8(() => {
|
|
8936
8966
|
});
|
|
8937
8967
|
}
|
|
@@ -8954,7 +8984,7 @@ function enableDevRendererAutoReload(rendererDir2) {
|
|
|
8954
8984
|
}
|
|
8955
8985
|
function runDevtoolsBootstrap(config = {}) {
|
|
8956
8986
|
try {
|
|
8957
|
-
|
|
8987
|
+
app15.setName(config.appName ?? "Dimina DevTools");
|
|
8958
8988
|
} catch {
|
|
8959
8989
|
}
|
|
8960
8990
|
setupCdpPort();
|
|
@@ -8962,7 +8992,7 @@ function runDevtoolsBootstrap(config = {}) {
|
|
|
8962
8992
|
registerDifileScheme();
|
|
8963
8993
|
}
|
|
8964
8994
|
async function createDevtoolsRuntime(config = {}) {
|
|
8965
|
-
await
|
|
8995
|
+
await app15.whenReady();
|
|
8966
8996
|
applyTheme(loadWorkbenchSettings().theme);
|
|
8967
8997
|
const rendererDir2 = config.rendererDir ?? rendererDir;
|
|
8968
8998
|
const mainWindow = createConfiguredMainWindow(config, rendererDir2);
|
|
@@ -9111,18 +9141,6 @@ async function createDevtoolsRuntime(config = {}) {
|
|
|
9111
9141
|
return instance;
|
|
9112
9142
|
}
|
|
9113
9143
|
|
|
9114
|
-
// src/main/app/lifecycle.ts
|
|
9115
|
-
import { app as app15, globalShortcut as globalShortcut2 } from "electron";
|
|
9116
|
-
function registerAppLifecycle() {
|
|
9117
|
-
app15.on("window-all-closed", () => {
|
|
9118
|
-
globalShortcut2.unregisterAll();
|
|
9119
|
-
app15.quit();
|
|
9120
|
-
});
|
|
9121
|
-
app15.on("before-quit", () => {
|
|
9122
|
-
globalShortcut2.unregisterAll();
|
|
9123
|
-
});
|
|
9124
|
-
}
|
|
9125
|
-
|
|
9126
9144
|
// src/main/runtime/devtools-backend.ts
|
|
9127
9145
|
function createDevtoolsBackend(config = {}) {
|
|
9128
9146
|
let instance = null;
|
|
@@ -9133,9 +9151,11 @@ function createDevtoolsBackend(config = {}) {
|
|
|
9133
9151
|
// NOTE: `ownsWindows` is NOT structurally required — the framework's
|
|
9134
9152
|
// `mainWindowWebPreferences()` + `onMainWindowCreated()` hooks can supply both,
|
|
9135
9153
|
// and the project close→back lifecycle maps onto the Window facade's
|
|
9136
|
-
// `onClose`/`newSession` (probe-validated).
|
|
9137
|
-
// `runtime.windows.main`
|
|
9138
|
-
//
|
|
9154
|
+
// `onClose`/`newSession` (probe-validated). It is RETAINED BY DECISION, not
|
|
9155
|
+
// inertia: migrating to `runtime.windows.main` buys no user value at high
|
|
9156
|
+
// regression cost (see docs/deck-adoption-decision.md, F1). (The
|
|
9157
|
+
// `persist:simulator` partition is a fixed session used by child WCVs, not
|
|
9158
|
+
// main-window state.)
|
|
9139
9159
|
ownsWindows: true,
|
|
9140
9160
|
// Pre-ready: app name / CDP port / CSP / privileged scheme — must run before
|
|
9141
9161
|
// the framework awaits app.whenReady().
|
|
@@ -12,6 +12,11 @@ import type { WorkbenchAppConfig } from '../../shared/types.js';
|
|
|
12
12
|
* backend is present), so `assemble` ignores the framework `runtime` and builds
|
|
13
13
|
* the real devtools main window itself. Trust/frame unification and surfacing
|
|
14
14
|
* the runtime facade are deferred (see framework-extraction-v2.md §7).
|
|
15
|
+
*
|
|
16
|
+
* NOT migrating onto deck's high-level host API (Window facade / runtime.view /
|
|
17
|
+
* DeckSession / grants) is a DELIBERATE, reviewed decision — not a backlog item.
|
|
18
|
+
* The ROI matrix (every candidate NO-GO) + revisit conditions live in
|
|
19
|
+
* docs/deck-adoption-decision.md. Read it before re-proposing such a migration.
|
|
15
20
|
*/
|
|
16
21
|
export declare function createDevtoolsBackend(config?: WorkbenchAppConfig): RuntimeBackend;
|
|
17
22
|
//# sourceMappingURL=devtools-backend.d.ts.map
|
|
@@ -12,6 +12,11 @@ import { registerAppLifecycle } from '../app/lifecycle.js';
|
|
|
12
12
|
* backend is present), so `assemble` ignores the framework `runtime` and builds
|
|
13
13
|
* the real devtools main window itself. Trust/frame unification and surfacing
|
|
14
14
|
* the runtime facade are deferred (see framework-extraction-v2.md §7).
|
|
15
|
+
*
|
|
16
|
+
* NOT migrating onto deck's high-level host API (Window facade / runtime.view /
|
|
17
|
+
* DeckSession / grants) is a DELIBERATE, reviewed decision — not a backlog item.
|
|
18
|
+
* The ROI matrix (every candidate NO-GO) + revisit conditions live in
|
|
19
|
+
* docs/deck-adoption-decision.md. Read it before re-proposing such a migration.
|
|
15
20
|
*/
|
|
16
21
|
export function createDevtoolsBackend(config = {}) {
|
|
17
22
|
// Hoisted so `onShutdown` can reach the assembled context (assigned by `assemble`).
|
|
@@ -23,9 +28,11 @@ export function createDevtoolsBackend(config = {}) {
|
|
|
23
28
|
// NOTE: `ownsWindows` is NOT structurally required — the framework's
|
|
24
29
|
// `mainWindowWebPreferences()` + `onMainWindowCreated()` hooks can supply both,
|
|
25
30
|
// and the project close→back lifecycle maps onto the Window facade's
|
|
26
|
-
// `onClose`/`newSession` (probe-validated).
|
|
27
|
-
// `runtime.windows.main`
|
|
28
|
-
//
|
|
31
|
+
// `onClose`/`newSession` (probe-validated). It is RETAINED BY DECISION, not
|
|
32
|
+
// inertia: migrating to `runtime.windows.main` buys no user value at high
|
|
33
|
+
// regression cost (see docs/deck-adoption-decision.md, F1). (The
|
|
34
|
+
// `persist:simulator` partition is a fixed session used by child WCVs, not
|
|
35
|
+
// main-window state.)
|
|
29
36
|
ownsWindows: true,
|
|
30
37
|
// Pre-ready: app name / CDP port / CSP / privileged scheme — must run before
|
|
31
38
|
// the framework awaits app.whenReady().
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
* syntax: under strictFunctionTypes method signatures compare bivariantly,
|
|
16
16
|
* which would let a wrongly-narrowed implementation or host override slip
|
|
17
17
|
* past the drift sentinel.
|
|
18
|
-
* - `workspace.openProject` stays writable (no `readonly`)
|
|
19
|
-
*
|
|
18
|
+
* - `workspace.openProject` stays writable (no `readonly`) for backward
|
|
19
|
+
* compat: hosts MAY still gate permissions by reassigning it. The preferred
|
|
20
|
+
* path is now the declarative `WorkbenchAppConfig.onBeforeOpenProject` hook
|
|
21
|
+
* (runs before any side effect, throw to veto) — see host-migration.md §7.
|
|
20
22
|
*
|
|
21
23
|
* `asMiniappRuntime(ctx)` is an identity return — the contract is a typed
|
|
22
24
|
* VIEW onto the live context, not a snapshot/projection. That is what makes
|
|
@@ -74,6 +74,13 @@ export interface WorkbenchContext {
|
|
|
74
74
|
parentWindow: BrowserWindow;
|
|
75
75
|
templates: ProjectTemplate[];
|
|
76
76
|
}) => Promise<CustomCreateProjectDialogResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Host permission gate consulted by `workspace.openProject` BEFORE any side
|
|
79
|
+
* effect. Throwing vetoes the open (see `WorkbenchAppConfig.onBeforeOpenProject`).
|
|
80
|
+
* Wired from the config by `createDevtoolsRuntime`; undefined for the
|
|
81
|
+
* single-tenant default.
|
|
82
|
+
*/
|
|
83
|
+
onBeforeOpenProject?: (projectPath: string) => void | Promise<void>;
|
|
77
84
|
/**
|
|
78
85
|
* Trust predicate consulted by `IpcRegistry` for every incoming IPC.
|
|
79
86
|
* Resolves the currently-trusted senders (main renderer + overlays)
|
|
@@ -183,6 +190,8 @@ export interface CreateContextOptions extends Pick<WorkbenchConfig, 'adapter' |
|
|
|
183
190
|
builtinTemplates?: 'all' | 'none' | readonly string[];
|
|
184
191
|
/** Host-supplied "新建项目" dialog hook. */
|
|
185
192
|
customCreateProjectDialog?: WorkbenchContext['customCreateProjectDialog'];
|
|
193
|
+
/** Host permission gate run before a project opens (throw to veto). */
|
|
194
|
+
onBeforeOpenProject?: WorkbenchContext['onBeforeOpenProject'];
|
|
186
195
|
}
|
|
187
196
|
export declare function createWorkbenchContext(opts: CreateContextOptions): WorkbenchContext;
|
|
188
197
|
export { sanitizeTemplates };
|
|
@@ -37,6 +37,7 @@ export function createWorkbenchContext(opts) {
|
|
|
37
37
|
ctx.projectsProvider = opts.projectsProvider ?? createLocalProjectsProvider();
|
|
38
38
|
ctx.projectTemplates = resolveTemplates(BUILTIN_TEMPLATES, opts.projectTemplates ?? [], opts.builtinTemplates ?? 'all');
|
|
39
39
|
ctx.customCreateProjectDialog = opts.customCreateProjectDialog;
|
|
40
|
+
ctx.onBeforeOpenProject = opts.onBeforeOpenProject;
|
|
40
41
|
ctx.workspace = createWorkspaceService(ctx);
|
|
41
42
|
ctx.senderPolicy = createWorkbenchSenderPolicy(ctx);
|
|
42
43
|
return ctx;
|
|
@@ -80,6 +80,27 @@ export function createWorkspaceService(ctx) {
|
|
|
80
80
|
? provider.validateProjectDir(dirPath)
|
|
81
81
|
: null,
|
|
82
82
|
async openProject(projectPath) {
|
|
83
|
+
// Host permission gate — runs BEFORE any side effect (referer reset,
|
|
84
|
+
// session teardown, compile/dev-server spin-up). A throwing hook vetoes
|
|
85
|
+
// the open: return early with the error and leave the currently-active
|
|
86
|
+
// session fully intact. The declarative replacement for monkey-patching
|
|
87
|
+
// this method. See WorkbenchAppConfig.onBeforeOpenProject.
|
|
88
|
+
if (ctx.onBeforeOpenProject) {
|
|
89
|
+
try {
|
|
90
|
+
await ctx.onBeforeOpenProject(projectPath);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
// Surface the veto to the status bar — symmetric with the
|
|
94
|
+
// validateProjectDir rejection below (which already emits an error
|
|
95
|
+
// status). The framework caught the error, so it owns the minimal
|
|
96
|
+
// user-visible feedback; a host gate must not have to thread
|
|
97
|
+
// `notify` through a singleton just to report why the open was
|
|
98
|
+
// denied. The host can still layer richer UX (e.g. a dialog).
|
|
99
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
100
|
+
sendStatus('error', error);
|
|
101
|
+
return { success: false, error };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
83
104
|
clearSimulatorServicewechatReferer();
|
|
84
105
|
// Invalidate the outgoing session's onLog BEFORE teardown starts (same
|
|
85
106
|
// order as closeProject below): the dying compile worker flushes
|
|
@@ -6,6 +6,12 @@ export interface WindowOptions {
|
|
|
6
6
|
minWidth?: number;
|
|
7
7
|
minHeight?: number;
|
|
8
8
|
indexHtml: string;
|
|
9
|
+
/**
|
|
10
|
+
* Auto-show the window on `ready-to-show` in non-test envs. Defaults to
|
|
11
|
+
* `true`. `false` lets a login-gating host keep the window hidden and call
|
|
12
|
+
* `show()` itself. The test env always uses `showInactive()` regardless.
|
|
13
|
+
*/
|
|
14
|
+
autoShow?: boolean;
|
|
9
15
|
}
|
|
10
16
|
export declare function createMainWindow(opts: WindowOptions): BrowserWindow;
|
|
11
17
|
//# sourceMappingURL=create.d.ts.map
|
|
@@ -22,17 +22,24 @@ export function createMainWindow(opts) {
|
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
24
|
mainWindow.once('ready-to-show', () => {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const isTest = process.env.NODE_ENV === 'test';
|
|
26
|
+
// Visibility is governed by `autoShow` in BOTH envs. A login-gating host
|
|
27
|
+
// opts out via `autoShow: false` and reveals the window itself once auth
|
|
28
|
+
// passes — don't flash an un-authed window. The env only chooses HOW to
|
|
29
|
+
// show: test uses showInactive() so e2e windows don't steal focus, prod
|
|
30
|
+
// uses show(). The framework must never force-show when the host opted
|
|
31
|
+
// out, in test env either (that would fight the host's own reveal handler).
|
|
32
|
+
if (opts.autoShow !== false) {
|
|
33
|
+
if (isTest)
|
|
34
|
+
mainWindow.showInactive();
|
|
35
|
+
else
|
|
36
|
+
mainWindow.show();
|
|
27
37
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (!app.isPackaged && process.env.DIMINA_DEVTOOLS_MAIN_INSPECTOR === '1') {
|
|
34
|
-
mainWindow.webContents.openDevTools({ mode: 'detach' });
|
|
35
|
-
}
|
|
38
|
+
// Don't auto-open a detached DevTools for the devtools UI shell itself —
|
|
39
|
+
// it's noise for normal use (the mini-app's Console lives in the embedded
|
|
40
|
+
// right-panel DevTools, not here). Opt in via env for debugging the shell.
|
|
41
|
+
if (!isTest && !app.isPackaged && process.env.DIMINA_DEVTOOLS_MAIN_INSPECTOR === '1') {
|
|
42
|
+
mainWindow.webContents.openDevTools({ mode: 'detach' });
|
|
36
43
|
}
|
|
37
44
|
});
|
|
38
45
|
const rendererDir = path.dirname(opts.indexHtml);
|