@dimina-kit/devtools 0.4.0-dev.20260616102751 → 0.4.0-dev.20260624040247
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -25
- package/dist/main/app/app.js +14 -2
- package/dist/main/index.bundle.js +559 -111
- package/dist/main/ipc/bridge-router.js +57 -9
- package/dist/main/ipc/projects.js +1 -1
- package/dist/main/ipc/simulator.js +1 -1
- package/dist/main/runtime/devtools-backend.d.ts +1 -1
- package/dist/main/runtime/devtools-backend.js +1 -1
- package/dist/main/runtime/miniapp-runtime.d.ts +5 -5
- package/dist/main/services/console-forward/index.js +8 -1
- package/dist/main/services/elements-forward/index.js +36 -12
- package/dist/main/services/layout/index.d.ts +12 -0
- package/dist/main/services/layout/index.js +14 -2
- package/dist/main/services/network-forward/index.d.ts +5 -6
- package/dist/main/services/network-forward/index.js +9 -10
- package/dist/main/services/notifications/renderer-notifier.d.ts +3 -4
- package/dist/main/services/projects/index.js +1 -1
- package/dist/main/services/projects/types.d.ts +1 -1
- package/dist/main/services/projects/types.js +1 -1
- package/dist/main/services/service-console/console-api.d.ts +77 -0
- package/dist/main/services/service-console/console-api.js +103 -0
- package/dist/main/services/service-console/index.d.ts +47 -0
- package/dist/main/services/service-console/index.js +139 -0
- package/dist/main/services/service-host-pool/pool.d.ts +2 -3
- package/dist/main/services/simulator-storage/index.d.ts +2 -4
- package/dist/main/services/simulator-storage/index.js +2 -4
- package/dist/main/services/simulator-temp-files/index.js +2 -2
- package/dist/main/services/update/update-manager.d.ts +1 -1
- package/dist/main/services/update/update-manager.js +1 -1
- package/dist/main/services/views/host-toolbar-session-runtime.d.ts +4 -4
- package/dist/main/services/views/host-toolbar-session-runtime.js +4 -4
- package/dist/main/services/views/view-manager.d.ts +24 -1
- package/dist/main/services/views/view-manager.js +120 -41
- package/dist/main/services/workbench-context.d.ts +7 -6
- package/dist/main/services/workspace/workspace-service.js +11 -0
- package/dist/main/windows/service-host-window/create.d.ts +1 -0
- package/dist/main/windows/service-host-window/create.js +1 -0
- package/dist/preload/runtime/host-toolbar-port.d.ts +1 -1
- package/dist/preload/runtime/host-toolbar-port.js +1 -1
- package/dist/preload/runtime/host-toolbar-runtime.d.ts +8 -7
- package/dist/preload/runtime/host-toolbar-runtime.js +8 -7
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs +1 -1
- package/dist/preload/windows/simulator.cjs.map +1 -1
- package/dist/preload/windows/simulator.js +1 -1
- package/dist/renderer/assets/index-PtsdWlGu.js +50 -0
- package/dist/renderer/assets/{input-B8NDCYv3.js → input-DiCxYlqY.js} +2 -2
- package/dist/renderer/assets/{ipc-transport-DhrajiC5.js → ipc-transport-DSBmaWpJ.js} +1 -1
- package/dist/renderer/assets/ipc-transport-DZxf2YoM.css +1 -0
- package/dist/renderer/assets/{popover-DbZOg03s.js → popover-CyL_uffj.js} +2 -2
- package/dist/renderer/assets/{select-pW3Ysc9T.js → select-BSwvDMtA.js} +2 -2
- package/dist/renderer/assets/settings-Ch8XbFxf.js +2 -0
- package/dist/renderer/assets/{settings-api-BSKzKiWd.js → settings-api-e9ILe2JO.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-BGxjl25x.js → workbenchSettings-DZsHf1g_.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +11 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/service-host/preload.cjs +13 -15
- package/dist/service-host/sourcemap-rewrite.cjs +21 -12
- package/dist/shared/appdata-accumulator.d.ts +2 -2
- package/dist/shared/appdata-accumulator.js +3 -3
- package/dist/shared/constants.d.ts +1 -1
- package/dist/shared/constants.js +1 -1
- package/dist/shared/ipc-channels.d.ts +3 -3
- package/dist/shared/ipc-channels.js +3 -3
- package/dist/shared/open-in-editor.d.ts +20 -1
- package/dist/shared/open-in-editor.js +246 -3
- package/dist/shared/vpath.d.ts +2 -2
- package/dist/shared/vpath.js +2 -2
- package/dist/simulator/assets/{device-shell-BWX7Yopg.js → device-shell-TtcSXwhb.js} +2 -2
- package/dist/simulator/assets/{simulator-sf-D0mhw.js → simulator-CtyXt_4V.js} +3 -3
- package/dist/simulator/simulator.html +1 -1
- package/package.json +8 -6
- package/dist/renderer/assets/index-Z4Rh52G8.js +0 -50
- package/dist/renderer/assets/ipc-transport-9agi76dX.css +0 -1
- package/dist/renderer/assets/settings-CZJOHt8b.js +0 -2
|
@@ -11,6 +11,46 @@ import { ServiceHostPool } from '../services/service-host-pool/pool.js';
|
|
|
11
11
|
import { registerMiniappSessionConfigurator, SHARED_MINIAPP_PARTITION, } from '../services/views/miniapp-partition.js';
|
|
12
12
|
import { createConsoleForwarder } from '../services/console-forward/index.js';
|
|
13
13
|
import { STORAGE_API_NAMES } from '../services/simulator-storage/index.js';
|
|
14
|
+
// The compiled `logic.js` ships a RELATIVE `//# sourceMappingURL=logic.js.map`.
|
|
15
|
+
// `injectLogicBundle` loads it via `executeJavaScript`, which gives the injected
|
|
16
|
+
// script no base URL of its own — so DevTools resolves that relative map against
|
|
17
|
+
// the service-host DOCUMENT and 404s, leaving console frames / Sources links
|
|
18
|
+
// pointing at the compiled bundle instead of the developer's source. This rewrite
|
|
19
|
+
// turns the directive absolute.
|
|
20
|
+
//
|
|
21
|
+
// Inlined (not imported from `service-host/sourcemap-rewrite.cjs`) ON PURPOSE:
|
|
22
|
+
// the shipped main entry is the FLAT esbuild bundle (`dist/main/index.bundle.js`,
|
|
23
|
+
// see electron-builder.yml `extraMetadata.main`). A runtime `createRequire(...)`
|
|
24
|
+
// of the relative `.cjs` resolved against `import.meta.url`, which is the bundle
|
|
25
|
+
// at `dist/main/` (one level shallower than the tsc tree `dist/main/ipc/`), so
|
|
26
|
+
// the path 404'd and the PACKAGED app crashed on load. Bundling the logic inline
|
|
27
|
+
// is bundler-proof. KEEP IN SYNC with `service-host/sourcemap-rewrite.cjs` (the
|
|
28
|
+
// copied-not-bundled service-host preload still requires that one).
|
|
29
|
+
function rewriteSourceMappingUrl(source, scriptUrl) {
|
|
30
|
+
if (typeof source !== 'string' || !source)
|
|
31
|
+
return source;
|
|
32
|
+
const re = /(^|\n)[ \t]*\/\/[#@][ \t]*sourceMappingURL=([^\n]*)/g;
|
|
33
|
+
let lastIndex = -1;
|
|
34
|
+
let lastValue = '';
|
|
35
|
+
let m;
|
|
36
|
+
while ((m = re.exec(source)) !== null) {
|
|
37
|
+
lastIndex = m.index + m[1].length;
|
|
38
|
+
lastValue = (m[2] || '').trim();
|
|
39
|
+
}
|
|
40
|
+
if (lastIndex < 0 || !lastValue)
|
|
41
|
+
return source;
|
|
42
|
+
// Already absolute (scheme://, protocol-relative //host, or data:)? Leave it.
|
|
43
|
+
if (/^(?:[a-z][a-z0-9+.-]*:)?\/\//i.test(lastValue) || /^data:/i.test(lastValue))
|
|
44
|
+
return source;
|
|
45
|
+
let absolute;
|
|
46
|
+
try {
|
|
47
|
+
absolute = new URL(lastValue, scriptUrl).toString();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return source;
|
|
51
|
+
}
|
|
52
|
+
return `${source.slice(0, lastIndex)}\n//# sourceMappingURL=${absolute}`;
|
|
53
|
+
}
|
|
14
54
|
const STACK_ID = 'stack_0';
|
|
15
55
|
/** Hard ceiling on the pre-warm pool, mirroring ServiceHostPool/doc §3.3. */
|
|
16
56
|
const PREWARM_MAX_POOL_SIZE = 4;
|
|
@@ -413,7 +453,10 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
413
453
|
const appSessionId = bridgeId;
|
|
414
454
|
const simulatorWc = resolveSimulatorWebContents(ctx, opts.simulatorWcId, event.sender);
|
|
415
455
|
const pagePath = normalizePagePath(opts.pagePath || 'pages/index/index');
|
|
416
|
-
const
|
|
456
|
+
const workspaceProjectPath = typeof ctx.workspace.getProjectPath === 'function'
|
|
457
|
+
? ctx.workspace.getProjectPath()
|
|
458
|
+
: '';
|
|
459
|
+
const pkgRoot = path.resolve(opts.pkgRoot || workspaceProjectPath || process.cwd());
|
|
417
460
|
const root = opts.root || 'main';
|
|
418
461
|
// Resource base resolution. Preferred: the simulator-supplied dev-server
|
|
419
462
|
// origin, which statically serves the compiled `<appId>/<root>/…` tree (same
|
|
@@ -465,6 +508,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
465
508
|
appId,
|
|
466
509
|
pagePath,
|
|
467
510
|
pkgRoot,
|
|
511
|
+
root,
|
|
468
512
|
resourceBaseUrl,
|
|
469
513
|
hostEnvSnapshot: hostEnv,
|
|
470
514
|
});
|
|
@@ -568,6 +612,7 @@ async function handleSpawn(state, ctx, event, opts) {
|
|
|
568
612
|
appId,
|
|
569
613
|
pagePath,
|
|
570
614
|
pkgRoot,
|
|
615
|
+
root,
|
|
571
616
|
resourceBaseUrl,
|
|
572
617
|
hostEnvSnapshot: hostEnv,
|
|
573
618
|
}));
|
|
@@ -690,7 +735,10 @@ async function injectLogicBundle(ap) {
|
|
|
690
735
|
const res = await fetch(logicUrl);
|
|
691
736
|
if (!res.ok)
|
|
692
737
|
throw new Error(`logic.js fetch ${res.status} at ${logicUrl}`);
|
|
693
|
-
|
|
738
|
+
// Rewrite the relative `sourceMappingURL` to an absolute dev-server URL
|
|
739
|
+
// BEFORE injecting — `executeJavaScript` gives the script no base URL, so a
|
|
740
|
+
// relative map would 404 and break sourcemapped console frames / Sources.
|
|
741
|
+
const logicContent = rewriteSourceMappingUrl(await res.text(), logicUrl);
|
|
694
742
|
await ap.serviceWc.executeJavaScript(`${logicContent}\n//# sourceURL=${logicUrl}`, true);
|
|
695
743
|
}
|
|
696
744
|
catch (error) {
|
|
@@ -1056,13 +1104,13 @@ function makeLoadResource(ap, page, target) {
|
|
|
1056
1104
|
// dimina's service runtime reads hostEnv as `{ systemInfo, menuRect }`
|
|
1057
1105
|
// (core/host-env.js init → getSystemInfo/getMenuRect; invokeAPI resolves
|
|
1058
1106
|
// getSystemInfoSync/getWindowInfo/getDeviceInfo from hostEnv.systemInfo).
|
|
1059
|
-
//
|
|
1060
|
-
// `wx.getSystemInfoSync()`
|
|
1061
|
-
// `.screenWidth`
|
|
1062
|
-
//
|
|
1063
|
-
//
|
|
1064
|
-
// menuRect stays null
|
|
1065
|
-
//
|
|
1107
|
+
// The snapshot must be nested under `systemInfo`: a FLAT HostEnvSnapshot
|
|
1108
|
+
// leaves `systemInfo` null → `wx.getSystemInfoSync()` returns null and
|
|
1109
|
+
// pages reading `.screenWidth` throw. (render does NOT read hostEnv, so
|
|
1110
|
+
// this is service-only; the devtools sync-api-patch reads the separate
|
|
1111
|
+
// __diminaSpawnContext.hostEnvSnapshot and is unaffected.)
|
|
1112
|
+
// menuRect stays null — getMenuButtonBoundingClientRect is served by the
|
|
1113
|
+
// sync-api-patch / DeviceShell capsule, not this path.
|
|
1066
1114
|
hostEnv: { systemInfo: ap.hostEnv, menuRect: null },
|
|
1067
1115
|
},
|
|
1068
1116
|
};
|
|
@@ -49,7 +49,7 @@ export function registerProjectsIpc(ctx) {
|
|
|
49
49
|
const [dirPath] = validate(ProjectsChannel.Remove, ProjectsRemoveSchema, args);
|
|
50
50
|
return ctx.workspace.removeProject(dirPath);
|
|
51
51
|
})
|
|
52
|
-
// ──
|
|
52
|
+
// ── template catalog + create flow ──
|
|
53
53
|
.handle(ProjectsChannel.ListTemplates, () => {
|
|
54
54
|
// Sanitize at the IPC boundary: `generate` is a function and the
|
|
55
55
|
// structured-clone algorithm Electron uses for invoke would otherwise
|
|
@@ -7,7 +7,7 @@ export function registerSimulatorIpc(ctx) {
|
|
|
7
7
|
return new IpcRegistry(ctx.senderPolicy)
|
|
8
8
|
.handle(SimulatorChannel.AttachNative, (_, ...args) => {
|
|
9
9
|
const [simulatorUrl, simWidth] = validate(SimulatorChannel.AttachNative, SimulatorAttachNativeSchema, args);
|
|
10
|
-
ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
10
|
+
return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
|
|
11
11
|
})
|
|
12
12
|
.handle(SimulatorChannel.Detach, () => {
|
|
13
13
|
ctx.views.detachSimulator();
|
|
@@ -11,7 +11,7 @@ import type { WorkbenchAppConfig } from '../../shared/types.js';
|
|
|
11
11
|
* v2 scope: the backend owns window creation (the framework skips its own when a
|
|
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
|
-
* the runtime facade are deferred
|
|
14
|
+
* the runtime facade are deferred.
|
|
15
15
|
*
|
|
16
16
|
* NOT migrating onto deck's high-level host API (Window facade / runtime.view /
|
|
17
17
|
* DeckSession / grants) is a DELIBERATE, reviewed decision — not a backlog item.
|
|
@@ -11,7 +11,7 @@ import { registerAppLifecycle } from '../app/lifecycle.js';
|
|
|
11
11
|
* v2 scope: the backend owns window creation (the framework skips its own when a
|
|
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
|
-
* the runtime facade are deferred
|
|
14
|
+
* the runtime facade are deferred.
|
|
15
15
|
*
|
|
16
16
|
* NOT migrating onto deck's high-level host API (Window facade / runtime.view /
|
|
17
17
|
* DeckSession / grants) is a DELIBERATE, reviewed decision — not a backlog item.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* would drag every nested internal service type (ViewManager,
|
|
7
7
|
* BridgeRouterHandle, SimulatorApiRegistry, Electron WebContents…) onto the
|
|
8
8
|
* public semver face, so any internal refactor of those services becomes an
|
|
9
|
-
* unreviewed breaking change for downstream hosts
|
|
9
|
+
* unreviewed breaking change for downstream hosts. Instead this module
|
|
10
10
|
* names ONLY the audited downstream consumption surface, with structural DTOs
|
|
11
11
|
* and zero Electron types — non-Electron consumers can compile against it.
|
|
12
12
|
*
|
|
@@ -83,9 +83,9 @@ declare global {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
|
-
* Host-facing control surface for the toolbar WebContentsView —
|
|
87
|
-
*
|
|
88
|
-
*
|
|
86
|
+
* Host-facing control surface for the toolbar WebContentsView — a
|
|
87
|
+
* message-channel surface (`send`/`onMessage`), with no `webContents` escape
|
|
88
|
+
* hatch (that would put Electron types on the contract).
|
|
89
89
|
*/
|
|
90
90
|
export interface MiniappHostToolbar {
|
|
91
91
|
/**
|
|
@@ -171,7 +171,7 @@ export interface MiniappWorkspace {
|
|
|
171
171
|
} | null;
|
|
172
172
|
}
|
|
173
173
|
/**
|
|
174
|
-
* The stable miniapp-kernel surface a downstream host
|
|
174
|
+
* The stable miniapp-kernel surface a downstream host consumes.
|
|
175
175
|
* Compiler-enforced and versionable: widening it back toward internal
|
|
176
176
|
* plumbing is a deliberate semver decision, not an accident of projection.
|
|
177
177
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DisposableRegistry, toDisposable } from '@dimina-kit/electron-deck/main';
|
|
2
|
+
import { RENDER_FORWARD_SOURCE_URL } from '../service-console/console-api.js';
|
|
2
3
|
/** Console levels we re-emit into the service host. Anything else maps to 'log'. */
|
|
3
4
|
const FORWARDABLE_LEVELS = new Set(['log', 'warn', 'error', 'info', 'debug']);
|
|
4
5
|
/**
|
|
@@ -16,7 +17,13 @@ function buildForwardScript(level, args) {
|
|
|
16
17
|
const argsJson = JSON.stringify(args ?? []);
|
|
17
18
|
// `console[method]` (not `console.log`) preserves the original level so the
|
|
18
19
|
// DevTools severity filter still works on the forwarded line.
|
|
19
|
-
|
|
20
|
+
//
|
|
21
|
+
// The trailing `//# sourceURL` stamps this injected line with a sentinel URL.
|
|
22
|
+
// The service-console CDP capture (services/service-console) attached to THIS
|
|
23
|
+
// service host would otherwise re-capture this `console[...]` call as a fresh
|
|
24
|
+
// service entry and re-broadcast it to automation (duplicate). It skips any
|
|
25
|
+
// `consoleAPICalled` whose top frame URL === RENDER_FORWARD_SOURCE_URL.
|
|
26
|
+
return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}]('[视图]',...a)}catch(_){}})()\n//# sourceURL=${RENDER_FORWARD_SOURCE_URL}`;
|
|
20
27
|
}
|
|
21
28
|
export function createConsoleForwarder(bridge) {
|
|
22
29
|
const sinks = new Set();
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* no longer active is dropped (its in-flight command id is settled with an error
|
|
37
37
|
* so the front-end never leaks a pending request, and stale nodes never bleed into
|
|
38
38
|
* the new tree); and switching away and BACK to a previously-wired guest RESUMES
|
|
39
|
-
* its forwarding (a snapshot would strand it
|
|
39
|
+
* its forwarding (a snapshot would strand it).
|
|
40
40
|
*
|
|
41
41
|
* ── Degradation ──────────────────────────────────────────────────────────────
|
|
42
42
|
* Hook unavailable / `DevToolsAPI` missing / no active guest → routing is simply
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
*
|
|
47
47
|
* This is a production feature (no env gate, default on for the native simulator).
|
|
48
48
|
* It deliberately re-implements the small pure helpers it needs (routing table,
|
|
49
|
-
* hook + dispatch scripts)
|
|
49
|
+
* hook + dispatch scripts) as self-contained code.
|
|
50
50
|
*/
|
|
51
51
|
import { webContents as electronWebContents } from 'electron';
|
|
52
52
|
/**
|
|
@@ -173,7 +173,11 @@ function buildDocumentUpdatedScript() {
|
|
|
173
173
|
}
|
|
174
174
|
const DRAIN_INTERVAL_MS = 150;
|
|
175
175
|
/** Bounded retry for the front-end hook install (front-end boots asynchronously). */
|
|
176
|
-
|
|
176
|
+
// Per-load install poll window. Must outlast the gap between a devtools
|
|
177
|
+
// front-end `dom-ready` and `InspectorFrontendHost` becoming available on a
|
|
178
|
+
// cold/slow open (pool cold-start). 200×50ms = 10s — generous, and each future
|
|
179
|
+
// front-end load re-arms a fresh window anyway (see the `dom-ready` listener).
|
|
180
|
+
const INSTALL_POLL_TRIES = 200;
|
|
177
181
|
const INSTALL_POLL_INTERVAL_MS = 50;
|
|
178
182
|
/**
|
|
179
183
|
* Install Elements forwarding on a DevTools front-end host wc. Returns a disposer
|
|
@@ -194,8 +198,8 @@ export function installElementsForward(deps) {
|
|
|
194
198
|
// bridge per check — NOT a generation snapshot. An event/response is honoured
|
|
195
199
|
// only while its originating guest is still the active one, so switching away
|
|
196
200
|
// and BACK to a previously-wired guest RESUMES its forwarding (a snapshot would
|
|
197
|
-
// strand it forever
|
|
198
|
-
//
|
|
201
|
+
// strand it forever). It also means destroying some OTHER (non-active) guest
|
|
202
|
+
// never stales the active guest's in-flight commands.
|
|
199
203
|
const isActiveWcId = (id) => {
|
|
200
204
|
const a = activeRenderWc();
|
|
201
205
|
return a != null && a.id === id;
|
|
@@ -391,7 +395,7 @@ export function installElementsForward(deps) {
|
|
|
391
395
|
}
|
|
392
396
|
// A destroyed guest is no longer the active one, so its in-flight commands
|
|
393
397
|
// fail `isActiveWcId` and settle as errors on their own — no global bump
|
|
394
|
-
// (which would wrongly stale OTHER, still-active guests' commands
|
|
398
|
+
// (which would wrongly stale OTHER, still-active guests' commands).
|
|
395
399
|
// If we own this wc's session there is nothing left to detach; drop it.
|
|
396
400
|
selfAttached.delete(wc.id);
|
|
397
401
|
};
|
|
@@ -504,6 +508,17 @@ export function installElementsForward(deps) {
|
|
|
504
508
|
const onReady = () => {
|
|
505
509
|
if (disposed)
|
|
506
510
|
return;
|
|
511
|
+
// Re-arm safe: a devtools front-end (re)load re-runs this, so clear any
|
|
512
|
+
// in-flight timers from a prior attempt before starting fresh ones — without
|
|
513
|
+
// this a reload would stack intervals (leak) and double-drain.
|
|
514
|
+
if (installTimer) {
|
|
515
|
+
clearInterval(installTimer);
|
|
516
|
+
installTimer = null;
|
|
517
|
+
}
|
|
518
|
+
if (drainTimer) {
|
|
519
|
+
clearInterval(drainTimer);
|
|
520
|
+
drainTimer = null;
|
|
521
|
+
}
|
|
507
522
|
let tries = 0;
|
|
508
523
|
installTimer = setInterval(() => {
|
|
509
524
|
tries++;
|
|
@@ -550,12 +565,17 @@ export function installElementsForward(deps) {
|
|
|
550
565
|
.catch(() => { });
|
|
551
566
|
}, DRAIN_INTERVAL_MS);
|
|
552
567
|
};
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
568
|
+
// Re-install on EVERY devtools front-end load, not once. The hook lives in the
|
|
569
|
+
// front-end's `globalThis` (`__diminaElementsHookInstalled`), so any front-end
|
|
570
|
+
// (re)load wipes it — most importantly a service-host pool SWAP, which re-opens
|
|
571
|
+
// DevTools (`pointNativeDevtoolsAtServiceWc`) and re-bootstraps the front-end.
|
|
572
|
+
// A single-shot `once('dom-ready')` left the hook uninstalled after such a
|
|
573
|
+
// reload, so Elements silently fell back to the native service-host DOM. A
|
|
574
|
+
// PERSISTENT listener re-runs the (idempotent — the sentinel returns 'already')
|
|
575
|
+
// install on each load; the immediate call covers an already-loaded wc and the
|
|
576
|
+
// first `openDevTools` whose `dom-ready` may have fired before this ran.
|
|
577
|
+
devtoolsWc.on('dom-ready', onReady);
|
|
578
|
+
onReady();
|
|
559
579
|
let devtoolsClosedSub;
|
|
560
580
|
try {
|
|
561
581
|
// Devtools front-end wc is never pool-reset → use `'closed'` (fires only on
|
|
@@ -577,6 +597,10 @@ export function installElementsForward(deps) {
|
|
|
577
597
|
devtoolsClosedSub?.dispose();
|
|
578
598
|
}
|
|
579
599
|
catch { /* already gone */ }
|
|
600
|
+
try {
|
|
601
|
+
devtoolsWc.removeListener('dom-ready', onReady);
|
|
602
|
+
}
|
|
603
|
+
catch { /* already gone */ }
|
|
580
604
|
stop();
|
|
581
605
|
};
|
|
582
606
|
}
|
|
@@ -26,7 +26,19 @@ export declare function computeNativeSimulatorViewParams(rect: {
|
|
|
26
26
|
bounds: Bounds;
|
|
27
27
|
zoomFactor: number;
|
|
28
28
|
};
|
|
29
|
+
/** Renderer-side width of the settings PANEL (the opaque right strip). The
|
|
30
|
+
* settings WebContentsView itself spans the full content area (see
|
|
31
|
+
* `computeSettingsBounds`) as a transparent backdrop; the panel is positioned
|
|
32
|
+
* inside it at this width by `settings.tsx`. */
|
|
29
33
|
export declare const SETTINGS_W = 320;
|
|
34
|
+
/**
|
|
35
|
+
* The settings overlay is a FULL-content-area transparent backdrop (header
|
|
36
|
+
* excluded), identical to the popover region — NOT a right-edge strip. The
|
|
37
|
+
* renderer paints a transparent backdrop over the whole area and an opaque
|
|
38
|
+
* `SETTINGS_W`-wide panel on the right; a click on the transparent backdrop
|
|
39
|
+
* closes the overlay (clicks outside the panel must reach the backdrop, which is
|
|
40
|
+
* only possible when the view spans the whole area rather than just the strip).
|
|
41
|
+
*/
|
|
30
42
|
export declare function computeSettingsBounds(contentWidth: number, contentHeight: number, headerHeight: number): Bounds;
|
|
31
43
|
export declare function computePopoverBounds(contentWidth: number, contentHeight: number, headerHeight: number): Bounds;
|
|
32
44
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -23,12 +23,24 @@ export function computeNativeSimulatorViewParams(rect, zoomPercent) {
|
|
|
23
23
|
zoomFactor,
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
+
/** Renderer-side width of the settings PANEL (the opaque right strip). The
|
|
27
|
+
* settings WebContentsView itself spans the full content area (see
|
|
28
|
+
* `computeSettingsBounds`) as a transparent backdrop; the panel is positioned
|
|
29
|
+
* inside it at this width by `settings.tsx`. */
|
|
26
30
|
export const SETTINGS_W = 320;
|
|
31
|
+
/**
|
|
32
|
+
* The settings overlay is a FULL-content-area transparent backdrop (header
|
|
33
|
+
* excluded), identical to the popover region — NOT a right-edge strip. The
|
|
34
|
+
* renderer paints a transparent backdrop over the whole area and an opaque
|
|
35
|
+
* `SETTINGS_W`-wide panel on the right; a click on the transparent backdrop
|
|
36
|
+
* closes the overlay (clicks outside the panel must reach the backdrop, which is
|
|
37
|
+
* only possible when the view spans the whole area rather than just the strip).
|
|
38
|
+
*/
|
|
27
39
|
export function computeSettingsBounds(contentWidth, contentHeight, headerHeight) {
|
|
28
40
|
return {
|
|
29
|
-
x:
|
|
41
|
+
x: 0,
|
|
30
42
|
y: headerHeight,
|
|
31
|
-
width: Math.
|
|
43
|
+
width: Math.max(1, contentWidth),
|
|
32
44
|
height: Math.max(1, contentHeight - headerHeight),
|
|
33
45
|
};
|
|
34
46
|
}
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* `direct-request.ts`/`simulator-api-network.ts`, which call `fetch()` /
|
|
15
15
|
* `XMLHttpRequest`). Those requests therefore go through the simulator WCV's
|
|
16
16
|
* network stack — a DIFFERENT webContents than the one the DevTools front-end
|
|
17
|
-
* inspects — so they
|
|
18
|
-
*
|
|
17
|
+
* inspects — so they are otherwise invisible in the Network panel. This service
|
|
18
|
+
* surfaces them.
|
|
19
19
|
*
|
|
20
20
|
* ── How it surfaces them (primary sink: native Network tab) ─────────────────
|
|
21
21
|
* We attach the CDP `webContents.debugger` to the simulator WCV, `Network.enable`,
|
|
@@ -32,9 +32,8 @@
|
|
|
32
32
|
* into a namespaced virtual id (`dimina:sim:<epoch>:<rawId>`) before dispatch,
|
|
33
33
|
* keeping a raw→virtual map so redirects / extra-info / completion events on the
|
|
34
34
|
* same request stay correlated. We inject on the MAIN session (no `sessionId`),
|
|
35
|
-
* i.e. the events appear as activity on the currently-inspected target.
|
|
36
|
-
*
|
|
37
|
-
* (`Target.attachedToTarget` + hooking outbound CDP) is explicitly deferred.
|
|
35
|
+
* i.e. the events appear as activity on the currently-inspected target. Child-
|
|
36
|
+
* target routing (`Target.attachedToTarget` + hooking outbound CDP) is deferred.
|
|
38
37
|
*
|
|
39
38
|
* ── Fallback sink (console line) ────────────────────────────────────────────
|
|
40
39
|
* If the DevTools host wc is unavailable, or `window.DevToolsAPI.dispatchMessage`
|
|
@@ -127,7 +126,7 @@ export interface NetworkForwarder extends Disposable {
|
|
|
127
126
|
* Anything carrying a requestId must be namespaced consistently — even methods
|
|
128
127
|
* we don't (yet) forward — so the raw→virtual map stays coherent if forwarding
|
|
129
128
|
* is widened later. `requestServedFromCache` and `resourceChangedPriority` are
|
|
130
|
-
* included for that reason (
|
|
129
|
+
* included for that reason (rewrite-only today, not forwarded).
|
|
131
130
|
*/
|
|
132
131
|
export declare const REWRITE_REQUEST_ID_METHODS: ReadonlySet<string>;
|
|
133
132
|
/** The Network.* methods this one-shot pass forwards to the front-end. */
|
|
@@ -5,7 +5,7 @@ import { DisposableRegistry, toDisposable } from '@dimina-kit/electron-deck/main
|
|
|
5
5
|
* Anything carrying a requestId must be namespaced consistently — even methods
|
|
6
6
|
* we don't (yet) forward — so the raw→virtual map stays coherent if forwarding
|
|
7
7
|
* is widened later. `requestServedFromCache` and `resourceChangedPriority` are
|
|
8
|
-
* included for that reason (
|
|
8
|
+
* included for that reason (rewrite-only today, not forwarded).
|
|
9
9
|
*/
|
|
10
10
|
export const REWRITE_REQUEST_ID_METHODS = new Set([
|
|
11
11
|
'Network.requestWillBeSent',
|
|
@@ -243,10 +243,9 @@ export function createNetworkForwarder(bridge) {
|
|
|
243
243
|
let attachDisposables = null;
|
|
244
244
|
// The DevTools front-end host wc (primary sink), set by the ViewManager.
|
|
245
245
|
let devtoolsWc = null;
|
|
246
|
-
// Teardown for the wc 'destroyed' watcher on the current host (clears the host
|
|
247
|
-
// here, in this file — view-manager is owned by another change and untouched).
|
|
246
|
+
// Teardown for the wc 'destroyed' watcher on the current host (clears the host).
|
|
248
247
|
let devtoolsHostDisposable = null;
|
|
249
|
-
// ── Native-sink state machine
|
|
248
|
+
// ── Native-sink state machine ─────────────────────────────────────────────
|
|
250
249
|
let sink = 'idle';
|
|
251
250
|
// Buffered completed-request records while 'probing' — flushed to console if we
|
|
252
251
|
// degrade, dropped if we go ready (so a request shows in exactly one sink).
|
|
@@ -321,7 +320,7 @@ export function createNetworkForwarder(bridge) {
|
|
|
321
320
|
/** Trim the native queue to its cap, preferring to keep request-opening events.
|
|
322
321
|
* Active requests' first events (requestWillBeSent / ...ExtraInfo) are retained
|
|
323
322
|
* so later responseReceived/loadingFinished never become orphans in the panel;
|
|
324
|
-
* we drop the oldest NON-opening (low-value / completion) events first.
|
|
323
|
+
* we drop the oldest NON-opening (low-value / completion) events first. */
|
|
325
324
|
function trimQueue() {
|
|
326
325
|
if (dispatchQueue.length <= MAX_DISPATCH_QUEUE)
|
|
327
326
|
return;
|
|
@@ -355,15 +354,15 @@ export function createNetworkForwarder(bridge) {
|
|
|
355
354
|
}
|
|
356
355
|
const wc = resolveDevtoolsWc();
|
|
357
356
|
if (!wc) {
|
|
358
|
-
// Host went away mid-flight. Keep the queue bounded (
|
|
357
|
+
// Host went away mid-flight. Keep the queue bounded (the cap applies on
|
|
359
358
|
// EVERY path, not just no-host) and wait — setDevtoolsHost re-arms probing.
|
|
360
359
|
trimQueue();
|
|
361
360
|
return;
|
|
362
361
|
}
|
|
363
362
|
if (sink === 'idle')
|
|
364
363
|
beginProbing();
|
|
365
|
-
// Pack greedily up to MAX_BATCH_CHARS so one executeJavaScript stays sized
|
|
366
|
-
//
|
|
364
|
+
// Pack greedily up to MAX_BATCH_CHARS so one executeJavaScript stays sized;
|
|
365
|
+
// oversized single messages go via the chunked transport.
|
|
367
366
|
const batch = [];
|
|
368
367
|
let batchChars = 0;
|
|
369
368
|
let i = 0;
|
|
@@ -421,7 +420,7 @@ export function createNetworkForwarder(bridge) {
|
|
|
421
420
|
}).catch(() => {
|
|
422
421
|
// wc navigated / torn down mid-call, OR the script overflowed IPC. Re-queue
|
|
423
422
|
// (bounded) and let the next flush re-resolve the host. Best-effort; the
|
|
424
|
-
// ready-timeout still governs giving up.
|
|
423
|
+
// ready-timeout still governs giving up. Backoff is via the retry timer.
|
|
425
424
|
if (sink === 'degraded')
|
|
426
425
|
return;
|
|
427
426
|
dispatchQueue = batch.concat(dispatchQueue);
|
|
@@ -654,7 +653,7 @@ export function createNetworkForwarder(bridge) {
|
|
|
654
653
|
}
|
|
655
654
|
/**
|
|
656
655
|
* Route a completed request to EXACTLY ONE sink, per the native-sink state
|
|
657
|
-
* machine (
|
|
656
|
+
* machine (no double-display):
|
|
658
657
|
* - 'ready' : native path already rendered it → suppress console.
|
|
659
658
|
* - 'degraded' : native abandoned → console.
|
|
660
659
|
* - 'idle' : no host configured → console (the native queue never flushes).
|
|
@@ -39,10 +39,9 @@ export interface WorkbenchSettingsInitPayload {
|
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Unified entry point for every main → renderer event sent by the devtools
|
|
42
|
-
* main process.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* in exactly one place.
|
|
42
|
+
* main process. Instead of calling `someWebContents.send(channel, payload)`
|
|
43
|
+
* directly, every site goes through a typed method here so that channel names,
|
|
44
|
+
* payload shapes and `isDestroyed()` guards live in exactly one place.
|
|
46
45
|
*
|
|
47
46
|
* Methods resolve their target `WebContents` lazily from references provided
|
|
48
47
|
* at call time (or read from the owning context) and silently no-op when the
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// higher-level coordination (session + renderer notifications) lives in
|
|
4
4
|
// ../workspace/workspace-service.ts.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
6
|
+
// The extensibility surface lives in `types.ts` (ProjectsProvider,
|
|
7
7
|
// ProjectTemplate, CreateProjectInput) and `local-provider.ts` (the default
|
|
8
8
|
// implementation injected when the host omits `projectsProvider`).
|
|
9
9
|
export * from './project-repository.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public extensibility surface for the project list panel. Hosts that embed
|
|
3
|
-
* dimina-devtools (
|
|
3
|
+
* dimina-devtools (downstream hosts) can inject implementations of these types via
|
|
4
4
|
* `WorkbenchAppConfig` to fully take over the project source-of-truth, the
|
|
5
5
|
* template catalog, and the "新建项目" dialog.
|
|
6
6
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public extensibility surface for the project list panel. Hosts that embed
|
|
3
|
-
* dimina-devtools (
|
|
3
|
+
* dimina-devtools (downstream hosts) can inject implementations of these types via
|
|
4
4
|
* `WorkbenchAppConfig` to fully take over the project source-of-truth, the
|
|
5
5
|
* template catalog, and the "新建项目" dialog.
|
|
6
6
|
*/
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for the native-host service-console forwarder.
|
|
3
|
+
*
|
|
4
|
+
* The service-host's console is captured via CDP `Runtime.consoleAPICalled`,
|
|
5
|
+
* which preserves native source attribution. A `console.*` monkeypatch in
|
|
6
|
+
* `service-host/preload.cjs` would add a stack frame, so Chrome DevTools (attached
|
|
7
|
+
* natively to the service host) would attribute EVERY service-layer log to the
|
|
8
|
+
* wrapper line instead of the developer's source.
|
|
9
|
+
*
|
|
10
|
+
* These functions turn the CDP event shape into the `GuestConsoleEntry` shape
|
|
11
|
+
* the existing console fan-out (automation `App.logAdded`) expects, WITHOUT any
|
|
12
|
+
* electron / IO dependency so they are unit-testable in isolation. The async
|
|
13
|
+
* deep-fetch (`Runtime.callFunctionOn`) for object args lives in `index.ts`.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* sourceURL stamped on the render→service `[视图]` re-injection script
|
|
17
|
+
* (`console-forward.buildForwardScript`). The CDP capture skips any
|
|
18
|
+
* `consoleAPICalled` whose top frame carries this URL so a forwarded render line
|
|
19
|
+
* is not re-captured and re-broadcast as a service entry (duplicate / loop).
|
|
20
|
+
*/
|
|
21
|
+
export declare const RENDER_FORWARD_SOURCE_URL = "dimina://render-console-forward";
|
|
22
|
+
export type ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug';
|
|
23
|
+
/** Subset of a CDP `Runtime.RemoteObject` we read. */
|
|
24
|
+
export interface RemoteObjectLike {
|
|
25
|
+
type?: string;
|
|
26
|
+
subtype?: string;
|
|
27
|
+
value?: unknown;
|
|
28
|
+
unserializableValue?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
objectId?: string;
|
|
31
|
+
preview?: {
|
|
32
|
+
properties?: Array<{
|
|
33
|
+
name: string;
|
|
34
|
+
value: string;
|
|
35
|
+
type: string;
|
|
36
|
+
}>;
|
|
37
|
+
subtype?: string;
|
|
38
|
+
overflow?: boolean;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Subset of a CDP `Runtime.consoleAPICalled` params we read. */
|
|
42
|
+
export interface ConsoleApiParamsLike {
|
|
43
|
+
type?: string;
|
|
44
|
+
args?: RemoteObjectLike[];
|
|
45
|
+
stackTrace?: {
|
|
46
|
+
callFrames?: Array<{
|
|
47
|
+
url?: string;
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* CDP `consoleAPICalled.type` → our console level. CDP emits `'warning'` where
|
|
53
|
+
* we use `'warn'`; every other known level passes through; anything else (e.g.
|
|
54
|
+
* `'dir'`, `'table'`, `'trace'`, `undefined`) maps to `'log'`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function mapConsoleApiType(type: string | undefined): ConsoleLevel;
|
|
57
|
+
/**
|
|
58
|
+
* A single RemoteObject → a JSON-serializable value WITHOUT a CDP round-trip
|
|
59
|
+
* (shallow). Objects that need their full contents are flagged by
|
|
60
|
+
* {@link needsDeepFetch} and deep-serialized by the caller; this is the
|
|
61
|
+
* inline/best-effort fallback.
|
|
62
|
+
*/
|
|
63
|
+
export declare function remoteObjectToValue(ro: RemoteObjectLike): unknown;
|
|
64
|
+
/**
|
|
65
|
+
* Whether this RemoteObject must be deep-fetched via `Runtime.callFunctionOn`
|
|
66
|
+
* (returnByValue) to be fully serialized — i.e. a real object/array referenced
|
|
67
|
+
* by `objectId` with no inline `value`. Functions, primitives, `null`, and
|
|
68
|
+
* already-inlined values do not.
|
|
69
|
+
*/
|
|
70
|
+
export declare function needsDeepFetch(ro: RemoteObjectLike): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* True when a `consoleAPICalled` event is the render→service `[视图]`
|
|
73
|
+
* re-injection (its top call frame URL === the sentinel) and must NOT be
|
|
74
|
+
* re-forwarded — the original render entry already reached every consumer.
|
|
75
|
+
*/
|
|
76
|
+
export declare function isRenderForwardEvent(params: ConsoleApiParamsLike, sentinelUrl: string): boolean;
|
|
77
|
+
//# sourceMappingURL=console-api.d.ts.map
|