@dimina-kit/devtools 0.4.0-dev.20260718143821 → 0.4.0-dev.20260728065133
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 +67 -1
- package/dist/main/app/lifecycle.js +9 -0
- package/dist/main/index.bundle.js +928 -162
- package/dist/main/ipc/bridge-router.d.ts +36 -0
- package/dist/main/ipc/bridge-router.js +56 -0
- package/dist/main/ipc/index.d.ts +1 -0
- package/dist/main/ipc/index.js +1 -0
- package/dist/main/ipc/internal-devtools.d.ts +15 -0
- package/dist/main/ipc/internal-devtools.js +9 -0
- package/dist/main/services/compile-standby.js +4 -0
- package/dist/main/services/console-forward/cdp-inject.d.ts +18 -0
- package/dist/main/services/console-forward/cdp-inject.js +30 -0
- package/dist/main/services/console-forward/global-console-mirror.d.ts +33 -0
- package/dist/main/services/console-forward/global-console-mirror.js +71 -0
- package/dist/main/services/console-forward/global-diagnostics-mirror.d.ts +33 -0
- package/dist/main/services/console-forward/global-diagnostics-mirror.js +73 -0
- package/dist/main/services/console-forward/index.d.ts +15 -1
- package/dist/main/services/console-forward/index.js +42 -2
- package/dist/main/services/console-forward/internal-log.d.ts +11 -0
- package/dist/main/services/console-forward/internal-log.js +23 -0
- package/dist/main/services/console-forward/open-gated-relay.d.ts +67 -0
- package/dist/main/services/console-forward/open-gated-relay.js +55 -0
- package/dist/main/services/diagnostics/index.d.ts +10 -0
- package/dist/main/services/elements-forward/index.js +14 -96
- package/dist/main/services/network-forward/frontend-dispatch.d.ts +64 -0
- package/dist/main/services/network-forward/frontend-dispatch.js +113 -8
- package/dist/main/services/network-forward/global-body-gate.d.ts +46 -0
- package/dist/main/services/network-forward/global-body-gate.js +93 -0
- package/dist/main/services/network-forward/global-mirror-test-fixtures.d.ts +48 -0
- package/dist/main/services/network-forward/global-mirror-test-fixtures.js +96 -0
- package/dist/main/services/network-forward/index.d.ts +31 -0
- package/dist/main/services/network-forward/index.js +256 -8
- package/dist/main/services/network-forward/user-facing.d.ts +21 -0
- package/dist/main/services/network-forward/user-facing.js +50 -0
- package/dist/main/services/views/console-filter.d.ts +145 -0
- package/dist/main/services/views/console-filter.js +233 -0
- package/dist/main/services/views/frontend-bootstrap-gate.d.ts +59 -0
- package/dist/main/services/views/frontend-bootstrap-gate.js +117 -0
- package/dist/main/services/views/native-simulator-devtools-host.js +138 -30
- package/dist/main/services/views/view-manager-devtools-host-test-fixtures.d.ts +76 -0
- package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +182 -0
- package/dist/main/services/workbench-context.d.ts +10 -0
- package/dist/main/utils/theme.d.ts +10 -6
- package/dist/main/utils/theme.js +10 -6
- package/dist/main/windows/internal-devtools-window/index.d.ts +66 -0
- package/dist/main/windows/internal-devtools-window/index.js +160 -0
- package/dist/native-host/render/render.js +89 -73
- package/dist/native-host/service/service.js +2 -2
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +1 -1
- package/dist/preload/windows/simulator.cjs.map +1 -1
- package/dist/renderer/assets/index-M5NDq_vi.js +49 -0
- package/dist/renderer/assets/{input-c2OcrrZy.js → input-dsgeTmVX.js} +2 -2
- package/dist/renderer/assets/ipc-transport-BgFdT9bT.js +9 -0
- package/dist/renderer/assets/{popover-kv2qspWz.js → popover-Disfu1cx.js} +2 -2
- package/dist/renderer/assets/{select-DKqzMtTh.js → select-DAw1hzkl.js} +2 -2
- package/dist/renderer/assets/{settings-dJNKTGr8.js → settings-M_8GFW2M.js} +2 -2
- package/dist/renderer/assets/settings-api-DFR5eDl_.js +2 -0
- package/dist/renderer/assets/{workbenchSettings-DQ_VP5-W.js → workbenchSettings-CxdXeoOu.js} +2 -2
- package/dist/renderer/entries/main/index.html +5 -5
- package/dist/renderer/entries/popover/index.html +4 -4
- package/dist/renderer/entries/settings/index.html +4 -4
- package/dist/renderer/entries/workbench-settings/index.html +3 -3
- package/dist/shared/ipc-channels.d.ts +3 -0
- package/dist/shared/ipc-channels.js +6 -0
- package/package.json +7 -7
- package/dist/renderer/assets/index-DfDIvgvK.js +0 -49
- package/dist/renderer/assets/ipc-transport-CuDJ07aE.js +0 -9
- package/dist/renderer/assets/settings-api-qpXKDRXt.js +0 -2
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Negative text-filter for the right-panel (user-facing) Console — hides
|
|
3
|
+
* dimina framework internal log lines from the panel the mini-app author
|
|
4
|
+
* watches (see console-forward/internal-log.ts for
|
|
5
|
+
* the prefix judge this mirrors). The framework prints these via a plain
|
|
6
|
+
* `console.log` call INSIDE the inspected service host itself; main has no
|
|
7
|
+
* interception point for a native console line (see
|
|
8
|
+
* console-forward/index.ts's header comment) — the only lever available is
|
|
9
|
+
* the front-end's OWN Console filter setting.
|
|
10
|
+
*
|
|
11
|
+
* ── Mechanism ────────────────────────────────────────────────────────────
|
|
12
|
+
* The Console panel's text filter is a Global/Synced DevTools setting. On
|
|
13
|
+
* Chromium ~146 (post-M125 kebab-case renaming) that means TWO things a
|
|
14
|
+
* naive `localStorage['console.textFilter']` write gets both wrong:
|
|
15
|
+
* 1. The real setting name is kebab-case: `console.text-filter`.
|
|
16
|
+
* 2. Global/Synced settings are NOT backed by `window.localStorage` at
|
|
17
|
+
* all — they go through `InspectorFrontendHost.getPreferences`
|
|
18
|
+
* (async-callback read) / `.setPreference(key, jsonValue)` (sync
|
|
19
|
+
* write). Values are themselves JSON-stringified (e.g. `'"elements"'`
|
|
20
|
+
* for a string preference) — never a `localStorage` entry.
|
|
21
|
+
* (An earlier version of this comment cited `localStorage['panel-selectedTab']`
|
|
22
|
+
* as a "proven working" precedent for the localStorage approach — that was
|
|
23
|
+
* itself a misreading: the console-default tab selection actually works via
|
|
24
|
+
* a LIVE `UI.ViewManager.instance().showView('console')` call, not a
|
|
25
|
+
* persisted setting; see native-simulator-devtools-host.ts's console-default
|
|
26
|
+
* injection, which has since dropped the dead localStorage line alongside
|
|
27
|
+
* this fix.)
|
|
28
|
+
*
|
|
29
|
+
* ── Disk persistence: verified NOT to apply to this custom host ───────────
|
|
30
|
+
* A dedicated isolated e2e (`e2e/_diagnose-inspector-frontend-host.spec.ts`,
|
|
31
|
+
* clean `electronApp.close()` — not `kill -9`, which never lets Electron
|
|
32
|
+
* flush prefs and would confound the result) confirms `setPreference`/
|
|
33
|
+
* `getPreferences` DO round-trip correctly in-process (this function's
|
|
34
|
+
* output was read back byte-for-byte via the real production code path),
|
|
35
|
+
* but for THIS custom devtools:// front-end host (a plain BrowserWindow we
|
|
36
|
+
* point at `devtools://` ourselves, not Electron's native
|
|
37
|
+
* `webContents.openDevTools()`) nothing under `electron.devtools.preferences`
|
|
38
|
+
* — not even `panel-selected-tab` — survives to the on-disk Preferences
|
|
39
|
+
* file on a clean shutdown. That's fine for this function's purpose: every
|
|
40
|
+
* fresh launch starts with `existing === undefined`, so the `isUnset` branch
|
|
41
|
+
* always (re-)applies the default — exactly the desired "always filtered by
|
|
42
|
+
* default" behavior. The self-healing "stale mark" branch below still
|
|
43
|
+
* matters WITHIN a single running process (e.g. re-pointing the front-end at
|
|
44
|
+
* a new service host mid-session), where `getPreferences` reflects whatever
|
|
45
|
+
* was `setPreference`d earlier in that same process, including a real user
|
|
46
|
+
* customization typed into the filter box.
|
|
47
|
+
*
|
|
48
|
+
* `setPreference` values are themselves JSON-stringified (matching the
|
|
49
|
+
* `'"elements"'` shape observed above). A NEGATIVE filter (`-/regex/`) is
|
|
50
|
+
* DevTools' own "hide lines matching" syntax (the same `-` prefix a user
|
|
51
|
+
* types into the filter box themselves).
|
|
52
|
+
*
|
|
53
|
+
* Only overwrites when the user hasn't set their OWN filter — never clobber
|
|
54
|
+
* a real choice with this default. Re-injected on every (re)point like
|
|
55
|
+
* customizeDevtoolsTabs, so a service-host pool swap re-applies it.
|
|
56
|
+
*
|
|
57
|
+
* Self-healing default: a companion `…dimina-default` key marks the value WE
|
|
58
|
+
* last wrote. If `console.text-filter` still equals that mark, it is our own
|
|
59
|
+
* prior default going stale (e.g. this DEFAULT_INTERNAL_LOG_FILTER regex
|
|
60
|
+
* changing between releases), not a real user choice — safe to overwrite. A
|
|
61
|
+
* value that differs from the mark is the user's own customization and is
|
|
62
|
+
* left untouched. Without this, "only write when unset" permanently freezes
|
|
63
|
+
* whatever default first got written (real dev-machine finding: an older
|
|
64
|
+
* build's regex, missing the `[视图] ` prefix, survived across rebuilds and
|
|
65
|
+
* silently never updated).
|
|
66
|
+
*
|
|
67
|
+
* This covers the persisted setting a FRESH (not-yet-constructed) Console
|
|
68
|
+
* panel would read at boot. It does NOT by itself update an
|
|
69
|
+
* ALREADY-constructed Console panel's live filter box — real-machine
|
|
70
|
+
* evidence (empirical probe against the actual bundled Console panel, this
|
|
71
|
+
* session) showed the panel's own async bootstrap (Settings storage wiring,
|
|
72
|
+
* i18n, ActionRegistry, …) can still be constructing itself well after
|
|
73
|
+
* `applyConsoleFilter`'s injection point (right after `openDevTools()`,
|
|
74
|
+
* gated on `did-stop-loading` — the top document finishing load, NOT the
|
|
75
|
+
* front-end's own panel construction), so this preference write can land
|
|
76
|
+
* before OR after the panel reads it, and a "before" write does nothing for
|
|
77
|
+
* that already-visible filter box. `buildLiveConsoleFilterScript` below
|
|
78
|
+
* closes that gap by driving the panel's live filter object directly, with a
|
|
79
|
+
* bounded poll (no fixed delay — there is no public "Console panel
|
|
80
|
+
* constructed" event to await, only a checkable condition) standing in for
|
|
81
|
+
* the missing event this repo's own conventions call for.
|
|
82
|
+
*/
|
|
83
|
+
/**
|
|
84
|
+
* DevTools negative-filter regex hiding the dimina framework's internal-log
|
|
85
|
+
* lines (see console-forward/internal-log.ts's prefix judge) that have NO
|
|
86
|
+
* other interception point: SERVICE-layer entries (`^\[service\]`) are
|
|
87
|
+
* captured directly by the native CDP `Runtime.consoleAPICalled` attach on
|
|
88
|
+
* the service host (service-host/preload.cjs deliberately does not
|
|
89
|
+
* monkeypatch `console.*` there — see its header comment — so there is no
|
|
90
|
+
* main-owned code between the framework's call and the attached DevTools).
|
|
91
|
+
* This front-end filter is genuinely the only lever available for that half.
|
|
92
|
+
*
|
|
93
|
+
* RENDER-layer framework noise (`[system]`) no longer needs this filter:
|
|
94
|
+
* `console-forward/index.ts`'s `forwardRenderToServiceHost` now gates on
|
|
95
|
+
* `isInternalLogMessage` and simply never injects those entries into the
|
|
96
|
+
* service host's console at all — filtered at the source (main-owned code),
|
|
97
|
+
* so they never reach the right panel regardless of what a user types into
|
|
98
|
+
* this box. `-/…/ ` is DevTools' own "exclude" filter syntax.
|
|
99
|
+
*/
|
|
100
|
+
export declare const DEFAULT_INTERNAL_LOG_FILTER = "-/^\\[service\\]/";
|
|
101
|
+
/**
|
|
102
|
+
* Build the `executeJavaScript` source that seeds the Console panel's
|
|
103
|
+
* negative filter via `InspectorFrontendHost`, unless the user already set
|
|
104
|
+
* one of their own (or our own prior default has been customized away from).
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildConsoleFilterScript(negativeFilter?: string): string;
|
|
107
|
+
/**
|
|
108
|
+
* Build the `executeJavaScript` source that drives the Console panel's LIVE
|
|
109
|
+
* filter object directly — the fix for the gap `buildConsoleFilterScript`'s
|
|
110
|
+
* persisted-preference write cannot close (see this module's header
|
|
111
|
+
* comment). Empirically discovered live API (real-machine probe against the
|
|
112
|
+
* actual bundled `devtools://` Console panel, this session — not a guess):
|
|
113
|
+
* `Console.ConsoleView.instance().filter` exposes `textFilterUI` (the
|
|
114
|
+
* visible input box — `.setValue(text)` updates what the user sees) and
|
|
115
|
+
* `updateCurrentFilter()` / `onFilterChanged()` (re-parses the box's value
|
|
116
|
+
* into the filter actually applied to messages, and re-applies it to
|
|
117
|
+
* already-shown AND future messages). Verified end-to-end: after this
|
|
118
|
+
* sequence, a fresh `[service]`-prefixed message logged afterward is
|
|
119
|
+
* immediately hidden, matching the already-shown ones.
|
|
120
|
+
*
|
|
121
|
+
* Same "don't clobber a real user choice" contract as
|
|
122
|
+
* `buildConsoleFilterScript`, judged against the LIVE box value instead of a
|
|
123
|
+
* persisted one: only applies when the box currently reads empty (unset) or
|
|
124
|
+
* already equals this exact default (re-applying is a harmless no-op,
|
|
125
|
+
* correctly handles a re-point re-running this script against a panel that
|
|
126
|
+
* already has it applied).
|
|
127
|
+
*
|
|
128
|
+
* `Console.ConsoleView` has no lifecycle EVENT marking "fully constructed" —
|
|
129
|
+
* only the checkable condition of whether calling `.instance()` and reaching
|
|
130
|
+
* into `.filter.textFilterUI` throws. Retries on a bounded interval (see
|
|
131
|
+
* `LIVE_FILTER_POLL_MAX_ATTEMPTS`/`_INTERVAL_MS`) rather than a single fixed
|
|
132
|
+
* delay, and stops immediately on either success or a detected user
|
|
133
|
+
* customization — it does not keep polling once there is nothing left to do.
|
|
134
|
+
*
|
|
135
|
+
* Every tick gates on the front-end bootstrap probe BEFORE touching
|
|
136
|
+
* `ConsoleView.instance()`: an early construction transitively creates
|
|
137
|
+
* IssuesManager and permanently kills the front-end's own bootstrap
|
|
138
|
+
* (`ensureFirst` conflict in MainImpl.#createAppUI) — see
|
|
139
|
+
* frontend-bootstrap-gate.ts for the full mechanism. The main process
|
|
140
|
+
* additionally holds this whole injection behind `whenFrontendBootstrapped`;
|
|
141
|
+
* the in-realm probe is defense in depth for any other caller of this
|
|
142
|
+
* script builder.
|
|
143
|
+
*/
|
|
144
|
+
export declare function buildLiveConsoleFilterScript(negativeFilter?: string): string;
|
|
145
|
+
//# sourceMappingURL=console-filter.d.ts.map
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Negative text-filter for the right-panel (user-facing) Console — hides
|
|
3
|
+
* dimina framework internal log lines from the panel the mini-app author
|
|
4
|
+
* watches (see console-forward/internal-log.ts for
|
|
5
|
+
* the prefix judge this mirrors). The framework prints these via a plain
|
|
6
|
+
* `console.log` call INSIDE the inspected service host itself; main has no
|
|
7
|
+
* interception point for a native console line (see
|
|
8
|
+
* console-forward/index.ts's header comment) — the only lever available is
|
|
9
|
+
* the front-end's OWN Console filter setting.
|
|
10
|
+
*
|
|
11
|
+
* ── Mechanism ────────────────────────────────────────────────────────────
|
|
12
|
+
* The Console panel's text filter is a Global/Synced DevTools setting. On
|
|
13
|
+
* Chromium ~146 (post-M125 kebab-case renaming) that means TWO things a
|
|
14
|
+
* naive `localStorage['console.textFilter']` write gets both wrong:
|
|
15
|
+
* 1. The real setting name is kebab-case: `console.text-filter`.
|
|
16
|
+
* 2. Global/Synced settings are NOT backed by `window.localStorage` at
|
|
17
|
+
* all — they go through `InspectorFrontendHost.getPreferences`
|
|
18
|
+
* (async-callback read) / `.setPreference(key, jsonValue)` (sync
|
|
19
|
+
* write). Values are themselves JSON-stringified (e.g. `'"elements"'`
|
|
20
|
+
* for a string preference) — never a `localStorage` entry.
|
|
21
|
+
* (An earlier version of this comment cited `localStorage['panel-selectedTab']`
|
|
22
|
+
* as a "proven working" precedent for the localStorage approach — that was
|
|
23
|
+
* itself a misreading: the console-default tab selection actually works via
|
|
24
|
+
* a LIVE `UI.ViewManager.instance().showView('console')` call, not a
|
|
25
|
+
* persisted setting; see native-simulator-devtools-host.ts's console-default
|
|
26
|
+
* injection, which has since dropped the dead localStorage line alongside
|
|
27
|
+
* this fix.)
|
|
28
|
+
*
|
|
29
|
+
* ── Disk persistence: verified NOT to apply to this custom host ───────────
|
|
30
|
+
* A dedicated isolated e2e (`e2e/_diagnose-inspector-frontend-host.spec.ts`,
|
|
31
|
+
* clean `electronApp.close()` — not `kill -9`, which never lets Electron
|
|
32
|
+
* flush prefs and would confound the result) confirms `setPreference`/
|
|
33
|
+
* `getPreferences` DO round-trip correctly in-process (this function's
|
|
34
|
+
* output was read back byte-for-byte via the real production code path),
|
|
35
|
+
* but for THIS custom devtools:// front-end host (a plain BrowserWindow we
|
|
36
|
+
* point at `devtools://` ourselves, not Electron's native
|
|
37
|
+
* `webContents.openDevTools()`) nothing under `electron.devtools.preferences`
|
|
38
|
+
* — not even `panel-selected-tab` — survives to the on-disk Preferences
|
|
39
|
+
* file on a clean shutdown. That's fine for this function's purpose: every
|
|
40
|
+
* fresh launch starts with `existing === undefined`, so the `isUnset` branch
|
|
41
|
+
* always (re-)applies the default — exactly the desired "always filtered by
|
|
42
|
+
* default" behavior. The self-healing "stale mark" branch below still
|
|
43
|
+
* matters WITHIN a single running process (e.g. re-pointing the front-end at
|
|
44
|
+
* a new service host mid-session), where `getPreferences` reflects whatever
|
|
45
|
+
* was `setPreference`d earlier in that same process, including a real user
|
|
46
|
+
* customization typed into the filter box.
|
|
47
|
+
*
|
|
48
|
+
* `setPreference` values are themselves JSON-stringified (matching the
|
|
49
|
+
* `'"elements"'` shape observed above). A NEGATIVE filter (`-/regex/`) is
|
|
50
|
+
* DevTools' own "hide lines matching" syntax (the same `-` prefix a user
|
|
51
|
+
* types into the filter box themselves).
|
|
52
|
+
*
|
|
53
|
+
* Only overwrites when the user hasn't set their OWN filter — never clobber
|
|
54
|
+
* a real choice with this default. Re-injected on every (re)point like
|
|
55
|
+
* customizeDevtoolsTabs, so a service-host pool swap re-applies it.
|
|
56
|
+
*
|
|
57
|
+
* Self-healing default: a companion `…dimina-default` key marks the value WE
|
|
58
|
+
* last wrote. If `console.text-filter` still equals that mark, it is our own
|
|
59
|
+
* prior default going stale (e.g. this DEFAULT_INTERNAL_LOG_FILTER regex
|
|
60
|
+
* changing between releases), not a real user choice — safe to overwrite. A
|
|
61
|
+
* value that differs from the mark is the user's own customization and is
|
|
62
|
+
* left untouched. Without this, "only write when unset" permanently freezes
|
|
63
|
+
* whatever default first got written (real dev-machine finding: an older
|
|
64
|
+
* build's regex, missing the `[视图] ` prefix, survived across rebuilds and
|
|
65
|
+
* silently never updated).
|
|
66
|
+
*
|
|
67
|
+
* This covers the persisted setting a FRESH (not-yet-constructed) Console
|
|
68
|
+
* panel would read at boot. It does NOT by itself update an
|
|
69
|
+
* ALREADY-constructed Console panel's live filter box — real-machine
|
|
70
|
+
* evidence (empirical probe against the actual bundled Console panel, this
|
|
71
|
+
* session) showed the panel's own async bootstrap (Settings storage wiring,
|
|
72
|
+
* i18n, ActionRegistry, …) can still be constructing itself well after
|
|
73
|
+
* `applyConsoleFilter`'s injection point (right after `openDevTools()`,
|
|
74
|
+
* gated on `did-stop-loading` — the top document finishing load, NOT the
|
|
75
|
+
* front-end's own panel construction), so this preference write can land
|
|
76
|
+
* before OR after the panel reads it, and a "before" write does nothing for
|
|
77
|
+
* that already-visible filter box. `buildLiveConsoleFilterScript` below
|
|
78
|
+
* closes that gap by driving the panel's live filter object directly, with a
|
|
79
|
+
* bounded poll (no fixed delay — there is no public "Console panel
|
|
80
|
+
* constructed" event to await, only a checkable condition) standing in for
|
|
81
|
+
* the missing event this repo's own conventions call for.
|
|
82
|
+
*/
|
|
83
|
+
/**
|
|
84
|
+
* DevTools negative-filter regex hiding the dimina framework's internal-log
|
|
85
|
+
* lines (see console-forward/internal-log.ts's prefix judge) that have NO
|
|
86
|
+
* other interception point: SERVICE-layer entries (`^\[service\]`) are
|
|
87
|
+
* captured directly by the native CDP `Runtime.consoleAPICalled` attach on
|
|
88
|
+
* the service host (service-host/preload.cjs deliberately does not
|
|
89
|
+
* monkeypatch `console.*` there — see its header comment — so there is no
|
|
90
|
+
* main-owned code between the framework's call and the attached DevTools).
|
|
91
|
+
* This front-end filter is genuinely the only lever available for that half.
|
|
92
|
+
*
|
|
93
|
+
* RENDER-layer framework noise (`[system]`) no longer needs this filter:
|
|
94
|
+
* `console-forward/index.ts`'s `forwardRenderToServiceHost` now gates on
|
|
95
|
+
* `isInternalLogMessage` and simply never injects those entries into the
|
|
96
|
+
* service host's console at all — filtered at the source (main-owned code),
|
|
97
|
+
* so they never reach the right panel regardless of what a user types into
|
|
98
|
+
* this box. `-/…/ ` is DevTools' own "exclude" filter syntax.
|
|
99
|
+
*/
|
|
100
|
+
export const DEFAULT_INTERNAL_LOG_FILTER = '-/^\\[service\\]/';
|
|
101
|
+
/**
|
|
102
|
+
* Build the `executeJavaScript` source that seeds the Console panel's
|
|
103
|
+
* negative filter via `InspectorFrontendHost`, unless the user already set
|
|
104
|
+
* one of their own (or our own prior default has been customized away from).
|
|
105
|
+
*/
|
|
106
|
+
export function buildConsoleFilterScript(negativeFilter = DEFAULT_INTERNAL_LOG_FILTER) {
|
|
107
|
+
const keyJson = JSON.stringify('console.text-filter');
|
|
108
|
+
const markKeyJson = JSON.stringify('console.text-filter.dimina-default');
|
|
109
|
+
// The stored preference value is itself JSON-stringified (mirrors the
|
|
110
|
+
// real host's own `'"elements"'`-shaped entries).
|
|
111
|
+
const valueJsonLiteral = JSON.stringify(JSON.stringify(negativeFilter));
|
|
112
|
+
return `(function(){try{
|
|
113
|
+
var IFH = globalThis.InspectorFrontendHost;
|
|
114
|
+
if (!IFH || typeof IFH.getPreferences !== 'function' || typeof IFH.setPreference !== 'function') return;
|
|
115
|
+
IFH.getPreferences(function(prefs){
|
|
116
|
+
try {
|
|
117
|
+
var KEY = ${keyJson};
|
|
118
|
+
var MARK_KEY = ${markKeyJson};
|
|
119
|
+
var VALUE = ${valueJsonLiteral};
|
|
120
|
+
var existing = prefs ? prefs[KEY] : undefined;
|
|
121
|
+
var mark = prefs ? prefs[MARK_KEY] : undefined;
|
|
122
|
+
var isUnset = existing === undefined || existing === null || existing === '' || existing === '""';
|
|
123
|
+
var isOurStaleDefault = !isUnset && mark !== undefined && mark !== null && existing === mark;
|
|
124
|
+
if (isUnset || isOurStaleDefault) {
|
|
125
|
+
IFH.setPreference(KEY, VALUE);
|
|
126
|
+
IFH.setPreference(MARK_KEY, VALUE);
|
|
127
|
+
}
|
|
128
|
+
} catch(_){}
|
|
129
|
+
});
|
|
130
|
+
}catch(_){}})()`;
|
|
131
|
+
}
|
|
132
|
+
// Bound on how long `buildLiveConsoleFilterScript`'s in-realm poll retries
|
|
133
|
+
// before giving up — mirrors this module's other bounded waits (e.g.
|
|
134
|
+
// internal-devtools-window's CLOSE_WATCHDOG_MS): wait for the real condition,
|
|
135
|
+
// but never forever. `Console.ConsoleView` was observed (real-machine probe,
|
|
136
|
+
// this session) fully constructible well within a few seconds of the
|
|
137
|
+
// front-end's document settling; this leaves generous headroom.
|
|
138
|
+
const LIVE_FILTER_POLL_MAX_ATTEMPTS = 100;
|
|
139
|
+
const LIVE_FILTER_POLL_INTERVAL_MS = 100;
|
|
140
|
+
/**
|
|
141
|
+
* Build the `executeJavaScript` source that drives the Console panel's LIVE
|
|
142
|
+
* filter object directly — the fix for the gap `buildConsoleFilterScript`'s
|
|
143
|
+
* persisted-preference write cannot close (see this module's header
|
|
144
|
+
* comment). Empirically discovered live API (real-machine probe against the
|
|
145
|
+
* actual bundled `devtools://` Console panel, this session — not a guess):
|
|
146
|
+
* `Console.ConsoleView.instance().filter` exposes `textFilterUI` (the
|
|
147
|
+
* visible input box — `.setValue(text)` updates what the user sees) and
|
|
148
|
+
* `updateCurrentFilter()` / `onFilterChanged()` (re-parses the box's value
|
|
149
|
+
* into the filter actually applied to messages, and re-applies it to
|
|
150
|
+
* already-shown AND future messages). Verified end-to-end: after this
|
|
151
|
+
* sequence, a fresh `[service]`-prefixed message logged afterward is
|
|
152
|
+
* immediately hidden, matching the already-shown ones.
|
|
153
|
+
*
|
|
154
|
+
* Same "don't clobber a real user choice" contract as
|
|
155
|
+
* `buildConsoleFilterScript`, judged against the LIVE box value instead of a
|
|
156
|
+
* persisted one: only applies when the box currently reads empty (unset) or
|
|
157
|
+
* already equals this exact default (re-applying is a harmless no-op,
|
|
158
|
+
* correctly handles a re-point re-running this script against a panel that
|
|
159
|
+
* already has it applied).
|
|
160
|
+
*
|
|
161
|
+
* `Console.ConsoleView` has no lifecycle EVENT marking "fully constructed" —
|
|
162
|
+
* only the checkable condition of whether calling `.instance()` and reaching
|
|
163
|
+
* into `.filter.textFilterUI` throws. Retries on a bounded interval (see
|
|
164
|
+
* `LIVE_FILTER_POLL_MAX_ATTEMPTS`/`_INTERVAL_MS`) rather than a single fixed
|
|
165
|
+
* delay, and stops immediately on either success or a detected user
|
|
166
|
+
* customization — it does not keep polling once there is nothing left to do.
|
|
167
|
+
*
|
|
168
|
+
* Every tick gates on the front-end bootstrap probe BEFORE touching
|
|
169
|
+
* `ConsoleView.instance()`: an early construction transitively creates
|
|
170
|
+
* IssuesManager and permanently kills the front-end's own bootstrap
|
|
171
|
+
* (`ensureFirst` conflict in MainImpl.#createAppUI) — see
|
|
172
|
+
* frontend-bootstrap-gate.ts for the full mechanism. The main process
|
|
173
|
+
* additionally holds this whole injection behind `whenFrontendBootstrapped`;
|
|
174
|
+
* the in-realm probe is defense in depth for any other caller of this
|
|
175
|
+
* script builder.
|
|
176
|
+
*/
|
|
177
|
+
export function buildLiveConsoleFilterScript(negativeFilter = DEFAULT_INTERNAL_LOG_FILTER) {
|
|
178
|
+
const filterJson = JSON.stringify(negativeFilter);
|
|
179
|
+
const maxAttempts = JSON.stringify(LIVE_FILTER_POLL_MAX_ATTEMPTS);
|
|
180
|
+
const intervalMs = JSON.stringify(LIVE_FILTER_POLL_INTERVAL_MS);
|
|
181
|
+
return `(function(){
|
|
182
|
+
var VALUE = ${filterJson};
|
|
183
|
+
var attempts = 0;
|
|
184
|
+
function bootstrapReady() {
|
|
185
|
+
try {
|
|
186
|
+
var eui = globalThis.EUI;
|
|
187
|
+
if (!eui || !eui.ShortcutRegistry || !eui.ShortcutRegistry.ShortcutRegistry) return false;
|
|
188
|
+
eui.ShortcutRegistry.ShortcutRegistry.instance();
|
|
189
|
+
return true;
|
|
190
|
+
} catch (_) { return false; }
|
|
191
|
+
}
|
|
192
|
+
function tryApply() {
|
|
193
|
+
attempts++;
|
|
194
|
+
var scheduleRetry = attempts < ${maxAttempts};
|
|
195
|
+
// In-realm bootstrap probe FIRST (defense in depth on top of the
|
|
196
|
+
// main-process whenFrontendBootstrapped gate): touching
|
|
197
|
+
// Console.ConsoleView.instance() before the front-end's own
|
|
198
|
+
// MainImpl bootstrap completes constructs IssuesManager early and
|
|
199
|
+
// permanently kills that bootstrap (ensureFirst conflict) — the probe
|
|
200
|
+
// throws BEFORE constructing anything, so a not-ready tick costs
|
|
201
|
+
// nothing and never touches ConsoleView.
|
|
202
|
+
if (!bootstrapReady()) {
|
|
203
|
+
if (scheduleRetry) { setTimeout(tryApply, ${intervalMs}); return; }
|
|
204
|
+
console.warn('[console-filter] gave up applying the live Console filter after ' + attempts + ' attempts — the front-end bootstrap never completed');
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
var ConsoleNS = globalThis.Console;
|
|
209
|
+
var view = ConsoleNS && ConsoleNS.ConsoleView ? ConsoleNS.ConsoleView.instance() : null;
|
|
210
|
+
var f = view ? view.filter : null;
|
|
211
|
+
if (!f || !f.textFilterUI || typeof f.textFilterUI.setValue !== 'function' || typeof f.textFilterUI.value !== 'function') {
|
|
212
|
+
if (scheduleRetry) { setTimeout(tryApply, ${intervalMs}); return; }
|
|
213
|
+
console.warn('[console-filter] gave up applying the live Console filter after ' + attempts + ' attempts — Console.ConsoleView never became usable');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
var current = f.textFilterUI.value();
|
|
217
|
+
var isUnset = current === undefined || current === null || current === '';
|
|
218
|
+
var isOurDefault = current === VALUE;
|
|
219
|
+
if (isUnset || isOurDefault) {
|
|
220
|
+
f.textFilterUI.setValue(VALUE);
|
|
221
|
+
if (typeof f.updateCurrentFilter === 'function') f.updateCurrentFilter();
|
|
222
|
+
if (typeof f.onFilterChanged === 'function') f.onFilterChanged();
|
|
223
|
+
}
|
|
224
|
+
// Either applied, or a real user customization was detected — both
|
|
225
|
+
// are terminal: nothing left for a later retry to accomplish.
|
|
226
|
+
} catch(_) {
|
|
227
|
+
if (scheduleRetry) setTimeout(tryApply, ${intervalMs});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
tryApply();
|
|
231
|
+
})()`;
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=console-filter.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { WebContents } from 'electron';
|
|
2
|
+
/**
|
|
3
|
+
* The single "front-end bootstrap finished" gate every DevTools front-end
|
|
4
|
+
* injector must pass BEFORE running any `.instance()`-style script in the
|
|
5
|
+
* front-end realm.
|
|
6
|
+
*
|
|
7
|
+
* Why this must exist: the bundled front-end's own `MainImpl.#createAppUI`
|
|
8
|
+
* constructs its singletons in a fixed order, and several of them assert
|
|
9
|
+
* first-creation (`IssuesManager.instance({ensureFirst: true})`). An injected
|
|
10
|
+
* script that constructs a panel singleton early — e.g. a bare
|
|
11
|
+
* `Console.ConsoleView.instance()`, whose field initializers transitively
|
|
12
|
+
* create IssuesManager — makes that assertion throw, and the front-end's
|
|
13
|
+
* bootstrap dies as an unhandled rejection it NEVER recovers from:
|
|
14
|
+
* ActionRegistry/ShortcutRegistry are then never created and the panel
|
|
15
|
+
* renders no tabs at all (the "Missing actionRegistry for shortcutRegistry"
|
|
16
|
+
* permanent-failure mode, confirmed against the real bundled front-end with
|
|
17
|
+
* first-creator stack captures and the matching Chromium 146 source).
|
|
18
|
+
*
|
|
19
|
+
* Iron rule for injectors: BEFORE this gate reports ready, an injected
|
|
20
|
+
* script may only touch registries and InspectorFrontendHost preferences —
|
|
21
|
+
* never any `.instance()` call. (`customizeDevtoolsTabs` is the one
|
|
22
|
+
* documented pre-gate exception: it must run before ViewManager snapshots
|
|
23
|
+
* the view registry, and it only edits the registry.)
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Side-effect-free in-realm readiness probe, safe to feed directly to
|
|
27
|
+
* `wc.executeJavaScript`. `ShortcutRegistry.instance()` (no args) throws
|
|
28
|
+
* BEFORE constructing anything when the registry does not exist yet, so a
|
|
29
|
+
* false answer costs nothing — and a true answer proves `MainImpl` already
|
|
30
|
+
* passed the point where every bootstrap singleton (IssuesManager included)
|
|
31
|
+
* exists, making singleton-touching injections safe. `EUI` is the bundle's
|
|
32
|
+
* real exposure of the ui/legacy namespace (`globalThis.UI` does not exist
|
|
33
|
+
* on this front-end build). An expression, not a statement list: the value
|
|
34
|
+
* `executeJavaScript` resolves is the IIFE's completion value.
|
|
35
|
+
*/
|
|
36
|
+
export declare const FRONTEND_BOOTSTRAP_PROBE_SCRIPT = "(() => {\n try {\n const eui = globalThis.EUI\n if (!eui || !eui.ShortcutRegistry || !eui.ShortcutRegistry.ShortcutRegistry) return false\n eui.ShortcutRegistry.ShortcutRegistry.instance()\n return true\n } catch (_) {\n return false\n }\n})()";
|
|
37
|
+
export interface WhenFrontendBootstrappedOptions {
|
|
38
|
+
/** Wall-clock give-up bound. Past it the promise resolves false with a
|
|
39
|
+
* single warn — callers degrade silently, matching the surrounding
|
|
40
|
+
* modules' convention. */
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
/** Probe cadence while the front-end is still booting. */
|
|
43
|
+
intervalMs?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Poll the probe against `wc` until the front-end bootstrap is provably
|
|
47
|
+
* complete. Resolves true on readiness; false on timeout (one warn) or a
|
|
48
|
+
* destroyed wc — never rejects, and never leaves a live timer behind after
|
|
49
|
+
* settling. A rejected probe call (execution context torn down mid-load,
|
|
50
|
+
* navigation in flight) counts as "not ready yet", not as an error.
|
|
51
|
+
*
|
|
52
|
+
* The timeout is an INDEPENDENT hard deadline racing the poll — not a check
|
|
53
|
+
* inside the poll chain. A probe `executeJavaScript` promise that never
|
|
54
|
+
* settles (frame destroyed mid-call / a wc permanently stuck loading) would
|
|
55
|
+
* stall a chain-embedded check forever; the deadline settles this promise
|
|
56
|
+
* regardless.
|
|
57
|
+
*/
|
|
58
|
+
export declare function whenFrontendBootstrapped(wc: WebContents, opts?: WhenFrontendBootstrappedOptions): Promise<boolean>;
|
|
59
|
+
//# sourceMappingURL=frontend-bootstrap-gate.d.ts.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single "front-end bootstrap finished" gate every DevTools front-end
|
|
3
|
+
* injector must pass BEFORE running any `.instance()`-style script in the
|
|
4
|
+
* front-end realm.
|
|
5
|
+
*
|
|
6
|
+
* Why this must exist: the bundled front-end's own `MainImpl.#createAppUI`
|
|
7
|
+
* constructs its singletons in a fixed order, and several of them assert
|
|
8
|
+
* first-creation (`IssuesManager.instance({ensureFirst: true})`). An injected
|
|
9
|
+
* script that constructs a panel singleton early — e.g. a bare
|
|
10
|
+
* `Console.ConsoleView.instance()`, whose field initializers transitively
|
|
11
|
+
* create IssuesManager — makes that assertion throw, and the front-end's
|
|
12
|
+
* bootstrap dies as an unhandled rejection it NEVER recovers from:
|
|
13
|
+
* ActionRegistry/ShortcutRegistry are then never created and the panel
|
|
14
|
+
* renders no tabs at all (the "Missing actionRegistry for shortcutRegistry"
|
|
15
|
+
* permanent-failure mode, confirmed against the real bundled front-end with
|
|
16
|
+
* first-creator stack captures and the matching Chromium 146 source).
|
|
17
|
+
*
|
|
18
|
+
* Iron rule for injectors: BEFORE this gate reports ready, an injected
|
|
19
|
+
* script may only touch registries and InspectorFrontendHost preferences —
|
|
20
|
+
* never any `.instance()` call. (`customizeDevtoolsTabs` is the one
|
|
21
|
+
* documented pre-gate exception: it must run before ViewManager snapshots
|
|
22
|
+
* the view registry, and it only edits the registry.)
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Side-effect-free in-realm readiness probe, safe to feed directly to
|
|
26
|
+
* `wc.executeJavaScript`. `ShortcutRegistry.instance()` (no args) throws
|
|
27
|
+
* BEFORE constructing anything when the registry does not exist yet, so a
|
|
28
|
+
* false answer costs nothing — and a true answer proves `MainImpl` already
|
|
29
|
+
* passed the point where every bootstrap singleton (IssuesManager included)
|
|
30
|
+
* exists, making singleton-touching injections safe. `EUI` is the bundle's
|
|
31
|
+
* real exposure of the ui/legacy namespace (`globalThis.UI` does not exist
|
|
32
|
+
* on this front-end build). An expression, not a statement list: the value
|
|
33
|
+
* `executeJavaScript` resolves is the IIFE's completion value.
|
|
34
|
+
*/
|
|
35
|
+
export const FRONTEND_BOOTSTRAP_PROBE_SCRIPT = `(() => {
|
|
36
|
+
try {
|
|
37
|
+
const eui = globalThis.EUI
|
|
38
|
+
if (!eui || !eui.ShortcutRegistry || !eui.ShortcutRegistry.ShortcutRegistry) return false
|
|
39
|
+
eui.ShortcutRegistry.ShortcutRegistry.instance()
|
|
40
|
+
return true
|
|
41
|
+
} catch (_) {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
})()`;
|
|
45
|
+
// Matches the e2e suite's own bootstrap-wait window (console-filter-live's
|
|
46
|
+
// 45s probe poll) so a slow-but-alive bootstrap never lands in a band where
|
|
47
|
+
// production has given up while the spec still expects the injections.
|
|
48
|
+
const DEFAULT_TIMEOUT_MS = 45_000;
|
|
49
|
+
const DEFAULT_INTERVAL_MS = 150;
|
|
50
|
+
/**
|
|
51
|
+
* Poll the probe against `wc` until the front-end bootstrap is provably
|
|
52
|
+
* complete. Resolves true on readiness; false on timeout (one warn) or a
|
|
53
|
+
* destroyed wc — never rejects, and never leaves a live timer behind after
|
|
54
|
+
* settling. A rejected probe call (execution context torn down mid-load,
|
|
55
|
+
* navigation in flight) counts as "not ready yet", not as an error.
|
|
56
|
+
*
|
|
57
|
+
* The timeout is an INDEPENDENT hard deadline racing the poll — not a check
|
|
58
|
+
* inside the poll chain. A probe `executeJavaScript` promise that never
|
|
59
|
+
* settles (frame destroyed mid-call / a wc permanently stuck loading) would
|
|
60
|
+
* stall a chain-embedded check forever; the deadline settles this promise
|
|
61
|
+
* regardless.
|
|
62
|
+
*/
|
|
63
|
+
export function whenFrontendBootstrapped(wc, opts) {
|
|
64
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
65
|
+
const intervalMs = opts?.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
let timer = null;
|
|
68
|
+
let settled = false;
|
|
69
|
+
const finish = (ready) => {
|
|
70
|
+
if (settled)
|
|
71
|
+
return;
|
|
72
|
+
settled = true;
|
|
73
|
+
clearTimeout(deadline);
|
|
74
|
+
if (timer) {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
timer = null;
|
|
77
|
+
}
|
|
78
|
+
resolve(ready);
|
|
79
|
+
};
|
|
80
|
+
const deadline = setTimeout(() => {
|
|
81
|
+
// Within one call "ready" was never observed — a dead bootstrap and a
|
|
82
|
+
// merely-slow one are indistinguishable from out here; say so.
|
|
83
|
+
console.warn(`[frontend-bootstrap-gate] front-end bootstrap probe never reported ready within ${timeoutMs}ms — bootstrap-gated injections stay skipped for this host`);
|
|
84
|
+
finish(false);
|
|
85
|
+
}, timeoutMs);
|
|
86
|
+
deadline.unref?.();
|
|
87
|
+
const attempt = () => {
|
|
88
|
+
if (wc.isDestroyed()) {
|
|
89
|
+
finish(false);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
Promise.resolve()
|
|
93
|
+
.then(() => wc.executeJavaScript(FRONTEND_BOOTSTRAP_PROBE_SCRIPT))
|
|
94
|
+
.then((ready) => ready === true, () => false)
|
|
95
|
+
.then((ready) => {
|
|
96
|
+
if (settled)
|
|
97
|
+
return;
|
|
98
|
+
// Destroyed-check BEFORE honoring a ready answer: a probe that was
|
|
99
|
+
// in flight when the wc got destroyed can still resolve true, and
|
|
100
|
+
// reporting "bootstrapped" for a dead target contradicts this
|
|
101
|
+
// function's contract (destroyed ⇒ false).
|
|
102
|
+
if (wc.isDestroyed()) {
|
|
103
|
+
finish(false);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (ready) {
|
|
107
|
+
finish(true);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
timer = setTimeout(attempt, intervalMs);
|
|
111
|
+
timer.unref?.();
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
attempt();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=frontend-bootstrap-gate.js.map
|