@dimina-kit/electron-deck 0.1.0-dev.20260610082053

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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/client/index.d.ts +20 -0
  4. package/dist/client/index.d.ts.map +1 -0
  5. package/dist/client/index.js +310 -0
  6. package/dist/client/index.js.map +1 -0
  7. package/dist/client/layout-client.d.ts +51 -0
  8. package/dist/client/layout-client.d.ts.map +1 -0
  9. package/dist/electron-deck-DfFKeFEC.js +2295 -0
  10. package/dist/electron-deck-DfFKeFEC.js.map +1 -0
  11. package/dist/electron-deck.d.ts +57 -0
  12. package/dist/electron-deck.d.ts.map +1 -0
  13. package/dist/errors-NE2ig7L5.js +53 -0
  14. package/dist/errors-NE2ig7L5.js.map +1 -0
  15. package/dist/errors.d.ts +33 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/events.d.ts +14 -0
  18. package/dist/events.d.ts.map +1 -0
  19. package/dist/host/capability.d.ts +50 -0
  20. package/dist/host/capability.d.ts.map +1 -0
  21. package/dist/host/control-bus.d.ts +92 -0
  22. package/dist/host/control-bus.d.ts.map +1 -0
  23. package/dist/host/index.d.ts +42 -0
  24. package/dist/host/index.d.ts.map +1 -0
  25. package/dist/host/index.js +2 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +3 -0
  29. package/dist/internal/deck-app.d.ts +415 -0
  30. package/dist/internal/deck-app.d.ts.map +1 -0
  31. package/dist/internal/electron-types.d.ts +131 -0
  32. package/dist/internal/electron-types.d.ts.map +1 -0
  33. package/dist/internal/event-bus.d.ts +29 -0
  34. package/dist/internal/event-bus.d.ts.map +1 -0
  35. package/dist/internal/ipc-registry-memory.d.ts +25 -0
  36. package/dist/internal/ipc-registry-memory.d.ts.map +1 -0
  37. package/dist/internal/lifecycle-manager.d.ts +28 -0
  38. package/dist/internal/lifecycle-manager.d.ts.map +1 -0
  39. package/dist/internal/resource-registry.d.ts +9 -0
  40. package/dist/internal/resource-registry.d.ts.map +1 -0
  41. package/dist/internal/trust-set.d.ts +53 -0
  42. package/dist/internal/trust-set.d.ts.map +1 -0
  43. package/dist/internal/wire-transport.d.ts +159 -0
  44. package/dist/internal/wire-transport.d.ts.map +1 -0
  45. package/dist/main/compositor.d.ts +123 -0
  46. package/dist/main/compositor.d.ts.map +1 -0
  47. package/dist/main/connection.d.ts +37 -0
  48. package/dist/main/connection.d.ts.map +1 -0
  49. package/dist/main/debug-tap.d.ts +55 -0
  50. package/dist/main/debug-tap.d.ts.map +1 -0
  51. package/dist/main/disposable.d.ts +18 -0
  52. package/dist/main/disposable.d.ts.map +1 -0
  53. package/dist/main/index.d.ts +16 -0
  54. package/dist/main/index.d.ts.map +1 -0
  55. package/dist/main/index.js +152 -0
  56. package/dist/main/index.js.map +1 -0
  57. package/dist/main/logger.d.ts +15 -0
  58. package/dist/main/logger.d.ts.map +1 -0
  59. package/dist/main/scope.d.ts +52 -0
  60. package/dist/main/scope.d.ts.map +1 -0
  61. package/dist/main/view-handle.d.ts +131 -0
  62. package/dist/main/view-handle.d.ts.map +1 -0
  63. package/dist/preload/index.cjs +105 -0
  64. package/dist/preload/index.cjs.map +1 -0
  65. package/dist/preload/index.d.ts +43 -0
  66. package/dist/preload/index.d.ts.map +1 -0
  67. package/dist/preload/index.js +80 -0
  68. package/dist/preload/index.js.map +1 -0
  69. package/dist/protocol-BJqo-vP2.js +23 -0
  70. package/dist/protocol-BJqo-vP2.js.map +1 -0
  71. package/dist/shared/protocol.d.ts +76 -0
  72. package/dist/shared/protocol.d.ts.map +1 -0
  73. package/dist/types.d.ts +504 -0
  74. package/dist/types.d.ts.map +1 -0
  75. package/dist/view-handle-CR-yWNfr.js +701 -0
  76. package/dist/view-handle-CR-yWNfr.js.map +1 -0
  77. package/package.json +86 -0
@@ -0,0 +1,57 @@
1
+ import type { DeckConfig, DeckOptions, Runtime } from './types.js';
2
+ /**
3
+ * `electronDeck(config, options?)` 是 framework 唯一入口(见 README §3)。
4
+ *
5
+ * - Invalid config → reject `TypeError`,phase 不前进
6
+ * - Valid config → 装配 runtime + 调 `config.setup(runtime)` await 完成 →
7
+ * resolve。Phase 2 不接 Electron,resolve 后 framework 仍持有运行时;
8
+ * Phase 4 接 Electron app lifecycle 后,由 Electron event loop 撑住进程,
9
+ * `electronDeck()` 同样 resolve(host 的 main 文件不需 await 阻塞)。
10
+ *
11
+ * backend host(如 devtools)走 `electronDeck({ backend })`——backend 是
12
+ * {@link DeckConfig} 的字段,不再需要空 `{}` + options。
13
+ *
14
+ * `options` 是测试 / 非 Electron 环境用的注入点(见 {@link DeckOptions})。
15
+ * 生产路径不传 options:framework `await import('electron')` 取真 `ipcMain` /
16
+ * `BrowserWindow` / `WebContentsView`。
17
+ */
18
+ export declare function electronDeck(config: DeckConfig, options?: DeckOptions): Promise<void>;
19
+ /**
20
+ * Synchronous launch handle for `electronDeck`.
21
+ *
22
+ * `electronDeck(config)` is `async` and internally `await app.start()` →
23
+ * `await app.whenReady()`. A host ESM main entry doing `await electronDeck(config)`
24
+ * SUSPENDS module evaluation on the whenReady gate — but Electron's `ready` only
25
+ * fires once module evaluation finishes, so the gate never resolves: HARD DEADLOCK.
26
+ *
27
+ * `startElectronDeck` returns a plain handle SYNCHRONOUSLY (NOT a thenable), so a
28
+ * host's top-level `await handle.ready` never sits on the whenReady gate. Assembly
29
+ * still runs STRICTLY AFTER `app.whenReady()` resolves (gating intact inside
30
+ * `app.start()`); `handle.ready` resolves with the {@link Runtime}; `handle.dispose()`
31
+ * tears the app down even if called before the in-flight start finished.
32
+ *
33
+ * Invalid config throws a `TypeError` synchronously (matching `electronDeck`'s
34
+ * validate-first contract) — the error surfaces, never silently deadlocks.
35
+ */
36
+ export declare function startElectronDeck(config: DeckConfig, options?: DeckOptions): {
37
+ ready: Promise<Runtime>;
38
+ dispose(): Promise<void>;
39
+ };
40
+ /**
41
+ * Pure validation:不依赖 Electron / IPC / 任何 framework state,可单独 unit
42
+ * test。每一条检查对应 doc §3.3 字段约束。
43
+ *
44
+ * 验证语义保证:通过 validateConfig 的 config 不会在 framework Bind 阶段被拒。
45
+ * 含 HostEvent 来源、source 互斥、map vs array 等所有"shape 就绪"检查。
46
+ *
47
+ * @internal exported for tests
48
+ */
49
+ export declare function validateConfig(config: DeckConfig): void;
50
+ /**
51
+ * publish-time guard:HostEvent 未在 `config.events` 中显式列出时阻止 publish。
52
+ * 避免 module-load-order 隐式注册。
53
+ *
54
+ * @internal exported for tests
55
+ */
56
+ export declare function assertEventDeclared(declared: ReadonlySet<string>, eventName: string): void;
57
+ //# sourceMappingURL=electron-deck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electron-deck.d.ts","sourceRoot":"","sources":["../src/electron-deck.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAElE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,WAAW,GACnB;IAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CA4CvD;AAyED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA6DvD;AAaD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,EAC7B,SAAS,EAAE,MAAM,GACf,IAAI,CAIN"}
@@ -0,0 +1,53 @@
1
+ //#region src/errors.ts
2
+ /**
3
+ * `defineEvent()` 创建的事件未在 `DeckConfig.events` 中显式列出时,
4
+ * `publish()` 会抛此错。避免 module-load-order 隐式注册。
5
+ */
6
+ var UndeclaredHostEventError = class extends Error {
7
+ eventName;
8
+ constructor(eventName) {
9
+ super(`HostEvent "${eventName}" was not declared in DeckConfig.events. Add it to the events array so the framework knows to bind a transport for it.`);
10
+ this.name = "UndeclaredHostEventError";
11
+ this.eventName = eventName;
12
+ }
13
+ };
14
+ /**
15
+ * 在 Init / Bind 阶段调用 `HostEvent.publish()` 时抛 —— transport 尚未就绪。
16
+ * Setup / Ready 之后调用是安全的(fire-and-forget,无 replay)。
17
+ */
18
+ var EventNotBoundError = class extends Error {
19
+ eventName;
20
+ constructor(eventName) {
21
+ super(`HostEvent "${eventName}" publish() called before transport is bound. publish() is safe only from Setup phase onward.`);
22
+ this.name = "EventNotBoundError";
23
+ this.eventName = eventName;
24
+ }
25
+ };
26
+ /**
27
+ * webview 调 `client.ready()` 时 framework bridge 不在 `window` 上(host preload
28
+ * 漏装 `exposeDeckBridge()`)。
29
+ */
30
+ var DeckClientNotReadyError = class extends Error {
31
+ constructor(message = "Deck framework bridge is missing on window — did the host preload call exposeDeckBridge()?") {
32
+ super(message);
33
+ this.name = "DeckClientNotReadyError";
34
+ }
35
+ };
36
+ /**
37
+ * `client.invoke(name, ...)` 时远端 hostServices handler 抛错的封装。
38
+ * 保留原 error message,附带 remoteName / 可选 code 让 webview 侧便于分类。
39
+ */
40
+ var DeckRemoteError = class extends Error {
41
+ remoteName;
42
+ code;
43
+ constructor(remoteName, message, code) {
44
+ super(message);
45
+ this.name = "DeckRemoteError";
46
+ this.remoteName = remoteName;
47
+ if (code !== void 0) this.code = code;
48
+ }
49
+ };
50
+ //#endregion
51
+ export { UndeclaredHostEventError as i, DeckRemoteError as n, EventNotBoundError as r, DeckClientNotReadyError as t };
52
+
53
+ //# sourceMappingURL=errors-NE2ig7L5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-NE2ig7L5.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * `defineEvent()` 创建的事件未在 `DeckConfig.events` 中显式列出时,\n * `publish()` 会抛此错。避免 module-load-order 隐式注册。\n */\nexport class UndeclaredHostEventError extends Error {\n\treadonly eventName: string\n\tconstructor(eventName: string) {\n\t\tsuper(\n\t\t\t`HostEvent \"${eventName}\" was not declared in DeckConfig.events. ` +\n\t\t\t\t`Add it to the events array so the framework knows to bind a transport for it.`,\n\t\t)\n\t\tthis.name = 'UndeclaredHostEventError'\n\t\tthis.eventName = eventName\n\t}\n}\n\n/**\n * 在 Init / Bind 阶段调用 `HostEvent.publish()` 时抛 —— transport 尚未就绪。\n * Setup / Ready 之后调用是安全的(fire-and-forget,无 replay)。\n */\nexport class EventNotBoundError extends Error {\n\treadonly eventName: string\n\tconstructor(eventName: string) {\n\t\tsuper(\n\t\t\t`HostEvent \"${eventName}\" publish() called before transport is bound. ` +\n\t\t\t\t`publish() is safe only from Setup phase onward.`,\n\t\t)\n\t\tthis.name = 'EventNotBoundError'\n\t\tthis.eventName = eventName\n\t}\n}\n\n/**\n * webview 调 `client.ready()` 时 framework bridge 不在 `window` 上(host preload\n * 漏装 `exposeDeckBridge()`)。\n */\nexport class DeckClientNotReadyError extends Error {\n\tconstructor(message = 'Deck framework bridge is missing on window — did the host preload call exposeDeckBridge()?') {\n\t\tsuper(message)\n\t\tthis.name = 'DeckClientNotReadyError'\n\t}\n}\n\n/**\n * `client.invoke(name, ...)` 时远端 hostServices handler 抛错的封装。\n * 保留原 error message,附带 remoteName / 可选 code 让 webview 侧便于分类。\n */\nexport class DeckRemoteError extends Error {\n\treadonly remoteName: string\n\treadonly code?: string\n\tconstructor(remoteName: string, message: string, code?: string) {\n\t\tsuper(message)\n\t\tthis.name = 'DeckRemoteError'\n\t\tthis.remoteName = remoteName\n\t\tif (code !== undefined) this.code = code\n\t}\n}\n"],"mappings":";;;;;AAIA,IAAa,2BAAb,cAA8C,MAAM;CACnD;CACA,YAAY,WAAmB;EAC9B,MACC,cAAc,UAAU,uHAEzB;EACA,KAAK,OAAO;EACZ,KAAK,YAAY;CAClB;AACD;;;;;AAMA,IAAa,qBAAb,cAAwC,MAAM;CAC7C;CACA,YAAY,WAAmB;EAC9B,MACC,cAAc,UAAU,8FAEzB;EACA,KAAK,OAAO;EACZ,KAAK,YAAY;CAClB;AACD;;;;;AAMA,IAAa,0BAAb,cAA6C,MAAM;CAClD,YAAY,UAAU,8FAA8F;EACnH,MAAM,OAAO;EACb,KAAK,OAAO;CACb;AACD;;;;;AAMA,IAAa,kBAAb,cAAqC,MAAM;CAC1C;CACA;CACA,YAAY,YAAoB,SAAiB,MAAe;EAC/D,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,aAAa;EAClB,IAAI,SAAS,KAAA,GAAW,KAAK,OAAO;CACrC;AACD"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `defineEvent()` 创建的事件未在 `DeckConfig.events` 中显式列出时,
3
+ * `publish()` 会抛此错。避免 module-load-order 隐式注册。
4
+ */
5
+ export declare class UndeclaredHostEventError extends Error {
6
+ readonly eventName: string;
7
+ constructor(eventName: string);
8
+ }
9
+ /**
10
+ * 在 Init / Bind 阶段调用 `HostEvent.publish()` 时抛 —— transport 尚未就绪。
11
+ * Setup / Ready 之后调用是安全的(fire-and-forget,无 replay)。
12
+ */
13
+ export declare class EventNotBoundError extends Error {
14
+ readonly eventName: string;
15
+ constructor(eventName: string);
16
+ }
17
+ /**
18
+ * webview 调 `client.ready()` 时 framework bridge 不在 `window` 上(host preload
19
+ * 漏装 `exposeDeckBridge()`)。
20
+ */
21
+ export declare class DeckClientNotReadyError extends Error {
22
+ constructor(message?: string);
23
+ }
24
+ /**
25
+ * `client.invoke(name, ...)` 时远端 hostServices handler 抛错的封装。
26
+ * 保留原 error message,附带 remoteName / 可选 code 让 webview 侧便于分类。
27
+ */
28
+ export declare class DeckRemoteError extends Error {
29
+ readonly remoteName: string;
30
+ readonly code?: string;
31
+ constructor(remoteName: string, message: string, code?: string);
32
+ }
33
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;gBACd,SAAS,EAAE,MAAM;CAQ7B;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;gBACd,SAAS,EAAE,MAAM;CAQ7B;AAED;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACrC,OAAO,SAA+F;CAIlH;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;gBACV,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAM9D"}
@@ -0,0 +1,14 @@
1
+ import type { HostEvent, JsonValue } from './types.js';
2
+ export declare function defineEvent<P extends JsonValue>(name: string): HostEvent<P>;
3
+ /**
4
+ * 校验 `ev` 是否真的来自 `defineEvent()`。判定方式是 WeakMap 身份,而非
5
+ * `instanceof` —— 这样跨 vm.Context(同 module instance)也能工作。
6
+ *
7
+ * @internal
8
+ */
9
+ export declare function isHostEvent(ev: unknown): ev is HostEvent<JsonValue>;
10
+ /** @internal framework 在 Bind 阶段调;同实例重复 bind 覆盖前任 */
11
+ export declare function bindHostEvent<P extends JsonValue>(event: HostEvent<P>, publisher: (payload: P) => void): void;
12
+ /** @internal framework 在 Cleanup 阶段调 */
13
+ export declare function unbindHostEvent<P extends JsonValue>(event: HostEvent<P>): void;
14
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AA0DlE,wBAAgB,WAAW,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAK3E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,SAAS,CAAC,SAAS,CAAC,CAGnE;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,CAAC,SAAS,SAAS,EAChD,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,GAC7B,IAAI,CAQN;AAED,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAM9E"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Capability grant registry — P4 Phase B.
3
+ *
4
+ * Default-DENY authorization for privileged control commands. A command is
5
+ * allowed for a sender ONLY while a LIVE grant naming that command (exact,
6
+ * whitelisted) is bound to that exact senderId. A grant dies the instant its
7
+ * `senderScope` generation ends: navigation soft-reuse (`reset`), window
8
+ * destroy (`closed`), or early `dispose()`.
9
+ *
10
+ * Each grant is a DISTINCT object stored in a Set, so two grants for the same
11
+ * senderId union their commands, and revoking one (its `senderScope` died)
12
+ * never touches another grant for that same senderId. The per-grant `revoked`
13
+ * guard makes a closed scope's revoke a no-op against a newly-issued grant —
14
+ * the wc.id-reuse safety property.
15
+ *
16
+ * @internal exported via `/host`.
17
+ */
18
+ import type { Disposable } from '../types.js';
19
+ import type { Scope } from '../main/scope.js';
20
+ export interface Grant {
21
+ readonly senderId: number;
22
+ /** grant lifetime — revoked on this scope's reset/closed. */
23
+ readonly senderScope: Scope;
24
+ /**
25
+ * OPTIONAL — stored as the authorization boundary for FUTURE per-target
26
+ * view-command checks; the current grant gate authorizes by (senderId,
27
+ * command-name) only — no command resolves a target view yet, so targetScope is
28
+ * not consulted at dispatch. Reserved.
29
+ */
30
+ readonly targetScope?: Scope;
31
+ readonly commands: ReadonlySet<string>;
32
+ }
33
+ export interface CapabilityPolicy {
34
+ /** true iff a LIVE grant exists with grant.senderId === senderId AND name ∈ grant.commands. default-DENY. */
35
+ allows(senderId: number, name: string): boolean;
36
+ }
37
+ export declare function createCapabilityRegistry(): {
38
+ policy: CapabilityPolicy;
39
+ issue(grant: Grant): Disposable;
40
+ /**
41
+ * Synchronously revoke EVERY live grant whose `grant.senderId === senderId`.
42
+ * Mirrors the trust path's synchronous window-'closed' revocation so a grant
43
+ * is gone the instant a wc is destroyed — before the async wcScope cascade
44
+ * fires `'closed'`. This closes the wc.id-reuse privilege-escalation window
45
+ * (a reused wc.id can never inherit the old, not-yet-revoked grant). Each
46
+ * per-grant `revoke` is idempotent, so the later async `'closed'` is a no-op.
47
+ */
48
+ revokeBySenderId(senderId: number): void;
49
+ };
50
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/host/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,WAAW,KAAK;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAA;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,gBAAgB;IAChC,6GAA6G;IAC7G,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAC/C;AAED,wBAAgB,wBAAwB,IAAI;IAC3C,MAAM,EAAE,gBAAgB,CAAA;IACxB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,CAAA;IAC/B;;;;;;;OAOG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxC,CAsCA"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * ControlBus — a thin, domain-neutral facade over the existing
3
+ * {@link WireTransport} + {@link EventBus} + an injectable refcount
4
+ * {@link TrustSet}.
5
+ *
6
+ * Three verbs, no new gating logic of its own:
7
+ *
8
+ * - `command(name, handler)` : webview → main RPC. The facade owns the single
9
+ * command table and exposes {@link ControlBus.dispatch}; the wire's
10
+ * `invokeHost` (and `invokeSimulator`) seam calls `dispatch(name, args)` so a
11
+ * real webview→main invoke (after the wire's sender + main-frame gate) lands on
12
+ * the registered handler. Callers never see the wire `kind`. Trust + main-frame
13
+ * gating are entirely the wire's (`handleInvoke`): a trusted main-frame sender
14
+ * reaches the handler, an untrusted sender → `DECK_UNTRUSTED_SENDER`, a
15
+ * sub-frame → `DECK_UNTRUSTED_FRAME`.
16
+ * - `event(name)` : main → webview push, default-deny. `name` is added to the
17
+ * declared-event allowlist the wire reads; `publish` goes through `bus.publish`
18
+ * → wire fanout (undeclared names are dropped by the wire). `dispose` revokes
19
+ * the declaration.
20
+ * - `trust(wc, owner)` : delegates to `trustSet.admit` (refcount membership owned
21
+ * by `owner` Scope, so the lease is released when the owner tears down).
22
+ *
23
+ * Real wiring (Bug C): the command table is the SOLE command authority. The
24
+ * production caller builds the {@link WireTransport} with
25
+ * `invokeHost = (name, args) => controlBus.dispatch(name, args)` (and the same
26
+ * for `invokeSimulator`, since the facade hides the kind), and `declaredEvents`
27
+ * reading {@link ControlBus.declaredEvents}. So a real IPC invoke reaches the
28
+ * command handler through the wire — not a private test-only seam. Any
29
+ * config-declared host services register into this SAME table via `command()`,
30
+ * so there is one namespace (the host keeps names unique), never two registries
31
+ * that can collide.
32
+ *
33
+ * @internal exported via `/host`.
34
+ */
35
+ import type { Disposable, JsonValue } from '../types.js';
36
+ import type { EventBus } from '../internal/event-bus.js';
37
+ import type { InvokeCtx, MinimalWebContents, WireTransport } from '../internal/wire-transport.js';
38
+ import type { TrustSet } from '../internal/trust-set.js';
39
+ import type { Scope } from '../main/scope.js';
40
+ import type { CapabilityPolicy } from './capability.js';
41
+ export type { TrustSet };
42
+ export { createTrustSet } from '../internal/trust-set.js';
43
+ type CommandHandler = (...args: JsonValue[]) => JsonValue | Promise<JsonValue>;
44
+ export interface ControlBusEventHandle<P extends JsonValue> {
45
+ publish(payload: P): void;
46
+ dispose(): void;
47
+ }
48
+ export interface ControlBus {
49
+ /** Register a webview → main RPC handler under a domain-neutral `name`. */
50
+ command(name: string, handler: CommandHandler): Disposable;
51
+ /** Declare a main → webview push event (default-deny allowlist). */
52
+ event<P extends JsonValue>(name: string): ControlBusEventHandle<P>;
53
+ /** Admit a webContents into the refcount trust set, owned by `owner` Scope
54
+ * (the lease is released when `owner` resets/closes). */
55
+ trust(wc: MinimalWebContents, owner: Scope): Disposable;
56
+ /**
57
+ * Real wire entry point — the {@link WireTransport}'s `invokeHost` /
58
+ * `invokeSimulator` seam calls this with a domain-neutral `name` AFTER its
59
+ * trust + main-frame gate. Resolves the command table; throws if `name` is
60
+ * unregistered (the wire serialises that into an `InvokeFailure`). `ctx`
61
+ * carries the gated senderId (Phase B's grant gate reads it; Phase A passes
62
+ * it through unused).
63
+ */
64
+ dispatch(name: string, args: readonly JsonValue[], ctx: InvokeCtx): Promise<JsonValue>;
65
+ /**
66
+ * Current declared-event allowlist snapshot — the wire's `declaredEvents`
67
+ * seam reads this (lazy, per publish) so default-deny tracks `event()` /
68
+ * `dispose()` in real time.
69
+ */
70
+ declaredEvents(): readonly string[];
71
+ }
72
+ export interface CreateControlBusDeps {
73
+ /**
74
+ * Vestigial — the facade never calls into the wire from inside `dispatch` /
75
+ * `command` / `event` / `trust` (the wire is the one that calls `dispatch`,
76
+ * not the reverse). Made OPTIONAL so deck-app can construct the ControlBus
77
+ * BEFORE the WireTransport (which references the ControlBus from its
78
+ * `invokeHost` seam) — no circular dependency at construction time.
79
+ */
80
+ readonly transport?: WireTransport;
81
+ readonly bus: EventBus;
82
+ readonly trustSet: TrustSet;
83
+ /**
84
+ * P4 Phase B — privileged-command grant gate. When provided, `dispatch`
85
+ * default-DENIES any command not authorized by a live grant for the gated
86
+ * `ctx.senderId`. Omitted → no gate (backward-compatible "trusted may
87
+ * dispatch" behaviour).
88
+ */
89
+ readonly policy?: CapabilityPolicy;
90
+ }
91
+ export declare function createControlBus(deps: CreateControlBusDeps): ControlBus;
92
+ //# sourceMappingURL=control-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-bus.d.ts","sourceRoot":"","sources":["../../src/host/control-bus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AACjG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,YAAY,EAAE,QAAQ,EAAE,CAAA;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAEzD,KAAK,cAAc,GAAG,CAAC,GAAG,IAAI,EAAE,SAAS,EAAE,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;AAE9E,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,SAAS;IACzD,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAA;IACzB,OAAO,IAAI,IAAI,CAAA;CACf;AAED,MAAM,WAAW,UAAU;IAC1B,2EAA2E;IAC3E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,UAAU,CAAA;IAC1D,oEAAoE;IACpE,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAA;IAClE;8DAC0D;IAC1D,KAAK,CAAC,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,GAAG,UAAU,CAAA;IACvD;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,SAAS,EAAE,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IACtF;;;;OAIG;IACH,cAAc,IAAI,SAAS,MAAM,EAAE,CAAA;CACnC;AAED,MAAM,WAAW,oBAAoB;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAClC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,UAAU,CAgEvE"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * `@dimina-kit/electron-deck/host` — the cross-process host-shell transport.
3
+ *
4
+ * These are the transport pieces the `electronDeck()` entry (exported from this
5
+ * package's root, `@dimina-kit/electron-deck`) and domain backends construct to
6
+ * carry `hostServices` (trusted-webview RPC) and `events` (main→webview push)
7
+ * over a real Electron `ipcMain`:
8
+ *
9
+ * - `WireTransport` — the wire protocol (probe / invoke / event fanout)
10
+ * - `EventBus` — declared-event publisher fan-out
11
+ * - `InMemoryTypedIpcRegistry` — main-process handler/invoke registry the
12
+ * transport routes host/simulator kinds through
13
+ *
14
+ * The `electronDeck(config)` orchestration lives in this package's root entry
15
+ * (`@dimina-kit/electron-deck`, see `src/index.ts`); it stays domain-neutral and
16
+ * receives the domain assembly via an injected `RuntimeBackend`. Exposing the
17
+ * transport here lets a backend implementer assemble it. See
18
+ * packages/devtools/docs/workbench-model.md.
19
+ */
20
+ export { WireTransport, type InvokeCtx, type MinimalIpcMain, type MinimalWebContents, type WireTransportDeps, } from '../internal/wire-transport.js';
21
+ export { EventBus } from '../internal/event-bus.js';
22
+ export { InMemoryTypedIpcRegistry } from '../internal/ipc-registry-memory.js';
23
+ /**
24
+ * Domain-neutral facade (`command` / `event` / `trust`) over the wire + bus +
25
+ * trust set, plus the refcount trust-set primitive it depends on.
26
+ */
27
+ export { createControlBus, type ControlBus, type ControlBusEventHandle, type CreateControlBusDeps, } from './control-bus.js';
28
+ export { createTrustSet, type TrustSet, type TrustIndex } from '../internal/trust-set.js';
29
+ /**
30
+ * P4 Phase B — capability grant registry + policy (the privileged-command gate).
31
+ */
32
+ export { createCapabilityRegistry, type CapabilityPolicy, type Grant, } from './capability.js';
33
+ /** Pure config validation (rejects malformed config before assembly). */
34
+ export { validateConfig } from '../electron-deck.js';
35
+ /**
36
+ * Backend-facing types. `RuntimeBackend` / `TrustedSenderRef` also flow through
37
+ * the root entry (`@dimina-kit/electron-deck`); re-exported here so a backend
38
+ * implementer has one import site alongside the transport pieces.
39
+ */
40
+ export type { MinimalApp } from '../internal/electron-types.js';
41
+ export type { RuntimeBackend, TrustedSenderRef } from '../types.js';
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,aAAa,EACb,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAA;AAC7E;;;GAGG;AACH,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACzF;;GAEG;AACH,OAAO,EACL,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,KAAK,KAAK,GACX,MAAM,iBAAiB,CAAA;AACxB,yEAAyE;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD;;;;GAIG;AACH,YAAY,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAC/D,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,2 @@
1
+ import { a as WireTransport, c as InMemoryTypedIpcRegistry, i as createControlBus, l as EventBus, o as createCapabilityRegistry, r as validateConfig, s as createTrustSet } from "../electron-deck-DfFKeFEC.js";
2
+ export { EventBus, InMemoryTypedIpcRegistry, WireTransport, createCapabilityRegistry, createControlBus, createTrustSet, validateConfig };
@@ -0,0 +1,6 @@
1
+ export * from './errors.js';
2
+ export * from './types.js';
3
+ export { defineEvent } from './events.js';
4
+ export { electronDeck, startElectronDeck } from './electron-deck.js';
5
+ export type { DeckOptions } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { i as UndeclaredHostEventError, n as DeckRemoteError, r as EventNotBoundError, t as DeckClientNotReadyError } from "./errors-NE2ig7L5.js";
2
+ import { n as startElectronDeck, t as electronDeck, u as defineEvent } from "./electron-deck-DfFKeFEC.js";
3
+ export { DeckClientNotReadyError, DeckRemoteError, EventNotBoundError, UndeclaredHostEventError, defineEvent, electronDeck, startElectronDeck };