@dimina-kit/devtools 0.4.0-dev.20260702182435 → 0.4.0-dev.20260703101348
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 +5 -25
- package/dist/main/app/native-overview.d.ts +27 -0
- package/dist/main/app/native-overview.js +44 -0
- package/dist/main/index.bundle.js +1217 -735
- package/dist/main/ipc/bridge-router.d.ts +8 -0
- package/dist/main/ipc/bridge-router.js +526 -173
- package/dist/main/ipc/project-fs.js +39 -21
- package/dist/main/services/automation/handlers/app.js +143 -109
- package/dist/main/services/console-forward/index.d.ts +12 -1
- package/dist/main/services/console-forward/index.js +99 -1
- package/dist/main/services/diagnostics/index.d.ts +49 -0
- package/dist/main/services/diagnostics/index.js +61 -0
- package/dist/main/services/mcp/tools/simulator-tools.js +118 -97
- package/dist/main/services/network-forward/dispatch-batch.d.ts +22 -0
- package/dist/main/services/network-forward/dispatch-batch.js +21 -0
- package/dist/main/services/network-forward/index.js +37 -20
- package/dist/main/services/notifications/renderer-notifier.d.ts +39 -0
- package/dist/main/services/notifications/renderer-notifier.js +4 -1
- package/dist/main/services/projects/create-project-service.js +54 -34
- package/dist/main/services/projects/project-repository.js +2 -1
- package/dist/main/services/projects/types.d.ts +1 -32
- package/dist/main/services/service-console/console-api.js +36 -27
- package/dist/main/services/simulator-temp-files/disk.js +109 -86
- package/dist/main/services/views/simulator-session-policy.js +17 -0
- package/dist/main/services/workbench-coi-server.js +58 -45
- package/dist/main/services/workbench-context.d.ts +10 -0
- package/dist/main/services/workspace/workspace-service.js +12 -3
- package/dist/main/utils/logger.d.ts +5 -12
- package/dist/main/utils/logger.js +5 -45
- package/dist/main/windows/service-host-window/create.d.ts +15 -1
- package/dist/main/windows/service-host-window/create.js +11 -3
- package/dist/preload/instrumentation/wxml-extract.js +94 -62
- package/dist/preload/runtime/main-api-runner.d.ts +1 -1
- package/dist/preload/shared/api-compat.js +18 -55
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs +284 -565
- package/dist/preload/windows/main.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs +154 -83
- package/dist/preload/windows/simulator.cjs.map +3 -3
- package/dist/preload/windows/simulator.js +154 -83
- package/dist/render-host/render-inspect.js +63 -52
- package/dist/renderer/assets/index-BwzPwCmM.js +49 -0
- package/dist/renderer/assets/{input-Cjk0wSEh.js → input-CTb_le7F.js} +2 -2
- package/dist/renderer/assets/ipc-transport-BPWIV5hA.css +1 -0
- package/dist/renderer/assets/{ipc-transport-OZS-KmOW.js → ipc-transport-Ck5Xa8Tu.js} +2 -2
- package/dist/renderer/assets/popover-B1Zu2UQu.js +2 -0
- package/dist/renderer/assets/{select-BQDXi5ih.js → select-ozSk5Pt6.js} +2 -2
- package/dist/renderer/assets/{settings-tP3Px2KR.js → settings-CNwGOI22.js} +2 -2
- package/dist/renderer/assets/settings-api-DMbMp1Eq.js +2 -0
- package/dist/renderer/assets/workbenchSettings-Cr4EHo5w.js +8 -0
- 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/appdata-accumulator.js +53 -48
- package/dist/shared/bridge-channels.d.ts +22 -0
- package/dist/shared/ipc-channels.d.ts +3 -0
- package/dist/shared/ipc-channels.js +9 -0
- package/dist/shared/open-in-editor-resource-path.d.ts +56 -0
- package/dist/shared/open-in-editor-resource-path.js +133 -0
- package/dist/shared/open-in-editor.d.ts +2 -9
- package/dist/shared/open-in-editor.js +8 -93
- package/dist/shared/request-core.d.ts +84 -0
- package/dist/shared/request-core.js +168 -0
- package/dist/shared/simulator-api-metadata.d.ts +22 -17
- package/dist/shared/simulator-api-metadata.js +36 -0
- package/dist/shared/types.d.ts +20 -4
- package/dist/simulator/assets/{device-shell-CUl0ILfn.js → device-shell-C-wcFq3Z.js} +2 -2
- package/dist/simulator/assets/{jsx-runtime-CDK-o-S0.js → jsx-runtime-BDTY6fEq.js} +2 -2
- package/dist/simulator/assets/simulator-DU3-fS3v.js +10 -0
- package/dist/simulator/assets/simulator-mini-app-DzfMfnVM.js +2 -0
- package/dist/simulator/simulator.html +2 -2
- package/dist/vscode-workbench/assets/__vite-browser-external-CXi6Kz9W.js +1 -0
- package/dist/vscode-workbench/assets/{dist-CS7SQP3K.js → dist-TpGpmMGi.js} +3 -3
- package/dist/vscode-workbench/assets/{iconv-lite-umd-D3q-1-o6.js → iconv-lite-umd-C9tiCAJa.js} +1 -1
- package/dist/vscode-workbench/assets/{index-zjigpZ25.js → index-DJ1HyMZ7.js} +20 -22
- package/dist/vscode-workbench/assets/{jschardet-Cu4ufeHq.js → jschardet-DE1jV513.js} +1 -1
- package/dist/vscode-workbench/index.html +1 -1
- package/package.json +6 -6
- package/dist/renderer/assets/index-B-Dqb7G0.js +0 -49
- package/dist/renderer/assets/ipc-transport-D5dKIti1.css +0 -1
- package/dist/renderer/assets/popover-CQVvOe90.js +0 -2
- package/dist/renderer/assets/settings-api-B6x2mhaD.js +0 -2
- package/dist/renderer/assets/workbenchSettings-Bim9ol9R.js +0 -8
- package/dist/simulator/assets/simulator-Dz8iGcgy.js +0 -10
- package/dist/simulator/assets/simulator-mini-app-Bt639XL_.js +0 -2
- package/dist/vscode-workbench/assets/__vite-browser-external-B0DTNerG.js +0 -1
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
<style>
|
|
9
9
|
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: transparent !important; }
|
|
10
10
|
</style>
|
|
11
|
-
<script type="module" crossorigin src="../../assets/popover-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="../../assets/input-
|
|
14
|
-
<link rel="modulepreload" crossorigin href="../../assets/select-
|
|
11
|
+
<script type="module" crossorigin src="../../assets/popover-B1Zu2UQu.js"></script>
|
|
12
|
+
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-Ck5Xa8Tu.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="../../assets/input-CTb_le7F.js">
|
|
14
|
+
<link rel="modulepreload" crossorigin href="../../assets/select-ozSk5Pt6.js">
|
|
15
15
|
<link rel="modulepreload" crossorigin href="../../assets/constants-EAMiwL9_.js">
|
|
16
|
-
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-
|
|
16
|
+
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-BPWIV5hA.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="root"></div>
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
closes the overlay — mirrors the popover entry. */
|
|
12
12
|
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: transparent !important; }
|
|
13
13
|
</style>
|
|
14
|
-
<script type="module" crossorigin src="../../assets/settings-
|
|
15
|
-
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="../../assets/input-
|
|
17
|
-
<link rel="modulepreload" crossorigin href="../../assets/settings-api-
|
|
18
|
-
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-
|
|
14
|
+
<script type="module" crossorigin src="../../assets/settings-CNwGOI22.js"></script>
|
|
15
|
+
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-Ck5Xa8Tu.js">
|
|
16
|
+
<link rel="modulepreload" crossorigin href="../../assets/input-CTb_le7F.js">
|
|
17
|
+
<link rel="modulepreload" crossorigin href="../../assets/settings-api-DMbMp1Eq.js">
|
|
18
|
+
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-BPWIV5hA.css">
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
|
21
21
|
<div id="root"></div>
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
<!-- See entries/main/index.html for CSP rationale. -->
|
|
7
7
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: http: https:; font-src 'self' data:; media-src 'self' blob: http: https:; connect-src 'self' http: https: ws: wss:;" />
|
|
8
8
|
<title>开发工具设置</title>
|
|
9
|
-
<script type="module" crossorigin src="../../assets/workbenchSettings-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="../../assets/settings-api-
|
|
9
|
+
<script type="module" crossorigin src="../../assets/workbenchSettings-Cr4EHo5w.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-Ck5Xa8Tu.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="../../assets/settings-api-DMbMp1Eq.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="../../assets/constants-EAMiwL9_.js">
|
|
13
|
-
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-
|
|
13
|
+
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-BPWIV5hA.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="root"></div>
|
|
@@ -13,6 +13,54 @@
|
|
|
13
13
|
* through bridge-router (SERVICE_PUBLISH). Both feed this one accumulator so the
|
|
14
14
|
* decode/merge/page-only/init-gate policy can't drift between modes.
|
|
15
15
|
*/
|
|
16
|
+
/** Parse a service/worker message payload; a non-string is passed through as-is. */
|
|
17
|
+
function parseMessagePayload(message) {
|
|
18
|
+
if (typeof message !== 'string')
|
|
19
|
+
return message;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(message);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Decode a `ub` (update batch) body into patch entries, PAGE modules only —
|
|
29
|
+
* component-module updates are dropped (see `decodeWorkerMessage`).
|
|
30
|
+
*/
|
|
31
|
+
function decodeUpdateBatchBody(rawBody) {
|
|
32
|
+
const body = rawBody;
|
|
33
|
+
if (!body || typeof body !== 'object')
|
|
34
|
+
return null;
|
|
35
|
+
if (typeof body.bridgeId !== 'string' || !Array.isArray(body.updates))
|
|
36
|
+
return null;
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const u of body.updates) {
|
|
39
|
+
if (!u || typeof u.moduleId !== 'string')
|
|
40
|
+
continue;
|
|
41
|
+
if (!u.moduleId.startsWith('page_'))
|
|
42
|
+
continue;
|
|
43
|
+
out.push({ mode: 'patch', bridgeId: body.bridgeId, moduleId: u.moduleId, data: u.data });
|
|
44
|
+
}
|
|
45
|
+
return out.length > 0 ? out : null;
|
|
46
|
+
}
|
|
47
|
+
/** Decode a `page_*` instance-init body into its single init entry. */
|
|
48
|
+
function decodePageInitBody(moduleId, rawBody) {
|
|
49
|
+
const body = rawBody;
|
|
50
|
+
if (!body || typeof body !== 'object')
|
|
51
|
+
return null;
|
|
52
|
+
if (typeof body.bridgeId !== 'string' || typeof body.path !== 'string')
|
|
53
|
+
return null;
|
|
54
|
+
if (!body.data || typeof body.data !== 'object')
|
|
55
|
+
return null;
|
|
56
|
+
return [{
|
|
57
|
+
mode: 'init',
|
|
58
|
+
bridgeId: body.bridgeId,
|
|
59
|
+
moduleId,
|
|
60
|
+
componentPath: body.path,
|
|
61
|
+
data: body.data,
|
|
62
|
+
}];
|
|
63
|
+
}
|
|
16
64
|
/**
|
|
17
65
|
* Decode a service→render message into AppData entries, or null when it is not
|
|
18
66
|
* AppData-relevant. Policy: surface PAGE entries only — component entries are
|
|
@@ -20,63 +68,20 @@
|
|
|
20
68
|
* and never receive pageUnload, which would manifest as ghost tabs).
|
|
21
69
|
*/
|
|
22
70
|
export function decodeWorkerMessage(message) {
|
|
23
|
-
|
|
24
|
-
if (typeof payload === 'string') {
|
|
25
|
-
try {
|
|
26
|
-
payload = JSON.parse(payload);
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
71
|
+
const payload = parseMessagePayload(message);
|
|
32
72
|
if (!payload || typeof payload !== 'object')
|
|
33
73
|
return null;
|
|
34
74
|
const record = payload;
|
|
35
|
-
if (record.type === 'ub')
|
|
36
|
-
|
|
37
|
-
if (!body || typeof body !== 'object')
|
|
38
|
-
return null;
|
|
39
|
-
if (typeof body.bridgeId !== 'string' || !Array.isArray(body.updates))
|
|
40
|
-
return null;
|
|
41
|
-
const out = [];
|
|
42
|
-
for (const u of body.updates) {
|
|
43
|
-
if (!u || typeof u.moduleId !== 'string')
|
|
44
|
-
continue;
|
|
45
|
-
if (!u.moduleId.startsWith('page_'))
|
|
46
|
-
continue;
|
|
47
|
-
out.push({ mode: 'patch', bridgeId: body.bridgeId, moduleId: u.moduleId, data: u.data });
|
|
48
|
-
}
|
|
49
|
-
return out.length > 0 ? out : null;
|
|
50
|
-
}
|
|
75
|
+
if (record.type === 'ub')
|
|
76
|
+
return decodeUpdateBatchBody(record.body);
|
|
51
77
|
if (typeof record.type === 'string' && record.type.startsWith('page_')) {
|
|
52
|
-
|
|
53
|
-
if (!body || typeof body !== 'object')
|
|
54
|
-
return null;
|
|
55
|
-
if (typeof body.bridgeId !== 'string' || typeof body.path !== 'string')
|
|
56
|
-
return null;
|
|
57
|
-
if (!body.data || typeof body.data !== 'object')
|
|
58
|
-
return null;
|
|
59
|
-
return [{
|
|
60
|
-
mode: 'init',
|
|
61
|
-
bridgeId: body.bridgeId,
|
|
62
|
-
moduleId: record.type,
|
|
63
|
-
componentPath: body.path,
|
|
64
|
-
data: body.data,
|
|
65
|
-
}];
|
|
78
|
+
return decodePageInitBody(record.type, record.body);
|
|
66
79
|
}
|
|
67
80
|
return null;
|
|
68
81
|
}
|
|
69
82
|
/** main→worker direction: container signals page teardown so cache can evict. */
|
|
70
83
|
export function decodeOutgoingMessage(message) {
|
|
71
|
-
|
|
72
|
-
if (typeof payload === 'string') {
|
|
73
|
-
try {
|
|
74
|
-
payload = JSON.parse(payload);
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
84
|
+
const payload = parseMessagePayload(message);
|
|
80
85
|
if (!payload || typeof payload !== 'object')
|
|
81
86
|
return null;
|
|
82
87
|
const r = payload;
|
|
@@ -198,6 +198,16 @@ export interface AppManifest {
|
|
|
198
198
|
entryPagePath: string;
|
|
199
199
|
pages: string[];
|
|
200
200
|
tabBar?: TabBarConfig;
|
|
201
|
+
/**
|
|
202
|
+
* Provenance of this manifest: `'app-config'` when built from a real
|
|
203
|
+
* compiled `app-config.json` (its `pages` list is authoritative, so mount
|
|
204
|
+
* gates can validate membership against it); `'fallback'` when
|
|
205
|
+
* app-config.json was unreachable and the manifest is a single-page stand-in
|
|
206
|
+
* built from the spawn request. Mount gates only enforce against
|
|
207
|
+
* `'app-config'` — a `'fallback'` manifest has no compiled truth to check
|
|
208
|
+
* membership against, so it must let every page/nav target through.
|
|
209
|
+
*/
|
|
210
|
+
source: 'app-config' | 'fallback';
|
|
201
211
|
}
|
|
202
212
|
export interface SpawnRequest {
|
|
203
213
|
simulatorWcId?: number;
|
|
@@ -224,7 +234,19 @@ export interface SpawnRequest {
|
|
|
224
234
|
export interface SpawnResult {
|
|
225
235
|
appSessionId: string;
|
|
226
236
|
bridgeId: string;
|
|
237
|
+
/** The pagePath originally requested (unchanged even when a fallback applied — see `resolvedPagePath`). */
|
|
227
238
|
pagePath: string;
|
|
239
|
+
/**
|
|
240
|
+
* The pagePath the root PageSession was ACTUALLY spawned with. Equal to
|
|
241
|
+
* `pagePath` unless `pageFallbackApplied` is true, in which case the request
|
|
242
|
+
* was absent from `manifest.pages` and this is `manifest.entryPagePath`
|
|
243
|
+
* (or `manifest.pages[0]` when even that isn't a member). Callers that cache
|
|
244
|
+
* "the current page" (e.g. `SimulatorMiniApp`) must reconcile against this,
|
|
245
|
+
* not the original request.
|
|
246
|
+
*/
|
|
247
|
+
resolvedPagePath: string;
|
|
248
|
+
/** Whether `resolvedPagePath` differs from the request because it was absent from the compiled manifest. Always false for a `'fallback'` manifest (nothing to validate against). */
|
|
249
|
+
pageFallbackApplied: boolean;
|
|
228
250
|
serviceWcId: number;
|
|
229
251
|
resourceBaseUrl: string;
|
|
230
252
|
manifest: AppManifest;
|
|
@@ -165,6 +165,9 @@ export declare const ProjectChannel: {
|
|
|
165
165
|
readonly CaptureThumbnail: "project:captureThumbnail";
|
|
166
166
|
readonly GetThumbnail: "project:getThumbnail";
|
|
167
167
|
};
|
|
168
|
+
export declare const SessionChannel: {
|
|
169
|
+
readonly RuntimeStatus: "session:runtimeStatus";
|
|
170
|
+
};
|
|
168
171
|
export declare const ProjectFsChannel: {
|
|
169
172
|
readonly GetRoot: "project:fs:getRoot";
|
|
170
173
|
readonly ReadFile: "project:fs:readFile";
|
|
@@ -130,6 +130,15 @@ export const ProjectChannel = {
|
|
|
130
130
|
CaptureThumbnail: 'project:captureThumbnail',
|
|
131
131
|
GetThumbnail: 'project:getThumbnail',
|
|
132
132
|
};
|
|
133
|
+
// ── Session runtime status ───────────────────────────────────────────────
|
|
134
|
+
//
|
|
135
|
+
// Main → renderer push of the post-compile SESSION lifecycle (spawn → running
|
|
136
|
+
// → crash/timeout), distinct from `ProjectChannel.Status` which only tracks
|
|
137
|
+
// compile outcomes. Compile succeeding tells the renderer nothing about
|
|
138
|
+
// whether the simulator actually booted — this channel closes that gap.
|
|
139
|
+
export const SessionChannel = {
|
|
140
|
+
RuntimeStatus: 'session:runtimeStatus',
|
|
141
|
+
};
|
|
133
142
|
// ── Project file system (sandboxed to active project root) ────────────────
|
|
134
143
|
//
|
|
135
144
|
// Read/write access to the active project's files, used by the in-renderer
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure DevTools-resource-URL → project-relative-path resolution for the
|
|
3
|
+
* "open in editor" pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Every function here is `.toString()`-injected verbatim into the DevTools
|
|
6
|
+
* front-end realm by `buildDevtoolsProjectSourceLinksScript` (in
|
|
7
|
+
* `open-in-editor.ts`), alongside being called directly from the main process.
|
|
8
|
+
* That constrains each function to be self-contained (no closures over
|
|
9
|
+
* module-level state beyond calling the OTHER functions in this file, which
|
|
10
|
+
* the injection site also stringifies into the same scope) — no electron / DOM
|
|
11
|
+
* / node deps.
|
|
12
|
+
*/
|
|
13
|
+
export interface ProjectSourceContext {
|
|
14
|
+
/** Absolute project root on disk. */
|
|
15
|
+
projectRoot: string;
|
|
16
|
+
/** Resource server base URL used by the compiled miniapp. */
|
|
17
|
+
resourceBaseUrl: string;
|
|
18
|
+
appId: string;
|
|
19
|
+
/** Compiler output package root (`main` for the primary package). */
|
|
20
|
+
outputRoot: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function decodePathname(pathname: string): string;
|
|
23
|
+
export declare function normalizeSlashPath(value: string): string;
|
|
24
|
+
export declare function safeRelativePath(segments: string[]): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Taro/webpack build + runtime chunks are compiled output, not hand-written
|
|
27
|
+
* source. They also collide: dimina's own service runtime attributes its
|
|
28
|
+
* `log()` helper to a `common.js` on the SAME dev-server origin as the
|
|
29
|
+
* project's compiled `common.js` chunk, so the two are URL-indistinguishable
|
|
30
|
+
* and a dimina-core frame would otherwise open the project's chunk. Drop these
|
|
31
|
+
* well-known chunk basenames so a click falls through to the DevTools Sources
|
|
32
|
+
* panel instead of opening the wrong (or generated) file.
|
|
33
|
+
*/
|
|
34
|
+
export declare function excludeBuildChunk(rel: string | null): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* Real host filesystem paths use well-known absolute roots; when they are
|
|
37
|
+
* outside the active project they are runtime/devtools frames, not sources.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isOutsideKnownRoot(normalizedRaw: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Chromium may hand the open-resource hook a raw absolute filesystem path
|
|
42
|
+
* (already project-rooted). Returns `undefined` (not `null`) when the raw
|
|
43
|
+
* value is not under `projectRoot` at all, so the caller can distinguish "not
|
|
44
|
+
* this shape" from "matched, but excluded as a build chunk" (`null`).
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveFilesystemRawPath(normalizedRaw: string, projectRoot: string): string | null | undefined;
|
|
47
|
+
export declare function parseResourceUrl(raw: string, base: URL): URL | null;
|
|
48
|
+
export declare function resolveFileProtocolPath(resource: URL, projectRoot: string): string | null;
|
|
49
|
+
export declare function resolveHttpProtocolPath(resource: URL, base: URL, context: ProjectSourceContext): string | null;
|
|
50
|
+
/**
|
|
51
|
+
* Map a resource URL/path to a project-relative POSIX path, or null when it is
|
|
52
|
+
* not a mappable project source (framework frame, different origin, escapes
|
|
53
|
+
* the project root, or an excluded build chunk).
|
|
54
|
+
*/
|
|
55
|
+
export declare function projectAwareResourcePath(resourceUrl: string, context: ProjectSourceContext): string | null;
|
|
56
|
+
//# sourceMappingURL=open-in-editor-resource-path.d.ts.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure DevTools-resource-URL → project-relative-path resolution for the
|
|
3
|
+
* "open in editor" pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Every function here is `.toString()`-injected verbatim into the DevTools
|
|
6
|
+
* front-end realm by `buildDevtoolsProjectSourceLinksScript` (in
|
|
7
|
+
* `open-in-editor.ts`), alongside being called directly from the main process.
|
|
8
|
+
* That constrains each function to be self-contained (no closures over
|
|
9
|
+
* module-level state beyond calling the OTHER functions in this file, which
|
|
10
|
+
* the injection site also stringifies into the same scope) — no electron / DOM
|
|
11
|
+
* / node deps.
|
|
12
|
+
*/
|
|
13
|
+
export function decodePathname(pathname) {
|
|
14
|
+
return pathname.split('/').map((segment) => {
|
|
15
|
+
try {
|
|
16
|
+
return decodeURIComponent(segment);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return segment;
|
|
20
|
+
}
|
|
21
|
+
}).join('/');
|
|
22
|
+
}
|
|
23
|
+
export function normalizeSlashPath(value) {
|
|
24
|
+
return decodePathname(value.replace(/\\/g, '/')).replace(/\/+/g, '/');
|
|
25
|
+
}
|
|
26
|
+
export function safeRelativePath(segments) {
|
|
27
|
+
if (segments.length === 0 || segments.some((segment) => !segment || segment === '.' || segment === '..')) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return segments.join('/');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Taro/webpack build + runtime chunks are compiled output, not hand-written
|
|
34
|
+
* source. They also collide: dimina's own service runtime attributes its
|
|
35
|
+
* `log()` helper to a `common.js` on the SAME dev-server origin as the
|
|
36
|
+
* project's compiled `common.js` chunk, so the two are URL-indistinguishable
|
|
37
|
+
* and a dimina-core frame would otherwise open the project's chunk. Drop these
|
|
38
|
+
* well-known chunk basenames so a click falls through to the DevTools Sources
|
|
39
|
+
* panel instead of opening the wrong (or generated) file.
|
|
40
|
+
*/
|
|
41
|
+
export function excludeBuildChunk(rel) {
|
|
42
|
+
if (!rel)
|
|
43
|
+
return rel;
|
|
44
|
+
const baseName = rel.split('/').pop();
|
|
45
|
+
return baseName === 'common.js' || baseName === 'vendors.js' || baseName === 'runtime.js'
|
|
46
|
+
|| baseName === 'taro.js' || baseName === 'babelHelpers.js'
|
|
47
|
+
? null
|
|
48
|
+
: rel;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Real host filesystem paths use well-known absolute roots; when they are
|
|
52
|
+
* outside the active project they are runtime/devtools frames, not sources.
|
|
53
|
+
*/
|
|
54
|
+
export function isOutsideKnownRoot(normalizedRaw) {
|
|
55
|
+
return /^\/(?:Volumes|Users|home|private|tmp|var|opt|Applications)\//.test(normalizedRaw);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Chromium may hand the open-resource hook a raw absolute filesystem path
|
|
59
|
+
* (already project-rooted). Returns `undefined` (not `null`) when the raw
|
|
60
|
+
* value is not under `projectRoot` at all, so the caller can distinguish "not
|
|
61
|
+
* this shape" from "matched, but excluded as a build chunk" (`null`).
|
|
62
|
+
*/
|
|
63
|
+
export function resolveFilesystemRawPath(normalizedRaw, projectRoot) {
|
|
64
|
+
if (!projectRoot)
|
|
65
|
+
return undefined;
|
|
66
|
+
if (normalizedRaw !== projectRoot && !normalizedRaw.startsWith(`${projectRoot}/`))
|
|
67
|
+
return undefined;
|
|
68
|
+
const relative = normalizedRaw.slice(projectRoot.length).replace(/^\/+/, '');
|
|
69
|
+
return excludeBuildChunk(safeRelativePath(relative.split('/').filter(Boolean)));
|
|
70
|
+
}
|
|
71
|
+
export function parseResourceUrl(raw, base) {
|
|
72
|
+
try {
|
|
73
|
+
return raw.startsWith('/') && !raw.startsWith('//') ? new URL(raw, base.origin) : new URL(raw);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function resolveFileProtocolPath(resource, projectRoot) {
|
|
80
|
+
const filePath = normalizeSlashPath(resource.pathname);
|
|
81
|
+
if (!projectRoot || (filePath !== projectRoot && !filePath.startsWith(`${projectRoot}/`)))
|
|
82
|
+
return null;
|
|
83
|
+
return excludeBuildChunk(safeRelativePath(filePath.slice(projectRoot.length).replace(/^\/+/, '').split('/').filter(Boolean)));
|
|
84
|
+
}
|
|
85
|
+
export function resolveHttpProtocolPath(resource, base, context) {
|
|
86
|
+
if (resource.protocol !== 'http:' && resource.protocol !== 'https:')
|
|
87
|
+
return null;
|
|
88
|
+
if (resource.origin !== base.origin)
|
|
89
|
+
return null;
|
|
90
|
+
let segments = decodePathname(resource.pathname).split('/').filter(Boolean);
|
|
91
|
+
if (context.appId && segments[0] === context.appId) {
|
|
92
|
+
segments = segments.slice(1);
|
|
93
|
+
if (context.outputRoot && segments[0] === context.outputRoot)
|
|
94
|
+
segments = segments.slice(1);
|
|
95
|
+
}
|
|
96
|
+
return excludeBuildChunk(safeRelativePath(segments));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Map a resource URL/path to a project-relative POSIX path, or null when it is
|
|
100
|
+
* not a mappable project source (framework frame, different origin, escapes
|
|
101
|
+
* the project root, or an excluded build chunk).
|
|
102
|
+
*/
|
|
103
|
+
export function projectAwareResourcePath(resourceUrl, context) {
|
|
104
|
+
let base;
|
|
105
|
+
try {
|
|
106
|
+
base = new URL(context.resourceBaseUrl);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const projectRoot = normalizeSlashPath(context.projectRoot).replace(/\/$/, '');
|
|
112
|
+
const raw = resourceUrl.trim();
|
|
113
|
+
if (!raw)
|
|
114
|
+
return null;
|
|
115
|
+
const normalizedRaw = normalizeSlashPath(raw);
|
|
116
|
+
const filesystemRelative = resolveFilesystemRawPath(normalizedRaw, projectRoot);
|
|
117
|
+
if (filesystemRelative !== undefined)
|
|
118
|
+
return filesystemRelative;
|
|
119
|
+
if (isOutsideKnownRoot(normalizedRaw))
|
|
120
|
+
return null;
|
|
121
|
+
// Reject relative runtime labels such as `service.js` or
|
|
122
|
+
// `electron/js2c/renderer_init`; project source locations must be an
|
|
123
|
+
// absolute URL/path so they can be scoped to the active project.
|
|
124
|
+
if (!raw.startsWith('/') && !/^[a-z][a-z0-9+.-]*:/i.test(raw))
|
|
125
|
+
return null;
|
|
126
|
+
const resource = parseResourceUrl(raw, base);
|
|
127
|
+
if (!resource)
|
|
128
|
+
return null;
|
|
129
|
+
if (resource.protocol === 'file:')
|
|
130
|
+
return resolveFileProtocolPath(resource, projectRoot);
|
|
131
|
+
return resolveHttpProtocolPath(resource, base, context);
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=open-in-editor-resource-path.js.map
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
* node deps so it is unit-testable and shared by main + the injected front-end
|
|
17
17
|
* snippet's expectations.
|
|
18
18
|
*/
|
|
19
|
+
import { type ProjectSourceContext } from './open-in-editor-resource-path.js';
|
|
20
|
+
export type { ProjectSourceContext } from './open-in-editor-resource-path.js';
|
|
19
21
|
/**
|
|
20
22
|
* Sentinel scheme for the encoded "open in editor" request. A bare custom scheme
|
|
21
23
|
* (no `//authority`) keeps the encoded payload entirely in the URL's path/query,
|
|
@@ -32,15 +34,6 @@ export interface OpenInEditorRequest {
|
|
|
32
34
|
/** 0-based column as reported by DevTools (may be undefined). */
|
|
33
35
|
column?: number;
|
|
34
36
|
}
|
|
35
|
-
export interface ProjectSourceContext {
|
|
36
|
-
/** Absolute project root on disk. */
|
|
37
|
-
projectRoot: string;
|
|
38
|
-
/** Resource server base URL used by the compiled miniapp. */
|
|
39
|
-
resourceBaseUrl: string;
|
|
40
|
-
appId: string;
|
|
41
|
-
/** Compiler output package root (`main` for the primary package). */
|
|
42
|
-
outputRoot: string;
|
|
43
|
-
}
|
|
44
37
|
/**
|
|
45
38
|
* Encode an open-in-editor request as a sentinel URL the DevTools front-end can
|
|
46
39
|
* hand to `InspectorFrontendHost.openInNewTab(...)`. All fields ride in the
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* node deps so it is unit-testable and shared by main + the injected front-end
|
|
17
17
|
* snippet's expectations.
|
|
18
18
|
*/
|
|
19
|
+
import { decodePathname, excludeBuildChunk, isOutsideKnownRoot, normalizeSlashPath, parseResourceUrl, projectAwareResourcePath, resolveFileProtocolPath, resolveFilesystemRawPath, resolveHttpProtocolPath, safeRelativePath, } from './open-in-editor-resource-path.js';
|
|
19
20
|
/**
|
|
20
21
|
* Sentinel scheme for the encoded "open in editor" request. A bare custom scheme
|
|
21
22
|
* (no `//authority`) keeps the encoded payload entirely in the URL's path/query,
|
|
@@ -138,98 +139,6 @@ export function resourceUrlToProjectRelativePath(resourceUrl, expectedOriginOrCo
|
|
|
138
139
|
return null;
|
|
139
140
|
return segments.slice(1).join('/');
|
|
140
141
|
}
|
|
141
|
-
function decodePathname(pathname) {
|
|
142
|
-
return pathname.split('/').map((segment) => {
|
|
143
|
-
try {
|
|
144
|
-
return decodeURIComponent(segment);
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
return segment;
|
|
148
|
-
}
|
|
149
|
-
}).join('/');
|
|
150
|
-
}
|
|
151
|
-
function normalizeSlashPath(value) {
|
|
152
|
-
return decodePathname(value.replace(/\\/g, '/')).replace(/\/+/g, '/');
|
|
153
|
-
}
|
|
154
|
-
function safeRelativePath(segments) {
|
|
155
|
-
if (segments.length === 0 || segments.some((segment) => !segment || segment === '.' || segment === '..')) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
return segments.join('/');
|
|
159
|
-
}
|
|
160
|
-
function projectAwareResourcePath(resourceUrl, context) {
|
|
161
|
-
let base;
|
|
162
|
-
try {
|
|
163
|
-
base = new URL(context.resourceBaseUrl);
|
|
164
|
-
}
|
|
165
|
-
catch {
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
const projectRoot = normalizeSlashPath(context.projectRoot).replace(/\/$/, '');
|
|
169
|
-
const raw = resourceUrl.trim();
|
|
170
|
-
if (!raw)
|
|
171
|
-
return null;
|
|
172
|
-
// Taro/webpack build + runtime chunks are compiled output, not hand-written
|
|
173
|
-
// source. They also collide: dimina's own service runtime attributes its
|
|
174
|
-
// `log()` helper to a `common.js` on the SAME dev-server origin as the
|
|
175
|
-
// project's compiled `common.js` chunk, so the two are URL-indistinguishable
|
|
176
|
-
// and a dimina-core frame would otherwise open the project's chunk. Drop these
|
|
177
|
-
// well-known chunk basenames so a click falls through to the DevTools Sources
|
|
178
|
-
// panel instead of opening the wrong (or generated) file. Inlined (not a module
|
|
179
|
-
// const) because this function is `.toString()`-injected into the DevTools realm.
|
|
180
|
-
const excludeBuildChunk = (rel) => {
|
|
181
|
-
if (!rel)
|
|
182
|
-
return rel;
|
|
183
|
-
const base = rel.split('/').pop();
|
|
184
|
-
return base === 'common.js' || base === 'vendors.js' || base === 'runtime.js'
|
|
185
|
-
|| base === 'taro.js' || base === 'babelHelpers.js'
|
|
186
|
-
? null
|
|
187
|
-
: rel;
|
|
188
|
-
};
|
|
189
|
-
// Chromium may hand the open-resource hook a raw absolute filesystem path.
|
|
190
|
-
const normalizedRaw = normalizeSlashPath(raw);
|
|
191
|
-
if (projectRoot && (normalizedRaw === projectRoot || normalizedRaw.startsWith(`${projectRoot}/`))) {
|
|
192
|
-
const relative = normalizedRaw.slice(projectRoot.length).replace(/^\/+/, '');
|
|
193
|
-
return excludeBuildChunk(safeRelativePath(relative.split('/').filter(Boolean)));
|
|
194
|
-
}
|
|
195
|
-
// Sourcemap sources commonly use virtual root paths such as `/pages/x.js`.
|
|
196
|
-
// Real host filesystem paths use well-known absolute roots; when they are
|
|
197
|
-
// outside the active project they are runtime/devtools frames, not sources.
|
|
198
|
-
if (/^\/(?:Volumes|Users|home|private|tmp|var|opt|Applications)\//.test(normalizedRaw)) {
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
// Reject relative runtime labels such as `service.js` or
|
|
202
|
-
// `electron/js2c/renderer_init`; project source locations must be an
|
|
203
|
-
// absolute URL/path so they can be scoped to the active project.
|
|
204
|
-
if (!raw.startsWith('/') && !/^[a-z][a-z0-9+.-]*:/i.test(raw))
|
|
205
|
-
return null;
|
|
206
|
-
let resource;
|
|
207
|
-
try {
|
|
208
|
-
resource = raw.startsWith('/') && !raw.startsWith('//')
|
|
209
|
-
? new URL(raw, base.origin)
|
|
210
|
-
: new URL(raw);
|
|
211
|
-
}
|
|
212
|
-
catch {
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
|
-
if (resource.protocol === 'file:') {
|
|
216
|
-
const filePath = normalizeSlashPath(resource.pathname);
|
|
217
|
-
if (!projectRoot || (filePath !== projectRoot && !filePath.startsWith(`${projectRoot}/`)))
|
|
218
|
-
return null;
|
|
219
|
-
return excludeBuildChunk(safeRelativePath(filePath.slice(projectRoot.length).replace(/^\/+/, '').split('/').filter(Boolean)));
|
|
220
|
-
}
|
|
221
|
-
if (resource.protocol !== 'http:' && resource.protocol !== 'https:')
|
|
222
|
-
return null;
|
|
223
|
-
if (resource.origin !== base.origin)
|
|
224
|
-
return null;
|
|
225
|
-
let segments = decodePathname(resource.pathname).split('/').filter(Boolean);
|
|
226
|
-
if (context.appId && segments[0] === context.appId) {
|
|
227
|
-
segments = segments.slice(1);
|
|
228
|
-
if (context.outputRoot && segments[0] === context.outputRoot)
|
|
229
|
-
segments = segments.slice(1);
|
|
230
|
-
}
|
|
231
|
-
return excludeBuildChunk(safeRelativePath(segments));
|
|
232
|
-
}
|
|
233
142
|
/** Read the project/source routing metadata carried by a service-host spawn URL. */
|
|
234
143
|
export function projectSourceContextFromServiceHostUrl(serviceHostUrl, activeProjectRoot) {
|
|
235
144
|
let url;
|
|
@@ -286,10 +195,16 @@ export function buildDevtoolsProjectSourceLinksScript(context) {
|
|
|
286
195
|
}
|
|
287
196
|
|
|
288
197
|
const cfg = ${config}
|
|
289
|
-
const diminaProjectSourcePath = ${projectAwareResourcePath.toString()}
|
|
290
198
|
const decodePathname = ${decodePathname.toString()}
|
|
291
199
|
const normalizeSlashPath = ${normalizeSlashPath.toString()}
|
|
292
200
|
const safeRelativePath = ${safeRelativePath.toString()}
|
|
201
|
+
const excludeBuildChunk = ${excludeBuildChunk.toString()}
|
|
202
|
+
const isOutsideKnownRoot = ${isOutsideKnownRoot.toString()}
|
|
203
|
+
const resolveFilesystemRawPath = ${resolveFilesystemRawPath.toString()}
|
|
204
|
+
const parseResourceUrl = ${parseResourceUrl.toString()}
|
|
205
|
+
const resolveFileProtocolPath = ${resolveFileProtocolPath.toString()}
|
|
206
|
+
const resolveHttpProtocolPath = ${resolveHttpProtocolPath.toString()}
|
|
207
|
+
const diminaProjectSourcePath = ${projectAwareResourcePath.toString()}
|
|
293
208
|
const observedRoots = new Set()
|
|
294
209
|
const observers = []
|
|
295
210
|
const clickBindings = []
|