@dimina-kit/devtools 0.4.0-dev.20260729062524 → 0.4.0-dev.20260801163345

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 (104) hide show
  1. package/dist/main/app/app.js +7 -0
  2. package/dist/main/app/bootstrap.d.ts +8 -5
  3. package/dist/main/app/bootstrap.js +15 -15
  4. package/dist/main/index.bundle.js +2207 -5152
  5. package/dist/main/ipc/app-lifecycle.d.ts +1 -31
  6. package/dist/main/ipc/app-lifecycle.js +1 -53
  7. package/dist/main/ipc/bridge-router.d.ts +19 -152
  8. package/dist/main/ipc/bridge-router.js +28 -2186
  9. package/dist/main/ipc/page-scroll.d.ts +1 -13
  10. package/dist/main/ipc/page-scroll.js +1 -16
  11. package/dist/main/ipc/session-listener-bag.d.ts +1 -40
  12. package/dist/main/ipc/session-listener-bag.js +1 -39
  13. package/dist/main/services/console-forward/index.d.ts +1 -60
  14. package/dist/main/services/console-forward/index.js +1 -225
  15. package/dist/main/services/console-forward/internal-log.d.ts +1 -10
  16. package/dist/main/services/console-forward/internal-log.js +1 -22
  17. package/dist/main/services/diagnostics/index.d.ts +1 -58
  18. package/dist/main/services/diagnostics/index.js +1 -60
  19. package/dist/main/services/dimina-resource-server.d.ts +1 -6
  20. package/dist/main/services/dimina-resource-server.js +1 -98
  21. package/dist/main/services/mcp/target-manager.js +5 -1
  22. package/dist/main/services/network-forward/index.d.ts +15 -3
  23. package/dist/main/services/network-forward/index.js +30 -4
  24. package/dist/main/services/network-forward/websocket.d.ts +36 -0
  25. package/dist/main/services/network-forward/websocket.js +120 -0
  26. package/dist/main/services/service-host-pool/pool.d.ts +1 -196
  27. package/dist/main/services/service-host-pool/pool.js +1 -363
  28. package/dist/main/services/simulator/custom-apis.d.ts +1 -42
  29. package/dist/main/services/simulator/custom-apis.js +1 -46
  30. package/dist/main/services/simulator/referer.d.ts +1 -9
  31. package/dist/main/services/simulator/referer.js +1 -19
  32. package/dist/main/services/simulator-storage/service-storage-ops.d.ts +1 -39
  33. package/dist/main/services/simulator-storage/service-storage-ops.js +1 -66
  34. package/dist/main/services/simulator-temp-files/disk.d.ts +1 -54
  35. package/dist/main/services/simulator-temp-files/disk.js +1 -237
  36. package/dist/main/services/simulator-temp-files/fs-channels.d.ts +1 -68
  37. package/dist/main/services/simulator-temp-files/fs-channels.js +1 -107
  38. package/dist/main/services/simulator-temp-files/index.d.ts +1 -32
  39. package/dist/main/services/simulator-temp-files/index.js +1 -181
  40. package/dist/main/services/simulator-temp-files/request-handler.d.ts +1 -29
  41. package/dist/main/services/simulator-temp-files/request-handler.js +1 -177
  42. package/dist/main/services/simulator-temp-files/resolver.d.ts +1 -21
  43. package/dist/main/services/simulator-temp-files/resolver.js +1 -21
  44. package/dist/main/services/simulator-temp-files/store.d.ts +1 -13
  45. package/dist/main/services/simulator-temp-files/store.js +1 -23
  46. package/dist/main/services/views/miniapp-partition.d.ts +1 -89
  47. package/dist/main/services/views/miniapp-partition.js +1 -158
  48. package/dist/main/services/views/simulator-session-policy.d.ts +1 -27
  49. package/dist/main/services/views/simulator-session-policy.js +1 -98
  50. package/dist/main/services/workbench-context.d.ts +4 -1
  51. package/dist/main/services/workbench-context.js +17 -0
  52. package/dist/main/utils/ipc-registry.d.ts +21 -3
  53. package/dist/main/utils/ipc-registry.js +26 -23
  54. package/dist/main/utils/paths.d.ts +14 -0
  55. package/dist/main/utils/paths.js +14 -0
  56. package/dist/main/windows/service-host-window/create.d.ts +1 -92
  57. package/dist/main/windows/service-host-window/create.js +1 -154
  58. package/dist/native-host/common/common.js +154 -58
  59. package/dist/native-host/container/pageFrame.css +1 -1
  60. package/dist/native-host/render/render.js +6611 -3312
  61. package/dist/native-host/service/service.js +2 -2
  62. package/dist/preload/index.d.ts +2 -0
  63. package/dist/preload/index.js +1 -0
  64. package/dist/preload/runtime/clipboard.d.ts +6 -0
  65. package/dist/preload/runtime/clipboard.js +12 -0
  66. package/dist/preload/runtime/native-host.d.ts +2 -0
  67. package/dist/preload/runtime/native-host.js +5 -10
  68. package/dist/preload/runtime/node-bindings.d.ts +18 -0
  69. package/dist/preload/runtime/node-bindings.js +44 -0
  70. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  71. package/dist/preload/windows/main.cjs +1195 -897
  72. package/dist/preload/windows/main.cjs.map +4 -4
  73. package/dist/preload/windows/simulator.cjs +149 -60
  74. package/dist/preload/windows/simulator.cjs.map +4 -4
  75. package/dist/preload/windows/simulator.js +149 -60
  76. package/dist/render-host/pageFrame.html +3 -3
  77. package/dist/shared/bridge-channels.d.ts +1 -419
  78. package/dist/shared/bridge-channels.js +1 -89
  79. package/dist/shared/dmb-resource-url.d.ts +2 -0
  80. package/dist/shared/dmb-resource-url.js +2 -0
  81. package/dist/shared/ipc-channels.d.ts +2 -32
  82. package/dist/shared/ipc-channels.js +2 -5
  83. package/dist/shared/node-bindings.d.ts +2 -0
  84. package/dist/shared/node-bindings.js +2 -0
  85. package/dist/shared/request-core.d.ts +1 -83
  86. package/dist/shared/request-core.js +1 -167
  87. package/dist/simulator/assets/device-shell-Cw7c-IkG.js +2 -0
  88. package/dist/simulator/assets/{device-shell-BHz1v3Yo.css → device-shell-DbC5ccs8.css} +1 -1
  89. package/dist/simulator/assets/{jsx-runtime-hBv-rHqQ.js → jsx-runtime-DkKmJyBb.js} +2 -2
  90. package/dist/simulator/assets/simulator-COIE6R49.js +10 -0
  91. package/dist/simulator/assets/simulator-mini-app-BLn7XV8e.js +2 -0
  92. package/dist/simulator/simulator.html +2 -2
  93. package/dist/simulator/temp-files.d.ts +29 -0
  94. package/dist/simulator/temp-files.js +79 -0
  95. package/dist/simulator/types.d.ts +43 -0
  96. package/dist/simulator/types.js +2 -0
  97. package/package.json +6 -5
  98. package/dist/shared/simulator-api-metadata.d.ts +0 -26
  99. package/dist/shared/simulator-api-metadata.js +0 -59
  100. package/dist/shared/vpath.d.ts +0 -42
  101. package/dist/shared/vpath.js +0 -105
  102. package/dist/simulator/assets/device-shell-CH_DMYaz.js +0 -2
  103. package/dist/simulator/assets/simulator-DXraYerh.js +0 -10
  104. package/dist/simulator/assets/simulator-mini-app-w1Bhwkld.js +0 -2
@@ -1,364 +1,2 @@
1
- import { BrowserWindow } from 'electron';
2
- /** Blank placeholder URL loaded while warming / after reset. */
3
- const BLANK_URL = 'about:blank';
4
- /** Hard ceiling on pool size regardless of requested size (see prewarm-webview.md). */
5
- const HARD_MAX_POOL_SIZE = 4;
6
- /** Storage buckets cleared on every release (see prewarm-webview.md's reset checklist). */
7
- const RESET_STORAGES = [
8
- 'cookies',
9
- 'localstorage',
10
- 'indexdb',
11
- 'serviceworkers',
12
- 'cachestorage',
13
- ];
14
- export class ServiceHostPool {
15
- entries = new Map();
16
- currentSpec = null;
17
- targetSize = 0;
18
- maxPoolSize = 3;
19
- nextId = 0;
20
- disposed = false;
21
- /**
22
- * Warm `defaultPoolSize` entries with `defaultSpec`. Normally resolves once the
23
- * pool has reached `defaultPoolSize` ready entries — even if a warming window
24
- * crashes mid-init and is refilled. NOTE: `warmUpToTarget` caps its refill loop
25
- * with a bounded guard, so under SUSTAINED warm crashes `init` resolves
26
- * best-effort (possibly under-filled) rather than spinning forever — treat
27
- * `getStats().ready` as advisory after init, not a hard invariant.
28
- */
29
- async init(opts) {
30
- if (this.disposed)
31
- return;
32
- this.currentSpec = opts.defaultSpec;
33
- this.maxPoolSize = Math.min(opts.maxPoolSize ?? 3, HARD_MAX_POOL_SIZE);
34
- this.targetSize = Math.min(Math.max(opts.defaultPoolSize, 0), this.maxPoolSize);
35
- await this.warmUpToTarget();
36
- }
37
- /**
38
- * Hand a ready window matching `spec` to the caller. If none is ready, fall
39
- * back to synchronously constructing a fresh window — never blocking on warm
40
- * (see prewarm-webview.md's invariants section). Fallback windows carry `entryId === null` and
41
- * are destroyed (not pooled) on release.
42
- *
43
- * A spec change (different `preloadPath`) tears down all *pooled* entries and
44
- * re-targets the pool to the new spec; in-use entries are left to their owners
45
- * and disposed when returned (see `release`).
46
- */
47
- async acquire(spec) {
48
- if (this.currentSpec && this.currentSpec.preloadPath !== spec.preloadPath) {
49
- this.onSpecChange(spec);
50
- }
51
- else if (!this.currentSpec) {
52
- this.currentSpec = spec;
53
- }
54
- for (const entry of this.entries.values()) {
55
- if (entry.state === 'ready' && this.matches(entry.spec, spec)) {
56
- // A ready entry whose window died (closed/crashed) while idle must never
57
- // be handed out — navigating a destroyed WebContents silently no-ops the
58
- // spawn. Drop it (and refill) and keep scanning.
59
- if (entry.win.isDestroyed()) {
60
- this.reclaim(entry, { destroyIfPooled: false, refill: false });
61
- continue;
62
- }
63
- entry.state = 'in-use';
64
- return { win: entry.win, entryId: entry.id };
65
- }
66
- }
67
- // Pool miss → fallback create. Not pooled; entryId null.
68
- const win = this.createWindow(spec);
69
- // Kick the load but do not await — acquire must not block.
70
- void this.loadBlank(win);
71
- return { win, entryId: null };
72
- }
73
- /**
74
- * Return a window. Fallback windows (`entryId === null`) and entries whose
75
- * spec no longer matches the current pool spec are torn down. Otherwise the
76
- * window is reset (navigated to blank, then storage cleared) and re-pooled as
77
- * `ready`, unless that would exceed `maxPoolSize`.
78
- */
79
- async release(entryId, win) {
80
- if (entryId === null) {
81
- this.destroyWindow(win);
82
- return;
83
- }
84
- const entry = this.entries.get(entryId);
85
- if (!entry) {
86
- this.destroyWindow(win);
87
- return;
88
- }
89
- if (this.disposed || !this.currentSpec || !this.matches(entry.spec, this.currentSpec)) {
90
- this.disposeEntry(entry);
91
- return;
92
- }
93
- entry.state = 'resetting';
94
- await this.reset(entry);
95
- // The entry may have been disposed/crashed/spec-changed/destroyed underneath
96
- // the reset await; only re-pool if it is still the live, resetting entry with
97
- // a live window. A destroyed window must never be re-marked `ready` (a later
98
- // acquire would hand it out and the spawn would silently never boot).
99
- if (this.disposed
100
- || this.entries.get(entryId) !== entry
101
- || entry.state !== 'resetting'
102
- || entry.win.isDestroyed()) {
103
- this.destroyWindow(entry.win);
104
- this.entries.delete(entryId);
105
- return;
106
- }
107
- // Honor the hard cap: if re-pooling would exceed maxPoolSize, drop it.
108
- const otherPooled = this.warmCount() - (this.isWarm(entry) ? 1 : 0);
109
- if (otherPooled >= this.maxPoolSize) {
110
- this.disposeEntry(entry);
111
- return;
112
- }
113
- entry.state = 'ready';
114
- }
115
- /**
116
- * The owner of an acquired window reports it died externally (graceful close /
117
- * crash) — reclaim its in-use slot so it isn't leaked in `entries` forever
118
- * (bridge-router calls this on the `serviceAlreadyClosed` teardown path, where
119
- * `release` is intentionally skipped). No-op for an unknown id; idempotent;
120
- * never touches the (already-gone) window.
121
- */
122
- releaseDestroyed(entryId) {
123
- if (entryId === null)
124
- return;
125
- const entry = this.entries.get(entryId);
126
- if (!entry)
127
- return;
128
- this.reclaim(entry, { destroyIfPooled: false, refill: false });
129
- }
130
- /**
131
- * Re-target the pool. `target` is clamped to `[0, maxPoolSize]`. Pooled
132
- * entries beyond the target are disposed OLDEST-FIRST (see prewarm-webview.md); in-use
133
- * entries are untouched. Does not warm new entries up (use `init` / refill).
134
- */
135
- resize(target) {
136
- this.targetSize = Math.min(Math.max(target, 0), this.maxPoolSize);
137
- // Map iteration is insertion order, so `pooled` is oldest-first. Dispose the
138
- // oldest prefix and keep the `targetSize` most-recently-created entries.
139
- const pooled = [...this.entries.values()].filter((e) => this.isWarm(e));
140
- const surplus = pooled.length - this.targetSize;
141
- if (surplus <= 0)
142
- return;
143
- for (const entry of pooled.slice(0, surplus)) {
144
- this.disposeEntry(entry);
145
- }
146
- }
147
- /** Occupancy snapshot. */
148
- getStats() {
149
- let ready = 0;
150
- let inUse = 0;
151
- let warming = 0;
152
- let resetting = 0;
153
- for (const entry of this.entries.values()) {
154
- switch (entry.state) {
155
- case 'ready':
156
- ready++;
157
- break;
158
- case 'in-use':
159
- inUse++;
160
- break;
161
- case 'warming':
162
- warming++;
163
- break;
164
- case 'resetting':
165
- resetting++;
166
- break;
167
- }
168
- }
169
- return { total: this.entries.size, ready, inUse, warming, resetting, spec: this.currentSpec };
170
- }
171
- /** Tear down every entry and stop accepting work. */
172
- async dispose() {
173
- this.disposed = true;
174
- this.targetSize = 0;
175
- for (const entry of [...this.entries.values()]) {
176
- this.disposeEntry(entry);
177
- }
178
- }
179
- // ── internals ──────────────────────────────────────────────────────────
180
- matches(a, b) {
181
- return a.preloadPath === b.preloadPath;
182
- }
183
- /** ready + warming + resetting entries are "pooled" (owned by the pool). */
184
- isWarm(entry) {
185
- return entry.state === 'ready' || entry.state === 'warming' || entry.state === 'resetting';
186
- }
187
- warmCount() {
188
- let n = 0;
189
- for (const entry of this.entries.values()) {
190
- if (this.isWarm(entry))
191
- n++;
192
- }
193
- return n;
194
- }
195
- readyCount() {
196
- let n = 0;
197
- for (const entry of this.entries.values()) {
198
- if (entry.state === 'ready')
199
- n++;
200
- }
201
- return n;
202
- }
203
- /**
204
- * Drive the pool to `targetSize` ready entries and resolve only then. Loops so
205
- * a crash that drops a warming entry mid-init (which refills asynchronously
206
- * via `onGone`) is awaited too, instead of resolving on a stale snapshot. A
207
- * generous iteration guard prevents an unbounded spin if windows keep dying.
208
- */
209
- async warmUpToTarget() {
210
- if (!this.currentSpec)
211
- return;
212
- let guard = 0;
213
- const maxIterations = this.targetSize * 8 + 8;
214
- while (!this.disposed && this.readyCount() < this.targetSize && guard++ < maxIterations) {
215
- while (this.warmCount() < this.targetSize) {
216
- void this.warmOne(this.currentSpec);
217
- }
218
- const warming = [...this.entries.values()]
219
- .filter((e) => e.state === 'warming')
220
- .map((e) => e.ready);
221
- if (warming.length === 0)
222
- break;
223
- await Promise.all(warming);
224
- }
225
- }
226
- createWindow(spec) {
227
- return new BrowserWindow({
228
- show: false,
229
- width: spec.size?.width,
230
- height: spec.size?.height,
231
- webPreferences: {
232
- preload: spec.preloadPath,
233
- partition: spec.partition,
234
- // Mirror createServiceHostWindow's process model (create.ts:24-30): the
235
- // service-host preload does `require('electron')` and writes globals
236
- // onto the page realm, so it requires nodeIntegration:false,
237
- // contextIsolation:false, sandbox:false. Default to that contract; let a
238
- // caller override via the spec for a different runtime.
239
- nodeIntegration: spec.nodeIntegration ?? false,
240
- contextIsolation: spec.contextIsolation ?? false,
241
- sandbox: spec.sandbox ?? false,
242
- },
243
- });
244
- }
245
- loadBlank(win) {
246
- // `loadURL` resolves on did-finish-load in Electron; treat any failure as a
247
- // settled load so a single bad warm never wedges the pool. The synchronous
248
- // call ITSELF throws on an already-destroyed webContents (it isn't a
249
- // rejection) — swallow that too, so reset/release of a window that died
250
- // mid-flight resolves instead of rejecting (the "never wedges" contract).
251
- try {
252
- return Promise.resolve(win.webContents.loadURL(BLANK_URL)).then(() => undefined, () => undefined);
253
- }
254
- catch {
255
- return Promise.resolve();
256
- }
257
- }
258
- /** Construct + load a fresh pooled entry, registering crash recovery. */
259
- warmOne(spec) {
260
- const win = this.createWindow(spec);
261
- const id = `pool-${++this.nextId}`;
262
- const entry = { id, spec, state: 'warming', win, ready: Promise.resolve() };
263
- this.entries.set(id, entry);
264
- win.webContents.on('render-process-gone', () => this.onGone(entry));
265
- // A window can also die by graceful close (app quit / manual close), which
266
- // never fires render-process-gone. Observe it too so a pooled entry isn't
267
- // leaked. reclaim is a no-op if WE disposed it (disposeEntry deletes the
268
- // entry before its own destroy fires 'closed').
269
- win.once('closed', () => this.reclaim(entry, { destroyIfPooled: false, refill: false }));
270
- entry.ready = this.loadBlank(win).then(() => {
271
- if (entry.state === 'warming')
272
- entry.state = 'ready';
273
- });
274
- return entry.ready;
275
- }
276
- /**
277
- * Reset a released window back to a clean, blank state. Order matters
278
- * (see prewarm-webview.md's state-machine and reset-ordering sections): navigate to blank FIRST so the old document
279
- * stops running and in-flight requests are aborted, THEN clear storage — so a
280
- * still-live old page cannot re-populate storage after the clear.
281
- */
282
- async reset(entry) {
283
- await this.loadBlank(entry.win);
284
- // Consumers sharing a session opt out of the storage clear (see
285
- // ServiceHostSpec.clearStorageOnReset): clearing a shared partition would wipe
286
- // other live projects. Navigation-to-blank above still resets the JS realm.
287
- if (entry.spec.clearStorageOnReset === false)
288
- return;
289
- // The window may have been destroyed during the load await; touching a dead
290
- // webContents.session throws SYNCHRONOUSLY, which would reject release().
291
- if (entry.win.isDestroyed())
292
- return;
293
- try {
294
- const ses = entry.win.webContents.session;
295
- await ses.clearStorageData({ storages: [...RESET_STORAGES] });
296
- await ses.clearCache();
297
- }
298
- catch {
299
- // Window/session torn down mid-reset — release() re-checks isDestroyed and
300
- // disposes the entry, so swallowing here keeps release from rejecting.
301
- }
302
- }
303
- /** A spec change tears down pooled entries and re-targets the pool. */
304
- onSpecChange(spec) {
305
- for (const entry of [...this.entries.values()]) {
306
- if (this.isWarm(entry))
307
- this.disposeEntry(entry);
308
- }
309
- this.currentSpec = spec;
310
- }
311
- /**
312
- * Reclaim an entry whose window died externally (render crash, graceful close,
313
- * or an owner-reported destruction). A POOLED death frees a spare → refill
314
- * toward target; an IN-USE death is the caller's window → drop the bookkeeping
315
- * WITHOUT destroying it from under them, and do not refill (the spare count is
316
- * unaffected). `destroyIfPooled` destroys the husk for a pooled render crash
317
- * (the BrowserWindow object can outlive a dead render process); skip it for a
318
- * `'closed'`/owner-reported window that is already gone. No-op if the entry was
319
- * already disposed by us (disposeEntry deletes before its own destroy fires
320
- * `'closed'`, so this finds nothing).
321
- */
322
- reclaim(entry, opts) {
323
- if (!this.entries.has(entry.id))
324
- return;
325
- const wasPooled = this.isWarm(entry);
326
- entry.state = 'disposing';
327
- this.entries.delete(entry.id);
328
- if (wasPooled && opts.destroyIfPooled)
329
- this.destroyWindow(entry.win);
330
- // Refill ONLY on crash recovery (onGone). A graceful `'closed'` on a pooled
331
- // window happens exclusively at app/project teardown (the windows are hidden;
332
- // nothing else closes them) — refilling there would `new BrowserWindow` while
333
- // Electron is trying to quit, recreating windows faster than they close and
334
- // hanging the shutdown. So `refill` is opt-in per caller.
335
- if (!opts.refill || this.disposed || !this.currentSpec || !wasPooled)
336
- return;
337
- while (this.warmCount() < this.targetSize) {
338
- void this.warmOne(this.currentSpec);
339
- }
340
- }
341
- /** A pooled window's render process died — reclaim + refill (destroy the husk). */
342
- onGone(entry) {
343
- this.reclaim(entry, { destroyIfPooled: true, refill: true });
344
- }
345
- disposeEntry(entry) {
346
- entry.state = 'disposing';
347
- this.entries.delete(entry.id);
348
- this.destroyWindow(entry.win);
349
- }
350
- destroyWindow(win) {
351
- try {
352
- if (!win || (typeof win.isDestroyed === 'function' && win.isDestroyed()))
353
- return;
354
- if (typeof win.destroy === 'function')
355
- win.destroy();
356
- else if (typeof win.close === 'function')
357
- win.close();
358
- }
359
- catch {
360
- // A window already gone (e.g. crashed process) is fine to ignore.
361
- }
362
- }
363
- }
1
+ export * from '@dimina-kit/electron-runtime/main/service-host-pool';
364
2
  //# sourceMappingURL=pool.js.map
@@ -1,43 +1,2 @@
1
- export type SimulatorApiHandler = (params: unknown) => unknown | Promise<unknown>;
2
- export interface SimulatorApiRegistry {
3
- register(name: string, handler: SimulatorApiHandler): () => void;
4
- list(): string[];
5
- has(name: string): boolean;
6
- invoke(name: string, params: unknown): Promise<unknown>;
7
- clear(): void;
8
- }
9
- /**
10
- * Bridge request/response shapes shared by the simulator-side preload
11
- * (`src/preload/runtime/custom-apis.ts`) and the two host-side dispatchers that
12
- * service it (the trusted main-window renderer proxy was the original path; the
13
- * native-host top-level WebContentsView dispatcher in the ViewManager is the
14
- * current one). Kept here next to the registry so both stay in lockstep with
15
- * the preload contract.
16
- */
17
- export type CustomApiBridgeRequest = {
18
- id: number;
19
- op: 'list';
20
- } | {
21
- id: number;
22
- op: 'invoke';
23
- name: string;
24
- params: unknown;
25
- };
26
- export type CustomApiBridgeResponse = {
27
- id: number;
28
- result: unknown;
29
- } | {
30
- id: number;
31
- error: string;
32
- };
33
- /**
34
- * Run a single custom-apis bridge request against the given registry and return
35
- * the id-correlated response the preload's pending-map expects. Never throws:
36
- * a handler rejection / malformed request becomes an `{ id, error }` response so
37
- * the caller only has to ship it back over the bridge channel. The one shared
38
- * implementation behind both the `SimulatorCustomApiChannel` IPC handlers and
39
- * the native-host `ipc-message-host` dispatcher.
40
- */
41
- export declare function handleCustomApiBridgeRequest(apis: Pick<SimulatorApiRegistry, 'list' | 'invoke'>, req: CustomApiBridgeRequest): Promise<CustomApiBridgeResponse>;
42
- export declare function createSimulatorApiRegistry(): SimulatorApiRegistry;
1
+ export * from '@dimina-kit/electron-runtime/main/custom-apis';
43
2
  //# sourceMappingURL=custom-apis.d.ts.map
@@ -1,47 +1,2 @@
1
- /**
2
- * Run a single custom-apis bridge request against the given registry and return
3
- * the id-correlated response the preload's pending-map expects. Never throws:
4
- * a handler rejection / malformed request becomes an `{ id, error }` response so
5
- * the caller only has to ship it back over the bridge channel. The one shared
6
- * implementation behind both the `SimulatorCustomApiChannel` IPC handlers and
7
- * the native-host `ipc-message-host` dispatcher.
8
- */
9
- export async function handleCustomApiBridgeRequest(apis, req) {
10
- try {
11
- const result = req.op === 'list'
12
- ? apis.list()
13
- : await apis.invoke(req.name, req.params);
14
- return { id: req.id, result };
15
- }
16
- catch (err) {
17
- return { id: req.id, error: err instanceof Error ? err.message : String(err) };
18
- }
19
- }
20
- export function createSimulatorApiRegistry() {
21
- const handlers = new Map();
22
- return {
23
- register(name, handler) {
24
- handlers.set(name, handler);
25
- return () => {
26
- if (handlers.get(name) === handler)
27
- handlers.delete(name);
28
- };
29
- },
30
- list() {
31
- return Array.from(handlers.keys());
32
- },
33
- has(name) {
34
- return handlers.has(name);
35
- },
36
- async invoke(name, params) {
37
- const handler = handlers.get(name);
38
- if (!handler)
39
- throw new Error(`Simulator API "${name}" is not registered`);
40
- return await handler(params);
41
- },
42
- clear() {
43
- handlers.clear();
44
- },
45
- };
46
- }
1
+ export * from '@dimina-kit/electron-runtime/main/custom-apis';
47
2
  //# sourceMappingURL=custom-apis.js.map
@@ -1,10 +1,2 @@
1
- /**
2
- * WeChat-style page-frame referer for HTTPS requests proxied from the simulator session.
3
- * Format: https://servicewechat.com/{appId}/{version}/page-frame.html
4
- */
5
- export declare function buildServicewechatPageFrameReferer(appId: string, version?: string): string;
6
- /** Called when a project session is active so protocol.handle can force Referer. */
7
- export declare function setSimulatorServicewechatReferer(appId: string, version?: string): void;
8
- export declare function clearSimulatorServicewechatReferer(): void;
9
- export declare function getSimulatorServicewechatReferer(): string | null;
1
+ export * from '@dimina-kit/electron-runtime/main/referer';
10
2
  //# sourceMappingURL=referer.d.ts.map
@@ -1,20 +1,2 @@
1
- /**
2
- * WeChat-style page-frame referer for HTTPS requests proxied from the simulator session.
3
- * Format: https://servicewechat.com/{appId}/{version}/page-frame.html
4
- */
5
- const DEFAULT_VERSION = 'develop';
6
- let cachedRefererUrl = null;
7
- export function buildServicewechatPageFrameReferer(appId, version = DEFAULT_VERSION) {
8
- return `https://servicewechat.com/${appId}/${version}/page-frame.html`;
9
- }
10
- /** Called when a project session is active so protocol.handle can force Referer. */
11
- export function setSimulatorServicewechatReferer(appId, version) {
12
- cachedRefererUrl = buildServicewechatPageFrameReferer(appId, version && version.length > 0 ? version : DEFAULT_VERSION);
13
- }
14
- export function clearSimulatorServicewechatReferer() {
15
- cachedRefererUrl = null;
16
- }
17
- export function getSimulatorServicewechatReferer() {
18
- return cachedRefererUrl;
19
- }
1
+ export * from '@dimina-kit/electron-runtime/main/referer';
20
2
  //# sourceMappingURL=referer.js.map
@@ -1,40 +1,2 @@
1
- /**
2
- * service-storage-ops — localStorage primitives executed INSIDE the service-host
3
- * window (`wc`) via `executeJavaScript`, plus the wx-storage value encode/decode
4
- * pair.
5
- *
6
- * Under native-host the mini-app's storage lives on the service-host window's
7
- * `file://` origin (sync APIs write there via sync-impls/storage.ts, and the
8
- * unified async path routes there too). The Storage panel + the async-storage
9
- * runtime both read/write through here so there is exactly ONE store.
10
- *
11
- * The key/value scheme stays byte-compatible with
12
- * `src/service-host/sync-impls/storage.ts` (the authoritative wx storage impl):
13
- * - key = `${appId}_${key}`
14
- * - value = `typeof data === 'object' ? JSON.stringify(data) : String(data)`
15
- * - scoped clear removes every key whose name startsWith `${appId}_`
16
- *
17
- * Args are embedded via JSON.stringify so special characters can't break out of
18
- * the injected code. Reads tolerate failure (→ []/null); writes propagate so the
19
- * caller can fail the wx callback / surface the panel error.
20
- */
21
- import type { WebContents } from 'electron';
22
- /** Encode a wx storage value to its localStorage string form. Matches sync-impls/storage.ts. */
23
- export declare function encodeStorageValue(data: unknown): string;
24
- /** Decode a localStorage string back to a value (JSON.parse, falling back to the raw string). */
25
- export declare function decodeStorageValue(raw: string): unknown;
26
- export interface ServiceStorage {
27
- /** All [fullKey, value] entries whose key startsWith `prefix`. */
28
- readAll(prefix: string): Promise<Array<[string, string]>>;
29
- /** Raw value for a full (already-prefixed) key, or null if absent. */
30
- readOne(fullKey: string): Promise<string | null>;
31
- writeOne(fullKey: string, value: string): Promise<void>;
32
- removeOne(fullKey: string): Promise<void>;
33
- /** Remove every key whose name startsWith `prefix`. */
34
- clearPrefix(prefix: string): Promise<void>;
35
- /** Origin-wide localStorage.clear(). */
36
- clearAll(): Promise<void>;
37
- }
38
- /** localStorage ops executed inside `wc` (the service-host window) via executeJavaScript. */
39
- export declare function serviceStorage(wc: WebContents): ServiceStorage;
1
+ export * from '@dimina-kit/electron-runtime/main/service-storage-ops';
40
2
  //# sourceMappingURL=service-storage-ops.d.ts.map
@@ -1,67 +1,2 @@
1
- /** Encode a wx storage value to its localStorage string form. Matches sync-impls/storage.ts. */
2
- export function encodeStorageValue(data) {
3
- return typeof data === 'object' ? JSON.stringify(data) : String(data);
4
- }
5
- /** Decode a localStorage string back to a value (JSON.parse, falling back to the raw string). */
6
- export function decodeStorageValue(raw) {
7
- try {
8
- return JSON.parse(raw);
9
- }
10
- catch {
11
- return raw;
12
- }
13
- }
14
- /** localStorage ops executed inside `wc` (the service-host window) via executeJavaScript. */
15
- export function serviceStorage(wc) {
16
- return {
17
- async readAll(prefix) {
18
- const code = `(() => {
19
- const out = []
20
- const p = ${JSON.stringify(prefix)}
21
- for (let i = 0; i < localStorage.length; i++) {
22
- const k = localStorage.key(i)
23
- if (k && k.startsWith(p)) out.push([k, localStorage.getItem(k)])
24
- }
25
- return out
26
- })()`;
27
- try {
28
- const result = await wc.executeJavaScript(code);
29
- return Array.isArray(result) ? result : [];
30
- }
31
- catch {
32
- return [];
33
- }
34
- },
35
- async readOne(fullKey) {
36
- try {
37
- const result = await wc.executeJavaScript(`localStorage.getItem(${JSON.stringify(fullKey)})`);
38
- return result === null || result === undefined ? null : String(result);
39
- }
40
- catch {
41
- return null;
42
- }
43
- },
44
- async writeOne(fullKey, value) {
45
- await wc.executeJavaScript(`localStorage.setItem(${JSON.stringify(fullKey)}, ${JSON.stringify(value)})`);
46
- },
47
- async removeOne(fullKey) {
48
- await wc.executeJavaScript(`localStorage.removeItem(${JSON.stringify(fullKey)})`);
49
- },
50
- async clearPrefix(prefix) {
51
- const code = `(() => {
52
- const p = ${JSON.stringify(prefix)}
53
- const doomed = []
54
- for (let i = 0; i < localStorage.length; i++) {
55
- const k = localStorage.key(i)
56
- if (k && k.startsWith(p)) doomed.push(k)
57
- }
58
- doomed.forEach((k) => localStorage.removeItem(k))
59
- })()`;
60
- await wc.executeJavaScript(code);
61
- },
62
- async clearAll() {
63
- await wc.executeJavaScript('localStorage.clear()');
64
- },
65
- };
66
- }
1
+ export * from '@dimina-kit/electron-runtime/main/service-storage-ops';
67
2
  //# sourceMappingURL=service-storage-ops.js.map
@@ -1,55 +1,2 @@
1
- /**
2
- * Main-process disk reader/writer backing `difile://_store/*` and
3
- * `difile://<usr-rel>` URLs.
4
- *
5
- * Spec: `packages/devtools/docs/file-system.md`.
6
- *
7
- * - `readDiskFile(realPath, opts?)`: read a (possibly ranged) slice of a
8
- * file inside the USER_DATA_PATH sandbox. Returns `bytes` plus the
9
- * content metadata callers need to assemble an HTTP response without a
10
- * second `fs.stat` round-trip (`mime`, `etag`, `totalSize`).
11
- * - `writeDiskFile(realPath, bytes)`: write bytes into the sandbox,
12
- * creating parent directories on demand. Accepts both `Buffer` and
13
- * `ArrayBuffer`.
14
- * - `readDiskDir(realPath)`: list immediate children, no '.' / '..'.
15
- * - `statDiskFile(realPath)`: minimal stat surface (size/mtime/mode/flags).
16
- *
17
- * The caller is responsible for canonicalizing `realPath` through
18
- * `resolveVPath` *before* invoking these helpers — disk.ts assumes the
19
- * argument is already known to be inside the sandbox base.
20
- *
21
- * MIME resolution prefers magic-byte sniffing (first ~12 bytes) over file
22
- * extension, falling back to `application/octet-stream` for both unknown
23
- * extensions and unknown magic.
24
- *
25
- * ETag shape is `W/"<mtime-ms>-<size>"` — weak validator, both axes folded
26
- * into one token so byte-equal rewrites at the same timestamp still match.
27
- */
28
- export interface DiskReadResult {
29
- bytes: Buffer;
30
- mime: string;
31
- /** Weak ETag of the form `W/"<mtime>-<size>"`. */
32
- etag: string;
33
- /** Full file size in bytes, regardless of whether a Range slice was returned. */
34
- totalSize: number;
35
- }
36
- export interface DiskReadOptions {
37
- /** Inclusive byte range `[start, end]`. Omit to read the whole file. */
38
- range?: {
39
- start: number;
40
- end: number;
41
- };
42
- }
43
- export interface DiskStat {
44
- size: number;
45
- /** Unix milliseconds. */
46
- mtime: number;
47
- mode: number;
48
- isFile: boolean;
49
- isDirectory: boolean;
50
- }
51
- export declare function readDiskFile(realPath: string, opts?: DiskReadOptions): Promise<DiskReadResult>;
52
- export declare function writeDiskFile(realPath: string, bytes: Buffer | ArrayBuffer): Promise<void>;
53
- export declare function readDiskDir(realPath: string): Promise<string[]>;
54
- export declare function statDiskFile(realPath: string): Promise<DiskStat>;
1
+ export * from '@dimina-kit/electron-runtime/main/temp-files/disk';
55
2
  //# sourceMappingURL=disk.d.ts.map