@dimina-kit/devtools 0.3.2-dev.20260611060732 → 0.3.2-dev.20260611063505
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 +19 -6
- package/dist/main/api.d.ts +1 -1
- package/dist/main/app/app.js +3 -0
- package/dist/main/index.bundle.js +27 -6
- package/dist/main/services/toolbar/toolbar-store.d.ts +3 -3
- package/dist/main/services/toolbar/toolbar-store.js +18 -1
- package/dist/main/services/workbench-context.d.ts +6 -1
- package/dist/main/services/workspace/workspace-service.js +13 -7
- package/dist/renderer/assets/index-CZQOpCvg.js +50 -0
- package/dist/renderer/assets/{input-QGx6FFX1.js → input-CFHmbOgz.js} +2 -2
- package/dist/renderer/assets/{ipc-transport-DvZvwK-Z.js → ipc-transport-BkKKww3u.js} +1 -1
- package/dist/renderer/assets/ipc-transport-Bv_BVu4T.css +1 -0
- package/dist/renderer/assets/{popover-BOH1If1J.js → popover-h1M7n3tt.js} +2 -2
- package/dist/renderer/assets/{select-C7JQ8G5N.js → select-kj0n1oYf.js} +2 -2
- package/dist/renderer/assets/{settings-DpAbTJyF.js → settings-Cl4IcWnG.js} +2 -2
- package/dist/renderer/assets/{settings-api-RD2IZF53.js → settings-api-CCwo2eOi.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-CNJX4Qna.js → workbenchSettings-BzlpQnve.js} +2 -2
- package/dist/renderer/entries/main/index.html +5 -5
- 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/types.d.ts +37 -0
- package/package.json +6 -6
- package/dist/renderer/assets/index-CcJKzatF.js +0 -50
- package/dist/renderer/assets/ipc-transport-BT4QYQqu.css +0 -1
package/README.md
CHANGED
|
@@ -55,10 +55,14 @@ launch({
|
|
|
55
55
|
instance.registerSimulatorApi('login', (params) => myLogin(params))
|
|
56
56
|
|
|
57
57
|
// 工具栏:整表替换,随 host 状态(如登录态)重算时再 set 一次
|
|
58
|
-
const refreshToolbar = () =>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
const refreshToolbar = () => {
|
|
59
|
+
const currentUser = getCurrentUser()
|
|
60
|
+
instance.toolbar.set([
|
|
61
|
+
{ id: 'account', label: '当前用户', kind: 'avatar', placement: 'leading', displayInitial: currentUser?.name, avatarUrl: currentUser?.avatar, handler: () => showAccount() },
|
|
62
|
+
{ id: 'preview', label: '预览', placement: 'primary', handler: () => preview() },
|
|
63
|
+
{ id: 'deploy', label: '发布', placement: 'trailing', handler: () => deploy() },
|
|
64
|
+
])
|
|
65
|
+
}
|
|
62
66
|
refreshToolbar()
|
|
63
67
|
|
|
64
68
|
// 自定义 IPC:经 gated 的 IpcRegistry,不再裸 ipcMain.handle
|
|
@@ -68,6 +72,12 @@ launch({
|
|
|
68
72
|
// const win = createDialogWindow(/* ... */)
|
|
69
73
|
// instance.registerTrustedWindow(win)
|
|
70
74
|
},
|
|
75
|
+
onBeforeOpenProject: async ({ projectPath, instance }) => {
|
|
76
|
+
const ok = await canOpenProject(projectPath)
|
|
77
|
+
return ok
|
|
78
|
+
? { allow: true }
|
|
79
|
+
: { allow: false, reason: '当前账号没有项目权限' }
|
|
80
|
+
},
|
|
71
81
|
onBeforeClose: ({ context }) => {
|
|
72
82
|
// 窗口关闭前的自定义清理;session 关闭和 view 销毁由框架自动处理
|
|
73
83
|
},
|
|
@@ -203,8 +213,9 @@ src/
|
|
|
203
213
|
| `rendererDir` | `string` | 内置 | 自定义 renderer HTML 目录 |
|
|
204
214
|
| `icon` | `string` | — | 窗口/任务栏图标路径(macOS 使用 app bundle 图标) |
|
|
205
215
|
| `menuBuilder` | `(mainWindow, menuContext: MenuContext) => void` | 内置菜单 | 自定义菜单构建器;`menuContext` 为收窄后的 `MenuContext`,不含 `registry`/`senderPolicy` 等内部管线 |
|
|
206
|
-
| `onSetup` | `(instance) => void
|
|
207
|
-
| `
|
|
216
|
+
| `onSetup` | `(instance) => void \| Promise<void>` | — | 窗口和 context 创建后的回调,用于注册 Contribution(见下文)|
|
|
217
|
+
| `onBeforeOpenProject` | `({ projectPath, instance }) => BeforeOpenProjectResult \| Promise<BeforeOpenProjectResult>` | — | 项目目录校验通过后、关闭当前 session 和编译新项目之前的宿主准入钩子 |
|
|
218
|
+
| `onBeforeClose` | `(instance) => void \| Promise<void>` | — | 窗口关闭前的回调,session 关闭由框架自动处理 |
|
|
208
219
|
| `window` | `WorkbenchWindowConfig` | — | 窗口尺寸覆盖 |
|
|
209
220
|
| `updateChecker` | `UpdateChecker` | — | 自定义更新检查器;提供后启用"检查更新"功能 |
|
|
210
221
|
| `updateOptions` | `{ checkInterval?, initialDelay?, getCurrentVersion? }` | — | 仅当 `updateChecker` 提供时生效,默认 1h / 5s |
|
|
@@ -220,6 +231,8 @@ src/
|
|
|
220
231
|
| `instance.ipc` | `IpcRegistry` 实例,`instance.ipc.handle(channel, fn)` 注册自定义 IPC;已绑定 `senderPolicy` 网关 |
|
|
221
232
|
| `instance.registerTrustedWindow(win)` | 把 host 自有弹窗 `BrowserWindow` 加入受信 sender 集,否则其发起的 `instance.ipc` 调用会被网关拒绝。窗口关闭即移除 |
|
|
222
233
|
|
|
234
|
+
`onSetup` 可以返回 Promise;`createWorkbenchApp().start()` 会等待 `onSetup` 解析完成后才继续后续启动流程,因此宿主在 `onSetup` 内注册的 simulator API 会早于 simulator `<webview>` 首次枚举自定义 API。
|
|
235
|
+
|
|
223
236
|
### 内置面板 ID
|
|
224
237
|
|
|
225
238
|
`'wxml'` \| `'console'` \| `'appdata'` \| `'storage'`
|
package/dist/main/api.d.ts
CHANGED
|
@@ -14,5 +14,5 @@ export { IpcRegistry } from './utils/ipc-registry.js';
|
|
|
14
14
|
export type { SenderPolicy } from './utils/ipc-registry.js';
|
|
15
15
|
export { UpdateManager, createGitHubReleaseChecker } from './services/update/index.js';
|
|
16
16
|
export type { UpdateManagerOptions, GitHubReleaseCheckerOptions, PickAssetContext, VersionScheme, } from './services/update/index.js';
|
|
17
|
-
export type { WorkbenchConfig, WorkbenchAppConfig, CompilationAdapter, ProjectSession, ToolbarAction, BuiltinPanelId, BuiltinModuleId, UpdateChecker, UpdateInfo, } from '../shared/types.js';
|
|
17
|
+
export type { BeforeOpenProjectHook, BeforeOpenProjectResult, WorkbenchConfig, WorkbenchAppConfig, CompilationAdapter, ProjectSession, ToolbarAction, ToolbarActionInput, ToolbarActionKind, ToolbarActionPlacement, BuiltinPanelId, BuiltinModuleId, UpdateChecker, UpdateInfo, } from '../shared/types.js';
|
|
18
18
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/main/app/app.js
CHANGED
|
@@ -356,6 +356,9 @@ export async function createDevtoolsRuntime(config = {}) {
|
|
|
356
356
|
},
|
|
357
357
|
dispose: () => disposeContext(context),
|
|
358
358
|
};
|
|
359
|
+
if (config.onBeforeOpenProject) {
|
|
360
|
+
context.beforeOpenProject = (projectPath) => config.onBeforeOpenProject({ projectPath, instance });
|
|
361
|
+
}
|
|
359
362
|
if (config.onSetup) {
|
|
360
363
|
await config.onSetup(instance);
|
|
361
364
|
}
|
|
@@ -2762,15 +2762,21 @@ function createWorkspaceService(ctx) {
|
|
|
2762
2762
|
},
|
|
2763
2763
|
validateProjectDir: async (dirPath) => provider.validateProjectDir ? provider.validateProjectDir(dirPath) : null,
|
|
2764
2764
|
async openProject(projectPath) {
|
|
2765
|
-
clearSimulatorServicewechatReferer();
|
|
2766
|
-
await disposeSession();
|
|
2767
|
-
currentProjectPath = "";
|
|
2768
|
-
lastClosedProjectPath = "";
|
|
2769
2765
|
const dirError = provider.validateProjectDir ? await provider.validateProjectDir(projectPath) : null;
|
|
2770
2766
|
if (dirError) {
|
|
2771
2767
|
sendStatus("error", dirError);
|
|
2772
2768
|
return { success: false, error: dirError };
|
|
2773
2769
|
}
|
|
2770
|
+
const gate = ctx.beforeOpenProject ? await ctx.beforeOpenProject(projectPath) : void 0;
|
|
2771
|
+
if (gate && !gate.allow) {
|
|
2772
|
+
const message = gate.userMessage ?? gate.reason;
|
|
2773
|
+
sendStatus("error", message);
|
|
2774
|
+
return { success: false, error: message };
|
|
2775
|
+
}
|
|
2776
|
+
clearSimulatorServicewechatReferer();
|
|
2777
|
+
await disposeSession();
|
|
2778
|
+
currentProjectPath = "";
|
|
2779
|
+
lastClosedProjectPath = "";
|
|
2774
2780
|
sendStatus("compiling", "\u6B63\u5728\u7F16\u8BD1...");
|
|
2775
2781
|
const { compile } = loadWorkbenchSettings();
|
|
2776
2782
|
let session4;
|
|
@@ -2792,7 +2798,7 @@ function createWorkspaceService(ctx) {
|
|
|
2792
2798
|
bestEffort("updateLastOpened", () => {
|
|
2793
2799
|
if (provider.updateLastOpened) provider.updateLastOpened(projectPath);
|
|
2794
2800
|
});
|
|
2795
|
-
bestEffort("sendStatus", () => sendStatus("ready", "\u7F16\u8BD1\u5B8C\u6210"));
|
|
2801
|
+
bestEffort("sendStatus", () => sendStatus("ready", gate?.statusMessage ?? "\u7F16\u8BD1\u5B8C\u6210"));
|
|
2796
2802
|
bestEffort("applyReferer", () => applyRefererFromSession(session4));
|
|
2797
2803
|
return {
|
|
2798
2804
|
success: true,
|
|
@@ -2894,6 +2900,18 @@ function createLocalProjectsProvider() {
|
|
|
2894
2900
|
}
|
|
2895
2901
|
|
|
2896
2902
|
// src/main/services/toolbar/toolbar-store.ts
|
|
2903
|
+
function toPublicAction(action) {
|
|
2904
|
+
const projected = {
|
|
2905
|
+
id: action.id,
|
|
2906
|
+
label: action.label
|
|
2907
|
+
};
|
|
2908
|
+
if (action.kind) projected.kind = action.kind;
|
|
2909
|
+
if (action.placement) projected.placement = action.placement;
|
|
2910
|
+
if (action.icon) projected.icon = action.icon;
|
|
2911
|
+
if (action.displayInitial) projected.displayInitial = action.displayInitial;
|
|
2912
|
+
if (action.avatarUrl) projected.avatarUrl = action.avatarUrl;
|
|
2913
|
+
return projected;
|
|
2914
|
+
}
|
|
2897
2915
|
function createToolbarStore() {
|
|
2898
2916
|
let actions = [];
|
|
2899
2917
|
return {
|
|
@@ -2908,7 +2926,7 @@ function createToolbarStore() {
|
|
|
2908
2926
|
actions = next.slice();
|
|
2909
2927
|
},
|
|
2910
2928
|
list() {
|
|
2911
|
-
return actions.map(
|
|
2929
|
+
return actions.map(toPublicAction);
|
|
2912
2930
|
},
|
|
2913
2931
|
getHandler(id) {
|
|
2914
2932
|
return actions.find((a) => a.id === id)?.handler;
|
|
@@ -8897,6 +8915,9 @@ async function createDevtoolsRuntime(config = {}) {
|
|
|
8897
8915
|
},
|
|
8898
8916
|
dispose: () => disposeContext(context)
|
|
8899
8917
|
};
|
|
8918
|
+
if (config.onBeforeOpenProject) {
|
|
8919
|
+
context.beforeOpenProject = (projectPath) => config.onBeforeOpenProject({ projectPath, instance });
|
|
8920
|
+
}
|
|
8900
8921
|
if (config.onSetup) {
|
|
8901
8922
|
await config.onSetup(instance);
|
|
8902
8923
|
}
|
|
@@ -4,8 +4,8 @@ import type { ToolbarAction, ToolbarActionInput } from '../../../shared/types.js
|
|
|
4
4
|
*
|
|
5
5
|
* The toolbar is modelled as "one table the host recomputes from its current
|
|
6
6
|
* state": `set()` replaces the whole table atomically. The non-serialisable
|
|
7
|
-
* `handler` is kept main-process side; `list()` projects
|
|
8
|
-
*
|
|
7
|
+
* `handler` is kept main-process side; `list()` projects display metadata for
|
|
8
|
+
* the IPC boundary, and `getHandler()` resolves a handler by id.
|
|
9
9
|
*/
|
|
10
10
|
export interface ToolbarStore {
|
|
11
11
|
/**
|
|
@@ -14,7 +14,7 @@ export interface ToolbarStore {
|
|
|
14
14
|
* a rejected batch leaves the previous table intact.
|
|
15
15
|
*/
|
|
16
16
|
set(actions: ToolbarActionInput[]): void;
|
|
17
|
-
/** Project the current table to
|
|
17
|
+
/** Project the current table to serialisable display metadata — no `handler` leaks out. */
|
|
18
18
|
list(): ToolbarAction[];
|
|
19
19
|
/** Resolve the handler stored under `id`, or `undefined` if unknown. */
|
|
20
20
|
getHandler(id: string): (() => void | Promise<void>) | undefined;
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
function toPublicAction(action) {
|
|
2
|
+
const projected = {
|
|
3
|
+
id: action.id,
|
|
4
|
+
label: action.label,
|
|
5
|
+
};
|
|
6
|
+
if (action.kind)
|
|
7
|
+
projected.kind = action.kind;
|
|
8
|
+
if (action.placement)
|
|
9
|
+
projected.placement = action.placement;
|
|
10
|
+
if (action.icon)
|
|
11
|
+
projected.icon = action.icon;
|
|
12
|
+
if (action.displayInitial)
|
|
13
|
+
projected.displayInitial = action.displayInitial;
|
|
14
|
+
if (action.avatarUrl)
|
|
15
|
+
projected.avatarUrl = action.avatarUrl;
|
|
16
|
+
return projected;
|
|
17
|
+
}
|
|
1
18
|
export function createToolbarStore() {
|
|
2
19
|
let actions = [];
|
|
3
20
|
return {
|
|
@@ -13,7 +30,7 @@ export function createToolbarStore() {
|
|
|
13
30
|
actions = next.slice();
|
|
14
31
|
},
|
|
15
32
|
list() {
|
|
16
|
-
return actions.map(
|
|
33
|
+
return actions.map(toPublicAction);
|
|
17
34
|
},
|
|
18
35
|
getHandler(id) {
|
|
19
36
|
return actions.find((a) => a.id === id)?.handler;
|
|
@@ -15,7 +15,7 @@ import { type SimulatorApiRegistry } from './simulator/custom-apis.js';
|
|
|
15
15
|
import { type ToolbarStore } from './toolbar/toolbar-store.js';
|
|
16
16
|
import { sanitizeTemplates } from './projects/templates.js';
|
|
17
17
|
import type { ProjectsProvider, ProjectTemplate } from './projects/types.js';
|
|
18
|
-
import type { CustomCreateProjectDialogResult } from '../../shared/types.js';
|
|
18
|
+
import type { BeforeOpenProjectResult, CustomCreateProjectDialogResult } from '../../shared/types.js';
|
|
19
19
|
/**
|
|
20
20
|
* Shared mutable state for the workbench application.
|
|
21
21
|
* Passed to each IPC module so they can read/write shared state without closures.
|
|
@@ -72,6 +72,11 @@ export interface WorkbenchContext {
|
|
|
72
72
|
parentWindow: BrowserWindow;
|
|
73
73
|
templates: ProjectTemplate[];
|
|
74
74
|
}) => Promise<CustomCreateProjectDialogResult>;
|
|
75
|
+
/**
|
|
76
|
+
* Optional host gate for opening projects. Runs after basic directory
|
|
77
|
+
* validation and before the current project session is closed.
|
|
78
|
+
*/
|
|
79
|
+
beforeOpenProject?: (projectPath: string) => BeforeOpenProjectResult | Promise<BeforeOpenProjectResult>;
|
|
75
80
|
/**
|
|
76
81
|
* Trust predicate consulted by `IpcRegistry` for every incoming IPC.
|
|
77
82
|
* Resolves the currently-trusted senders (main renderer + overlays)
|
|
@@ -62,12 +62,6 @@ export function createWorkspaceService(ctx) {
|
|
|
62
62
|
? provider.validateProjectDir(dirPath)
|
|
63
63
|
: null,
|
|
64
64
|
async openProject(projectPath) {
|
|
65
|
-
clearSimulatorServicewechatReferer();
|
|
66
|
-
await disposeSession();
|
|
67
|
-
currentProjectPath = '';
|
|
68
|
-
// A fresh open starts a clean sandbox window — drop any previously
|
|
69
|
-
// recorded last-closed root so it can't accept writes after this point.
|
|
70
|
-
lastClosedProjectPath = '';
|
|
71
65
|
// Reject obviously broken projects up front so we never spin up a
|
|
72
66
|
// compile/server that the simulator will then fetch asset-by-asset.
|
|
73
67
|
// Without this guard, deleted recent-list entries and typo'd CLI paths
|
|
@@ -82,6 +76,18 @@ export function createWorkspaceService(ctx) {
|
|
|
82
76
|
sendStatus('error', dirError);
|
|
83
77
|
return { success: false, error: dirError };
|
|
84
78
|
}
|
|
79
|
+
const gate = ctx.beforeOpenProject ? await ctx.beforeOpenProject(projectPath) : undefined;
|
|
80
|
+
if (gate && !gate.allow) {
|
|
81
|
+
const message = gate.userMessage ?? gate.reason;
|
|
82
|
+
sendStatus('error', message);
|
|
83
|
+
return { success: false, error: message };
|
|
84
|
+
}
|
|
85
|
+
clearSimulatorServicewechatReferer();
|
|
86
|
+
await disposeSession();
|
|
87
|
+
currentProjectPath = '';
|
|
88
|
+
// A fresh open starts a clean sandbox window — drop any previously
|
|
89
|
+
// recorded last-closed root so it can't accept writes after this point.
|
|
90
|
+
lastClosedProjectPath = '';
|
|
85
91
|
sendStatus('compiling', '正在编译...');
|
|
86
92
|
const { compile } = loadWorkbenchSettings();
|
|
87
93
|
let session;
|
|
@@ -105,7 +111,7 @@ export function createWorkspaceService(ctx) {
|
|
|
105
111
|
if (provider.updateLastOpened)
|
|
106
112
|
provider.updateLastOpened(projectPath);
|
|
107
113
|
});
|
|
108
|
-
bestEffort('sendStatus', () => sendStatus('ready', '编译完成'));
|
|
114
|
+
bestEffort('sendStatus', () => sendStatus('ready', gate?.statusMessage ?? '编译完成'));
|
|
109
115
|
bestEffort('applyReferer', () => applyRefererFromSession(session));
|
|
110
116
|
return {
|
|
111
117
|
success: true,
|