@dimina-kit/devtools 0.3.2-dev.20260611135124 → 0.4.0-dev.20260612152115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/dist/main/api.d.ts +1 -1
- package/dist/main/app/app.js +22 -12
- package/dist/main/app/launch.d.ts +4 -4
- package/dist/main/app/launch.js +5 -17
- package/dist/main/index.bundle.js +372 -225
- package/dist/main/ipc/bridge-router.js +35 -8
- package/dist/main/ipc/views.js +10 -1
- package/dist/main/menu/index.d.ts +2 -2
- package/dist/main/menu/index.js +4 -2
- package/dist/main/runtime/miniapp-runtime.d.ts +79 -11
- package/dist/main/services/notifications/renderer-notifier.d.ts +11 -0
- package/dist/main/services/notifications/renderer-notifier.js +3 -0
- package/dist/main/services/views/host-toolbar-port-channel.d.ts +10 -0
- package/dist/main/services/views/host-toolbar-port-channel.js +89 -10
- package/dist/main/services/views/view-manager.d.ts +28 -4
- package/dist/main/services/views/view-manager.js +42 -8
- package/dist/main/services/workbench-context.d.ts +7 -0
- package/dist/main/services/workbench-context.js +5 -0
- package/dist/main/services/workspace/workspace-service.d.ts +3 -7
- package/dist/main/services/workspace/workspace-service.js +66 -0
- package/dist/main/windows/settings-window/index.d.ts +33 -0
- package/dist/main/windows/settings-window/index.js +59 -0
- package/dist/preload/index.d.ts +2 -2
- package/dist/preload/index.js +2 -2
- package/dist/preload/runtime/host-toolbar-port.d.ts +10 -5
- package/dist/preload/runtime/host-toolbar-port.js +24 -0
- package/dist/preload/windows/host-toolbar-runtime.cjs +20 -1
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs +9 -7
- package/dist/preload/windows/main.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs.map +1 -1
- package/dist/renderer/assets/index-Bi_6SS-L.js +50 -0
- package/dist/renderer/assets/{input-6fpCXV-n.js → input-DgqX2UvN.js} +2 -2
- package/dist/renderer/assets/{ipc-transport-D22e4dv7.js → ipc-transport-CsFhDJ7q.js} +2 -2
- package/dist/renderer/assets/ipc-transport-SnOAk0Jq.css +1 -0
- package/dist/renderer/assets/{popover-CdGdKkkc.js → popover-D_2o_52M.js} +2 -2
- package/dist/renderer/assets/{select-X0sbjwdP.js → select-BJYsdghn.js} +2 -2
- package/dist/renderer/assets/{settings-CS4jYaCw.js → settings-CivkfizP.js} +2 -2
- package/dist/renderer/assets/{settings-api-CCWTAao_.js → settings-api-7mXkBy5-.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-Bpzaj3bm.js → workbenchSettings-BwpwxuzM.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +5 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/shared/ipc-channels.d.ts +11 -0
- package/dist/shared/ipc-channels.js +14 -0
- package/dist/shared/types.d.ts +48 -11
- package/dist/simulator/assets/bridge-channels-BUQ5AbvJ.js +2 -0
- package/dist/simulator/assets/device-shell-BEnc2k-W.js +2 -0
- package/dist/simulator/assets/{simulator-DHylZf9Z.js → simulator-cV1PERi6.js} +3 -3
- package/dist/simulator/assets/simulator-mini-app-CYtW6bMd.js +2 -0
- package/dist/simulator/simulator.html +1 -1
- package/package.json +4 -4
- package/dist/renderer/assets/index-DLzjz1wv.js +0 -50
- package/dist/renderer/assets/ipc-transport-Bs8Sf1B2.css +0 -1
- package/dist/simulator/assets/device-shell-fH2cI-3q.js +0 -2
- package/dist/simulator/assets/simulator-mini-app-BDNu5n26.js +0 -2
|
@@ -41,6 +41,13 @@ export interface WorkbenchContext {
|
|
|
41
41
|
windows: WindowService;
|
|
42
42
|
/** Unified main → renderer event dispatcher */
|
|
43
43
|
notify: RendererNotifier;
|
|
44
|
+
/**
|
|
45
|
+
* Open (or re-focus) the standalone workbench-settings window. First-class
|
|
46
|
+
* member so contract holders (`MiniappRuntime` / `MenuContext`) can open
|
|
47
|
+
* settings without reaching into `windows`/`notify` plumbing. Wired by
|
|
48
|
+
* `createWorkbenchContext` to the real `openSettingsWindow` path.
|
|
49
|
+
*/
|
|
50
|
+
openSettings: () => Promise<void>;
|
|
44
51
|
/** Single source of truth for project + session + per-project settings */
|
|
45
52
|
workspace: WorkspaceService;
|
|
46
53
|
/**
|
|
@@ -4,6 +4,7 @@ import { defaultAdapter } from './default-adapter.js';
|
|
|
4
4
|
import { createRendererNotifier, } from './notifications/renderer-notifier.js';
|
|
5
5
|
import { createViewManager } from './views/view-manager.js';
|
|
6
6
|
import { createWindowService } from './window-service.js';
|
|
7
|
+
import { openSettingsWindow } from '../windows/settings-window/index.js';
|
|
7
8
|
import { createWorkspaceService, } from './workspace/workspace-service.js';
|
|
8
9
|
import { createLocalProjectsProvider } from './projects/local-provider.js';
|
|
9
10
|
import { createSimulatorApiRegistry, } from './simulator/custom-apis.js';
|
|
@@ -29,6 +30,10 @@ export function createWorkbenchContext(opts) {
|
|
|
29
30
|
ctx.windows = createWindowService(opts.mainWindow);
|
|
30
31
|
ctx.views = createViewManager(ctx);
|
|
31
32
|
ctx.notify = createRendererNotifier(ctx);
|
|
33
|
+
// Lazy closure (not a bound snapshot): reads ctx.windows/notify/rendererDir
|
|
34
|
+
// at call time through the live context, which structurally satisfies the
|
|
35
|
+
// helper's narrow OpenSettingsWindowDeps.
|
|
36
|
+
ctx.openSettings = () => openSettingsWindow(ctx);
|
|
32
37
|
ctx.projectsProvider = opts.projectsProvider ?? createLocalProjectsProvider();
|
|
33
38
|
ctx.projectTemplates = resolveTemplates(BUILTIN_TEMPLATES, opts.projectTemplates ?? [], opts.builtinTemplates ?? 'all');
|
|
34
39
|
ctx.customCreateProjectDialog = opts.customCreateProjectDialog;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompileConfig } from '../../../shared/types.js';
|
|
1
|
+
import type { AppInfo, CompileConfig, ProjectSession } from '../../../shared/types.js';
|
|
2
2
|
import type { WorkbenchContext } from '../workbench-context.js';
|
|
3
3
|
import type { Project, ProjectPages, ProjectSettings } from '../projects/project-repository.js';
|
|
4
4
|
/**
|
|
@@ -9,7 +9,7 @@ import type { Project, ProjectPages, ProjectSettings } from '../projects/project
|
|
|
9
9
|
export interface OpenProjectResult {
|
|
10
10
|
success: boolean;
|
|
11
11
|
port?: number;
|
|
12
|
-
appInfo?:
|
|
12
|
+
appInfo?: AppInfo;
|
|
13
13
|
error?: string;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -32,11 +32,7 @@ export interface WorkspaceService {
|
|
|
32
32
|
validateProjectDir(dirPath: string): Promise<string | null>;
|
|
33
33
|
openProject(projectPath: string): Promise<OpenProjectResult>;
|
|
34
34
|
closeProject(): Promise<void>;
|
|
35
|
-
getSession():
|
|
36
|
-
close: () => Promise<void>;
|
|
37
|
-
port: number;
|
|
38
|
-
appInfo: unknown;
|
|
39
|
-
} | null;
|
|
35
|
+
getSession(): ProjectSession | null;
|
|
40
36
|
getProjectPath(): string;
|
|
41
37
|
/**
|
|
42
38
|
* The project path most recently torn down by `closeProject`, or '' if none
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import * as repo from '../projects/project-repository.js';
|
|
2
3
|
import { DEFAULT_COMPILE_CONFIG } from '../projects/types.js';
|
|
3
4
|
import { clearSimulatorServicewechatReferer, setSimulatorServicewechatReferer, } from '../simulator/referer.js';
|
|
4
5
|
import { loadWorkbenchSettings } from '../settings/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Runtime guard for the adapter-return boundary: `session.appInfo` must be an
|
|
8
|
+
* object carrying a string `appId` (the renderer derives its IPC scoping from
|
|
9
|
+
* it; a session without one cannot be driven). Loose: extra fields pass
|
|
10
|
+
* through untouched — only the contract-critical `appId` is enforced.
|
|
11
|
+
*/
|
|
12
|
+
const SessionAppInfoSchema = z.looseObject({ appId: z.string() });
|
|
5
13
|
/** Build a workspace service bound to the given workbench context. */
|
|
6
14
|
export function createWorkspaceService(ctx) {
|
|
7
15
|
let currentSession = null;
|
|
@@ -10,6 +18,16 @@ export function createWorkspaceService(ctx) {
|
|
|
10
18
|
// accept an in-flight write that targets the just-closed project. Reset at
|
|
11
19
|
// the start of every `openProject` so it never accumulates a stale root.
|
|
12
20
|
let lastClosedProjectPath = '';
|
|
21
|
+
// Session generation for the onLog closure handed to the adapter: a closed
|
|
22
|
+
// (or switched-away-from) session's compile worker dies asynchronously, so
|
|
23
|
+
// buffered log lines can still arrive through the OLD closure after
|
|
24
|
+
// closeProject/openProject. Each openProject claims a new generation and
|
|
25
|
+
// closeProject invalidates the current one; a stale closure sees the
|
|
26
|
+
// mismatch and drops the line instead of polluting the next project's
|
|
27
|
+
// compile panel. (Deliberately NOT a `currentSession !== null` check: the
|
|
28
|
+
// first compile's log lines arrive while the adapter promise is still
|
|
29
|
+
// pending, before currentSession is assigned.)
|
|
30
|
+
let logGeneration = 0;
|
|
13
31
|
function sendStatus(status, message, hotReload) {
|
|
14
32
|
ctx.notify.projectStatus(hotReload ? { status, message, hotReload: true } : { status, message });
|
|
15
33
|
}
|
|
@@ -63,6 +81,14 @@ export function createWorkspaceService(ctx) {
|
|
|
63
81
|
: null,
|
|
64
82
|
async openProject(projectPath) {
|
|
65
83
|
clearSimulatorServicewechatReferer();
|
|
84
|
+
// Invalidate the outgoing session's onLog BEFORE teardown starts (same
|
|
85
|
+
// order as closeProject below): the dying compile worker flushes
|
|
86
|
+
// buffered lines DURING disposeSession(), and with the old generation
|
|
87
|
+
// still current they would pass the staleness guard and pollute the
|
|
88
|
+
// incoming project's compile-log timeline. The new session claims its
|
|
89
|
+
// own fresh generation further down (after dispose), so its onLog
|
|
90
|
+
// forwards normally.
|
|
91
|
+
logGeneration++;
|
|
66
92
|
await disposeSession();
|
|
67
93
|
currentProjectPath = '';
|
|
68
94
|
// A fresh open starts a clean sandbox window — drop any previously
|
|
@@ -84,6 +110,9 @@ export function createWorkspaceService(ctx) {
|
|
|
84
110
|
}
|
|
85
111
|
sendStatus('compiling', '正在编译...');
|
|
86
112
|
const { compile } = loadWorkbenchSettings();
|
|
113
|
+
// This open owns the log channel until the next open/close bumps the
|
|
114
|
+
// generation — the onLog closure below checks it per line.
|
|
115
|
+
const sessionGeneration = ++logGeneration;
|
|
87
116
|
let session;
|
|
88
117
|
try {
|
|
89
118
|
session = await ctx.adapter.openProject({
|
|
@@ -92,6 +121,21 @@ export function createWorkspaceService(ctx) {
|
|
|
92
121
|
watch: compile.watch,
|
|
93
122
|
onRebuild: () => sendStatus('ready', '编译完成,已热更新', true),
|
|
94
123
|
onBuildError: (err) => sendStatus('error', String(err)),
|
|
124
|
+
// Per-line dmcc log (already filtered in devkit). Stamp the
|
|
125
|
+
// wall-clock capture time here and push verbatim on the dedicated
|
|
126
|
+
// compile-log channel — never through projectStatus, whose
|
|
127
|
+
// one-event-per-payload contract feeds compileEvents. Stale lines
|
|
128
|
+
// (a closed/replaced session's worker flushing its buffers) are
|
|
129
|
+
// dropped via the generation check.
|
|
130
|
+
onLog: (entry) => {
|
|
131
|
+
if (sessionGeneration !== logGeneration)
|
|
132
|
+
return;
|
|
133
|
+
ctx.notify.compileLog({
|
|
134
|
+
stream: entry.stream,
|
|
135
|
+
text: entry.text,
|
|
136
|
+
at: Date.now(),
|
|
137
|
+
});
|
|
138
|
+
},
|
|
95
139
|
});
|
|
96
140
|
}
|
|
97
141
|
catch (err) {
|
|
@@ -99,6 +143,25 @@ export function createWorkspaceService(ctx) {
|
|
|
99
143
|
sendStatus('error', String(err));
|
|
100
144
|
return { success: false, error: String(err) };
|
|
101
145
|
}
|
|
146
|
+
// Adapter-return boundary: enforce the AppInfo producer contract the
|
|
147
|
+
// moment the adapter resolves, BEFORE the session is recorded. A
|
|
148
|
+
// session without a string appId cannot be driven by the renderer, so
|
|
149
|
+
// it must never become the active session. The adapter already spun up
|
|
150
|
+
// live resources (compile watcher, dev-server port) — close them
|
|
151
|
+
// best-effort before reporting; the validation report is the law and a
|
|
152
|
+
// failing close() must not mask it (or escape as a throw).
|
|
153
|
+
if (!SessionAppInfoSchema.safeParse(session.appInfo).success) {
|
|
154
|
+
try {
|
|
155
|
+
await session.close();
|
|
156
|
+
}
|
|
157
|
+
catch (closeErr) {
|
|
158
|
+
console.warn('[workspace] closing appId-less adapter session failed (non-fatal):', closeErr);
|
|
159
|
+
}
|
|
160
|
+
const error = 'adapter returned session.appInfo without a string appId — ' +
|
|
161
|
+
'the CompilationAdapter must supply appInfo.appId';
|
|
162
|
+
sendStatus('error', error);
|
|
163
|
+
return { success: false, error };
|
|
164
|
+
}
|
|
102
165
|
currentSession = session;
|
|
103
166
|
currentProjectPath = projectPath;
|
|
104
167
|
bestEffort('updateLastOpened', () => {
|
|
@@ -114,6 +177,9 @@ export function createWorkspaceService(ctx) {
|
|
|
114
177
|
};
|
|
115
178
|
},
|
|
116
179
|
async closeProject() {
|
|
180
|
+
// Invalidate the active session's onLog BEFORE teardown starts — lines
|
|
181
|
+
// flushed by the dying compile worker must not reach the panel.
|
|
182
|
+
logGeneration++;
|
|
117
183
|
clearSimulatorServicewechatReferer();
|
|
118
184
|
await disposeSession();
|
|
119
185
|
// Record the root being torn down BEFORE clearing it, so a teardown/
|
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
import type { BrowserWindow } from 'electron';
|
|
2
|
+
import { type WorkbenchSettings } from '../../services/settings/index.js';
|
|
1
3
|
export { createSettingsWindow } from './create.js';
|
|
2
4
|
export { wireSettingsWindowEvents } from './events.js';
|
|
5
|
+
/**
|
|
6
|
+
* Exactly what `openSettingsWindow` needs — its OWN narrow deps interface,
|
|
7
|
+
* not a `Pick<WorkbenchContext, …>`: picking from the full context couples
|
|
8
|
+
* this helper to the whole context type (and made the contract's old
|
|
9
|
+
* `windows: object` pass-through promise unfulfillable). A full
|
|
10
|
+
* `WorkbenchContext` satisfies this structurally, so assembly points pass
|
|
11
|
+
* the context straight through.
|
|
12
|
+
*/
|
|
13
|
+
export interface OpenSettingsWindowDeps {
|
|
14
|
+
/** Absolute path to the renderer dist directory (settings entry HTML). */
|
|
15
|
+
rendererDir: string;
|
|
16
|
+
windows: {
|
|
17
|
+
readonly mainWindow: BrowserWindow;
|
|
18
|
+
readonly settingsWindow: BrowserWindow | null;
|
|
19
|
+
setSettingsWindow(win: BrowserWindow | null): void;
|
|
20
|
+
};
|
|
21
|
+
notify: {
|
|
22
|
+
workbenchSettingsInit(window: BrowserWindow, payload: {
|
|
23
|
+
settings: WorkbenchSettings;
|
|
24
|
+
}): void;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Open (or re-focus) the standalone workbench-settings window. Reuses the
|
|
29
|
+
* live window when one is already registered; otherwise creates it, registers
|
|
30
|
+
* it on the window service, and wires its `closed` cleanup. Concurrent calls
|
|
31
|
+
* share a single in-flight creation (exactly one window; every caller still
|
|
32
|
+
* gets the show/focus/snapshot semantics). Always shows + focuses, then
|
|
33
|
+
* pushes the current settings snapshot into it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function openSettingsWindow(deps: OpenSettingsWindowDeps): Promise<void>;
|
|
3
36
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,3 +1,62 @@
|
|
|
1
|
+
import { createSettingsWindow } from './create.js';
|
|
2
|
+
import { wireSettingsWindowEvents } from './events.js';
|
|
3
|
+
import { loadWorkbenchSettings, } from '../../services/settings/index.js';
|
|
1
4
|
export { createSettingsWindow } from './create.js';
|
|
2
5
|
export { wireSettingsWindowEvents } from './events.js';
|
|
6
|
+
/**
|
|
7
|
+
* In-flight creation guard, keyed by the windows registry (the identity that
|
|
8
|
+
* owns the `settingsWindow` slot). Overlapping `openSettingsWindow` calls
|
|
9
|
+
* before the first creation lands must share ONE creation — without this,
|
|
10
|
+
* both observe `settingsWindow === null` across the async construction
|
|
11
|
+
* boundary, build two BrowserWindows, and the loser is orphaned (alive,
|
|
12
|
+
* unreachable, never reused).
|
|
13
|
+
*/
|
|
14
|
+
const inFlightCreations = new WeakMap();
|
|
15
|
+
async function getOrCreateSettingsWindow(deps) {
|
|
16
|
+
const existing = deps.windows.settingsWindow;
|
|
17
|
+
if (existing && !existing.isDestroyed())
|
|
18
|
+
return existing;
|
|
19
|
+
const inFlight = inFlightCreations.get(deps.windows);
|
|
20
|
+
if (inFlight)
|
|
21
|
+
return inFlight;
|
|
22
|
+
const creation = (async () => {
|
|
23
|
+
const win = await createSettingsWindow(deps.windows.mainWindow, deps.rendererDir);
|
|
24
|
+
deps.windows.setSettingsWindow(win);
|
|
25
|
+
wireSettingsWindowEvents(win, () => {
|
|
26
|
+
// Electron delivers 'closed' asynchronously: a just-destroyed window's
|
|
27
|
+
// late callback may arrive AFTER a successor was registered. Only the
|
|
28
|
+
// CURRENT registration's own close may clear the slot — a stale
|
|
29
|
+
// window's close must not drop a live successor.
|
|
30
|
+
if (deps.windows.settingsWindow === win) {
|
|
31
|
+
deps.windows.setSettingsWindow(null);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return win;
|
|
35
|
+
})();
|
|
36
|
+
inFlightCreations.set(deps.windows, creation);
|
|
37
|
+
try {
|
|
38
|
+
return await creation;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
if (inFlightCreations.get(deps.windows) === creation) {
|
|
42
|
+
inFlightCreations.delete(deps.windows);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Open (or re-focus) the standalone workbench-settings window. Reuses the
|
|
48
|
+
* live window when one is already registered; otherwise creates it, registers
|
|
49
|
+
* it on the window service, and wires its `closed` cleanup. Concurrent calls
|
|
50
|
+
* share a single in-flight creation (exactly one window; every caller still
|
|
51
|
+
* gets the show/focus/snapshot semantics). Always shows + focuses, then
|
|
52
|
+
* pushes the current settings snapshot into it.
|
|
53
|
+
*/
|
|
54
|
+
export async function openSettingsWindow(deps) {
|
|
55
|
+
const win = await getOrCreateSettingsWindow(deps);
|
|
56
|
+
win.show();
|
|
57
|
+
win.focus();
|
|
58
|
+
deps.notify.workbenchSettingsInit(win, {
|
|
59
|
+
settings: loadWorkbenchSettings(),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
3
62
|
//# sourceMappingURL=index.js.map
|
package/dist/preload/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { installConsoleInstrumentation } from './instrumentation/console.js';
|
|
|
13
13
|
export { createAppDataSource } from './instrumentation/app-data.js';
|
|
14
14
|
export type { AppDataSnapshot } from './instrumentation/app-data.js';
|
|
15
15
|
/**
|
|
16
|
-
* @deprecated Will be removed in
|
|
16
|
+
* @deprecated Will be removed in 0.5.0. Under the native-host (sole)
|
|
17
17
|
* runtime the simulator top frame is a top-level WebContentsView — the page DOM
|
|
18
18
|
* lives in child render-host `<webview>` guests, so this top-frame DOM observer
|
|
19
19
|
* only ever publishes `null`. Panel WXML flows over the main-process
|
|
@@ -21,7 +21,7 @@ export type { AppDataSnapshot } from './instrumentation/app-data.js';
|
|
|
21
21
|
*/
|
|
22
22
|
export { createWxmlSource } from './instrumentation/wxml.js';
|
|
23
23
|
/**
|
|
24
|
-
* @deprecated Will be removed in
|
|
24
|
+
* @deprecated Will be removed in 0.5.0. The host's
|
|
25
25
|
* `miniapp-snapshot:push/pull` IPC has no receiving end under the native-host
|
|
26
26
|
* (sole) runtime: the simulator is a top-level WebContentsView without an
|
|
27
27
|
* embedder (its `sendToHost` fires into the void) and the renderer-side puller
|
package/dist/preload/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
export { installConsoleInstrumentation } from './instrumentation/console.js';
|
|
13
13
|
export { createAppDataSource } from './instrumentation/app-data.js';
|
|
14
14
|
/**
|
|
15
|
-
* @deprecated Will be removed in
|
|
15
|
+
* @deprecated Will be removed in 0.5.0. Under the native-host (sole)
|
|
16
16
|
* runtime the simulator top frame is a top-level WebContentsView — the page DOM
|
|
17
17
|
* lives in child render-host `<webview>` guests, so this top-frame DOM observer
|
|
18
18
|
* only ever publishes `null`. Panel WXML flows over the main-process
|
|
@@ -20,7 +20,7 @@ export { createAppDataSource } from './instrumentation/app-data.js';
|
|
|
20
20
|
*/
|
|
21
21
|
export { createWxmlSource } from './instrumentation/wxml.js';
|
|
22
22
|
/**
|
|
23
|
-
* @deprecated Will be removed in
|
|
23
|
+
* @deprecated Will be removed in 0.5.0. The host's
|
|
24
24
|
* `miniapp-snapshot:push/pull` IPC has no receiving end under the native-host
|
|
25
25
|
* (sole) runtime: the simulator is a top-level WebContentsView without an
|
|
26
26
|
* embedder (its `sendToHost` fires into the void) and the renderer-side puller
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Preload side of the host-toolbar gated narrow channel.
|
|
3
3
|
*
|
|
4
|
+
* ── PUBLIC SURFACE EVOLUTION RULE ───────────────────────────────────────────
|
|
5
|
+
* `window.diminaHostToolbar` is a published page-facing API, typed by the
|
|
6
|
+
* exported `DiminaHostToolbarPageBridge` (src/main/runtime/miniapp-runtime.ts)
|
|
7
|
+
* — arbitrary host toolbar pages compile against it. Members may only be
|
|
8
|
+
* ADDED, never changed: any semantic change to an existing member (signature,
|
|
9
|
+
* return shape, queueing/throw behavior) ships under a NEW name instead.
|
|
10
|
+
* Exception: security fixes / compliance corrections may change existing
|
|
11
|
+
* member semantics, and MUST be called out in the release's version notes.
|
|
12
|
+
* Keep the exported bridge type in lockstep with what is exposed here.
|
|
13
|
+
*
|
|
4
14
|
* Receives the per-load MessagePort main transfers on `did-finish-load`
|
|
5
15
|
* (`ViewChannel.HostToolbarPort`, `event.ports[0]`) and bridges it to the page
|
|
6
16
|
* as `window.diminaHostToolbar` — EXACTLY `{ send, onMessage }`, functions
|
|
@@ -35,10 +45,5 @@
|
|
|
35
45
|
* envelope (queued first-comers survive), one console.warn per load.
|
|
36
46
|
*/
|
|
37
47
|
export declare const HOST_TOOLBAR_PENDING_LIMIT = 128;
|
|
38
|
-
/**
|
|
39
|
-
* Subscribe the handshake channel and expose the page bridge. Call ONLY from
|
|
40
|
-
* a passing toolbar-runtime guard (`activateHostToolbarRuntime`) — a failing
|
|
41
|
-
* guard must leave zero footprint (no bridge key, no IPC listener).
|
|
42
|
-
*/
|
|
43
48
|
export declare function installHostToolbarPortBridge(): void;
|
|
44
49
|
//# sourceMappingURL=host-toolbar-port.d.ts.map
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Preload side of the host-toolbar gated narrow channel.
|
|
3
3
|
*
|
|
4
|
+
* ── PUBLIC SURFACE EVOLUTION RULE ───────────────────────────────────────────
|
|
5
|
+
* `window.diminaHostToolbar` is a published page-facing API, typed by the
|
|
6
|
+
* exported `DiminaHostToolbarPageBridge` (src/main/runtime/miniapp-runtime.ts)
|
|
7
|
+
* — arbitrary host toolbar pages compile against it. Members may only be
|
|
8
|
+
* ADDED, never changed: any semantic change to an existing member (signature,
|
|
9
|
+
* return shape, queueing/throw behavior) ships under a NEW name instead.
|
|
10
|
+
* Exception: security fixes / compliance corrections may change existing
|
|
11
|
+
* member semantics, and MUST be called out in the release's version notes.
|
|
12
|
+
* Keep the exported bridge type in lockstep with what is exposed here.
|
|
13
|
+
*
|
|
4
14
|
* Receives the per-load MessagePort main transfers on `did-finish-load`
|
|
5
15
|
* (`ViewChannel.HostToolbarPort`, `event.ports[0]`) and bridges it to the page
|
|
6
16
|
* as `window.diminaHostToolbar` — EXACTLY `{ send, onMessage }`, functions
|
|
@@ -43,6 +53,18 @@ export const HOST_TOOLBAR_PENDING_LIMIT = 128;
|
|
|
43
53
|
* a passing toolbar-runtime guard (`activateHostToolbarRuntime`) — a failing
|
|
44
54
|
* guard must leave zero footprint (no bridge key, no IPC listener).
|
|
45
55
|
*/
|
|
56
|
+
/**
|
|
57
|
+
* Entry-waist channel validation, parity with the main side's
|
|
58
|
+
* `hostToolbar.onMessage` guard (same TypeError, message names `channel`).
|
|
59
|
+
* Runs BEFORE any state is touched (no queue slot, no registry entry), in
|
|
60
|
+
* both port states — a page author's typo throws at the call site instead of
|
|
61
|
+
* vanishing into main's silent inbound drop.
|
|
62
|
+
*/
|
|
63
|
+
function assertValidChannel(method, channel) {
|
|
64
|
+
if (typeof channel !== 'string' || channel === '') {
|
|
65
|
+
throw new TypeError(`diminaHostToolbar.${method}: channel must be a non-empty string`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
46
68
|
export function installHostToolbarPortBridge() {
|
|
47
69
|
let activePort = null;
|
|
48
70
|
const pending = [];
|
|
@@ -96,6 +118,7 @@ export function installHostToolbarPortBridge() {
|
|
|
96
118
|
// isolated world.
|
|
97
119
|
contextBridge.exposeInMainWorld(BRIDGE_KEY, {
|
|
98
120
|
send(channel, payload) {
|
|
121
|
+
assertValidChannel('send', channel);
|
|
99
122
|
const envelope = { channel, payload };
|
|
100
123
|
if (activePort) {
|
|
101
124
|
activePort.postMessage(envelope);
|
|
@@ -114,6 +137,7 @@ export function installHostToolbarPortBridge() {
|
|
|
114
137
|
pending.push(envelope);
|
|
115
138
|
},
|
|
116
139
|
onMessage(channel, handler) {
|
|
140
|
+
assertValidChannel('onMessage', channel);
|
|
117
141
|
const entry = { channel, handler };
|
|
118
142
|
handlers.push(entry);
|
|
119
143
|
return () => {
|
|
@@ -134,7 +134,17 @@ var ViewChannel = {
|
|
|
134
134
|
* main → main-window renderer: push the reserved host-toolbar height so the
|
|
135
135
|
* renderer placeholder div resizes (closing the dynamic-height loop).
|
|
136
136
|
*/
|
|
137
|
-
HostToolbarHeightChanged: "view:host-toolbar:height-changed"
|
|
137
|
+
HostToolbarHeightChanged: "view:host-toolbar:height-changed",
|
|
138
|
+
/**
|
|
139
|
+
* main ← main-window renderer (invoke): pull the last NOTIFIED toolbar
|
|
140
|
+
* height retained in main. Mount-time replay companion to
|
|
141
|
+
* `HostToolbarHeightChanged`: the push listener mounts with the project
|
|
142
|
+
* view and the toolbar's size-advertiser deduplicates (never re-reports),
|
|
143
|
+
* so a height pushed while no project view was mounted would otherwise be
|
|
144
|
+
* lost forever (cold start on the project list races it; close-project →
|
|
145
|
+
* reopen hits it deterministically). No payload; resolves a number.
|
|
146
|
+
*/
|
|
147
|
+
HostToolbarGetHeight: "view:host-toolbar:get-height"
|
|
138
148
|
};
|
|
139
149
|
|
|
140
150
|
// src/preload/runtime/host-toolbar-advertiser.ts
|
|
@@ -173,6 +183,13 @@ function installHostToolbarAdvertiserWhenReady() {
|
|
|
173
183
|
var import_electron2 = require("electron");
|
|
174
184
|
var BRIDGE_KEY = "diminaHostToolbar";
|
|
175
185
|
var HOST_TOOLBAR_PENDING_LIMIT = 128;
|
|
186
|
+
function assertValidChannel(method, channel) {
|
|
187
|
+
if (typeof channel !== "string" || channel === "") {
|
|
188
|
+
throw new TypeError(
|
|
189
|
+
`diminaHostToolbar.${method}: channel must be a non-empty string`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
176
193
|
function installHostToolbarPortBridge() {
|
|
177
194
|
let activePort = null;
|
|
178
195
|
const pending = [];
|
|
@@ -209,6 +226,7 @@ function installHostToolbarPortBridge() {
|
|
|
209
226
|
});
|
|
210
227
|
import_electron2.contextBridge.exposeInMainWorld(BRIDGE_KEY, {
|
|
211
228
|
send(channel, payload) {
|
|
229
|
+
assertValidChannel("send", channel);
|
|
212
230
|
const envelope = { channel, payload };
|
|
213
231
|
if (activePort) {
|
|
214
232
|
activePort.postMessage(envelope);
|
|
@@ -226,6 +244,7 @@ function installHostToolbarPortBridge() {
|
|
|
226
244
|
pending.push(envelope);
|
|
227
245
|
},
|
|
228
246
|
onMessage(channel, handler) {
|
|
247
|
+
assertValidChannel("onMessage", channel);
|
|
229
248
|
const entry = { channel, handler };
|
|
230
249
|
handlers.push(entry);
|
|
231
250
|
return () => {
|