@dimina-kit/devtools 0.3.1-dev.20260518114324 → 0.3.2-dev.20260522085907
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 +33 -71
- package/dist/main/app/app.js +5 -0
- package/dist/main/app/bootstrap.js +2 -1
- package/dist/main/app/launch.d.ts +1 -1
- package/dist/main/app/launch.js +6 -7
- package/dist/main/index.bundle.js +306 -317
- package/dist/main/ipc/panels.js +3 -5
- package/dist/main/ipc/projects.d.ts +1 -1
- package/dist/main/ipc/projects.js +5 -5
- package/dist/main/ipc/settings.d.ts +1 -1
- package/dist/main/ipc/settings.js +14 -1
- package/dist/main/ipc/simulator.d.ts +1 -1
- package/dist/main/ipc/simulator.js +1 -10
- package/dist/main/services/automation/exec.d.ts +2 -0
- package/dist/main/services/automation/exec.js +7 -9
- package/dist/main/services/automation/handlers/app.js +37 -51
- package/dist/main/services/automation/handlers/element.js +27 -41
- package/dist/main/services/default-adapter.js +3 -3
- package/dist/main/services/mcp/index.d.ts +1 -0
- package/dist/main/services/mcp/index.js +1 -0
- package/dist/main/services/mcp/server.js +5 -0
- package/dist/main/services/mcp/status.d.ts +10 -0
- package/dist/main/services/mcp/status.js +14 -0
- package/dist/main/services/mcp/target-manager.js +2 -1
- package/dist/main/services/notifications/renderer-notifier.d.ts +3 -3
- package/dist/main/services/notifications/renderer-notifier.js +3 -6
- package/dist/main/services/projects/local-provider.js +3 -3
- package/dist/main/services/projects/project-repository.d.ts +0 -1
- package/dist/main/services/settings/index.js +2 -1
- package/dist/main/services/simulator-storage/index.js +47 -77
- package/dist/main/services/views/view-manager.d.ts +3 -7
- package/dist/main/services/views/view-manager.js +20 -27
- package/dist/main/services/window-service.d.ts +3 -3
- package/dist/main/services/workbench-context.d.ts +3 -6
- package/dist/main/services/workbench-context.js +1 -3
- package/dist/main/services/workspace/workspace-service.js +8 -24
- package/dist/main/utils/theme.d.ts +24 -0
- package/dist/main/utils/theme.js +38 -1
- package/dist/preload/index.d.ts +5 -2
- package/dist/preload/index.js +3 -2
- package/dist/preload/instrumentation/app-data.d.ts +32 -2
- package/dist/preload/instrumentation/app-data.js +187 -172
- package/dist/preload/instrumentation/index.d.ts +2 -2
- package/dist/preload/instrumentation/index.js +2 -2
- package/dist/preload/instrumentation/wxml.d.ts +16 -4
- package/dist/preload/instrumentation/wxml.js +188 -178
- package/dist/preload/miniapp-snapshot/host.d.ts +12 -0
- package/dist/preload/miniapp-snapshot/host.js +117 -0
- package/dist/preload/miniapp-snapshot/types.d.ts +62 -0
- package/dist/preload/miniapp-snapshot/types.js +15 -0
- package/dist/preload/runtime/bridge.js +5 -24
- package/dist/preload/runtime/custom-apis.d.ts +1 -1
- package/dist/preload/runtime/custom-apis.js +3 -7
- package/dist/preload/shared/expose.d.ts +15 -0
- package/dist/preload/shared/expose.js +33 -0
- package/dist/preload/shared/page-iframe.d.ts +3 -0
- package/dist/preload/shared/page-iframe.js +6 -0
- package/dist/preload/shared/types.d.ts +2 -0
- package/dist/preload/windows/simulator.js +400 -348
- package/dist/renderer/assets/constants-DI382mTP.js +2 -0
- package/dist/renderer/assets/index-D8VFYBh-.js +46 -0
- package/dist/renderer/assets/{input-DqVQNCx_.js → input-CoWcfa8u.js} +2 -2
- package/dist/renderer/assets/ipc-transport-Cd2xPrsa.js +9 -0
- package/dist/renderer/assets/popover-Nq5gT9DO.js +2 -0
- package/dist/renderer/assets/select-By5KH-UG.js +2 -0
- package/dist/renderer/assets/{settings-BFNfnYvU.js → settings-Dj_N70qR.js} +2 -2
- package/dist/renderer/assets/settings-api-Do0_Smq1.js +2 -0
- package/dist/renderer/assets/workbenchSettings-CazSLGYt.js +8 -0
- package/dist/renderer/entries/main/index.html +5 -4
- package/dist/renderer/entries/popover/index.html +5 -4
- package/dist/renderer/entries/settings/index.html +4 -4
- package/dist/renderer/entries/workbench-settings/index.html +4 -3
- package/dist/shared/ipc-channels.d.ts +4 -12
- package/dist/shared/ipc-channels.js +10 -14
- package/dist/shared/simulator-route.d.ts +72 -0
- package/dist/shared/simulator-route.js +169 -0
- package/dist/shared/types.d.ts +2 -10
- package/dist/simulator/assets/simulator-DJCozrU5.js +9 -0
- package/dist/simulator/simulator.html +6 -43
- package/package.json +4 -4
- package/dist/preload/instrumentation/disposable.d.ts +0 -11
- package/dist/preload/instrumentation/disposable.js +0 -15
- package/dist/renderer/assets/index-Czz_bp6b.js +0 -46
- package/dist/renderer/assets/ipc-transport-CCHrCtDr.js +0 -9
- package/dist/renderer/assets/popover-BRg4XI_w.js +0 -2
- package/dist/renderer/assets/select-CvILHHZU.js +0 -2
- package/dist/renderer/assets/settings-api-DOAgmBst.js +0 -2
- package/dist/renderer/assets/workbenchSettings-DjVMgMMH.js +0 -8
- package/dist/simulator/assets/simulator-DL6kOCq-.js +0 -9
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { app, nativeTheme } from 'electron';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { DEFAULT_CDP_PORT } from '../../../shared/constants.js';
|
|
4
5
|
const DEFAULTS = {
|
|
5
6
|
cdp: {
|
|
6
7
|
enabled: false,
|
|
7
|
-
port:
|
|
8
|
+
port: DEFAULT_CDP_PORT,
|
|
8
9
|
},
|
|
9
10
|
mcp: {
|
|
10
11
|
enabled: false,
|
|
@@ -204,6 +204,35 @@ export function setupSimulatorStorage(host, options) {
|
|
|
204
204
|
}
|
|
205
205
|
return { securityOrigin: cachedOrigin, isLocalStorage: true };
|
|
206
206
|
}
|
|
207
|
+
async function withStorageWrite(fn) {
|
|
208
|
+
await ensureAttached();
|
|
209
|
+
if (!attachedWc || attachedWc.isDestroyed()) {
|
|
210
|
+
return { ok: false, error: 'simulator not attached' };
|
|
211
|
+
}
|
|
212
|
+
const storageId = await getStorageId();
|
|
213
|
+
if (!storageId)
|
|
214
|
+
return { ok: false, error: 'failed to resolve simulator origin' };
|
|
215
|
+
try {
|
|
216
|
+
return await fn({ wc: attachedWc, storageId });
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
return { ok: false, error: e.message };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async function withStorageRead(fallback, fn) {
|
|
223
|
+
await ensureAttached();
|
|
224
|
+
if (!attachedWc || attachedWc.isDestroyed())
|
|
225
|
+
return fallback;
|
|
226
|
+
try {
|
|
227
|
+
const storageId = await getStorageId();
|
|
228
|
+
if (!storageId)
|
|
229
|
+
return fallback;
|
|
230
|
+
return await fn({ wc: attachedWc, storageId });
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return fallback;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
207
236
|
/**
|
|
208
237
|
* Push a storage event synthesised from the write path itself, in addition
|
|
209
238
|
* to whatever CDP forwards via `DOMStorage.domStorageItem*`. The CDP
|
|
@@ -228,109 +257,53 @@ export function setupSimulatorStorage(host, options) {
|
|
|
228
257
|
host.send(SimulatorStorageChannel.Event, evt);
|
|
229
258
|
}
|
|
230
259
|
async function setItem(key, value) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return { ok: false, error: 'simulator not attached' };
|
|
234
|
-
}
|
|
235
|
-
const storageId = await getStorageId();
|
|
236
|
-
if (!storageId)
|
|
237
|
-
return { ok: false, error: 'failed to resolve simulator origin' };
|
|
238
|
-
try {
|
|
239
|
-
await attachedWc.debugger.sendCommand('DOMStorage.setDOMStorageItem', {
|
|
240
|
-
storageId,
|
|
241
|
-
key,
|
|
242
|
-
value,
|
|
243
|
-
});
|
|
260
|
+
return withStorageWrite(async ({ wc, storageId }) => {
|
|
261
|
+
await wc.debugger.sendCommand('DOMStorage.setDOMStorageItem', { storageId, key, value });
|
|
244
262
|
pushSyntheticEvent({ type: 'added', key, newValue: value });
|
|
245
263
|
return { ok: true };
|
|
246
|
-
}
|
|
247
|
-
catch (e) {
|
|
248
|
-
return { ok: false, error: e.message };
|
|
249
|
-
}
|
|
264
|
+
});
|
|
250
265
|
}
|
|
251
266
|
async function removeItem(key) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return { ok: false, error: 'simulator not attached' };
|
|
255
|
-
}
|
|
256
|
-
const storageId = await getStorageId();
|
|
257
|
-
if (!storageId)
|
|
258
|
-
return { ok: false, error: 'failed to resolve simulator origin' };
|
|
259
|
-
try {
|
|
260
|
-
await attachedWc.debugger.sendCommand('DOMStorage.removeDOMStorageItem', {
|
|
261
|
-
storageId,
|
|
262
|
-
key,
|
|
263
|
-
});
|
|
267
|
+
return withStorageWrite(async ({ wc, storageId }) => {
|
|
268
|
+
await wc.debugger.sendCommand('DOMStorage.removeDOMStorageItem', { storageId, key });
|
|
264
269
|
pushSyntheticEvent({ type: 'removed', key });
|
|
265
270
|
return { ok: true };
|
|
266
|
-
}
|
|
267
|
-
catch (e) {
|
|
268
|
-
return { ok: false, error: e.message };
|
|
269
|
-
}
|
|
271
|
+
});
|
|
270
272
|
}
|
|
271
273
|
// Scoped clear: when an appId is active, removes only its prefixed keys so
|
|
272
274
|
// we don't nuke other projects' state sharing the simulator partition.
|
|
273
275
|
// Falls back to origin-wide `DOMStorage.clear` only when no active appId is
|
|
274
276
|
// set (matches the snapshot filter's documented null-fallback).
|
|
275
277
|
async function clearScoped() {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
return { ok: false, error: 'simulator not attached' };
|
|
279
|
-
}
|
|
280
|
-
const storageId = await getStorageId();
|
|
281
|
-
if (!storageId)
|
|
282
|
-
return { ok: false, error: 'failed to resolve simulator origin' };
|
|
283
|
-
const prefix = activePrefix();
|
|
284
|
-
try {
|
|
278
|
+
return withStorageWrite(async ({ wc, storageId }) => {
|
|
279
|
+
const prefix = activePrefix();
|
|
285
280
|
if (!prefix) {
|
|
286
|
-
await
|
|
281
|
+
await wc.debugger.sendCommand('DOMStorage.clear', { storageId });
|
|
287
282
|
return { ok: true };
|
|
288
283
|
}
|
|
289
|
-
const result = (await
|
|
284
|
+
const result = (await wc.debugger.sendCommand('DOMStorage.getDOMStorageItems', {
|
|
290
285
|
storageId,
|
|
291
286
|
}));
|
|
292
287
|
for (const [key] of result.entries) {
|
|
293
288
|
if (!key.startsWith(prefix))
|
|
294
289
|
continue;
|
|
295
|
-
await
|
|
296
|
-
storageId,
|
|
297
|
-
key,
|
|
298
|
-
});
|
|
290
|
+
await wc.debugger.sendCommand('DOMStorage.removeDOMStorageItem', { storageId, key });
|
|
299
291
|
}
|
|
300
292
|
return { ok: true };
|
|
301
|
-
}
|
|
302
|
-
catch (e) {
|
|
303
|
-
return { ok: false, error: e.message };
|
|
304
|
-
}
|
|
293
|
+
});
|
|
305
294
|
}
|
|
306
295
|
// Origin-wide clear regardless of the active appId — wipes every project's
|
|
307
296
|
// state in the shared simulator partition. The renderer guards this with a
|
|
308
297
|
// confirm dialog; we don't second-guess here.
|
|
309
298
|
async function clearAll() {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return { ok: false, error: 'simulator not attached' };
|
|
313
|
-
}
|
|
314
|
-
const storageId = await getStorageId();
|
|
315
|
-
if (!storageId)
|
|
316
|
-
return { ok: false, error: 'failed to resolve simulator origin' };
|
|
317
|
-
try {
|
|
318
|
-
await attachedWc.debugger.sendCommand('DOMStorage.clear', { storageId });
|
|
299
|
+
return withStorageWrite(async ({ wc, storageId }) => {
|
|
300
|
+
await wc.debugger.sendCommand('DOMStorage.clear', { storageId });
|
|
319
301
|
return { ok: true };
|
|
320
|
-
}
|
|
321
|
-
catch (e) {
|
|
322
|
-
return { ok: false, error: e.message };
|
|
323
|
-
}
|
|
302
|
+
});
|
|
324
303
|
}
|
|
325
304
|
async function getSnapshot() {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return [];
|
|
329
|
-
try {
|
|
330
|
-
const storageId = await getStorageId();
|
|
331
|
-
if (!storageId)
|
|
332
|
-
return [];
|
|
333
|
-
const result = (await attachedWc.debugger.sendCommand('DOMStorage.getDOMStorageItems', {
|
|
305
|
+
return withStorageRead([], async ({ wc, storageId }) => {
|
|
306
|
+
const result = (await wc.debugger.sendCommand('DOMStorage.getDOMStorageItems', {
|
|
334
307
|
storageId,
|
|
335
308
|
}));
|
|
336
309
|
const prefix = activePrefix();
|
|
@@ -340,10 +313,7 @@ export function setupSimulatorStorage(host, options) {
|
|
|
340
313
|
// Keys are returned with their `${appId}_` prefix intact; stripping is
|
|
341
314
|
// a follow-up so the panel UI can stay compatible with the raw keys.
|
|
342
315
|
return filtered.map(([key, value]) => ({ key, value }));
|
|
343
|
-
}
|
|
344
|
-
catch {
|
|
345
|
-
return [];
|
|
346
|
-
}
|
|
316
|
+
});
|
|
347
317
|
}
|
|
348
318
|
// Attach to any simulator webview that already exists (project may have
|
|
349
319
|
// been opened before this function runs).
|
|
@@ -5,7 +5,7 @@ import { type WorkbenchContext } from '../workbench-context.js';
|
|
|
5
5
|
* full WorkbenchContext here; typing it this way documents the actual dependency.
|
|
6
6
|
*/
|
|
7
7
|
export interface ViewManagerContext {
|
|
8
|
-
|
|
8
|
+
windows: WorkbenchContext['windows'];
|
|
9
9
|
rendererDir: string;
|
|
10
10
|
panels: string[];
|
|
11
11
|
notify: WorkbenchContext['notify'];
|
|
@@ -52,14 +52,10 @@ export interface ViewManager {
|
|
|
52
52
|
repositionAll(): void;
|
|
53
53
|
/** Destroy all overlay webContents and null out the cached views. */
|
|
54
54
|
disposeAll(): void;
|
|
55
|
-
/** Log current child-view count of the main contentView. */
|
|
56
|
-
logChildViews(label: string): void;
|
|
57
|
-
/** Reposition only the simulator overlay (for simulator width changes). */
|
|
58
|
-
positionSimulator(simWidth: number): void;
|
|
59
|
-
/** Reposition only the settings overlay. */
|
|
60
|
-
positionSettings(): void;
|
|
61
55
|
/** Return the webContents ID of the currently attached simulator. */
|
|
62
56
|
getSimulatorWebContentsId(): number | null;
|
|
57
|
+
/** Return the live webContents of the currently attached simulator, or null. */
|
|
58
|
+
getSimulatorWebContents(): WebContents | null;
|
|
63
59
|
/** Return the last known simulator width. */
|
|
64
60
|
getLastSimWidth(): number;
|
|
65
61
|
/** Whether the simulator overlay is currently added to the contentView. */
|
|
@@ -24,9 +24,9 @@ export function createViewManager(ctx) {
|
|
|
24
24
|
function destroyViewInternal(view) {
|
|
25
25
|
if (!view)
|
|
26
26
|
return;
|
|
27
|
-
if (!ctx.mainWindow.isDestroyed()) {
|
|
27
|
+
if (!ctx.windows.mainWindow.isDestroyed()) {
|
|
28
28
|
try {
|
|
29
|
-
ctx.mainWindow.contentView.removeChildView(view);
|
|
29
|
+
ctx.windows.mainWindow.contentView.removeChildView(view);
|
|
30
30
|
}
|
|
31
31
|
catch { /* already removed */ }
|
|
32
32
|
}
|
|
@@ -38,21 +38,21 @@ export function createViewManager(ctx) {
|
|
|
38
38
|
catch { /* ignore */ }
|
|
39
39
|
}
|
|
40
40
|
function applySimulatorBounds(simWidth) {
|
|
41
|
-
if (!simulatorView || ctx.mainWindow.isDestroyed())
|
|
41
|
+
if (!simulatorView || ctx.windows.mainWindow.isDestroyed())
|
|
42
42
|
return;
|
|
43
|
-
const [w = 0, h = 0] = ctx.mainWindow.getContentSize();
|
|
43
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
44
44
|
simulatorView.setBounds(layout.computeSimulatorBounds(w, h, simWidth));
|
|
45
45
|
}
|
|
46
46
|
function applySettingsBounds() {
|
|
47
|
-
if (!settingsView || ctx.mainWindow.isDestroyed())
|
|
47
|
+
if (!settingsView || ctx.windows.mainWindow.isDestroyed())
|
|
48
48
|
return;
|
|
49
|
-
const [w = 0, h = 0] = ctx.mainWindow.getContentSize();
|
|
49
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
50
50
|
settingsView.setBounds(layout.computeSettingsBounds(w, h));
|
|
51
51
|
}
|
|
52
52
|
function applyPopoverBounds() {
|
|
53
|
-
if (!popoverView || ctx.mainWindow.isDestroyed())
|
|
53
|
+
if (!popoverView || ctx.windows.mainWindow.isDestroyed())
|
|
54
54
|
return;
|
|
55
|
-
const [w = 0, h = 0] = ctx.mainWindow.getContentSize();
|
|
55
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
56
56
|
popoverView.setBounds(layout.computePopoverBounds(w, h));
|
|
57
57
|
}
|
|
58
58
|
// ── ViewManager methods ─────────────────────────────────────────────────
|
|
@@ -105,7 +105,7 @@ export function createViewManager(ctx) {
|
|
|
105
105
|
`).catch(() => { });
|
|
106
106
|
});
|
|
107
107
|
if (getDefaultTab(ctx) === 'simulator') {
|
|
108
|
-
ctx.mainWindow.contentView.addChildView(simulatorView);
|
|
108
|
+
ctx.windows.mainWindow.contentView.addChildView(simulatorView);
|
|
109
109
|
simulatorViewAdded = true;
|
|
110
110
|
applySimulatorBounds(simWidth);
|
|
111
111
|
}
|
|
@@ -126,7 +126,7 @@ export function createViewManager(ctx) {
|
|
|
126
126
|
if (!simulatorView)
|
|
127
127
|
return;
|
|
128
128
|
if (!simulatorViewAdded) {
|
|
129
|
-
ctx.mainWindow.contentView.addChildView(simulatorView);
|
|
129
|
+
ctx.windows.mainWindow.contentView.addChildView(simulatorView);
|
|
130
130
|
simulatorViewAdded = true;
|
|
131
131
|
}
|
|
132
132
|
applySimulatorBounds(simWidth);
|
|
@@ -134,7 +134,7 @@ export function createViewManager(ctx) {
|
|
|
134
134
|
function hideSimulator() {
|
|
135
135
|
if (simulatorView && simulatorViewAdded) {
|
|
136
136
|
try {
|
|
137
|
-
ctx.mainWindow.contentView.removeChildView(simulatorView);
|
|
137
|
+
ctx.windows.mainWindow.contentView.removeChildView(simulatorView);
|
|
138
138
|
}
|
|
139
139
|
catch (e) {
|
|
140
140
|
console.error('[workbench] hideSimulator error', e);
|
|
@@ -158,7 +158,7 @@ export function createViewManager(ctx) {
|
|
|
158
158
|
await settingsView.webContents.loadFile(path.join(ctx.rendererDir, 'entries/settings/index.html'));
|
|
159
159
|
}
|
|
160
160
|
if (!settingsViewAdded) {
|
|
161
|
-
ctx.mainWindow.contentView.addChildView(settingsView);
|
|
161
|
+
ctx.windows.mainWindow.contentView.addChildView(settingsView);
|
|
162
162
|
settingsViewAdded = true;
|
|
163
163
|
}
|
|
164
164
|
applySettingsBounds();
|
|
@@ -166,7 +166,7 @@ export function createViewManager(ctx) {
|
|
|
166
166
|
function hideSettings() {
|
|
167
167
|
if (settingsView && settingsViewAdded) {
|
|
168
168
|
try {
|
|
169
|
-
ctx.mainWindow.contentView.removeChildView(settingsView);
|
|
169
|
+
ctx.windows.mainWindow.contentView.removeChildView(settingsView);
|
|
170
170
|
}
|
|
171
171
|
catch { /* ignore */ }
|
|
172
172
|
settingsViewAdded = false;
|
|
@@ -186,7 +186,7 @@ export function createViewManager(ctx) {
|
|
|
186
186
|
applyNavigationHardening(popover.webContents, ctx.rendererDir);
|
|
187
187
|
popoverView = popover;
|
|
188
188
|
popover.setBackgroundColor('#00000000');
|
|
189
|
-
ctx.mainWindow.contentView.addChildView(popover);
|
|
189
|
+
ctx.windows.mainWindow.contentView.addChildView(popover);
|
|
190
190
|
applyPopoverBounds();
|
|
191
191
|
popover.webContents.once('did-finish-load', () => {
|
|
192
192
|
ctx.notify.popoverInit(popover, data);
|
|
@@ -211,16 +211,6 @@ export function createViewManager(ctx) {
|
|
|
211
211
|
function disposeAll() {
|
|
212
212
|
detachSimulator();
|
|
213
213
|
}
|
|
214
|
-
function logChildViews(_label) {
|
|
215
|
-
// Debug helper — intentionally a no-op in production. Kept on the
|
|
216
|
-
// ViewManager interface so call sites and tests stay stable.
|
|
217
|
-
}
|
|
218
|
-
function positionSimulator(simWidth) {
|
|
219
|
-
applySimulatorBounds(simWidth);
|
|
220
|
-
}
|
|
221
|
-
function positionSettings() {
|
|
222
|
-
applySettingsBounds();
|
|
223
|
-
}
|
|
224
214
|
function resize(simWidth) {
|
|
225
215
|
lastSimWidth = simWidth;
|
|
226
216
|
if (simulatorViewAdded)
|
|
@@ -250,10 +240,13 @@ export function createViewManager(ctx) {
|
|
|
250
240
|
hidePopover,
|
|
251
241
|
repositionAll,
|
|
252
242
|
disposeAll,
|
|
253
|
-
logChildViews,
|
|
254
|
-
positionSimulator,
|
|
255
|
-
positionSettings,
|
|
256
243
|
getSimulatorWebContentsId: () => simulatorWebContentsId,
|
|
244
|
+
getSimulatorWebContents: () => {
|
|
245
|
+
if (simulatorWebContentsId == null)
|
|
246
|
+
return null;
|
|
247
|
+
const wc = webContents.fromId(simulatorWebContentsId);
|
|
248
|
+
return wc && !wc.isDestroyed() ? wc : null;
|
|
249
|
+
},
|
|
257
250
|
getLastSimWidth: () => lastSimWidth,
|
|
258
251
|
isSimulatorAdded: () => simulatorViewAdded,
|
|
259
252
|
hasSimulatorView: () => simulatorView !== null,
|
|
@@ -2,9 +2,9 @@ import type { BrowserWindow } from 'electron';
|
|
|
2
2
|
/**
|
|
3
3
|
* Owns every top-level BrowserWindow the workbench is responsible for.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* This service is the single source of truth for the main and settings
|
|
6
|
+
* windows; callers reach them via `ctx.windows.mainWindow` /
|
|
7
|
+
* `ctx.windows.settingsWindow`.
|
|
8
8
|
*/
|
|
9
9
|
export interface WindowService {
|
|
10
10
|
/** The primary devtools window. Created during app bootstrap. */
|
|
@@ -7,21 +7,18 @@ import { type ViewManager } from './views/view-manager.js';
|
|
|
7
7
|
import { type WindowService } from './window-service.js';
|
|
8
8
|
import { type WorkspaceService } from './workspace/workspace-service.js';
|
|
9
9
|
import { sanitizeTemplates } from './projects/templates.js';
|
|
10
|
-
import type {
|
|
10
|
+
import type { ProjectsProvider, ProjectTemplate } from './projects/types.js';
|
|
11
|
+
import type { CustomCreateProjectDialogResult } from '../../shared/types.js';
|
|
11
12
|
/**
|
|
12
13
|
* Shared mutable state for the workbench application.
|
|
13
14
|
* Passed to each IPC module so they can read/write shared state without closures.
|
|
14
15
|
*/
|
|
15
16
|
export interface WorkbenchContext {
|
|
16
|
-
/** @deprecated use ctx.windows.mainWindow */
|
|
17
|
-
mainWindow: BrowserWindow;
|
|
18
17
|
adapter: CompilationAdapter;
|
|
19
18
|
/** Absolute path to the preload script loaded into the simulator webview */
|
|
20
19
|
preloadPath: string;
|
|
21
20
|
/** Absolute path to the renderer dist directory */
|
|
22
21
|
rendererDir: string;
|
|
23
|
-
/** @deprecated use ctx.windows.settingsWindow / setSettingsWindow / closeSettingsWindow */
|
|
24
|
-
workbenchSettingsWindow: BrowserWindow | null;
|
|
25
22
|
/** Built-in panel IDs to display (default: all) */
|
|
26
23
|
panels: string[];
|
|
27
24
|
/** Custom API namespace names (e.g. ['qd']) passed to the simulator */
|
|
@@ -73,7 +70,7 @@ export interface WorkbenchContext {
|
|
|
73
70
|
customCreateProjectDialog?: (ctx: {
|
|
74
71
|
parentWindow: BrowserWindow;
|
|
75
72
|
templates: ProjectTemplate[];
|
|
76
|
-
}) => Promise<
|
|
73
|
+
}) => Promise<CustomCreateProjectDialogResult>;
|
|
77
74
|
/**
|
|
78
75
|
* Trust predicate consulted by `IpcRegistry` for every incoming IPC.
|
|
79
76
|
* Resolves the currently-trusted senders (main renderer + overlays)
|
|
@@ -20,7 +20,6 @@ export function getDefaultTab(ctx) {
|
|
|
20
20
|
}
|
|
21
21
|
export function createWorkbenchContext(opts) {
|
|
22
22
|
const ctx = {
|
|
23
|
-
mainWindow: opts.mainWindow,
|
|
24
23
|
adapter: opts.adapter ?? defaultAdapter,
|
|
25
24
|
preloadPath: opts.preloadPath,
|
|
26
25
|
rendererDir: opts.rendererDir,
|
|
@@ -29,10 +28,9 @@ export function createWorkbenchContext(opts) {
|
|
|
29
28
|
appName: opts.appName ?? 'Dimina DevTools',
|
|
30
29
|
toolbarActions: opts.toolbarActions,
|
|
31
30
|
brandingProvider: opts.brandingProvider,
|
|
32
|
-
workbenchSettingsWindow: null,
|
|
33
31
|
};
|
|
34
32
|
ctx.registry = new DisposableRegistry();
|
|
35
|
-
ctx.windows = createWindowService(
|
|
33
|
+
ctx.windows = createWindowService(opts.mainWindow);
|
|
36
34
|
ctx.views = createViewManager(ctx);
|
|
37
35
|
ctx.notify = createRendererNotifier(ctx);
|
|
38
36
|
ctx.projectsProvider = opts.projectsProvider ?? createLocalProjectsProvider();
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { webContents } from 'electron';
|
|
2
1
|
import * as repo from '../projects/project-repository.js';
|
|
3
2
|
import { DEFAULT_COMPILE_CONFIG } from '../projects/types.js';
|
|
4
3
|
import { clearSimulatorServicewechatReferer, setSimulatorServicewechatReferer, } from '../simulator/referer.js';
|
|
@@ -39,24 +38,12 @@ export function createWorkspaceService(ctx) {
|
|
|
39
38
|
setSimulatorServicewechatReferer(appInfo.appId, typeof appInfo.version === 'string' ? appInfo.version : undefined);
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
|
-
// Delegate to the host-injected (or default)
|
|
43
|
-
// context. When the host omits an optional method,
|
|
44
|
-
// documented default — never silently fall back to
|
|
45
|
-
// remote provider's project paths are not on the local
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
// values (used in a couple of legacy tests). createWorkbenchContext
|
|
49
|
-
// always installs LocalProjectsProvider, so production never enters this
|
|
50
|
-
// branch.
|
|
51
|
-
const provider = ctx.projectsProvider ?? {
|
|
52
|
-
listProjects: () => repo.listProjects(),
|
|
53
|
-
addProject: (p) => repo.addProject(p),
|
|
54
|
-
removeProject: (p) => repo.removeProject(p),
|
|
55
|
-
validateProjectDir: (p) => repo.validateProjectDir(p),
|
|
56
|
-
updateLastOpened: (p) => repo.updateLastOpened(p),
|
|
57
|
-
getCompileConfig: (p) => repo.getCompileConfig(p),
|
|
58
|
-
saveCompileConfig: (p, c) => repo.saveCompileConfig(p, c),
|
|
59
|
-
};
|
|
41
|
+
// Delegate to the host-injected (or default LocalProjectsProvider)
|
|
42
|
+
// ProjectsProvider on the context. When the host omits an optional method,
|
|
43
|
+
// we apply a safe documented default — never silently fall back to
|
|
44
|
+
// `repo.*`, because a remote provider's project paths are not on the local
|
|
45
|
+
// filesystem.
|
|
46
|
+
const provider = ctx.projectsProvider;
|
|
60
47
|
return {
|
|
61
48
|
listProjects: async () => provider.listProjects(),
|
|
62
49
|
addProject: async (dirPath) => provider.addProject(dirPath),
|
|
@@ -129,11 +116,8 @@ export function createWorkspaceService(ctx) {
|
|
|
129
116
|
getProjectPath: () => currentProjectPath,
|
|
130
117
|
hasActiveSession: () => currentSession !== null,
|
|
131
118
|
async captureThumbnail(projectPath) {
|
|
132
|
-
const
|
|
133
|
-
if (!
|
|
134
|
-
return null;
|
|
135
|
-
const wc = webContents.fromId(simWcId);
|
|
136
|
-
if (!wc || wc.isDestroyed())
|
|
119
|
+
const wc = ctx.views.getSimulatorWebContents();
|
|
120
|
+
if (!wc)
|
|
137
121
|
return null;
|
|
138
122
|
try {
|
|
139
123
|
const image = await wc.capturePage();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Disposable } from './disposable.js';
|
|
1
2
|
/**
|
|
2
3
|
* Background color that matches the current system color scheme.
|
|
3
4
|
* Pass as `backgroundColor` when creating BrowserWindows to prevent
|
|
@@ -7,4 +8,27 @@
|
|
|
7
8
|
* Light: hsl(0 0% 98%) ≈ #fafafa (--color-bg)
|
|
8
9
|
*/
|
|
9
10
|
export declare function themeBg(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Install a single process-wide listener that keeps every window's native
|
|
13
|
+
* `backgroundColor` in sync with the active color scheme.
|
|
14
|
+
*
|
|
15
|
+
* A window's `backgroundColor` is otherwise frozen at the value passed to its
|
|
16
|
+
* constructor: after a theme switch the stale color bleeds through wherever
|
|
17
|
+
* native chrome and the WebContents meet. On Windows/Linux (in-window menu
|
|
18
|
+
* bar) it shows as a light hairline between the menu bar and the page; on
|
|
19
|
+
* macOS (global menu bar) it is latent — only a wrong-color flash on resize.
|
|
20
|
+
* The defect is platform-agnostic, so the fix is too: one `nativeTheme`
|
|
21
|
+
* `updated` listener re-syncs every current and future BrowserWindow.
|
|
22
|
+
*
|
|
23
|
+
* Known limitation: on Linux the `updated` event does not fire for OS-level
|
|
24
|
+
* system theme changes (electron/electron#25925) — only for explicit
|
|
25
|
+
* `nativeTheme.themeSource` assignments. In-app theme switches go through
|
|
26
|
+
* `applyTheme()` and are unaffected on every platform; the gap is limited to
|
|
27
|
+
* Linux + `theme: 'system'` + an OS theme change, an upstream Electron
|
|
28
|
+
* limitation that also leaves the renderer's `prefers-color-scheme` stale.
|
|
29
|
+
*
|
|
30
|
+
* Returns a Disposable that detaches the listener. Install it once during
|
|
31
|
+
* app setup and hand the Disposable to the workbench registry.
|
|
32
|
+
*/
|
|
33
|
+
export declare function installThemeBackgroundSync(): Disposable;
|
|
10
34
|
//# sourceMappingURL=theme.d.ts.map
|
package/dist/main/utils/theme.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { nativeTheme } from 'electron';
|
|
1
|
+
import { BrowserWindow, nativeTheme } from 'electron';
|
|
2
|
+
import { toDisposable } from './disposable.js';
|
|
2
3
|
/**
|
|
3
4
|
* Background color that matches the current system color scheme.
|
|
4
5
|
* Pass as `backgroundColor` when creating BrowserWindows to prevent
|
|
@@ -10,4 +11,40 @@ import { nativeTheme } from 'electron';
|
|
|
10
11
|
export function themeBg() {
|
|
11
12
|
return nativeTheme.shouldUseDarkColors ? '#1a1a1a' : '#fafafa';
|
|
12
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Install a single process-wide listener that keeps every window's native
|
|
16
|
+
* `backgroundColor` in sync with the active color scheme.
|
|
17
|
+
*
|
|
18
|
+
* A window's `backgroundColor` is otherwise frozen at the value passed to its
|
|
19
|
+
* constructor: after a theme switch the stale color bleeds through wherever
|
|
20
|
+
* native chrome and the WebContents meet. On Windows/Linux (in-window menu
|
|
21
|
+
* bar) it shows as a light hairline between the menu bar and the page; on
|
|
22
|
+
* macOS (global menu bar) it is latent — only a wrong-color flash on resize.
|
|
23
|
+
* The defect is platform-agnostic, so the fix is too: one `nativeTheme`
|
|
24
|
+
* `updated` listener re-syncs every current and future BrowserWindow.
|
|
25
|
+
*
|
|
26
|
+
* Known limitation: on Linux the `updated` event does not fire for OS-level
|
|
27
|
+
* system theme changes (electron/electron#25925) — only for explicit
|
|
28
|
+
* `nativeTheme.themeSource` assignments. In-app theme switches go through
|
|
29
|
+
* `applyTheme()` and are unaffected on every platform; the gap is limited to
|
|
30
|
+
* Linux + `theme: 'system'` + an OS theme change, an upstream Electron
|
|
31
|
+
* limitation that also leaves the renderer's `prefers-color-scheme` stale.
|
|
32
|
+
*
|
|
33
|
+
* Returns a Disposable that detaches the listener. Install it once during
|
|
34
|
+
* app setup and hand the Disposable to the workbench registry.
|
|
35
|
+
*/
|
|
36
|
+
export function installThemeBackgroundSync() {
|
|
37
|
+
const apply = () => {
|
|
38
|
+
const bg = themeBg();
|
|
39
|
+
for (const win of BrowserWindow.getAllWindows()) {
|
|
40
|
+
if (!win.isDestroyed()) {
|
|
41
|
+
win.setBackgroundColor(bg);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
nativeTheme.on('updated', apply);
|
|
46
|
+
return toDisposable(() => {
|
|
47
|
+
nativeTheme.removeListener('updated', apply);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
13
50
|
//# sourceMappingURL=theme.js.map
|
package/dist/preload/index.d.ts
CHANGED
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
* bundled by esbuild, never re-exported through this barrel.
|
|
11
11
|
*/
|
|
12
12
|
export { installConsoleInstrumentation } from './instrumentation/console.js';
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
13
|
+
export { createAppDataSource } from './instrumentation/app-data.js';
|
|
14
|
+
export type { AppDataSnapshot } from './instrumentation/app-data.js';
|
|
15
|
+
export { createWxmlSource } from './instrumentation/wxml.js';
|
|
16
|
+
export { createMiniappSnapshotHost } from './miniapp-snapshot/host.js';
|
|
17
|
+
export type { MiniappSnapshotHost, MiniappSnapshotSource, SnapshotEnvelope, SnapshotSourceId, } from './miniapp-snapshot/types.js';
|
|
15
18
|
export { installSimulatorBridge } from './runtime/bridge.js';
|
|
16
19
|
export { installCustomApisBridge } from './runtime/custom-apis.js';
|
|
17
20
|
export type { DiminaCustomApisBridge } from './runtime/custom-apis.js';
|
package/dist/preload/index.js
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
* bundled by esbuild, never re-exported through this barrel.
|
|
11
11
|
*/
|
|
12
12
|
export { installConsoleInstrumentation } from './instrumentation/console.js';
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
13
|
+
export { createAppDataSource } from './instrumentation/app-data.js';
|
|
14
|
+
export { createWxmlSource } from './instrumentation/wxml.js';
|
|
15
|
+
export { createMiniappSnapshotHost } from './miniapp-snapshot/host.js';
|
|
15
16
|
export { installSimulatorBridge } from './runtime/bridge.js';
|
|
16
17
|
export { installCustomApisBridge } from './runtime/custom-apis.js';
|
|
17
18
|
export { setupApiCompatHook } from './shared/api-compat.js';
|
|
@@ -1,3 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type { MiniappSnapshotSource } from '../miniapp-snapshot/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The AppData snapshot — the full, cumulative panel state.
|
|
4
|
+
*
|
|
5
|
+
* - `bridges` lists every page bridge in chronological (insertion) order, each
|
|
6
|
+
* carrying its page route (`pagePath`), so renderer tabs render in a stable
|
|
7
|
+
* sequence.
|
|
8
|
+
* - `entries` maps `bridgeId → (componentPath | moduleId) → setData state`.
|
|
9
|
+
*/
|
|
10
|
+
export interface AppDataSnapshot {
|
|
11
|
+
bridges: Array<{
|
|
12
|
+
id: string;
|
|
13
|
+
pagePath: string | null;
|
|
14
|
+
}>;
|
|
15
|
+
entries: Record<string, Record<string, unknown>>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The AppData snapshot data source.
|
|
19
|
+
*
|
|
20
|
+
* Instruments `window.Worker` (incoming `message` decoding + outgoing
|
|
21
|
+
* `postMessage` interception) and installs `window.__simulatorHook.appData`,
|
|
22
|
+
* accumulating per-(bridgeId, moduleId) setData state in an internal cache.
|
|
23
|
+
* Every cache mutation — an accepted `ub`/`page_*` worker message, or a
|
|
24
|
+
* `pageUnload` evicting a bridge — calls `emit()` so the `miniappSnapshot`
|
|
25
|
+
* host republishes the full snapshot. The source itself never touches IPC:
|
|
26
|
+
* the host owns push, pull and the install-time publish.
|
|
27
|
+
*
|
|
28
|
+
* It keeps the `__simulatorData.getAppdata()` automation surface working by
|
|
29
|
+
* mirroring the flat cache into the simulator bridge via `setAppDataSnapshot`
|
|
30
|
+
* / `clearAppDataSnapshot`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createAppDataSource(): MiniappSnapshotSource<AppDataSnapshot>;
|
|
3
33
|
//# sourceMappingURL=app-data.d.ts.map
|