@dimina-kit/devtools 0.4.0-dev.20260824071518 → 0.4.0-dev.20260828092243

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 (153) hide show
  1. package/dist/main/api.d.ts +1 -1
  2. package/dist/main/app/app.js +55 -2
  3. package/dist/main/index.bundle.js +887 -234
  4. package/dist/main/ipc/index.d.ts +2 -0
  5. package/dist/main/ipc/index.js +2 -0
  6. package/dist/main/ipc/popover.js +1 -1
  7. package/dist/main/ipc/project-create.d.ts +15 -0
  8. package/dist/main/ipc/project-create.js +26 -0
  9. package/dist/main/ipc/projects.d.ts +1 -1
  10. package/dist/main/ipc/projects.js +11 -0
  11. package/dist/main/ipc/settings.js +2 -1
  12. package/dist/main/ipc/simulator-module.d.ts +4 -3
  13. package/dist/main/ipc/simulator-module.js +4 -5
  14. package/dist/main/ipc/tooltip.js +1 -1
  15. package/dist/main/ipc/views.d.ts +15 -1
  16. package/dist/main/ipc/views.js +61 -4
  17. package/dist/main/runtime/miniapp-runtime.d.ts +87 -19
  18. package/dist/main/services/notifications/renderer-notifier.d.ts +30 -1
  19. package/dist/main/services/notifications/renderer-notifier.js +23 -1
  20. package/dist/main/services/projects/project-repository.d.ts +4 -1
  21. package/dist/main/services/projects/project-repository.js +63 -5
  22. package/dist/main/services/update/update-manager.d.ts +17 -3
  23. package/dist/main/services/update/update-manager.js +25 -6
  24. package/dist/main/services/views/host-dialog-port-channel.d.ts +18 -0
  25. package/dist/main/services/views/host-dialog-port-channel.js +15 -0
  26. package/dist/main/services/views/host-dialog-session-runtime.d.ts +10 -0
  27. package/dist/main/services/views/host-dialog-session-runtime.js +17 -0
  28. package/dist/main/services/views/host-dialog-view.d.ts +95 -0
  29. package/dist/main/services/views/host-dialog-view.js +147 -0
  30. package/dist/main/services/views/host-sidebar-port-channel.d.ts +18 -0
  31. package/dist/main/services/views/host-sidebar-port-channel.js +15 -0
  32. package/dist/main/services/views/host-sidebar-session-runtime.d.ts +10 -0
  33. package/dist/main/services/views/host-sidebar-session-runtime.js +17 -0
  34. package/dist/main/services/views/host-sidebar-view.d.ts +59 -0
  35. package/dist/main/services/views/host-sidebar-view.js +44 -0
  36. package/dist/main/services/views/host-slot-port-channel.d.ts +107 -0
  37. package/dist/main/services/views/host-slot-port-channel.js +261 -0
  38. package/dist/main/services/views/host-slot-session-runtime.d.ts +40 -0
  39. package/dist/main/services/views/host-slot-session-runtime.js +50 -0
  40. package/dist/main/services/views/host-slot-view.d.ts +109 -0
  41. package/dist/main/services/views/host-slot-view.js +147 -0
  42. package/dist/main/services/views/host-toolbar-port-channel.d.ts +6 -91
  43. package/dist/main/services/views/host-toolbar-port-channel.js +10 -243
  44. package/dist/main/services/views/host-toolbar-session-runtime.d.ts +5 -30
  45. package/dist/main/services/views/host-toolbar-session-runtime.js +9 -47
  46. package/dist/main/services/views/host-toolbar-view.d.ts +34 -7
  47. package/dist/main/services/views/host-toolbar-view.js +30 -224
  48. package/dist/main/services/views/managed-web-contents-view.d.ts +48 -0
  49. package/dist/main/services/views/managed-web-contents-view.js +123 -0
  50. package/dist/main/services/views/overlay-panels-view.d.ts +23 -0
  51. package/dist/main/services/views/overlay-panels-view.js +93 -4
  52. package/dist/main/services/views/placement-reconciler.d.ts +14 -2
  53. package/dist/main/services/views/placement-reconciler.js +27 -0
  54. package/dist/main/services/views/placement-test-driver.d.ts +1 -0
  55. package/dist/main/services/views/placement-test-driver.js +3 -0
  56. package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +3 -1
  57. package/dist/main/services/views/view-manager.d.ts +10 -78
  58. package/dist/main/services/views/view-manager.js +34 -3
  59. package/dist/main/utils/paths.d.ts +4 -0
  60. package/dist/main/utils/paths.js +4 -0
  61. package/dist/main/utils/sender-policy.js +10 -0
  62. package/dist/native-host/common/common.js +65 -62
  63. package/dist/native-host/render/render.js +2230 -2052
  64. package/dist/native-host/service/service.js +2 -2
  65. package/dist/preload/runtime/host-dialog-advertiser.d.ts +22 -0
  66. package/dist/preload/runtime/host-dialog-advertiser.js +37 -0
  67. package/dist/preload/runtime/host-dialog-port.d.ts +44 -0
  68. package/dist/preload/runtime/host-dialog-port.js +53 -0
  69. package/dist/preload/runtime/host-dialog-runtime.d.ts +28 -0
  70. package/dist/preload/runtime/host-dialog-runtime.js +36 -0
  71. package/dist/preload/runtime/host-sidebar-advertiser.d.ts +19 -0
  72. package/dist/preload/runtime/host-sidebar-advertiser.js +35 -0
  73. package/dist/preload/runtime/host-sidebar-port.d.ts +44 -0
  74. package/dist/preload/runtime/host-sidebar-port.js +53 -0
  75. package/dist/preload/runtime/host-sidebar-runtime.d.ts +28 -0
  76. package/dist/preload/runtime/host-sidebar-runtime.js +36 -0
  77. package/dist/preload/runtime/host-slot-port-bridge.d.ts +18 -0
  78. package/dist/preload/runtime/host-slot-port-bridge.js +112 -0
  79. package/dist/preload/runtime/host-toolbar-advertiser.d.ts +5 -13
  80. package/dist/preload/runtime/host-toolbar-advertiser.js +18 -38
  81. package/dist/preload/runtime/host-toolbar-port.d.ts +9 -0
  82. package/dist/preload/runtime/host-toolbar-port.js +11 -95
  83. package/dist/preload/runtime/wait-for-slot-root.d.ts +20 -0
  84. package/dist/preload/runtime/wait-for-slot-root.js +52 -0
  85. package/dist/preload/windows/host-dialog-runtime.cjs +353 -0
  86. package/dist/preload/windows/host-dialog-runtime.cjs.map +7 -0
  87. package/dist/preload/windows/host-dialog-runtime.d.ts +2 -0
  88. package/dist/preload/windows/host-dialog-runtime.js +13 -0
  89. package/dist/preload/windows/host-sidebar-runtime.cjs +354 -0
  90. package/dist/preload/windows/host-sidebar-runtime.cjs.map +7 -0
  91. package/dist/preload/windows/host-sidebar-runtime.d.ts +2 -0
  92. package/dist/preload/windows/host-sidebar-runtime.js +13 -0
  93. package/dist/preload/windows/host-toolbar-runtime.cjs +134 -51
  94. package/dist/preload/windows/host-toolbar-runtime.cjs.map +3 -3
  95. package/dist/preload/windows/simulator.cjs.map +1 -1
  96. package/dist/renderer/assets/button-DsNqZm7o.js +2 -0
  97. package/dist/renderer/assets/constants-D7DfVqMp.js +2 -0
  98. package/dist/renderer/assets/constants-D8zsejFq.js +2 -0
  99. package/dist/renderer/assets/createLucideIcon-CYJeT1ji.js +2 -0
  100. package/dist/renderer/assets/dialog-pT4qWmka.js +46 -0
  101. package/dist/renderer/assets/dist-o70xmpc1.js +2 -0
  102. package/dist/renderer/assets/hostSidebarDefault-NvGZlE9O.js +2 -0
  103. package/dist/renderer/assets/index-zErhG3ta.js +5 -0
  104. package/dist/renderer/assets/input-4QxTXMZN.js +2 -0
  105. package/dist/renderer/assets/ipc-channels-overlays-Blr5TNoB.js +2 -0
  106. package/dist/renderer/assets/jsx-runtime-B-3rq1y5.css +1 -0
  107. package/dist/renderer/assets/jsx-runtime-CqVdW3eg.js +9 -0
  108. package/dist/renderer/assets/popover-CJiSWwuE.js +2 -0
  109. package/dist/renderer/assets/project-api-DZ1Zi6EC.js +2 -0
  110. package/dist/renderer/assets/projectCreateDialog-DMWNhw_1.js +2 -0
  111. package/dist/renderer/assets/select-C86pNcsu.js +2 -0
  112. package/dist/renderer/assets/settings-BoI8mLT1.js +2 -0
  113. package/dist/renderer/assets/settings-api-Bs_g4NHs.js +2 -0
  114. package/dist/renderer/assets/settings-tab-bar-DHLLygqv.js +2 -0
  115. package/dist/renderer/assets/tooltip-BhAyY0T4.js +2 -0
  116. package/dist/renderer/assets/types-YYjkvane.js +2 -0
  117. package/dist/renderer/assets/updateDialog-DPum3wx1.js +2 -0
  118. package/dist/renderer/assets/utils-kfQov6Pa.js +2 -0
  119. package/dist/renderer/assets/view-api-DFhb2R8-.js +2 -0
  120. package/dist/renderer/assets/{workbenchSettings-oq_EyfKf.js → workbenchSettings-DrajRQUk.js} +3 -3
  121. package/dist/renderer/entries/host-sidebar-default/index.html +21 -0
  122. package/dist/renderer/entries/main/index.html +15 -8
  123. package/dist/renderer/entries/popover/index.html +10 -7
  124. package/dist/renderer/entries/project-create-dialog/index.html +27 -0
  125. package/dist/renderer/entries/settings/index.html +10 -7
  126. package/dist/renderer/entries/tooltip/index.html +5 -4
  127. package/dist/renderer/entries/update-dialog/index.html +25 -0
  128. package/dist/renderer/entries/workbench-settings/index.html +11 -7
  129. package/dist/service-host/preload.cjs +10 -0
  130. package/dist/shared/constants.d.ts +22 -0
  131. package/dist/shared/constants.js +22 -0
  132. package/dist/shared/ipc-channels-overlays.d.ts +156 -0
  133. package/dist/shared/ipc-channels-overlays.js +186 -0
  134. package/dist/shared/ipc-channels.d.ts +0 -77
  135. package/dist/shared/ipc-channels.js +0 -98
  136. package/dist/shared/ipc-schemas.d.ts +33 -0
  137. package/dist/shared/ipc-schemas.js +41 -0
  138. package/dist/shared/types.d.ts +10 -0
  139. package/dist/shared/view-ids.d.ts +7 -0
  140. package/dist/shared/view-ids.js +10 -0
  141. package/package.json +8 -8
  142. package/dist/renderer/assets/constants-Bdz0LHdy.js +0 -2
  143. package/dist/renderer/assets/index-CtznrmHR.js +0 -49
  144. package/dist/renderer/assets/input-Dmm6nob5.js +0 -2
  145. package/dist/renderer/assets/ipc-transport-BOg0gR9W.js +0 -9
  146. package/dist/renderer/assets/ipc-transport-DgQhZaE9.css +0 -1
  147. package/dist/renderer/assets/popover-Cd1FEGOX.js +0 -2
  148. package/dist/renderer/assets/select-BaYox7If.js +0 -2
  149. package/dist/renderer/assets/settings-BXvwuFaz.js +0 -2
  150. package/dist/renderer/assets/settings-api-Bo9GbYqs.js +0 -2
  151. package/dist/renderer/assets/settings-tab-bar-Beia6lMr.js +0 -2
  152. package/dist/renderer/assets/tooltip-DfQqK3Sk.js +0 -2
  153. package/dist/renderer/assets/view-api-nn69je7A.js +0 -2
@@ -4,6 +4,44 @@ import fs from 'fs';
4
4
  import { DEFAULT_SCENE } from '../../../shared/constants.js';
5
5
  import { createLogger } from '../../utils/logger.js';
6
6
  const log = createLogger('projects');
7
+ /**
8
+ * Merge project.config.json + project.private.config.json (private wins),
9
+ * mirroring `dimina/fe/packages/compiler/src/env.js`'s `storeInfo`.
10
+ */
11
+ function readProjectConfig(dirPath) {
12
+ let merged = {};
13
+ for (const fileName of ['project.config.json', 'project.private.config.json']) {
14
+ const configPath = path.join(dirPath, fileName);
15
+ if (!fs.existsSync(configPath))
16
+ continue;
17
+ try {
18
+ merged = { ...merged, ...JSON.parse(fs.readFileSync(configPath, 'utf-8')) };
19
+ }
20
+ catch (err) {
21
+ log.warn(`Failed to parse ${configPath}`, err);
22
+ }
23
+ }
24
+ return merged;
25
+ }
26
+ /**
27
+ * Mirrors `dimina/fe/packages/compiler/src/env.js`'s `detectRuntimeType` —
28
+ * an explicit `compileType` wins, else a mini-game is inferred from
29
+ * game.json + game.js/.ts with no app.json present.
30
+ */
31
+ function detectRuntimeType(dirPath) {
32
+ const compileType = readProjectConfig(dirPath).compileType;
33
+ if (compileType === 'game')
34
+ return 'minigame';
35
+ if (compileType === 'miniprogram')
36
+ return 'miniprogram';
37
+ const hasMiniProgramConfig = fs.existsSync(path.join(dirPath, 'app.json'));
38
+ const hasMiniGameConfig = fs.existsSync(path.join(dirPath, 'game.json'));
39
+ const hasMiniGameEntry = ['game.js', 'game.ts']
40
+ .some((fileName) => fs.existsSync(path.join(dirPath, fileName)));
41
+ if (!hasMiniProgramConfig && hasMiniGameConfig && hasMiniGameEntry)
42
+ return 'minigame';
43
+ return 'miniprogram';
44
+ }
7
45
  function getProjectsFile() {
8
46
  return path.join(app.getPath('userData'), 'dimina-projects.json');
9
47
  }
@@ -28,6 +66,12 @@ export function validateProjectDir(dirPath) {
28
66
  if (!fs.existsSync(dirPath)) {
29
67
  return `小程序目录不存在:${dirPath}`;
30
68
  }
69
+ if (detectRuntimeType(dirPath) === 'minigame') {
70
+ if (!fs.existsSync(path.join(dirPath, 'game.json'))) {
71
+ return '该目录缺少 game.json,请选择包含小游戏源码的目录';
72
+ }
73
+ return null;
74
+ }
31
75
  if (!fs.existsSync(path.join(dirPath, 'app.json'))) {
32
76
  const configPath = path.join(dirPath, 'project.config.json');
33
77
  if (fs.existsSync(configPath)) {
@@ -63,10 +107,11 @@ export function addProject(dirPath) {
63
107
  catch (err) {
64
108
  log.warn('Failed to read project name from config', err);
65
109
  }
66
- const project = { name, path: dirPath, lastOpened: null };
110
+ const type = detectRuntimeType(dirPath);
111
+ const project = { name, path: dirPath, lastOpened: null, type };
67
112
  const idx = projects.findIndex((p) => p.path === dirPath);
68
113
  if (idx >= 0) {
69
- projects[idx] = { ...projects[idx], name };
114
+ projects[idx] = { ...projects[idx], name, type };
70
115
  }
71
116
  else {
72
117
  projects.unshift(project);
@@ -88,13 +133,26 @@ export function updateLastOpened(dirPath) {
88
133
  export function getCompileConfig(dirPath) {
89
134
  const projects = load();
90
135
  const project = projects.find((p) => p.path === dirPath);
91
- return (project?.compileConfig ?? {
92
- startPage: '',
136
+ if (project?.compileConfig)
137
+ return project.compileConfig;
138
+ // Default startPage to the project's real entry page (mirrors
139
+ // getProjectPages: 'game' for mini-games, app.json's entryPagePath for
140
+ // mini-programs) rather than a mini-program-only literal — the simulator
141
+ // URL builders' own 'pages/index/index' fallback only fires when this is
142
+ // still empty (unreadable/malformed manifest).
143
+ return {
144
+ startPage: getProjectPages(dirPath).entryPagePath,
93
145
  scene: DEFAULT_SCENE,
94
146
  queryParams: [],
95
- });
147
+ };
96
148
  }
97
149
  export function getProjectPages(dirPath) {
150
+ if (detectRuntimeType(dirPath) === 'minigame') {
151
+ // Mini-games have no page router — the compiler always emits a single
152
+ // synthetic 'game' entry (dimina/fe/packages/compiler/src/env.js
153
+ // storeAppConfig), mirrored here rather than reading a nonexistent app.json.
154
+ return { pages: ['game'], entryPagePath: 'game' };
155
+ }
98
156
  const appJsonPath = path.join(dirPath, 'app.json');
99
157
  try {
100
158
  const appJson = JSON.parse(fs.readFileSync(appJsonPath, 'utf-8'));
@@ -1,9 +1,13 @@
1
- import { BrowserWindow } from 'electron';
2
1
  import type { UpdateChecker, UpdateInfo } from '../../../shared/types.js';
3
2
  import { type SenderPolicy } from '../../utils/ipc-registry.js';
4
3
  export interface UpdateManagerOptions {
5
4
  checker: UpdateChecker;
6
- mainWindow: BrowserWindow;
5
+ /** Show the update-available overlay panel, fed the discovered update's info. */
6
+ showUpdatePanel: (info: UpdateInfo) => void;
7
+ /** Forward a download-progress tick into the (already-shown) update overlay. */
8
+ notifyDownloadProgress: (percent: number) => void;
9
+ /** Hide the update overlay panel — the renderer's close (any path) forwards here. */
10
+ hideUpdatePanel: () => void;
7
11
  /** Check interval in milliseconds. Default: 1 hour */
8
12
  checkInterval?: number;
9
13
  /** Delay before the first check after startup in ms. Default: 5000 */
@@ -20,7 +24,9 @@ export interface UpdateManagerOptions {
20
24
  }
21
25
  export declare class UpdateManager {
22
26
  private checker;
23
- private mainWindow;
27
+ private showUpdatePanel;
28
+ private notifyDownloadProgress;
29
+ private hideUpdatePanel;
24
30
  private getCurrentVersion;
25
31
  private latestUpdate;
26
32
  private downloadedPath;
@@ -37,6 +43,14 @@ export declare class UpdateManager {
37
43
  private timer;
38
44
  private initialTimer;
39
45
  private ipc;
46
+ /**
47
+ * Set by `dispose()`. Clearing the timers only stops FUTURE ticks — an
48
+ * in-flight `checkAndNotify()` invocation (already past its `await
49
+ * this.check()`) has no timer left to cancel it, and would otherwise call
50
+ * `showUpdatePanel` after dispose has torn down the overlay panel that
51
+ * owns (e.g. `views.disposeAll()` destroying its WebContentsView).
52
+ */
53
+ private disposed;
40
54
  constructor(opts: UpdateManagerOptions);
41
55
  private registerIpc;
42
56
  check(): Promise<{
@@ -1,9 +1,11 @@
1
1
  import { app, shell } from 'electron';
2
- import { UpdateChannel } from '../../../shared/ipc-channels.js';
2
+ import { UpdateChannel } from '../../../shared/ipc-channels-overlays.js';
3
3
  import { IpcRegistry } from '../../utils/ipc-registry.js';
4
4
  export class UpdateManager {
5
5
  checker;
6
- mainWindow;
6
+ showUpdatePanel;
7
+ notifyDownloadProgress;
8
+ hideUpdatePanel;
7
9
  getCurrentVersion;
8
10
  latestUpdate = null;
9
11
  downloadedPath = null;
@@ -20,9 +22,19 @@ export class UpdateManager {
20
22
  timer = null;
21
23
  initialTimer = null;
22
24
  ipc;
25
+ /**
26
+ * Set by `dispose()`. Clearing the timers only stops FUTURE ticks — an
27
+ * in-flight `checkAndNotify()` invocation (already past its `await
28
+ * this.check()`) has no timer left to cancel it, and would otherwise call
29
+ * `showUpdatePanel` after dispose has torn down the overlay panel that
30
+ * owns (e.g. `views.disposeAll()` destroying its WebContentsView).
31
+ */
32
+ disposed = false;
23
33
  constructor(opts) {
24
34
  this.checker = opts.checker;
25
- this.mainWindow = opts.mainWindow;
35
+ this.showUpdatePanel = opts.showUpdatePanel;
36
+ this.notifyDownloadProgress = opts.notifyDownloadProgress;
37
+ this.hideUpdatePanel = opts.hideUpdatePanel;
26
38
  this.getCurrentVersion = opts.getCurrentVersion ?? (() => app.getVersion());
27
39
  this.ipc = new IpcRegistry(opts.senderPolicy);
28
40
  this.registerIpc();
@@ -32,7 +44,8 @@ export class UpdateManager {
32
44
  this.ipc
33
45
  .handle(UpdateChannel.Check, async () => this.check())
34
46
  .handle(UpdateChannel.Download, async () => this.download())
35
- .handle(UpdateChannel.Install, async () => this.install());
47
+ .handle(UpdateChannel.Install, async () => this.install())
48
+ .on(UpdateChannel.Close, () => this.hideUpdatePanel());
36
49
  }
37
50
  async check() {
38
51
  try {
@@ -69,7 +82,7 @@ export class UpdateManager {
69
82
  }
70
83
  try {
71
84
  const filePath = await this.checker.downloadUpdate(this.latestUpdate, (percent) => {
72
- this.mainWindow.webContents.send(UpdateChannel.DownloadProgress, { percent });
85
+ this.notifyDownloadProgress(percent);
73
86
  });
74
87
  this.downloadedPath = filePath;
75
88
  return { success: true, filePath };
@@ -104,6 +117,7 @@ export class UpdateManager {
104
117
  * the timer clears + handler removals are scheduled synchronously.
105
118
  */
106
119
  dispose() {
120
+ this.disposed = true;
107
121
  if (this.timer) {
108
122
  clearInterval(this.timer);
109
123
  this.timer = null;
@@ -120,12 +134,17 @@ export class UpdateManager {
120
134
  }
121
135
  async checkAndNotify() {
122
136
  const result = await this.check();
137
+ // dispose() only cancels the timers that SCHEDULE future ticks — a tick
138
+ // already in flight (past this await) has nothing left to cancel it, and
139
+ // must not call into a torn-down panel/registry after the fact.
140
+ if (this.disposed)
141
+ return;
123
142
  if (!result.hasUpdate || !result.info)
124
143
  return;
125
144
  if (this.hasNotified)
126
145
  return;
127
146
  this.hasNotified = true;
128
- this.mainWindow.webContents.send(UpdateChannel.Available, result.info);
147
+ this.showUpdatePanel(result.info);
129
148
  }
130
149
  }
131
150
  //# sourceMappingURL=update-manager.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Dialog-specific instantiation of `createHostSlotPortChannel` (see that
3
+ * module for the full per-load handshake / navigation-invalidation
4
+ * contract).
5
+ */
6
+ import type { WebContents } from 'electron';
7
+ import { type HostSlotMessageSubscription, type HostSlotPortChannel } from './host-slot-port-channel.js';
8
+ export type HostDialogMessageSubscription = HostSlotMessageSubscription;
9
+ export type HostDialogPortChannel = HostSlotPortChannel;
10
+ export declare function createHostDialogPortChannel(opts: {
11
+ /**
12
+ * Is `wc` still the manager's CURRENT live dialog webContents? Guards a
13
+ * stale wc's late `did-finish-load` from hijacking the channel after a
14
+ * rebuild swapped the view out underneath it.
15
+ */
16
+ isCurrent: (wc: WebContents) => boolean;
17
+ }): HostDialogPortChannel;
18
+ //# sourceMappingURL=host-dialog-port-channel.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Dialog-specific instantiation of `createHostSlotPortChannel` (see that
3
+ * module for the full per-load handshake / navigation-invalidation
4
+ * contract).
5
+ */
6
+ import { ViewChannel } from '../../../shared/ipc-channels-overlays.js';
7
+ import { createHostSlotPortChannel, } from './host-slot-port-channel.js';
8
+ export function createHostDialogPortChannel(opts) {
9
+ return createHostSlotPortChannel({
10
+ isCurrent: opts.isCurrent,
11
+ channel: ViewChannel.HostDialogPort,
12
+ logPrefix: '[host-dialog]',
13
+ });
14
+ }
15
+ //# sourceMappingURL=host-dialog-port-channel.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Dialog-specific instantiation of `createHostSlotSessionRuntime` (see that
3
+ * module for the full ref-counting contract). Kept as a thin, independently
4
+ * named wrapper — same rationale as `host-toolbar-session-runtime.ts` — so
5
+ * a dialog-focused test can `vi.resetModules()` this module's state without
6
+ * touching the toolbar/sidebar's independent ref-counts.
7
+ */
8
+ export declare function acquireHostDialogSessionRuntime(): void;
9
+ export declare function releaseHostDialogSessionRuntime(): void;
10
+ //# sourceMappingURL=host-dialog-session-runtime.d.ts.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Dialog-specific instantiation of `createHostSlotSessionRuntime` (see that
3
+ * module for the full ref-counting contract). Kept as a thin, independently
4
+ * named wrapper — same rationale as `host-toolbar-session-runtime.ts` — so
5
+ * a dialog-focused test can `vi.resetModules()` this module's state without
6
+ * touching the toolbar/sidebar's independent ref-counts.
7
+ */
8
+ import { createHostSlotSessionRuntime } from './host-slot-session-runtime.js';
9
+ import { hostDialogRuntimePreloadPath } from '../../utils/paths.js';
10
+ const runtime = createHostSlotSessionRuntime(hostDialogRuntimePreloadPath);
11
+ export function acquireHostDialogSessionRuntime() {
12
+ runtime.acquire();
13
+ }
14
+ export function releaseHostDialogSessionRuntime() {
15
+ runtime.release();
16
+ }
17
+ //# sourceMappingURL=host-dialog-session-runtime.js.map
@@ -0,0 +1,95 @@
1
+ import type { WebContents } from 'electron';
2
+ import type { PlacementReconciler } from './placement-reconciler.js';
3
+ import type { ViewManagerContext } from './view-manager.js';
4
+ import type { HostDialogMessageSubscription } from './host-dialog-port-channel.js';
5
+ export type HostDialogAxis = 'block' | 'inline';
6
+ /**
7
+ * The control object the downstream host uses to own the dialog
8
+ * WebContentsView. Unlike `HostToolbarControl` / `HostSidebarControl`
9
+ * (persistent strips), the dialog is a by-demand overlay: no extent-mode
10
+ * setter (it always self-sizes from its own reverse advertiser, with a
11
+ * conservative default while unmeasured — see below) and an explicit
12
+ * `show()`/`hide()`/`isVisible()` surface instead of always being present
13
+ * once loaded.
14
+ */
15
+ export interface HostDialogControl {
16
+ /** Load a URL into the dialog view (lazy-creates the view). */
17
+ loadURL(url: string): Promise<void>;
18
+ /** Load a local file into the dialog view (lazy-creates the view). */
19
+ loadFile(path: string): Promise<void>;
20
+ /** The dialog view's live WebContents, or null if not yet created/destroyed. */
21
+ readonly webContents: WebContents | null;
22
+ /** Same contract as `HostToolbarControl.setPreloadPath`. */
23
+ setPreloadPath(path: string | null): void;
24
+ /**
25
+ * Register a host-side handler for messages the dialog PAGE sends via
26
+ * `window.diminaHostDialog.send(channel, payload)`. Same contract as
27
+ * `HostToolbarControl.onMessage`.
28
+ */
29
+ onMessage(channel: string, handler: (payload: unknown) => void): HostDialogMessageSubscription;
30
+ /** Same contract as `HostToolbarControl.onReady`. */
31
+ onReady(handler: () => void): HostDialogMessageSubscription;
32
+ /** Same contract as `HostToolbarControl.send`. */
33
+ send(channel: string, payload: unknown): boolean;
34
+ /**
35
+ * Show the dialog, centered in the main window using its self-advertised
36
+ * size on both axes (a conservative default for any axis not yet
37
+ * measured). Creates the view's placement if needed; does not (re)load
38
+ * content — the host must `loadURL`/`loadFile` first. Idempotent while
39
+ * already visible (re-centers with the latest measured extent instead of
40
+ * no-op, in case a resize happened while hidden).
41
+ */
42
+ show(): void;
43
+ /** Hide the dialog (kept alive, content preserved) without destroying the view. */
44
+ hide(): void;
45
+ /** Whether the dialog is currently shown. */
46
+ isVisible(): boolean;
47
+ }
48
+ /**
49
+ * The host-dialog slice of `ViewManager`'s public surface, split into its
50
+ * own file for the same file-length reason as sidebar's
51
+ * `HostSidebarViewManagerMembers` — a by-demand, dual-axis, main-centered
52
+ * overlay rather than a persistent strip.
53
+ */
54
+ export interface HostDialogViewManagerMembers {
55
+ /** Return the webContents ID of the host-dialog overlay if alive, else null. */
56
+ getHostDialogWebContentsId(): number | null;
57
+ /** Reverse size-advertiser sink for either axis; re-centers while visible. */
58
+ reportHostDialogMeasuredExtent(axis: HostDialogAxis, extent: number): void;
59
+ /** Host-facing control surface for the dialog WebContentsView. */
60
+ readonly hostDialog: HostDialogControl;
61
+ }
62
+ export interface HostDialogView {
63
+ readonly control: HostDialogControl;
64
+ /**
65
+ * Reverse size-advertiser sink for either axis. While visible, immediately
66
+ * re-centers with the newly measured extent; while hidden, just retains it
67
+ * for the next `show()`. Non-finite / non-positive reports are dropped —
68
+ * same fail-closed posture as the base slots' extent validation.
69
+ */
70
+ reportMeasuredExtent(axis: HostDialogAxis, extent: number): void;
71
+ getHostDialogWebContentsId(): number | null;
72
+ /**
73
+ * Re-center in the main window's CURRENT content rect, e.g. after a
74
+ * main-window resize. No-op while hidden — the next `show()` computes
75
+ * fresh bounds anyway, so there is nothing to reapply.
76
+ */
77
+ reposition(): void;
78
+ dispose(): void;
79
+ }
80
+ /**
81
+ * Host-dialog factory — its PLACEMENT is deliberately NOT built on
82
+ * `createHostSlotView`. That factory models a persistent, single-axis,
83
+ * renderer-anchored strip (`setBaseDesired`); the dialog is a by-demand,
84
+ * dual-axis, main-centered overlay (`setOverlayDesired` /
85
+ * `deleteOverlayDesired`), closer in shape to the settings/popover/tooltip
86
+ * overlays in `overlay-panels-view.ts` than to the toolbar/sidebar. It still
87
+ * doesn't reuse `createOverlayPanel` from that file: those panels load a
88
+ * FIXED renderer-dir entry and push typed data, whereas the dialog loads
89
+ * ARBITRARY host content and needs the toolbar/sidebar's `loadURL`/`loadFile`
90
+ * + gated port-channel surface. The underlying WebContentsView lazy-create /
91
+ * liveness / load / teardown lifecycle IS shared with the base slots though
92
+ * — see `managed-web-contents-view.ts`.
93
+ */
94
+ export declare function createHostDialogView(ctx: ViewManagerContext, reconciler: PlacementReconciler): HostDialogView;
95
+ //# sourceMappingURL=host-dialog-view.d.ts.map
@@ -0,0 +1,147 @@
1
+ import { HOST_DIALOG_RUNTIME_MARKER } from '../../../shared/constants.js';
2
+ import { VIEW_ID, VIEW_LAYER } from '../../../shared/view-ids.js';
3
+ import { acquireHostDialogSessionRuntime, releaseHostDialogSessionRuntime, } from './host-dialog-session-runtime.js';
4
+ import { createHostDialogPortChannel } from './host-dialog-port-channel.js';
5
+ import { createManagedWebContentsView } from './managed-web-contents-view.js';
6
+ // Shown immediately on `show()` for whichever axis hasn't been measured yet.
7
+ // The dialog is a by-demand overlay — there is no renderer placeholder to
8
+ // pre-report intrinsic size the way the toolbar/sidebar's forward anchor
9
+ // does, so the first show of a not-yet-measured axis has nothing to center
10
+ // against. Waiting/polling for the report would mask the async race (banned
11
+ // by this repo's timing rules); a conservative default plus a re-center the
12
+ // moment `reportMeasuredExtent` lands is the fail-safe alternative.
13
+ const DEFAULT_WIDTH = 480;
14
+ const DEFAULT_HEIGHT = 320;
15
+ /**
16
+ * Host-dialog factory — its PLACEMENT is deliberately NOT built on
17
+ * `createHostSlotView`. That factory models a persistent, single-axis,
18
+ * renderer-anchored strip (`setBaseDesired`); the dialog is a by-demand,
19
+ * dual-axis, main-centered overlay (`setOverlayDesired` /
20
+ * `deleteOverlayDesired`), closer in shape to the settings/popover/tooltip
21
+ * overlays in `overlay-panels-view.ts` than to the toolbar/sidebar. It still
22
+ * doesn't reuse `createOverlayPanel` from that file: those panels load a
23
+ * FIXED renderer-dir entry and push typed data, whereas the dialog loads
24
+ * ARBITRARY host content and needs the toolbar/sidebar's `loadURL`/`loadFile`
25
+ * + gated port-channel surface. The underlying WebContentsView lazy-create /
26
+ * liveness / load / teardown lifecycle IS shared with the base slots though
27
+ * — see `managed-web-contents-view.ts`.
28
+ */
29
+ export function createHostDialogView(ctx, reconciler) {
30
+ const port = createHostDialogPortChannel({
31
+ isCurrent: (wc) => managed.liveWebContents()?.id === wc.id,
32
+ });
33
+ let visible = false;
34
+ let width = DEFAULT_WIDTH;
35
+ let height = DEFAULT_HEIGHT;
36
+ const managed = createManagedWebContentsView({
37
+ reconciler,
38
+ viewId: VIEW_ID.hostDialog,
39
+ marker: HOST_DIALOG_RUNTIME_MARKER,
40
+ sessionRuntime: {
41
+ acquire: acquireHostDialogSessionRuntime,
42
+ release: releaseHostDialogSessionRuntime,
43
+ },
44
+ port,
45
+ onBroken: () => {
46
+ // Same "withdraw the stale desired placement" contract as hide(): a
47
+ // crashed dialog must not resurrect as a blank, content-less modal the
48
+ // next time something calls reposition() (e.g. a window resize).
49
+ visible = false;
50
+ reconciler.deleteOverlayDesired(VIEW_ID.hostDialog);
51
+ },
52
+ });
53
+ function computeBounds() {
54
+ const [winW = 0, winH = 0] = ctx.windows.mainWindow.getContentSize();
55
+ // Clamp to the window so a dialog whose advertised/default size exceeds
56
+ // the current content area still gets valid non-negative bounds instead
57
+ // of spilling off-window or going negative.
58
+ const w = Math.min(width, Math.max(1, winW));
59
+ const h = Math.min(height, Math.max(1, winH));
60
+ return {
61
+ x: Math.max(0, Math.round((winW - w) / 2)),
62
+ y: Math.max(0, Math.round((winH - h) / 2)),
63
+ width: w,
64
+ height: h,
65
+ };
66
+ }
67
+ function present() {
68
+ reconciler.setOverlayDesired(VIEW_ID.hostDialog, {
69
+ viewId: VIEW_ID.hostDialog,
70
+ placement: { visible: true, bounds: computeBounds() },
71
+ layer: VIEW_LAYER.hostDialog,
72
+ });
73
+ reconciler.reconcileNow();
74
+ }
75
+ function reportMeasuredExtent(axis, extent) {
76
+ if (!Number.isFinite(extent) || extent <= 0)
77
+ return;
78
+ if (axis === 'inline') {
79
+ width = extent;
80
+ }
81
+ else {
82
+ height = extent;
83
+ }
84
+ if (visible)
85
+ present();
86
+ }
87
+ // The host swaps content into the SAME dialog view via loadURL/loadFile
88
+ // (e.g. re-purposing one dialog for a different prompt) — width/height are
89
+ // this factory's own closure state, seeded once from the DEFAULT_*
90
+ // constants and only ever mutated by reportMeasuredExtent, so without a
91
+ // reset here a fresh, unmeasured document would inherit the PREVIOUS
92
+ // document's size until it happens to report its own. And while the
93
+ // dialog is currently VISIBLE, resetting the closure state alone doesn't
94
+ // reach the screen — the on-screen bounds only change via `present()` —
95
+ // so without the same `if (visible) present()` `reportMeasuredExtent`
96
+ // already does, the OLD document's bounds would stay displayed
97
+ // indefinitely (forever, if the new document never reports at all, e.g. a
98
+ // fixture missing `[data-host-dialog-root]`) instead of falling back to
99
+ // the default the moment the swap happens.
100
+ function resetMeasuredExtent() {
101
+ width = DEFAULT_WIDTH;
102
+ height = DEFAULT_HEIGHT;
103
+ if (visible)
104
+ present();
105
+ }
106
+ const control = {
107
+ loadURL: (url) => {
108
+ resetMeasuredExtent();
109
+ return managed.loadURL(url);
110
+ },
111
+ loadFile: (filePath) => {
112
+ resetMeasuredExtent();
113
+ return managed.loadFile(filePath);
114
+ },
115
+ get webContents() {
116
+ return managed.liveWebContents();
117
+ },
118
+ setPreloadPath: (path) => managed.setPreloadPath(path),
119
+ onMessage: (channel, handler) => port.onMessage(channel, handler),
120
+ onReady: (handler) => port.onReady(handler),
121
+ send: (channel, payload) => port.send(channel, payload),
122
+ show() {
123
+ managed.ensureView();
124
+ visible = true;
125
+ present();
126
+ },
127
+ hide() {
128
+ visible = false;
129
+ reconciler.deleteOverlayDesired(VIEW_ID.hostDialog);
130
+ reconciler.reconcileNow();
131
+ },
132
+ isVisible: () => visible,
133
+ };
134
+ reconciler.registerView(VIEW_ID.hostDialog, {
135
+ getView: () => managed.getView(),
136
+ ensureView: () => managed.ensureView(),
137
+ });
138
+ return {
139
+ control,
140
+ reportMeasuredExtent,
141
+ getHostDialogWebContentsId: () => managed.liveWebContents()?.id ?? null,
142
+ reposition: () => { if (visible)
143
+ present(); },
144
+ dispose: () => managed.dispose(),
145
+ };
146
+ }
147
+ //# sourceMappingURL=host-dialog-view.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Sidebar-specific instantiation of `createHostSlotPortChannel` (see that
3
+ * module for the full per-load handshake / navigation-invalidation
4
+ * contract).
5
+ */
6
+ import type { WebContents } from 'electron';
7
+ import { type HostSlotMessageSubscription, type HostSlotPortChannel } from './host-slot-port-channel.js';
8
+ export type HostSidebarMessageSubscription = HostSlotMessageSubscription;
9
+ export type HostSidebarPortChannel = HostSlotPortChannel;
10
+ export declare function createHostSidebarPortChannel(opts: {
11
+ /**
12
+ * Is `wc` still the manager's CURRENT live sidebar webContents? Guards a
13
+ * stale wc's late `did-finish-load` from hijacking the channel after a
14
+ * rebuild swapped the view out underneath it.
15
+ */
16
+ isCurrent: (wc: WebContents) => boolean;
17
+ }): HostSidebarPortChannel;
18
+ //# sourceMappingURL=host-sidebar-port-channel.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Sidebar-specific instantiation of `createHostSlotPortChannel` (see that
3
+ * module for the full per-load handshake / navigation-invalidation
4
+ * contract).
5
+ */
6
+ import { ViewChannel } from '../../../shared/ipc-channels-overlays.js';
7
+ import { createHostSlotPortChannel, } from './host-slot-port-channel.js';
8
+ export function createHostSidebarPortChannel(opts) {
9
+ return createHostSlotPortChannel({
10
+ isCurrent: opts.isCurrent,
11
+ channel: ViewChannel.HostSidebarPort,
12
+ logPrefix: '[host-sidebar]',
13
+ });
14
+ }
15
+ //# sourceMappingURL=host-sidebar-port-channel.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sidebar-specific instantiation of `createHostSlotSessionRuntime` (see that
3
+ * module for the full ref-counting contract). Kept as a thin, independently
4
+ * named wrapper — same rationale as `host-toolbar-session-runtime.ts` — so
5
+ * a sidebar-focused test can `vi.resetModules()` this module's state without
6
+ * touching the toolbar's independent ref-count.
7
+ */
8
+ export declare function acquireHostSidebarSessionRuntime(): void;
9
+ export declare function releaseHostSidebarSessionRuntime(): void;
10
+ //# sourceMappingURL=host-sidebar-session-runtime.d.ts.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Sidebar-specific instantiation of `createHostSlotSessionRuntime` (see that
3
+ * module for the full ref-counting contract). Kept as a thin, independently
4
+ * named wrapper — same rationale as `host-toolbar-session-runtime.ts` — so
5
+ * a sidebar-focused test can `vi.resetModules()` this module's state without
6
+ * touching the toolbar's independent ref-count.
7
+ */
8
+ import { createHostSlotSessionRuntime } from './host-slot-session-runtime.js';
9
+ import { hostSidebarRuntimePreloadPath } from '../../utils/paths.js';
10
+ const runtime = createHostSlotSessionRuntime(hostSidebarRuntimePreloadPath);
11
+ export function acquireHostSidebarSessionRuntime() {
12
+ runtime.acquire();
13
+ }
14
+ export function releaseHostSidebarSessionRuntime() {
15
+ runtime.release();
16
+ }
17
+ //# sourceMappingURL=host-sidebar-session-runtime.js.map
@@ -0,0 +1,59 @@
1
+ import type { HostSlotControl } from './host-slot-view.js';
2
+ import type { PlacementReconciler } from './placement-reconciler.js';
3
+ import type { ViewManagerContext } from './view-manager.js';
4
+ /**
5
+ * Width mode for the host-sidebar placeholder strip, mirroring
6
+ * `HostToolbarHeightMode` on the inline axis.
7
+ */
8
+ export type HostSidebarWidthMode = 'auto' | {
9
+ fixed: number;
10
+ };
11
+ /**
12
+ * The control object the downstream host uses to own the sidebar
13
+ * WebContentsView. Derives the shared members from `HostSlotControl` — see
14
+ * that interface for their contract, which carries over unchanged on the
15
+ * inline axis — and adds only `setWidthMode` in place of the base's
16
+ * `setExtentMode`, mirroring `HostToolbarControl.setHeightMode`.
17
+ */
18
+ export interface HostSidebarControl extends Omit<HostSlotControl, 'setExtentMode'> {
19
+ /**
20
+ * Pin or unpin the sidebar strip width. Same contract as
21
+ * `HostToolbarControl.setHeightMode` on the inline axis.
22
+ */
23
+ setWidthMode(mode: HostSidebarWidthMode): void;
24
+ }
25
+ /**
26
+ * The host-sidebar slice of `ViewManager`'s public surface, split into its
27
+ * own file (mixed in via `extends`) to keep view-manager.ts under the repo's
28
+ * file-length ratchet. Mirrors `hostToolbar`'s members on the inline axis;
29
+ * never coexists with a height-cycle dependency on settings/popover/tooltip.
30
+ */
31
+ export interface HostSidebarViewManagerMembers {
32
+ /** Return the webContents ID of the host-sidebar overlay if alive, else null. */
33
+ getHostSidebarWebContentsId(): number | null;
34
+ /** Return the last host-sidebar width NOTIFIED to the main-window renderer. */
35
+ getHostSidebarWidth(): number;
36
+ /** Reverse size-advertiser sink for the sidebar strip's inline (width) axis. */
37
+ setHostSidebarWidth(extent: number): void;
38
+ /** Host-facing control surface for the sidebar WebContentsView. */
39
+ readonly hostSidebar: HostSidebarControl;
40
+ }
41
+ export interface HostSidebarView {
42
+ readonly control: HostSidebarControl;
43
+ setHostSidebarWidth(extent: number): void;
44
+ getHostSidebarWidth(): number;
45
+ getHostSidebarWebContentsId(): number | null;
46
+ dispose(): void;
47
+ }
48
+ /**
49
+ * Sidebar-specific instantiation of `createHostSlotView` (see that module for
50
+ * the full lazy-create / port-channel / extent-mode contract). Symmetric to
51
+ * `createHostToolbarView` on the inline (width) axis instead of block
52
+ * (height) — the slot itself is axis-agnostic (a single advertised extent
53
+ * number); which CSS dimension it resizes is decided entirely by the host's
54
+ * renderer placeholder layout, not here. The sidebar never coexists with the
55
+ * settings/popover/tooltip overlays, so unlike the toolbar there is no
56
+ * `reapplyPresentOverlays` dependency to thread through.
57
+ */
58
+ export declare function createHostSidebarView(ctx: ViewManagerContext, reconciler: PlacementReconciler): HostSidebarView;
59
+ //# sourceMappingURL=host-sidebar-view.d.ts.map