@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.
Files changed (87) hide show
  1. package/dist/main/app/app.js +5 -25
  2. package/dist/main/app/native-overview.d.ts +27 -0
  3. package/dist/main/app/native-overview.js +44 -0
  4. package/dist/main/index.bundle.js +1217 -735
  5. package/dist/main/ipc/bridge-router.d.ts +8 -0
  6. package/dist/main/ipc/bridge-router.js +526 -173
  7. package/dist/main/ipc/project-fs.js +39 -21
  8. package/dist/main/services/automation/handlers/app.js +143 -109
  9. package/dist/main/services/console-forward/index.d.ts +12 -1
  10. package/dist/main/services/console-forward/index.js +99 -1
  11. package/dist/main/services/diagnostics/index.d.ts +49 -0
  12. package/dist/main/services/diagnostics/index.js +61 -0
  13. package/dist/main/services/mcp/tools/simulator-tools.js +118 -97
  14. package/dist/main/services/network-forward/dispatch-batch.d.ts +22 -0
  15. package/dist/main/services/network-forward/dispatch-batch.js +21 -0
  16. package/dist/main/services/network-forward/index.js +37 -20
  17. package/dist/main/services/notifications/renderer-notifier.d.ts +39 -0
  18. package/dist/main/services/notifications/renderer-notifier.js +4 -1
  19. package/dist/main/services/projects/create-project-service.js +54 -34
  20. package/dist/main/services/projects/project-repository.js +2 -1
  21. package/dist/main/services/projects/types.d.ts +1 -32
  22. package/dist/main/services/service-console/console-api.js +36 -27
  23. package/dist/main/services/simulator-temp-files/disk.js +109 -86
  24. package/dist/main/services/views/simulator-session-policy.js +17 -0
  25. package/dist/main/services/workbench-coi-server.js +58 -45
  26. package/dist/main/services/workbench-context.d.ts +10 -0
  27. package/dist/main/services/workspace/workspace-service.js +12 -3
  28. package/dist/main/utils/logger.d.ts +5 -12
  29. package/dist/main/utils/logger.js +5 -45
  30. package/dist/main/windows/service-host-window/create.d.ts +15 -1
  31. package/dist/main/windows/service-host-window/create.js +11 -3
  32. package/dist/preload/instrumentation/wxml-extract.js +94 -62
  33. package/dist/preload/runtime/main-api-runner.d.ts +1 -1
  34. package/dist/preload/shared/api-compat.js +18 -55
  35. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  36. package/dist/preload/windows/main.cjs +284 -565
  37. package/dist/preload/windows/main.cjs.map +2 -2
  38. package/dist/preload/windows/simulator.cjs +154 -83
  39. package/dist/preload/windows/simulator.cjs.map +3 -3
  40. package/dist/preload/windows/simulator.js +154 -83
  41. package/dist/render-host/render-inspect.js +63 -52
  42. package/dist/renderer/assets/index-BwzPwCmM.js +49 -0
  43. package/dist/renderer/assets/{input-Cjk0wSEh.js → input-CTb_le7F.js} +2 -2
  44. package/dist/renderer/assets/ipc-transport-BPWIV5hA.css +1 -0
  45. package/dist/renderer/assets/{ipc-transport-OZS-KmOW.js → ipc-transport-Ck5Xa8Tu.js} +2 -2
  46. package/dist/renderer/assets/popover-B1Zu2UQu.js +2 -0
  47. package/dist/renderer/assets/{select-BQDXi5ih.js → select-ozSk5Pt6.js} +2 -2
  48. package/dist/renderer/assets/{settings-tP3Px2KR.js → settings-CNwGOI22.js} +2 -2
  49. package/dist/renderer/assets/settings-api-DMbMp1Eq.js +2 -0
  50. package/dist/renderer/assets/workbenchSettings-Cr4EHo5w.js +8 -0
  51. package/dist/renderer/entries/main/index.html +6 -6
  52. package/dist/renderer/entries/popover/index.html +5 -5
  53. package/dist/renderer/entries/settings/index.html +5 -5
  54. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  55. package/dist/shared/appdata-accumulator.js +53 -48
  56. package/dist/shared/bridge-channels.d.ts +22 -0
  57. package/dist/shared/ipc-channels.d.ts +3 -0
  58. package/dist/shared/ipc-channels.js +9 -0
  59. package/dist/shared/open-in-editor-resource-path.d.ts +56 -0
  60. package/dist/shared/open-in-editor-resource-path.js +133 -0
  61. package/dist/shared/open-in-editor.d.ts +2 -9
  62. package/dist/shared/open-in-editor.js +8 -93
  63. package/dist/shared/request-core.d.ts +84 -0
  64. package/dist/shared/request-core.js +168 -0
  65. package/dist/shared/simulator-api-metadata.d.ts +22 -17
  66. package/dist/shared/simulator-api-metadata.js +36 -0
  67. package/dist/shared/types.d.ts +20 -4
  68. package/dist/simulator/assets/{device-shell-CUl0ILfn.js → device-shell-C-wcFq3Z.js} +2 -2
  69. package/dist/simulator/assets/{jsx-runtime-CDK-o-S0.js → jsx-runtime-BDTY6fEq.js} +2 -2
  70. package/dist/simulator/assets/simulator-DU3-fS3v.js +10 -0
  71. package/dist/simulator/assets/simulator-mini-app-DzfMfnVM.js +2 -0
  72. package/dist/simulator/simulator.html +2 -2
  73. package/dist/vscode-workbench/assets/__vite-browser-external-CXi6Kz9W.js +1 -0
  74. package/dist/vscode-workbench/assets/{dist-CS7SQP3K.js → dist-TpGpmMGi.js} +3 -3
  75. package/dist/vscode-workbench/assets/{iconv-lite-umd-D3q-1-o6.js → iconv-lite-umd-C9tiCAJa.js} +1 -1
  76. package/dist/vscode-workbench/assets/{index-zjigpZ25.js → index-DJ1HyMZ7.js} +20 -22
  77. package/dist/vscode-workbench/assets/{jschardet-Cu4ufeHq.js → jschardet-DE1jV513.js} +1 -1
  78. package/dist/vscode-workbench/index.html +1 -1
  79. package/package.json +6 -6
  80. package/dist/renderer/assets/index-B-Dqb7G0.js +0 -49
  81. package/dist/renderer/assets/ipc-transport-D5dKIti1.css +0 -1
  82. package/dist/renderer/assets/popover-CQVvOe90.js +0 -2
  83. package/dist/renderer/assets/settings-api-B6x2mhaD.js +0 -2
  84. package/dist/renderer/assets/workbenchSettings-Bim9ol9R.js +0 -8
  85. package/dist/simulator/assets/simulator-Dz8iGcgy.js +0 -10
  86. package/dist/simulator/assets/simulator-mini-app-Bt639XL_.js +0 -2
  87. 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-CQVvOe90.js"></script>
12
- <link rel="modulepreload" crossorigin href="../../assets/ipc-transport-OZS-KmOW.js">
13
- <link rel="modulepreload" crossorigin href="../../assets/input-Cjk0wSEh.js">
14
- <link rel="modulepreload" crossorigin href="../../assets/select-BQDXi5ih.js">
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-D5dKIti1.css">
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-tP3Px2KR.js"></script>
15
- <link rel="modulepreload" crossorigin href="../../assets/ipc-transport-OZS-KmOW.js">
16
- <link rel="modulepreload" crossorigin href="../../assets/input-Cjk0wSEh.js">
17
- <link rel="modulepreload" crossorigin href="../../assets/settings-api-B6x2mhaD.js">
18
- <link rel="stylesheet" crossorigin href="../../assets/ipc-transport-D5dKIti1.css">
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-Bim9ol9R.js"></script>
10
- <link rel="modulepreload" crossorigin href="../../assets/ipc-transport-OZS-KmOW.js">
11
- <link rel="modulepreload" crossorigin href="../../assets/settings-api-B6x2mhaD.js">
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-D5dKIti1.css">
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
- let payload = message;
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
- const body = record.body;
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
- const body = record.body;
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
- let payload = message;
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 = []