@geometra/proxy 1.18.1

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.
@@ -0,0 +1,328 @@
1
+ import { WebSocketServer } from 'ws';
2
+ import { attachFiles, pickListboxOption, resolveExistingFiles, selectNativeOption, wheelAt, } from './dom-actions.js';
3
+ import { coalescePatches, diffLayout } from './diff-layout.js';
4
+ import { extractGeometry } from './extractor.js';
5
+ import { isClickEventMessage, isCompositionMessage, isFileMessage, isKeyMessage, isListboxPickMessage, isResizeMessage, isSelectOptionMessage, isWheelMessage, PROXY_PROTOCOL_VERSION, } from './types.js';
6
+ function isProtocolCompatible(peerVersion) {
7
+ if (peerVersion === undefined)
8
+ return true;
9
+ if (typeof peerVersion !== 'number' || !Number.isFinite(peerVersion))
10
+ return false;
11
+ return peerVersion <= PROXY_PROTOCOL_VERSION;
12
+ }
13
+ function cloneLayout(layout) {
14
+ return structuredClone(layout);
15
+ }
16
+ function normalizePlaywrightKey(key) {
17
+ if (key === ' ')
18
+ return 'Space';
19
+ return key;
20
+ }
21
+ async function applyKeyPhase(page, msg) {
22
+ if (msg.eventType !== 'onKeyDown' && msg.eventType !== 'onKeyUp')
23
+ return;
24
+ const k = normalizePlaywrightKey(msg.key);
25
+ /**
26
+ * `geometra_key` sends a single `onKeyDown` with `code === key` (e.g. Enter).
27
+ * `geometra_type` sends `onKeyDown` / `onKeyUp` pairs with `code` like `KeyA` and `key` like `a`.
28
+ */
29
+ const singleShotSpecial = msg.code === msg.key;
30
+ if (msg.eventType === 'onKeyDown') {
31
+ if (msg.shiftKey)
32
+ await page.keyboard.down('Shift');
33
+ if (msg.ctrlKey)
34
+ await page.keyboard.down('Control');
35
+ if (msg.metaKey)
36
+ await page.keyboard.down('Meta');
37
+ if (msg.altKey)
38
+ await page.keyboard.down('Alt');
39
+ if (singleShotSpecial) {
40
+ await page.keyboard.press(k);
41
+ if (msg.altKey)
42
+ await page.keyboard.up('Alt');
43
+ if (msg.metaKey)
44
+ await page.keyboard.up('Meta');
45
+ if (msg.ctrlKey)
46
+ await page.keyboard.up('Control');
47
+ if (msg.shiftKey)
48
+ await page.keyboard.up('Shift');
49
+ }
50
+ else {
51
+ await page.keyboard.down(k);
52
+ }
53
+ return;
54
+ }
55
+ if (singleShotSpecial) {
56
+ return;
57
+ }
58
+ await page.keyboard.up(k);
59
+ if (msg.altKey)
60
+ await page.keyboard.up('Alt');
61
+ if (msg.metaKey)
62
+ await page.keyboard.up('Meta');
63
+ if (msg.ctrlKey)
64
+ await page.keyboard.up('Control');
65
+ if (msg.shiftKey)
66
+ await page.keyboard.up('Shift');
67
+ }
68
+ async function handleClientMessage(page, ws, raw, onViewportOrInput, onHandlerError) {
69
+ let msg;
70
+ try {
71
+ msg = JSON.parse(String(raw));
72
+ }
73
+ catch {
74
+ return;
75
+ }
76
+ if (typeof msg !== 'object' || msg === null || typeof msg.type !== 'string')
77
+ return;
78
+ const pv = 'protocolVersion' in msg ? msg.protocolVersion : undefined;
79
+ if (!isProtocolCompatible(pv)) {
80
+ ws.send(JSON.stringify({
81
+ type: 'error',
82
+ message: `Client protocol ${String(pv)} is newer than proxy protocol ${PROXY_PROTOCOL_VERSION}`,
83
+ protocolVersion: PROXY_PROTOCOL_VERSION,
84
+ }));
85
+ return;
86
+ }
87
+ const wireError = (message) => {
88
+ ws.send(JSON.stringify({ type: 'error', message, protocolVersion: PROXY_PROTOCOL_VERSION }));
89
+ };
90
+ try {
91
+ if (isResizeMessage(msg)) {
92
+ const w = Math.max(1, Math.floor(msg.width));
93
+ const h = Math.max(1, Math.floor(msg.height));
94
+ await page.setViewportSize({ width: w, height: h });
95
+ onViewportOrInput('resize');
96
+ return;
97
+ }
98
+ if (isClickEventMessage(msg)) {
99
+ const x = msg.x;
100
+ const y = msg.y;
101
+ if (typeof x === 'number' && typeof y === 'number' && Number.isFinite(x) && Number.isFinite(y)) {
102
+ await page.mouse.click(x, y);
103
+ onViewportOrInput('input');
104
+ }
105
+ return;
106
+ }
107
+ if (isKeyMessage(msg)) {
108
+ await applyKeyPhase(page, msg);
109
+ onViewportOrInput('input');
110
+ return;
111
+ }
112
+ if (isCompositionMessage(msg)) {
113
+ const data = typeof msg.data === 'string' ? msg.data : '';
114
+ if (msg.eventType === 'onCompositionUpdate' || msg.eventType === 'onCompositionEnd') {
115
+ await page.keyboard.insertText(data);
116
+ onViewportOrInput('input');
117
+ }
118
+ return;
119
+ }
120
+ if (isFileMessage(msg)) {
121
+ const paths = resolveExistingFiles(msg.paths);
122
+ await attachFiles(page, paths, {
123
+ clickX: msg.x,
124
+ clickY: msg.y,
125
+ strategy: msg.strategy,
126
+ dropX: msg.dropX,
127
+ dropY: msg.dropY,
128
+ });
129
+ onViewportOrInput('input');
130
+ return;
131
+ }
132
+ if (isListboxPickMessage(msg)) {
133
+ await pickListboxOption(page, msg.label, {
134
+ exact: msg.exact,
135
+ openX: msg.openX,
136
+ openY: msg.openY,
137
+ });
138
+ onViewportOrInput('input');
139
+ return;
140
+ }
141
+ if (isSelectOptionMessage(msg)) {
142
+ await selectNativeOption(page, msg.x, msg.y, {
143
+ value: msg.value,
144
+ label: msg.label,
145
+ index: msg.index,
146
+ });
147
+ onViewportOrInput('input');
148
+ return;
149
+ }
150
+ if (isWheelMessage(msg)) {
151
+ const dx = typeof msg.deltaX === 'number' && Number.isFinite(msg.deltaX) ? msg.deltaX : 0;
152
+ const dy = typeof msg.deltaY === 'number' && Number.isFinite(msg.deltaY) ? msg.deltaY : 0;
153
+ const x = typeof msg.x === 'number' && Number.isFinite(msg.x) ? msg.x : undefined;
154
+ const y = typeof msg.y === 'number' && Number.isFinite(msg.y) ? msg.y : undefined;
155
+ await wheelAt(page, dx, dy, x, y);
156
+ onViewportOrInput('input');
157
+ }
158
+ }
159
+ catch (err) {
160
+ onHandlerError(err);
161
+ wireError(err instanceof Error ? err.message : String(err));
162
+ }
163
+ }
164
+ export function startGeometryWebSocket(options) {
165
+ const debounceMs = options.debounceMs ?? 50;
166
+ const clients = new Set();
167
+ const wss = new WebSocketServer({ port: options.port });
168
+ let prevLayout = null;
169
+ let prevTreeJson = null;
170
+ let debounceTimer = null;
171
+ let extracting = false;
172
+ let pendingExtract = false;
173
+ function broadcastSnapshot(snap) {
174
+ const treeChanged = prevTreeJson !== snap.treeJson;
175
+ let outbound;
176
+ if (!prevLayout || treeChanged) {
177
+ outbound = {
178
+ type: 'frame',
179
+ layout: snap.layout,
180
+ tree: snap.tree,
181
+ protocolVersion: PROXY_PROTOCOL_VERSION,
182
+ };
183
+ prevLayout = cloneLayout(snap.layout);
184
+ prevTreeJson = snap.treeJson;
185
+ }
186
+ else {
187
+ const rawPatches = diffLayout(prevLayout, snap.layout);
188
+ const patches = coalescePatches(rawPatches);
189
+ if (patches.length === 0) {
190
+ return;
191
+ }
192
+ if (patches.length > 20) {
193
+ outbound = {
194
+ type: 'frame',
195
+ layout: snap.layout,
196
+ tree: snap.tree,
197
+ protocolVersion: PROXY_PROTOCOL_VERSION,
198
+ };
199
+ }
200
+ else {
201
+ outbound = { type: 'patch', patches, protocolVersion: PROXY_PROTOCOL_VERSION };
202
+ }
203
+ prevLayout = cloneLayout(snap.layout);
204
+ prevTreeJson = snap.treeJson;
205
+ }
206
+ const text = JSON.stringify(outbound);
207
+ for (const ws of clients) {
208
+ if (ws.readyState === ws.OPEN) {
209
+ ws.send(text);
210
+ }
211
+ }
212
+ }
213
+ async function runExtract() {
214
+ try {
215
+ const snap = await extractGeometry(options.page);
216
+ broadcastSnapshot(snap);
217
+ }
218
+ catch (err) {
219
+ options.onError?.(err);
220
+ const errMsg = {
221
+ type: 'error',
222
+ message: err instanceof Error ? err.message : String(err),
223
+ protocolVersion: PROXY_PROTOCOL_VERSION,
224
+ };
225
+ const errText = JSON.stringify(errMsg);
226
+ for (const ws of clients) {
227
+ if (ws.readyState === ws.OPEN)
228
+ ws.send(errText);
229
+ }
230
+ }
231
+ }
232
+ async function runExtractQueued() {
233
+ if (extracting) {
234
+ pendingExtract = true;
235
+ return;
236
+ }
237
+ extracting = true;
238
+ try {
239
+ await runExtract();
240
+ while (pendingExtract) {
241
+ pendingExtract = false;
242
+ await runExtract();
243
+ }
244
+ }
245
+ finally {
246
+ extracting = false;
247
+ }
248
+ }
249
+ function scheduleExtract() {
250
+ if (debounceTimer !== null)
251
+ clearTimeout(debounceTimer);
252
+ debounceTimer = setTimeout(() => {
253
+ debounceTimer = null;
254
+ void runExtractQueued();
255
+ }, debounceMs);
256
+ }
257
+ wss.on('listening', () => {
258
+ const addr = wss.address();
259
+ const p = typeof addr === 'object' && addr ? addr.port : options.port;
260
+ options.onListening?.(p);
261
+ });
262
+ wss.on('connection', (ws) => {
263
+ clients.add(ws);
264
+ if (prevLayout && prevTreeJson !== null) {
265
+ const snap = {
266
+ layout: prevLayout,
267
+ tree: JSON.parse(prevTreeJson),
268
+ treeJson: prevTreeJson,
269
+ };
270
+ const text = JSON.stringify({
271
+ type: 'frame',
272
+ layout: snap.layout,
273
+ tree: snap.tree,
274
+ protocolVersion: PROXY_PROTOCOL_VERSION,
275
+ });
276
+ if (ws.readyState === ws.OPEN)
277
+ ws.send(text);
278
+ }
279
+ ws.on('message', (raw) => {
280
+ void handleClientMessage(options.page, ws, raw, kind => {
281
+ if (kind === 'resize') {
282
+ void runExtractQueued();
283
+ }
284
+ else {
285
+ scheduleExtract();
286
+ }
287
+ }, err => options.onError?.(err)).catch(err => options.onError?.(err));
288
+ });
289
+ ws.on('close', () => {
290
+ clients.delete(ws);
291
+ });
292
+ });
293
+ return {
294
+ scheduleExtract,
295
+ flushExtract: async () => {
296
+ if (debounceTimer !== null) {
297
+ clearTimeout(debounceTimer);
298
+ debounceTimer = null;
299
+ }
300
+ await runExtractQueued();
301
+ },
302
+ close: () => new Promise((resolve, reject) => {
303
+ for (const ws of clients) {
304
+ ws.close();
305
+ }
306
+ clients.clear();
307
+ wss.close(err => (err ? reject(err) : resolve()));
308
+ }),
309
+ };
310
+ }
311
+ export async function installDomObserver(page, scheduleExtract) {
312
+ await page.exposeFunction('__geometraProxyNotify', () => {
313
+ scheduleExtract();
314
+ });
315
+ await page.evaluate(() => {
316
+ const w = window;
317
+ const observer = new MutationObserver(() => {
318
+ void w.__geometraProxyNotify?.();
319
+ });
320
+ observer.observe(document.documentElement, {
321
+ subtree: true,
322
+ childList: true,
323
+ attributes: true,
324
+ characterData: true,
325
+ });
326
+ });
327
+ }
328
+ //# sourceMappingURL=geometry-ws.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry-ws.js","sourceRoot":"","sources":["../src/geometry-ws.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ import { chromium } from 'playwright';
3
+ import { installDomObserver, startGeometryWebSocket } from './geometry-ws.js';
4
+ function printUsage() {
5
+ console.error(`Usage: geometra-proxy <url> [--port <n>] [--width <n>] [--height <n>] [--headed]
6
+
7
+ Open <url> in headless Chromium and stream GEOM v1 frames on WebSocket (JSON text).
8
+
9
+ Examples:
10
+ geometra-proxy http://localhost:8080 --port 3200
11
+ geometra-proxy https://example.com --port 3200 --width 1440 --height 900
12
+ geometra-proxy http://localhost:3000 --headed
13
+
14
+ Requires Chromium for Playwright: npx playwright install chromium
15
+ `);
16
+ }
17
+ function parseArgs(argv) {
18
+ let url = '';
19
+ let port = 3200;
20
+ let width = 1280;
21
+ let height = 720;
22
+ let headed = false;
23
+ for (let i = 0; i < argv.length; i++) {
24
+ const a = argv[i];
25
+ if (a === '--port') {
26
+ port = Math.max(1, Number(argv[++i] ?? '0') || 3200);
27
+ }
28
+ else if (a === '--width') {
29
+ width = Math.max(1, Number(argv[++i] ?? '0') || 1280);
30
+ }
31
+ else if (a === '--height') {
32
+ height = Math.max(1, Number(argv[++i] ?? '0') || 720);
33
+ }
34
+ else if (a === '--headed') {
35
+ headed = true;
36
+ }
37
+ else if (!a.startsWith('-')) {
38
+ url = a;
39
+ }
40
+ else {
41
+ console.error(`Unknown option: ${a}`);
42
+ printUsage();
43
+ process.exit(1);
44
+ }
45
+ }
46
+ return { url, port, width, height, headed };
47
+ }
48
+ async function main() {
49
+ const { url, port, width, height, headed } = parseArgs(process.argv.slice(2));
50
+ if (!url) {
51
+ printUsage();
52
+ process.exit(1);
53
+ }
54
+ const browser = await chromium.launch({ headless: !headed });
55
+ const page = await browser.newPage();
56
+ await page.setViewportSize({ width, height });
57
+ console.error(`[geometra-proxy] Loading ${url} …`);
58
+ await page.goto(url, { waitUntil: 'domcontentloaded' });
59
+ const hub = startGeometryWebSocket({
60
+ port,
61
+ page,
62
+ debounceMs: 50,
63
+ onListening(p) {
64
+ console.error(`[geometra-proxy] WebSocket listening on ws://127.0.0.1:${p}`);
65
+ },
66
+ onError(err) {
67
+ console.error('[geometra-proxy] error:', err);
68
+ },
69
+ });
70
+ await hub.flushExtract();
71
+ await installDomObserver(page, hub.scheduleExtract);
72
+ console.error(`[geometra-proxy] Ready. Connect MCP with geometra_connect({ url: "ws://127.0.0.1:${port}" })`);
73
+ const shutdown = async () => {
74
+ try {
75
+ await hub.close();
76
+ }
77
+ catch {
78
+ /* ignore */
79
+ }
80
+ await browser.close();
81
+ process.exit(0);
82
+ };
83
+ process.on('SIGINT', () => void shutdown());
84
+ process.on('SIGTERM', () => void shutdown());
85
+ }
86
+ main().catch(err => {
87
+ console.error('[geometra-proxy] fatal:', err);
88
+ process.exit(1);
89
+ });
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { LayoutSnapshot } from './types.js';
2
+ /** Add (dx,dy) to every node in a layout subtree (in place). */
3
+ export declare function offsetLayoutSubtree(root: LayoutSnapshot, dx: number, dy: number): void;
4
+ //# sourceMappingURL=layout-offset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-offset.d.ts","sourceRoot":"","sources":["../src/layout-offset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAMtF"}
@@ -0,0 +1,9 @@
1
+ /** Add (dx,dy) to every node in a layout subtree (in place). */
2
+ export function offsetLayoutSubtree(root, dx, dy) {
3
+ root.x += dx;
4
+ root.y += dy;
5
+ for (const c of root.children) {
6
+ offsetLayoutSubtree(c, dx, dy);
7
+ }
8
+ }
9
+ //# sourceMappingURL=layout-offset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-offset.js","sourceRoot":"","sources":["../src/layout-offset.ts"],"names":[],"mappings":"AAEA,gEAAgE;AAChE,MAAM,UAAU,mBAAmB,CAAC,IAAoB,EAAE,EAAU,EAAE,EAAU;IAC9E,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;IACZ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;IACZ,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,mBAAmB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;IAChC,CAAC;AACH,CAAC"}
@@ -0,0 +1,109 @@
1
+ /** Layout snapshot aligned with Textura {@link ComputedLayout} / GEOM v1 `frame.layout`. */
2
+ export interface LayoutSnapshot {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ children: LayoutSnapshot[];
8
+ }
9
+ /** Synthetic UI tree shape consumed by `@geometra/mcp` `buildA11yTree` (JSON-serializable). */
10
+ export interface TreeSnapshot {
11
+ kind: 'box' | 'text' | 'image';
12
+ props: Record<string, unknown>;
13
+ semantic?: Record<string, unknown>;
14
+ /** Truthy flags only — matches JSON round-trips from native Geometra servers. */
15
+ handlers?: {
16
+ onClick?: boolean;
17
+ onKeyDown?: boolean;
18
+ onKeyUp?: boolean;
19
+ };
20
+ children?: TreeSnapshot[];
21
+ }
22
+ export interface GeometrySnapshot {
23
+ layout: LayoutSnapshot;
24
+ tree: TreeSnapshot;
25
+ /** `JSON.stringify(tree)` for deciding frame vs patch. */
26
+ treeJson: string;
27
+ }
28
+ export declare const PROXY_PROTOCOL_VERSION: 1;
29
+ export type ClientEventMessage = {
30
+ type: 'event';
31
+ eventType: string;
32
+ x: number;
33
+ y: number;
34
+ protocolVersion?: number;
35
+ };
36
+ export type ClientKeyMessage = {
37
+ type: 'key';
38
+ eventType: 'onKeyDown' | 'onKeyUp';
39
+ key: string;
40
+ code: string;
41
+ shiftKey: boolean;
42
+ ctrlKey: boolean;
43
+ metaKey: boolean;
44
+ altKey: boolean;
45
+ protocolVersion?: number;
46
+ };
47
+ export type ClientResizeMessage = {
48
+ type: 'resize';
49
+ width: number;
50
+ height: number;
51
+ capabilities?: {
52
+ binaryFraming?: boolean;
53
+ };
54
+ protocolVersion?: number;
55
+ };
56
+ export type ClientCompositionMessage = {
57
+ type: 'composition';
58
+ eventType: 'onCompositionStart' | 'onCompositionUpdate' | 'onCompositionEnd';
59
+ data: string;
60
+ protocolVersion?: number;
61
+ };
62
+ export type ClientFileMessage = {
63
+ type: 'file';
64
+ paths: string[];
65
+ x?: number;
66
+ y?: number;
67
+ strategy?: 'auto' | 'chooser' | 'hidden' | 'drop';
68
+ dropX?: number;
69
+ dropY?: number;
70
+ protocolVersion?: number;
71
+ };
72
+ export type ClientListboxPickMessage = {
73
+ type: 'listboxPick';
74
+ label: string;
75
+ exact?: boolean;
76
+ openX?: number;
77
+ openY?: number;
78
+ protocolVersion?: number;
79
+ };
80
+ export type ClientSelectOptionMessage = {
81
+ type: 'selectOption';
82
+ x: number;
83
+ y: number;
84
+ value?: string;
85
+ label?: string;
86
+ index?: number;
87
+ protocolVersion?: number;
88
+ };
89
+ export type ClientWheelMessage = {
90
+ type: 'wheel';
91
+ deltaX?: number;
92
+ deltaY?: number;
93
+ x?: number;
94
+ y?: number;
95
+ protocolVersion?: number;
96
+ };
97
+ export type ParsedClientMessage = ClientEventMessage | ClientKeyMessage | ClientResizeMessage | ClientCompositionMessage | ClientFileMessage | ClientListboxPickMessage | ClientSelectOptionMessage | ClientWheelMessage | {
98
+ type: string;
99
+ protocolVersion?: number;
100
+ };
101
+ export declare function isKeyMessage(msg: ParsedClientMessage): msg is ClientKeyMessage;
102
+ export declare function isResizeMessage(msg: ParsedClientMessage): msg is ClientResizeMessage;
103
+ export declare function isClickEventMessage(msg: ParsedClientMessage): msg is ClientEventMessage;
104
+ export declare function isCompositionMessage(msg: ParsedClientMessage): msg is ClientCompositionMessage;
105
+ export declare function isFileMessage(msg: ParsedClientMessage): msg is ClientFileMessage;
106
+ export declare function isSelectOptionMessage(msg: ParsedClientMessage): msg is ClientSelectOptionMessage;
107
+ export declare function isWheelMessage(msg: ParsedClientMessage): msg is ClientWheelMessage;
108
+ export declare function isListboxPickMessage(msg: ParsedClientMessage): msg is ClientListboxPickMessage;
109
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,30 @@
1
+ export const PROXY_PROTOCOL_VERSION = 1;
2
+ export function isKeyMessage(msg) {
3
+ return msg.type === 'key' && 'eventType' in msg && 'key' in msg && 'code' in msg;
4
+ }
5
+ export function isResizeMessage(msg) {
6
+ return msg.type === 'resize' && 'width' in msg && 'height' in msg;
7
+ }
8
+ export function isClickEventMessage(msg) {
9
+ return msg.type === 'event' && 'eventType' in msg && msg.eventType === 'onClick' && 'x' in msg && 'y' in msg;
10
+ }
11
+ export function isCompositionMessage(msg) {
12
+ return msg.type === 'composition' && 'eventType' in msg && 'data' in msg;
13
+ }
14
+ export function isFileMessage(msg) {
15
+ return msg.type === 'file' && 'paths' in msg && Array.isArray(msg.paths);
16
+ }
17
+ export function isSelectOptionMessage(msg) {
18
+ return (msg.type === 'selectOption' &&
19
+ 'x' in msg &&
20
+ 'y' in msg &&
21
+ typeof msg.x === 'number' &&
22
+ typeof msg.y === 'number');
23
+ }
24
+ export function isWheelMessage(msg) {
25
+ return msg.type === 'wheel';
26
+ }
27
+ export function isListboxPickMessage(msg) {
28
+ return msg.type === 'listboxPick' && 'label' in msg && typeof msg.label === 'string';
29
+ }
30
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA0BA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAU,CAAA;AAuFhD,MAAM,UAAU,YAAY,CAAC,GAAwB;IACnD,OAAO,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,WAAW,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,CAAA;AAClF,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAwB;IACtD,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,GAAG,IAAI,QAAQ,IAAI,GAAG,CAAA;AACnE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAwB;IAC1D,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,IAAI,WAAW,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,CAAA;AAC9G,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAwB;IAC3D,OAAO,GAAG,CAAC,IAAI,KAAK,aAAa,IAAI,WAAW,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,CAAA;AAC1E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAwB;IACpD,OAAO,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,CAAE,GAAyB,CAAC,KAAK,CAAC,CAAA;AACjG,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAwB;IAC5D,OAAO,CACL,GAAG,CAAC,IAAI,KAAK,cAAc;QAC3B,GAAG,IAAI,GAAG;QACV,GAAG,IAAI,GAAG;QACV,OAAQ,GAAiC,CAAC,CAAC,KAAK,QAAQ;QACxD,OAAQ,GAAiC,CAAC,CAAC,KAAK,QAAQ,CACzD,CAAA;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAwB;IACrD,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAA;AAC7B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAwB;IAC3D,OAAO,GAAG,CAAC,IAAI,KAAK,aAAa,IAAI,OAAO,IAAI,GAAG,IAAI,OAAQ,GAAgC,CAAC,KAAK,KAAK,QAAQ,CAAA;AACpH,CAAC"}