@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.
- package/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/client/index.d.ts +20 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +310 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/layout-client.d.ts +51 -0
- package/dist/client/layout-client.d.ts.map +1 -0
- package/dist/electron-deck-DfFKeFEC.js +2295 -0
- package/dist/electron-deck-DfFKeFEC.js.map +1 -0
- package/dist/electron-deck.d.ts +57 -0
- package/dist/electron-deck.d.ts.map +1 -0
- package/dist/errors-NE2ig7L5.js +53 -0
- package/dist/errors-NE2ig7L5.js.map +1 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/events.d.ts +14 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/host/capability.d.ts +50 -0
- package/dist/host/capability.d.ts.map +1 -0
- package/dist/host/control-bus.d.ts +92 -0
- package/dist/host/control-bus.d.ts.map +1 -0
- package/dist/host/index.d.ts +42 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/internal/deck-app.d.ts +415 -0
- package/dist/internal/deck-app.d.ts.map +1 -0
- package/dist/internal/electron-types.d.ts +131 -0
- package/dist/internal/electron-types.d.ts.map +1 -0
- package/dist/internal/event-bus.d.ts +29 -0
- package/dist/internal/event-bus.d.ts.map +1 -0
- package/dist/internal/ipc-registry-memory.d.ts +25 -0
- package/dist/internal/ipc-registry-memory.d.ts.map +1 -0
- package/dist/internal/lifecycle-manager.d.ts +28 -0
- package/dist/internal/lifecycle-manager.d.ts.map +1 -0
- package/dist/internal/resource-registry.d.ts +9 -0
- package/dist/internal/resource-registry.d.ts.map +1 -0
- package/dist/internal/trust-set.d.ts +53 -0
- package/dist/internal/trust-set.d.ts.map +1 -0
- package/dist/internal/wire-transport.d.ts +159 -0
- package/dist/internal/wire-transport.d.ts.map +1 -0
- package/dist/main/compositor.d.ts +123 -0
- package/dist/main/compositor.d.ts.map +1 -0
- package/dist/main/connection.d.ts +37 -0
- package/dist/main/connection.d.ts.map +1 -0
- package/dist/main/debug-tap.d.ts +55 -0
- package/dist/main/debug-tap.d.ts.map +1 -0
- package/dist/main/disposable.d.ts +18 -0
- package/dist/main/disposable.d.ts.map +1 -0
- package/dist/main/index.d.ts +16 -0
- package/dist/main/index.d.ts.map +1 -0
- package/dist/main/index.js +152 -0
- package/dist/main/index.js.map +1 -0
- package/dist/main/logger.d.ts +15 -0
- package/dist/main/logger.d.ts.map +1 -0
- package/dist/main/scope.d.ts +52 -0
- package/dist/main/scope.d.ts.map +1 -0
- package/dist/main/view-handle.d.ts +131 -0
- package/dist/main/view-handle.d.ts.map +1 -0
- package/dist/preload/index.cjs +105 -0
- package/dist/preload/index.cjs.map +1 -0
- package/dist/preload/index.d.ts +43 -0
- package/dist/preload/index.d.ts.map +1 -0
- package/dist/preload/index.js +80 -0
- package/dist/preload/index.js.map +1 -0
- package/dist/protocol-BJqo-vP2.js +23 -0
- package/dist/protocol-BJqo-vP2.js.map +1 -0
- package/dist/shared/protocol.d.ts +76 -0
- package/dist/shared/protocol.d.ts.map +1 -0
- package/dist/types.d.ts +504 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/view-handle-CR-yWNfr.js +701 -0
- package/dist/view-handle-CR-yWNfr.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Disposable, MaybePromise, ResourceRegistry } from '../types.js';
|
|
2
|
+
export declare class ResourceRegistryImpl implements ResourceRegistry {
|
|
3
|
+
private entries;
|
|
4
|
+
private nextId;
|
|
5
|
+
private allDisposed;
|
|
6
|
+
add(d: Disposable | (() => MaybePromise<void>)): Disposable;
|
|
7
|
+
disposeAll(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=resource-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-registry.d.ts","sourceRoot":"","sources":["../../src/internal/resource-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAyB7E,qBAAa,oBAAqB,YAAW,gBAAgB;IAC5D,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,WAAW,CAAQ;IAE3B,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU;IAyBrD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAqBjC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TrustSet — SEALED refcount membership of trusted webContents (P2).
|
|
3
|
+
*
|
|
4
|
+
* Refcount membership extracted from `DeckApp`'s former private `trustedWcRefs`
|
|
5
|
+
* (Map<wc, refcount>) so the same primitive can back both `DeckApp` and the
|
|
6
|
+
* domain-neutral `ControlBus` facade.
|
|
7
|
+
*
|
|
8
|
+
* SEALED WRITE MODEL: there is exactly ONE writer — `admit(wc, owner)`. It forces
|
|
9
|
+
* every trust lease to be OWNED by a `Scope`, so a lease can never outlive its
|
|
10
|
+
* owner and no un-owned / leaked lease is possible. The old public `add(wc)`
|
|
11
|
+
* (un-owned lease minting) and the `deleteEntry(wc)` imperative wipe are GONE:
|
|
12
|
+
* - releasing a lease early → use the Disposable `admit` returns;
|
|
13
|
+
* - releasing ALL of an owner's leases → close/reset that owner Scope (the
|
|
14
|
+
* refcount-- disposers are owned by it, so its teardown zeroes them).
|
|
15
|
+
*
|
|
16
|
+
* Semantics (unchanged refcount core):
|
|
17
|
+
* - `admit(wc, owner)` increments the wc's refcount and owns the matching
|
|
18
|
+
* refcount-- on `owner`; the entry is removed when the count reaches zero.
|
|
19
|
+
* - `isTrusted(id)` is true iff any live entry's `.id === id`.
|
|
20
|
+
* - `snapshot()` returns the live keys (used for event fanout).
|
|
21
|
+
*
|
|
22
|
+
* Idempotency note: each refcount-- disposer is one-shot and guarded by a
|
|
23
|
+
* `c === undefined` check — disposing a handle after the entry has already been
|
|
24
|
+
* dropped (e.g. via the owner's teardown) reads `refs.get(wc)`, sees `undefined`,
|
|
25
|
+
* and returns without touching the map, so a residual handle can never resurrect
|
|
26
|
+
* or mis-decrement a re-added entry.
|
|
27
|
+
*
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
import type { Disposable } from '../types.js';
|
|
31
|
+
import type { MinimalWebContents } from './wire-transport.js';
|
|
32
|
+
import type { Scope } from '../main/scope.js';
|
|
33
|
+
/** Read-only trust index (gate + fanout). No write surface. */
|
|
34
|
+
export interface TrustIndex {
|
|
35
|
+
/** true iff some live entry's `.id === id`. */
|
|
36
|
+
isTrusted(id: number): boolean;
|
|
37
|
+
/** live keys, for event fanout. */
|
|
38
|
+
snapshot(): readonly MinimalWebContents[];
|
|
39
|
+
}
|
|
40
|
+
/** Admit-capable trust set. The ONLY writer is `admit`, which forces an owner
|
|
41
|
+
* Scope so a trust lease can never outlive its owner (no un-owned lease). */
|
|
42
|
+
export interface TrustSet extends TrustIndex {
|
|
43
|
+
/**
|
|
44
|
+
* Admit `wc` to the trust set (refcount++). The refcount-- release is OWNED by
|
|
45
|
+
* `owner` (so `owner.reset()`/`close()` releases it automatically). Returns a
|
|
46
|
+
* one-shot Disposable that releases JUST this lease early (idempotent; never
|
|
47
|
+
* double-decrements, and a later `owner` teardown over an already-released
|
|
48
|
+
* lease is a safe no-op via the refs-undefined guard).
|
|
49
|
+
*/
|
|
50
|
+
admit(wc: MinimalWebContents, owner: Scope): Disposable;
|
|
51
|
+
}
|
|
52
|
+
export declare function createTrustSet(): TrustSet;
|
|
53
|
+
//# sourceMappingURL=trust-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-set.d.ts","sourceRoot":"","sources":["../../src/internal/trust-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IAC1B,+CAA+C;IAC/C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;IAC9B,mCAAmC;IACnC,QAAQ,IAAI,SAAS,kBAAkB,EAAE,CAAA;CACzC;AAED;8EAC8E;AAC9E,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC3C;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,GAAG,UAAU,CAAA;CACvD;AAED,wBAAgB,cAAc,IAAI,QAAQ,CAwCzC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WireTransport — main 端的真 Electron wire 桥接(Phase 3b)。
|
|
3
|
+
*
|
|
4
|
+
* 责任:
|
|
5
|
+
* - 在 `ipcMain.handle('__electron-deck:invoke')` / `'__electron-deck:probe'` 上路由
|
|
6
|
+
* webview → main 的 RPC 请求,按 `senderPolicy` gating + kind 派发到 host /
|
|
7
|
+
* simulator handler,序列化成 `InvokeResponse` 帧。
|
|
8
|
+
* - 订阅 framework `EventBus`,把 declared `HostEvent.publish(payload)` 通过
|
|
9
|
+
* `webContents.send('__electron-deck:event', envelope)` 推送给所有 trusted
|
|
10
|
+
* webContents。
|
|
11
|
+
*
|
|
12
|
+
* 该类只持有 deps 引用,不直接 import 'electron';测试用 plain DI 注入 fake。
|
|
13
|
+
* 生命周期一次性:start → dispose 后不能再 start(避免 listener 泄露 / 句柄
|
|
14
|
+
* 双重注册);hot-restart 由 host 重新构造新实例。
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
import type { JsonValue, SenderPolicy } from '../types.js';
|
|
19
|
+
import type { EventBus } from './event-bus.js';
|
|
20
|
+
/**
|
|
21
|
+
* Framework-reserved invoke failure codes —— 全部带 `DECK_` 前缀,避免与
|
|
22
|
+
* host 自定义 code 冲突。Client / host 都不应抛同前缀。
|
|
23
|
+
*/
|
|
24
|
+
export declare const DECK_CODE: {
|
|
25
|
+
readonly UntrustedSender: "DECK_UNTRUSTED_SENDER";
|
|
26
|
+
readonly UntrustedFrame: "DECK_UNTRUSTED_FRAME";
|
|
27
|
+
readonly UnknownKind: "DECK_UNKNOWN_KIND";
|
|
28
|
+
readonly BadRequest: "DECK_BAD_REQUEST";
|
|
29
|
+
/** P4 Phase B — the grant gate denied a privileged command for this sender. */
|
|
30
|
+
readonly Forbidden: "DECK_FORBIDDEN";
|
|
31
|
+
};
|
|
32
|
+
/** Minimal RenderFrameHost identity used for main-frame discrimination. */
|
|
33
|
+
export interface FrameRef {
|
|
34
|
+
readonly routingId: number;
|
|
35
|
+
readonly processId: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Per-invoke context threaded from {@link WireTransport.handleInvoke} into the
|
|
39
|
+
* host/simulator invoke seams. Constructed ONLY after the wire's trust gate +
|
|
40
|
+
* main-frame gate have both passed, so `senderId` is a real trusted webContents
|
|
41
|
+
* id (never undefined). Phase B's grant gate (in `ControlBus.dispatch`) reads
|
|
42
|
+
* this; Phase A just plumbs it through as a REQUIRED param so a missing call
|
|
43
|
+
* site is a COMPILE error, not a silent security downgrade.
|
|
44
|
+
*/
|
|
45
|
+
export interface InvokeCtx {
|
|
46
|
+
/** webContents id of the invoke sender (after the wire's trust + main-frame gates). */
|
|
47
|
+
readonly senderId: number;
|
|
48
|
+
/** sender frame ref; main-frame already validated. Kept for future per-frame use; may be null. */
|
|
49
|
+
readonly senderFrame: FrameRef | null;
|
|
50
|
+
}
|
|
51
|
+
export interface MinimalIpcMain {
|
|
52
|
+
handle(channel: string, handler: (event: {
|
|
53
|
+
sender: {
|
|
54
|
+
id: number;
|
|
55
|
+
mainFrame?: FrameRef | null;
|
|
56
|
+
};
|
|
57
|
+
senderFrame?: FrameRef | null;
|
|
58
|
+
}, ...args: unknown[]) => unknown | Promise<unknown>): void;
|
|
59
|
+
removeHandler(channel: string): void;
|
|
60
|
+
}
|
|
61
|
+
export interface MinimalWebContents {
|
|
62
|
+
readonly id: number;
|
|
63
|
+
isDestroyed(): boolean;
|
|
64
|
+
send(channel: string, payload: unknown): void;
|
|
65
|
+
}
|
|
66
|
+
export interface WireTransportDeps {
|
|
67
|
+
readonly ipcMain: MinimalIpcMain;
|
|
68
|
+
readonly bus: EventBus;
|
|
69
|
+
readonly senderPolicy: SenderPolicy;
|
|
70
|
+
/** 取当前 trusted webContents 快照;用于 event push 广播。lazy:每次 publish 重调。 */
|
|
71
|
+
readonly trustedWebContents: () => readonly MinimalWebContents[];
|
|
72
|
+
/** 路由 host kind 调用;handler 抛错由 WireTransport 接住 → InvokeFailure。
|
|
73
|
+
* `ctx` 必填:携带已过 trust + main-frame gate 的 senderId(Phase B 授权门读它)。 */
|
|
74
|
+
readonly invokeHost: (name: string, args: readonly JsonValue[], ctx: InvokeCtx) => Promise<JsonValue>;
|
|
75
|
+
/** 路由 simulator kind 调用;同上(`ctx` 必填)。 */
|
|
76
|
+
readonly invokeSimulator: (name: string, args: readonly JsonValue[], ctx: InvokeCtx) => Promise<JsonValue>;
|
|
77
|
+
/**
|
|
78
|
+
* 已声明的 event name 集合,作为 wire fanout 的 allowlist。**必填,
|
|
79
|
+
* default-deny** —— 未在该集合内的 event name 不会跨进程下发(防止
|
|
80
|
+
* framework 内部代码意外调 `bus.publish('foo')` 时 leak 给 webview)。
|
|
81
|
+
* 调用方需保证每次返回的是当前 declared event 名字列表(lazy 快照,每次
|
|
82
|
+
* publish 重读)。
|
|
83
|
+
*/
|
|
84
|
+
readonly declaredEvents: () => readonly string[];
|
|
85
|
+
/**
|
|
86
|
+
* OPTIONAL slot-token inbound: `__electron-deck:place` apply path. When
|
|
87
|
+
* provided, `start()` registers the `Place` handler (same trust + main-frame
|
|
88
|
+
* gate as invoke). On gate pass → `onPlace(senderId, slotToken, placement)`.
|
|
89
|
+
*/
|
|
90
|
+
readonly onPlace?: (senderId: number, slotToken: string, placement: unknown) => void;
|
|
91
|
+
/**
|
|
92
|
+
* OPTIONAL slot-token inbound: `__electron-deck:layout-subscribe` per-wc
|
|
93
|
+
* replay request. When provided, `start()` registers the `LayoutSubscribe`
|
|
94
|
+
* handler (same gate). On gate pass → `onLayoutSubscribe(senderId)`.
|
|
95
|
+
*/
|
|
96
|
+
readonly onLayoutSubscribe?: (senderId: number) => void;
|
|
97
|
+
}
|
|
98
|
+
export declare class WireTransport {
|
|
99
|
+
private readonly deps;
|
|
100
|
+
private state;
|
|
101
|
+
private busSubscription;
|
|
102
|
+
/** Whether the optional Place / LayoutSubscribe handlers were registered
|
|
103
|
+
* (either eagerly at start() via deps, or lazily via armSlotChannels) — so
|
|
104
|
+
* dispose() only removes channels it actually registered. */
|
|
105
|
+
private placeRegistered;
|
|
106
|
+
private layoutSubscribeRegistered;
|
|
107
|
+
/** Effective slot callbacks. Populated from deps at start() (eager path, used
|
|
108
|
+
* by the wire unit tests) OR by {@link armSlotChannels} (lazy path, used by
|
|
109
|
+
* deck-app so an app with no anchored views registers only Invoke + Probe). */
|
|
110
|
+
private onPlaceCb;
|
|
111
|
+
private onLayoutSubscribeCb;
|
|
112
|
+
constructor(deps: WireTransportDeps);
|
|
113
|
+
start(): void;
|
|
114
|
+
private tryRemoveHandler;
|
|
115
|
+
private registerPlaceHandler;
|
|
116
|
+
private unregisterPlaceHandler;
|
|
117
|
+
private registerLayoutSubscribeHandler;
|
|
118
|
+
private unregisterLayoutSubscribeHandler;
|
|
119
|
+
/**
|
|
120
|
+
* Lazily register the slot-token inbound channels (`Place` + `LayoutSubscribe`)
|
|
121
|
+
* on an already-started wire, wiring them to the given callbacks. Idempotent:
|
|
122
|
+
* subsequent calls just refresh the callbacks (the handlers are registered
|
|
123
|
+
* once). deck-app calls this on the FIRST anchored `placeIn`, so an app with
|
|
124
|
+
* no anchored views never registers these channels (keeping the wire's
|
|
125
|
+
* handler footprint at Invoke + Probe until a slot is actually minted).
|
|
126
|
+
*/
|
|
127
|
+
armSlotChannels(onPlace: (senderId: number, slotToken: string, placement: unknown) => void, onLayoutSubscribe: (senderId: number) => void): void;
|
|
128
|
+
dispose(): void;
|
|
129
|
+
private handleProbe;
|
|
130
|
+
/**
|
|
131
|
+
* Defense-in-depth main-frame check (mirrors devtools' verified
|
|
132
|
+
* `isMainFrameSender`). A trusted webContents may embed a sub-frame of
|
|
133
|
+
* arbitrary origin; only its top frame should reach gated invoke, so a
|
|
134
|
+
* sub-frame can't spoof the trusted sender id.
|
|
135
|
+
*
|
|
136
|
+
* - NEITHER field modeled → frame-unaware stub → not a real frame boundary;
|
|
137
|
+
* the sender-id gate is the boundary → allow (back-compat with the legacy
|
|
138
|
+
* `{ sender: { id } }` stubs).
|
|
139
|
+
* - either null (incl. a real event whose `senderFrame` resolved to null after
|
|
140
|
+
* navigate-after-send / frame destruction, or a partial/malformed event) →
|
|
141
|
+
* fail-closed → reject.
|
|
142
|
+
* - main frame (routingId + processId match) → allow; else (sub frame) reject.
|
|
143
|
+
*/
|
|
144
|
+
private isMainFrameSender;
|
|
145
|
+
private handleInvoke;
|
|
146
|
+
/**
|
|
147
|
+
* `__electron-deck:place` inbound. Same gate as {@link handleInvoke}
|
|
148
|
+
* (trust + main-frame). On any failure (malformed payload, untrusted sender,
|
|
149
|
+
* sub-frame) → DROP silently (return undefined; never call `onPlace`).
|
|
150
|
+
*/
|
|
151
|
+
private handlePlace;
|
|
152
|
+
/**
|
|
153
|
+
* `__electron-deck:layout-subscribe` inbound. Same gate as {@link handleInvoke}.
|
|
154
|
+
* On gate pass → `onLayoutSubscribe(senderId)`; else DROP silently.
|
|
155
|
+
*/
|
|
156
|
+
private handleLayoutSubscribe;
|
|
157
|
+
private fanoutEvent;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=wire-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-transport.d.ts","sourceRoot":"","sources":["../../src/internal/wire-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Compositor` — engine-agnostic z-order planner for a window's native child
|
|
3
|
+
* views (foundation: the spikes in `.repro/electron-deck-spikes/`).
|
|
4
|
+
*
|
|
5
|
+
* It separates INTENT (mount / unmount / reorder a view into a zone, at a
|
|
6
|
+
* relative position) from APPLICATION (`commit()` computes the minimal sequence
|
|
7
|
+
* of host add/remove calls that transforms the host's current child order into
|
|
8
|
+
* the target order).
|
|
9
|
+
*
|
|
10
|
+
* The host's observable z-semantics this planner is built on (from the spikes):
|
|
11
|
+
* - `addChildView` of an ALREADY-mounted child raises it to the top WITHOUT a
|
|
12
|
+
* remove first and WITHOUT reloading it.
|
|
13
|
+
* - `addChildView` of a NEW child appends it to the end (= topmost).
|
|
14
|
+
* - A batch of remove/add in ONE synchronous tick re-lands at the target order
|
|
15
|
+
* with zero renderer reloads.
|
|
16
|
+
* - `addChildView` into a destroyed contentView throws synchronously.
|
|
17
|
+
*
|
|
18
|
+
* Ordering model. Every mounted view carries `(zone, orderKey, viewId)`. The
|
|
19
|
+
* total render order is that triple, ascending: lower zone renders BELOW higher
|
|
20
|
+
* zone (zones stack), `orderKey` orders within a zone, and `viewId` is a pure
|
|
21
|
+
* tiebreak so the order is deterministic even if two keys collide. `orderKey` is
|
|
22
|
+
* a FRACTIONAL key: reorder-before(X) sets the moved view's key to the midpoint
|
|
23
|
+
* between X's key and its in-zone predecessor's key, so a reorder is O(1) and
|
|
24
|
+
* perturbs no other view's key. When repeated midpoints exhaust float precision
|
|
25
|
+
* in a gap, the affected zone is RENUMBERED (rebalance) to evenly-spaced integer
|
|
26
|
+
* keys — invisible, because the renumber preserves the existing relative order.
|
|
27
|
+
*
|
|
28
|
+
* mount epoch. A genuinely-new mount gets a fresh monotonically-increasing
|
|
29
|
+
* `mountSeq` and lands at the top of its zone. Re-mounting a view that is STILL
|
|
30
|
+
* mounted is a pure no-op (same orderKey/mountSeq, zero host churn). But an
|
|
31
|
+
* `unmount(id)` followed by `mount(id)` is a NEW instance: it gets a new
|
|
32
|
+
* mountSeq and lands at the top — it never resumes the old slot.
|
|
33
|
+
*
|
|
34
|
+
* commit. We fold the batch of intents into the FINAL target state (last-state,
|
|
35
|
+
* not a write-log replay), then diff the host's current children against that
|
|
36
|
+
* target. The longest increasing subsequence (LIS) of views already in correct
|
|
37
|
+
* relative order — computed over the current∩target intersection — is left
|
|
38
|
+
* untouched; every other shared view is `removeChildView` + `addChildView`, and
|
|
39
|
+
* each brand-new view gets one explicit `addChildView`. All in one synchronous
|
|
40
|
+
* pass. On failure `commit()` throws a typed {@link CommitError}: a destroyed
|
|
41
|
+
* host with additions pending throws `host-destroyed` BEFORE touching native
|
|
42
|
+
* (applied:false); a native call that throws mid-apply is caught and the host is
|
|
43
|
+
* rolled back to its pre-apply snapshot, then `apply-failed` is thrown with
|
|
44
|
+
* whether the rollback recovered the snapshot. A no-op commit, and a destroyed
|
|
45
|
+
* host with only removals pending, are SILENT (teardown-friendly).
|
|
46
|
+
*/
|
|
47
|
+
/** A handle to a native child view. Identity is by `id`. */
|
|
48
|
+
export type NativeViewRef = {
|
|
49
|
+
readonly id: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Typed failure thrown by {@link Compositor.commit}. `kind` distinguishes a
|
|
53
|
+
* preflight refusal (`host-destroyed`, native byte-for-byte pre-commit,
|
|
54
|
+
* `applied:false`) from a mid-apply native throw (`apply-failed`,
|
|
55
|
+
* `applied:'partial'`); for `apply-failed`, `recovered` reports whether the
|
|
56
|
+
* best-effort rollback restored the pre-apply snapshot order (`false` ⇒ native
|
|
57
|
+
* is untrusted and the host must be treated as dead).
|
|
58
|
+
*/
|
|
59
|
+
export declare class CommitError extends Error {
|
|
60
|
+
readonly kind: 'host-destroyed' | 'apply-failed';
|
|
61
|
+
readonly applied: false | 'partial';
|
|
62
|
+
readonly recovered?: boolean;
|
|
63
|
+
constructor(args: {
|
|
64
|
+
kind: 'host-destroyed' | 'apply-failed';
|
|
65
|
+
applied: false | 'partial';
|
|
66
|
+
recovered?: boolean;
|
|
67
|
+
message?: string;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The native content-view surface the Compositor drives. In production this is
|
|
72
|
+
* an Electron `contentView` (`addChildView` / `removeChildView`); in tests it is
|
|
73
|
+
* a faithful fake. `children()` returns the current order, LAST = topmost.
|
|
74
|
+
*/
|
|
75
|
+
export interface ContentViewHost {
|
|
76
|
+
/** Already-mounted ref → raise to top (no remove, no reload); new ref →
|
|
77
|
+
* append to the end (top). */
|
|
78
|
+
addChildView(v: NativeViewRef): void;
|
|
79
|
+
removeChildView(v: NativeViewRef): void;
|
|
80
|
+
readonly isDestroyed: boolean;
|
|
81
|
+
/** Current child order; LAST element is the topmost. */
|
|
82
|
+
children(): readonly NativeViewRef[];
|
|
83
|
+
}
|
|
84
|
+
export interface Compositor {
|
|
85
|
+
/** Idempotent attach. A view STILL mounted → pure no-op (unchanged
|
|
86
|
+
* orderKey/mountSeq, zero host calls). A new view (or one re-mounted after
|
|
87
|
+
* unmount) → fresh mountSeq, lands at the top (end) of its zone. */
|
|
88
|
+
mount(view: NativeViewRef, opts?: {
|
|
89
|
+
zone?: number;
|
|
90
|
+
}): void;
|
|
91
|
+
/** Detach a view. A subsequent mount of the same id is a NEW instance. */
|
|
92
|
+
unmount(viewId: string): void;
|
|
93
|
+
/** Move a view: `before` slots it immediately before that anchor (midpoint of
|
|
94
|
+
* the anchor and its predecessor); `before: null` sends it to the end (top)
|
|
95
|
+
* of the zone. `zone` moves it to a different zone. An illegal `before`
|
|
96
|
+
* (unknown / unmounted id, or one whose zone conflicts with an explicit
|
|
97
|
+
* `zone`) throws SYNCHRONOUSLY. */
|
|
98
|
+
reorder(viewId: string, opts: {
|
|
99
|
+
zone?: number;
|
|
100
|
+
before?: string | null;
|
|
101
|
+
}): void;
|
|
102
|
+
/** Apply the folded target state to the host with the minimal add/remove
|
|
103
|
+
* sequence (LIS-preserving). Returns void on success. Throws a typed
|
|
104
|
+
* {@link CommitError} on failure: `kind:'host-destroyed'` (applied:false) when
|
|
105
|
+
* the host is destroyed and there are ADDITIONS to apply — thrown BEFORE
|
|
106
|
+
* touching native; `kind:'apply-failed'` (applied:'partial') when a native
|
|
107
|
+
* call throws mid-apply, after a best-effort rollback to the pre-apply
|
|
108
|
+
* snapshot (`recovered` flags whether the snapshot was restored). A no-op
|
|
109
|
+
* commit, and a destroyed host with ONLY removals pending, are SILENT. */
|
|
110
|
+
commit(): void;
|
|
111
|
+
/** Fold the intent state to EMPTY and commit, removing every native view
|
|
112
|
+
* this window's compositor mounted from the host. The resulting commit is
|
|
113
|
+
* REMOVALS-ONLY, so it reuses {@link commit}'s teardown-friendly
|
|
114
|
+
* "destroyed host + only removals → silent" path (A1.2.1): on an
|
|
115
|
+
* already-destroyed host it makes zero host calls and throws nothing.
|
|
116
|
+
*
|
|
117
|
+
* Optional on the interface so a partial test double (or a caller that only
|
|
118
|
+
* needs mount/unmount/reorder/commit) still structurally satisfies
|
|
119
|
+
* `Compositor`; the real {@link createCompositor} always implements it. */
|
|
120
|
+
detachAll?(): void;
|
|
121
|
+
}
|
|
122
|
+
export declare function createCompositor(host: ContentViewHost): Compositor;
|
|
123
|
+
//# sourceMappingURL=compositor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compositor.d.ts","sourceRoot":"","sources":["../../src/main/compositor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,4DAA4D;AAC5D,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnD;;;;;;;GAOG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,cAAc,CAAA;IAChD,QAAQ,CAAC,OAAO,EAAE,KAAK,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;gBAChB,IAAI,EAAE;QACjB,IAAI,EAAE,gBAAgB,GAAG,cAAc,CAAA;QACvC,OAAO,EAAE,KAAK,GAAG,SAAS,CAAA;QAC1B,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,OAAO,CAAC,EAAE,MAAM,CAAA;KAChB;CAOD;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;kCAC8B;IAC9B,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;IACpC,eAAe,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,wDAAwD;IACxD,QAAQ,IAAI,SAAS,aAAa,EAAE,CAAA;CACrC;AAED,MAAM,WAAW,UAAU;IACzB;;wEAEoE;IACpE,KAAK,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC1D,0EAA0E;IAC1E,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B;;;;uCAImC;IACnC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;IAC9E;;;;;;;8EAO0E;IAC1E,MAAM,IAAI,IAAI,CAAA;IACd;;;;;;;;+EAQ2E;IAC3E,SAAS,CAAC,IAAI,IAAI,CAAA;CACnB;AAkBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,UAAU,CA2PlE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection-layer primitive (`Connection` / `ConnectionRegistry`) described in
|
|
3
|
+
* packages/electron-deck/docs/foundation.md §4.
|
|
4
|
+
*
|
|
5
|
+
* A `Connection` is one trusted webContents (keyed by the unforgeable `wc.id`).
|
|
6
|
+
* It holds a single `DisposableRegistry` as its "lifetime segment" container.
|
|
7
|
+
* The segment tears down deterministically (LIFO) on hard-destroy
|
|
8
|
+
* (`wc.once('destroyed')`) or soft-reuse (`reset(id)`):
|
|
9
|
+
* - hard destroy → dispose segment, fire 'closed' once, de-register.
|
|
10
|
+
* - soft reset → dispose segment, swap in a fresh registry, fire 'reset',
|
|
11
|
+
* connection stays alive & registered.
|
|
12
|
+
*
|
|
13
|
+
* §4.3: the terminal hook is `'destroyed'` (NOT `'render-process-gone'`), and
|
|
14
|
+
* `DisposableRegistry.disposeAll` is async (LIFO) — so close/reset are async.
|
|
15
|
+
*/
|
|
16
|
+
import type { WebContents } from 'electron';
|
|
17
|
+
import { type Disposable } from './disposable.js';
|
|
18
|
+
export interface Connection {
|
|
19
|
+
readonly id: number;
|
|
20
|
+
readonly webContents: WebContents;
|
|
21
|
+
readonly alive: boolean;
|
|
22
|
+
/** Register a resource cleaned up with the current lifetime segment; the
|
|
23
|
+
* returned Disposable releases it early. */
|
|
24
|
+
own(d: Disposable | (() => void)): Disposable;
|
|
25
|
+
/** Connection-level lifecycle events; returns an unsubscribe Disposable. */
|
|
26
|
+
on(ev: 'reset' | 'closed', cb: () => void): Disposable;
|
|
27
|
+
}
|
|
28
|
+
export interface ConnectionRegistry {
|
|
29
|
+
/** Build/fetch the connection for a (trusted) webContents; idempotent. */
|
|
30
|
+
acquire(wc: WebContents): Connection;
|
|
31
|
+
get(id: number): Connection | undefined;
|
|
32
|
+
all(): readonly Connection[];
|
|
33
|
+
/** Soft reuse: dispose the current segment, then swap in a fresh registry. */
|
|
34
|
+
reset(id: number): void;
|
|
35
|
+
}
|
|
36
|
+
export declare function createConnectionRegistry(): ConnectionRegistry;
|
|
37
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/main/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAKrE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB;gDAC4C;IAC5C,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,UAAU,CAAA;IAC7C,4EAA4E;IAC5E,EAAE,CAAC,EAAE,EAAE,OAAO,GAAG,QAAQ,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,UAAU,CAAA;CACvD;AAED,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,EAAE,WAAW,GAAG,UAAU,CAAA;IACpC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;IACvC,GAAG,IAAI,SAAS,UAAU,EAAE,CAAA;IAC5B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAmBD,wBAAgB,wBAAwB,IAAI,kBAAkB,CAmJ7D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* debugTap (foundation.md §7) — a flag-gated ring buffer for observing an
|
|
3
|
+
* IPC / cross-wc bridge message stream.
|
|
4
|
+
*
|
|
5
|
+
* Hung on a dispatch chokepoint (e.g. bridge-router's SERVICE_INVOKE /
|
|
6
|
+
* RENDER_INVOKE / PUBLISH / API_RESPONSE handlers), it records per-message
|
|
7
|
+
* metadata — connection id / channel / direction / appSession / duration /
|
|
8
|
+
* error — into a bounded ring so a hidden panel (or a test) can inspect the
|
|
9
|
+
* last N messages when debugging the cross-wc state machine.
|
|
10
|
+
*
|
|
11
|
+
* Design constraints:
|
|
12
|
+
* - Default OFF: `record()` is a near-free no-op when disabled, so the hot
|
|
13
|
+
* path costs nothing in production unless the flag is set.
|
|
14
|
+
* - Caller-supplied `ts`: the electron-deck package never calls `Date.now()`
|
|
15
|
+
* (determinism / resumability), so each entry carries a timestamp the
|
|
16
|
+
* caller stamps.
|
|
17
|
+
* - Bounded: a finite ring (default 1000) evicts oldest-first; it never grows
|
|
18
|
+
* without bound.
|
|
19
|
+
*/
|
|
20
|
+
export interface DebugTapEntry {
|
|
21
|
+
/** Caller-stamped timestamp (ms). The primitive never reads the clock. */
|
|
22
|
+
ts: number;
|
|
23
|
+
/** The channel / message kind (e.g. 'SERVICE_INVOKE', 'API_RESPONSE'). */
|
|
24
|
+
channel: string;
|
|
25
|
+
/** Ingress (main received) vs egress (main sent). */
|
|
26
|
+
direction: 'in' | 'out';
|
|
27
|
+
/** webContents.id of the connection this message is attributed to. */
|
|
28
|
+
connectionId?: number;
|
|
29
|
+
/** bridge-router app session this message routes within, if known. */
|
|
30
|
+
appSessionId?: string;
|
|
31
|
+
/** For request/response pairs: how long the handler took (ms). */
|
|
32
|
+
durationMs?: number;
|
|
33
|
+
/** Error message if the message produced a failure. */
|
|
34
|
+
error?: string;
|
|
35
|
+
/** Short human-readable summary of the payload (no large blobs). */
|
|
36
|
+
summary?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface DebugTap {
|
|
39
|
+
/** Whether recording is on. When false, `record` is a no-op. */
|
|
40
|
+
readonly enabled: boolean;
|
|
41
|
+
/** Append one entry to the ring (no-op when disabled). */
|
|
42
|
+
record(entry: DebugTapEntry): void;
|
|
43
|
+
/** Snapshot of buffered entries, oldest → newest. Safe to retain/mutate. */
|
|
44
|
+
entries(): readonly DebugTapEntry[];
|
|
45
|
+
/** Empty the ring. */
|
|
46
|
+
clear(): void;
|
|
47
|
+
}
|
|
48
|
+
export interface DebugTapOptions {
|
|
49
|
+
/** Default false — the tap is OFF unless explicitly enabled. */
|
|
50
|
+
enabled?: boolean;
|
|
51
|
+
/** Max retained entries; oldest evicted past this. Default 1000. */
|
|
52
|
+
capacity?: number;
|
|
53
|
+
}
|
|
54
|
+
export declare function createDebugTap(options?: DebugTapOptions): DebugTap;
|
|
55
|
+
//# sourceMappingURL=debug-tap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-tap.d.ts","sourceRoot":"","sources":["../../src/main/debug-tap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,EAAE,EAAE,MAAM,CAAA;IACV,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,SAAS,EAAE,IAAI,GAAG,KAAK,CAAA;IACvB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,0DAA0D;IAC1D,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;IAClC,4EAA4E;IAC5E,OAAO,IAAI,SAAS,aAAa,EAAE,CAAA;IACnC,sBAAsB;IACtB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAID,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CA8BtE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface Disposable {
|
|
2
|
+
dispose(): void | Promise<void>;
|
|
3
|
+
}
|
|
4
|
+
export type DisposeFn = () => void | Promise<void>;
|
|
5
|
+
export declare function toDisposable(fn: DisposeFn): Disposable;
|
|
6
|
+
export declare class DisposableRegistry implements Disposable {
|
|
7
|
+
private entries;
|
|
8
|
+
private _disposed;
|
|
9
|
+
/**
|
|
10
|
+
* Number of live entries. A wrapper's `dispose` splices its entry out and
|
|
11
|
+
* `disposeAll` clears the array, so `entries.length` is the live count.
|
|
12
|
+
*/
|
|
13
|
+
get size(): number;
|
|
14
|
+
add(d: Disposable | DisposeFn): Disposable;
|
|
15
|
+
disposeAll(): Promise<void>;
|
|
16
|
+
dispose(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=disposable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disposable.d.ts","sourceRoot":"","sources":["../../src/main/disposable.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAChC;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAElD,wBAAgB,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,UAAU,CAStD;AAOD,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAQ;IAEzB;;;OAGG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU;IAmBpC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAGzB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dimina-kit/electron-deck/main` — main-process foundation primitives.
|
|
3
|
+
*
|
|
4
|
+
* The connection layer (foundation.md §4): one `Connection` per trusted
|
|
5
|
+
* webContents, owning a single `DisposableRegistry` lifetime segment that tears
|
|
6
|
+
* down deterministically on hard-destroy or soft-reuse. devtools (and qdmp)
|
|
7
|
+
* consume this as the substrate for connection-scoped resource ownership.
|
|
8
|
+
*/
|
|
9
|
+
export { createConnectionRegistry, type Connection, type ConnectionRegistry, } from './connection.js';
|
|
10
|
+
export { DisposableRegistry, toDisposable, type Disposable, type DisposeFn, } from './disposable.js';
|
|
11
|
+
export { createScope, type Scope } from './scope.js';
|
|
12
|
+
export { createCompositor, CommitError, type Compositor, type ContentViewHost, type NativeViewRef, } from './compositor.js';
|
|
13
|
+
export { createViewHandle, type ViewHandle, type ViewHandleDeps, type NativeView, type PlaceTarget, type Placement, type Bounds, } from './view-handle.js';
|
|
14
|
+
export { createLogger, setLogLevel, type Logger } from './logger.js';
|
|
15
|
+
export { createDebugTap, type DebugTap, type DebugTapEntry, type DebugTapOptions, } from './debug-tap.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,wBAAwB,EACxB,KAAK,UAAU,EACf,KAAK,kBAAkB,GACxB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,MAAM,GACZ,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AACpE,OAAO,EACL,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAA"}
|