@tom2012/cc-web 2026.5.24-b → 2026.5.24-c

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 (49) hide show
  1. package/README.md +1 -1
  2. package/backend/dist/__tests__/browser-chrome-e2e.test.d.ts +2 -0
  3. package/backend/dist/__tests__/browser-chrome-e2e.test.d.ts.map +1 -0
  4. package/backend/dist/__tests__/browser-chrome-e2e.test.js +121 -0
  5. package/backend/dist/__tests__/browser-chrome-e2e.test.js.map +1 -0
  6. package/backend/dist/__tests__/browser-chrome.test.d.ts +2 -0
  7. package/backend/dist/__tests__/browser-chrome.test.d.ts.map +1 -0
  8. package/backend/dist/__tests__/browser-chrome.test.js +169 -0
  9. package/backend/dist/__tests__/browser-chrome.test.js.map +1 -0
  10. package/backend/dist/browser-chrome/input-forwarder.d.ts +32 -0
  11. package/backend/dist/browser-chrome/input-forwarder.d.ts.map +1 -0
  12. package/backend/dist/browser-chrome/input-forwarder.js +92 -0
  13. package/backend/dist/browser-chrome/input-forwarder.js.map +1 -0
  14. package/backend/dist/browser-chrome/screencast.d.ts +21 -0
  15. package/backend/dist/browser-chrome/screencast.d.ts.map +1 -0
  16. package/backend/dist/browser-chrome/screencast.js +78 -0
  17. package/backend/dist/browser-chrome/screencast.js.map +1 -0
  18. package/backend/dist/browser-chrome/session-manager.d.ts +38 -0
  19. package/backend/dist/browser-chrome/session-manager.d.ts.map +1 -0
  20. package/backend/dist/browser-chrome/session-manager.js +175 -0
  21. package/backend/dist/browser-chrome/session-manager.js.map +1 -0
  22. package/backend/dist/index.d.ts.map +1 -1
  23. package/backend/dist/index.js +53 -0
  24. package/backend/dist/index.js.map +1 -1
  25. package/backend/dist/routes/browser-chrome.d.ts +4 -0
  26. package/backend/dist/routes/browser-chrome.d.ts.map +1 -0
  27. package/backend/dist/routes/browser-chrome.js +106 -0
  28. package/backend/dist/routes/browser-chrome.js.map +1 -0
  29. package/backend/package-lock.json +45 -0
  30. package/backend/package.json +1 -0
  31. package/frontend/dist/assets/{ChatOverlay-Cm7M9uTo.js → ChatOverlay-DWnJouqf.js} +1 -1
  32. package/frontend/dist/assets/{GraphPreview-Bu-zdWO0.js → GraphPreview-BhYiu0BC.js} +1 -1
  33. package/frontend/dist/assets/{MobilePage-DHSd8DBY.js → MobilePage-CpwaYT93.js} +3 -3
  34. package/frontend/dist/assets/{OfficePreview-CKOQ-aQd.js → OfficePreview-AIsCrFJN.js} +2 -2
  35. package/frontend/dist/assets/{PdfPreview-G8fpvo6_.js → PdfPreview-BOf3iH2G.js} +1 -1
  36. package/frontend/dist/assets/{ProjectPage-D8O-uvJ3.js → ProjectPage-BLDngPUN.js} +5 -5
  37. package/frontend/dist/assets/SettingsPage-898duvMO.js +13 -0
  38. package/frontend/dist/assets/{SkillHubPage-BcohQzQq.js → SkillHubPage-Cf3oFMk3.js} +1 -1
  39. package/frontend/dist/assets/{chevron-down-BjD1KDpf.js → chevron-down-CWdHpHQs.js} +1 -1
  40. package/frontend/dist/assets/{index-dlR56s5t.js → index-DoKF15jh.js} +1 -1
  41. package/frontend/dist/assets/{index-Fi22OrSt.js → index-DtlKk29C.js} +2 -2
  42. package/frontend/dist/assets/{index-BxSzFzfM.js → index-DzV3STk-.js} +1 -1
  43. package/frontend/dist/assets/{jszip.min-j8-Zud6N.js → jszip.min-BiyTb6vp.js} +1 -1
  44. package/frontend/dist/assets/{search-CfhpkpXs.js → search-DAr7qjB5.js} +1 -1
  45. package/frontend/dist/assets/select-IaWIRuom.js +13 -0
  46. package/frontend/dist/index.html +1 -1
  47. package/package.json +1 -1
  48. package/frontend/dist/assets/SettingsPage-a3v0GKkG.js +0 -13
  49. package/frontend/dist/assets/select-nwQBXqLw.js +0 -13
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A self-hosted web application (distributed as npm package) that provides a browser-based interface for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI sessions. Create projects, each with a persistent terminal running Claude Code, and interact with them through a real-time terminal UI.
4
4
 
5
- **Current version**: v2026.5.24-b | [GitHub](https://github.com/zbc0315/cc-web) | MIT License
5
+ **Current version**: v2026.5.24-c | [GitHub](https://github.com/zbc0315/cc-web) | MIT License
6
6
 
7
7
  ## Features
8
8
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=browser-chrome-e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-chrome-e2e.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/browser-chrome-e2e.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ /**
37
+ * E2E: launches real headless chromium via SessionManager and verifies
38
+ * screencast frames are delivered. Skipped if chromium binary missing.
39
+ *
40
+ * Run: npx vitest run src/__tests__/browser-chrome-e2e.test.ts
41
+ */
42
+ const vitest_1 = require("vitest");
43
+ const http = __importStar(require("http"));
44
+ const playwright_1 = require("playwright");
45
+ const session_manager_1 = require("../browser-chrome/session-manager");
46
+ const screencast_1 = require("../browser-chrome/screencast");
47
+ // Skip if chromium binary not installed locally — keeps CI green when
48
+ // `npx playwright install chromium` hasn't run.
49
+ let chromiumAvailable = false;
50
+ try {
51
+ const path = playwright_1.chromium.executablePath();
52
+ chromiumAvailable = !!path;
53
+ }
54
+ catch {
55
+ chromiumAvailable = false;
56
+ }
57
+ vitest_1.describe.skipIf(!chromiumAvailable)('browser-chrome e2e (real chromium)', () => {
58
+ let upstream;
59
+ let upstreamPort = 0;
60
+ // Minimal mock WS that captures sent messages — avoids needing a real
61
+ // server/client pair just to verify screencast delivers frames.
62
+ function mockWs() {
63
+ const sent = [];
64
+ const ws = {
65
+ readyState: 1, // OPEN
66
+ bufferedAmount: 0,
67
+ send: (data) => sent.push(data),
68
+ close: () => { ws.readyState = 3; },
69
+ };
70
+ return { sent, ws };
71
+ }
72
+ (0, vitest_1.afterAll)(async () => {
73
+ await session_manager_1.browserChromeSessions.destroyAll();
74
+ if (upstream)
75
+ await new Promise(r => upstream.close(() => r()));
76
+ }, 30000);
77
+ (0, vitest_1.it)('starts chromium, navigates to local server, and delivers screencast frames', async () => {
78
+ upstream = http.createServer((req, res) => {
79
+ res.writeHead(200, { 'Content-Type': 'text/html' });
80
+ // Animated page is required — CDP screencast only emits frames on
81
+ // visual change, a fully static page yields zero frames.
82
+ res.end(`<html><body style="background:#f00;font-size:48px">
83
+ <div id="c">0</div>
84
+ <script>let n=0;setInterval(()=>{document.getElementById('c').textContent=++n},50)</script>
85
+ </body></html>`);
86
+ });
87
+ await new Promise(r => upstream.listen(0, '127.0.0.1', r));
88
+ upstreamPort = upstream.address().port;
89
+ const session = await session_manager_1.browserChromeSessions.getOrCreate('e2e-user');
90
+ (0, vitest_1.expect)(session.sid).toBeTruthy();
91
+ (0, vitest_1.expect)(session.username).toBe('e2e-user');
92
+ await session.page.goto(`http://127.0.0.1:${upstreamPort}/`, { waitUntil: 'load' });
93
+ (0, vitest_1.expect)(session.page.url()).toContain('127.0.0.1');
94
+ const { sent, ws } = mockWs();
95
+ const stop = await (0, screencast_1.startScreencast)(session, ws);
96
+ // Wait for at least 1 frame (chromium usually emits within 200ms after page paints).
97
+ await new Promise((resolve, reject) => {
98
+ const t = setTimeout(() => reject(new Error('no frame in 3s')), 3000);
99
+ const i = setInterval(() => {
100
+ if (sent.length > 0) {
101
+ clearTimeout(t);
102
+ clearInterval(i);
103
+ resolve();
104
+ }
105
+ }, 50);
106
+ });
107
+ (0, vitest_1.expect)(sent.length).toBeGreaterThan(0);
108
+ const msg = JSON.parse(sent[0]);
109
+ (0, vitest_1.expect)(msg.type).toBe('frame');
110
+ (0, vitest_1.expect)(msg.format).toBe('jpeg');
111
+ (0, vitest_1.expect)(typeof msg.data).toBe('string');
112
+ (0, vitest_1.expect)(msg.data.length).toBeGreaterThan(100);
113
+ await stop();
114
+ }, 30000);
115
+ (0, vitest_1.it)('reuses session for same user', async () => {
116
+ const a = await session_manager_1.browserChromeSessions.getOrCreate('reuse-user');
117
+ const b = await session_manager_1.browserChromeSessions.getOrCreate('reuse-user');
118
+ (0, vitest_1.expect)(a.sid).toBe(b.sid);
119
+ }, 30000);
120
+ });
121
+ //# sourceMappingURL=browser-chrome-e2e.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-chrome-e2e.test.js","sourceRoot":"","sources":["../../src/__tests__/browser-chrome-e2e.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=browser-chrome.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-chrome.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/browser-chrome.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const vitest_1 = require("vitest");
37
+ const jwt = __importStar(require("jsonwebtoken"));
38
+ const session_manager_1 = require("../browser-chrome/session-manager");
39
+ const config_1 = require("../config");
40
+ (0, vitest_1.describe)('mintSessionToken / verifySessionToken', () => {
41
+ (0, vitest_1.it)('round-trips a valid token', () => {
42
+ const token = (0, session_manager_1.mintSessionToken)('sid-1', 'tom');
43
+ const claim = (0, session_manager_1.verifySessionToken)(token);
44
+ (0, vitest_1.expect)(claim).toEqual({ sid: 'sid-1', username: 'tom' });
45
+ });
46
+ (0, vitest_1.it)('rejects token with wrong typ', () => {
47
+ const config = (0, config_1.getConfig)();
48
+ const wrongTyp = jwt.sign({ sid: 'x', username: 'tom', typ: 'user' }, config.jwtSecret, { expiresIn: '1h' });
49
+ (0, vitest_1.expect)((0, session_manager_1.verifySessionToken)(wrongTyp)).toBeNull();
50
+ });
51
+ (0, vitest_1.it)('rejects token signed with wrong secret', () => {
52
+ const wrong = jwt.sign({ sid: 'x', username: 'tom', typ: 'browser-chrome' }, 'wrong-secret', { expiresIn: '1h' });
53
+ (0, vitest_1.expect)((0, session_manager_1.verifySessionToken)(wrong)).toBeNull();
54
+ });
55
+ (0, vitest_1.it)('rejects token missing sid or username', () => {
56
+ const config = (0, config_1.getConfig)();
57
+ const noSid = jwt.sign({ username: 'tom', typ: 'browser-chrome' }, config.jwtSecret, { expiresIn: '1h' });
58
+ (0, vitest_1.expect)((0, session_manager_1.verifySessionToken)(noSid)).toBeNull();
59
+ const noUser = jwt.sign({ sid: 'x', typ: 'browser-chrome' }, config.jwtSecret, { expiresIn: '1h' });
60
+ (0, vitest_1.expect)((0, session_manager_1.verifySessionToken)(noUser)).toBeNull();
61
+ });
62
+ (0, vitest_1.it)('rejects malformed token', () => {
63
+ (0, vitest_1.expect)((0, session_manager_1.verifySessionToken)('not-a-jwt')).toBeNull();
64
+ (0, vitest_1.expect)((0, session_manager_1.verifySessionToken)('')).toBeNull();
65
+ });
66
+ });
67
+ // Pure-logic tests for input-forwarder require it to export sanitize helpers
68
+ // or accept a mock page. We test sanitize/clamp behavior indirectly by
69
+ // constructing edge-case messages and asserting they don't throw with a
70
+ // minimal mock Page.
71
+ (0, vitest_1.describe)('handleInput (with mock page)', () => {
72
+ // Lazy import to avoid pulling playwright at module load.
73
+ (0, vitest_1.it)('clamps out-of-range click coords and ignores invalid modifiers', async () => {
74
+ const calls = [];
75
+ const mockPage = {
76
+ mouse: {
77
+ click: async (x, y, opts) => { calls.push(['click', x, y, opts.button]); },
78
+ move: async () => { calls.push(['move']); },
79
+ wheel: async (dx, dy) => { calls.push(['wheel', dx, dy]); },
80
+ },
81
+ keyboard: {
82
+ down: async (k) => { calls.push(['kd', k]); },
83
+ up: async (k) => { calls.push(['ku', k]); },
84
+ press: async (k) => { calls.push(['kp', k]); },
85
+ type: async (t) => { calls.push(['type', t]); },
86
+ },
87
+ setViewportSize: async (s) => { calls.push(['vp', s.width, s.height]); },
88
+ };
89
+ const mockSession = {
90
+ sid: 's', username: 'u', browser: {}, context: {},
91
+ page: mockPage, cdp: {},
92
+ createdAt: 0, lastActivityAt: 0,
93
+ viewport: { w: 1280, h: 800 }, url: '',
94
+ };
95
+ const { handleInput } = await Promise.resolve().then(() => __importStar(require('../browser-chrome/input-forwarder')));
96
+ // Negative coords clamp to 0; over-max clamp to viewport.
97
+ await handleInput(mockSession, { type: 'click', x: -100, y: -50 });
98
+ (0, vitest_1.expect)(calls).toContainEqual(['click', 0, 0, 'left']);
99
+ calls.length = 0;
100
+ await handleInput(mockSession, { type: 'click', x: 9999, y: 9999, button: 'right', modifiers: ['Shift', 'EvilMod'] });
101
+ // EvilMod dropped; Shift held around click.
102
+ (0, vitest_1.expect)(calls).toEqual([
103
+ ['kd', 'Shift'],
104
+ ['click', 1280, 800, 'right'],
105
+ ['ku', 'Shift'],
106
+ ]);
107
+ // Scroll clamps delta.
108
+ calls.length = 0;
109
+ await handleInput(mockSession, { type: 'scroll', x: 100, y: 100, deltaX: 999999, deltaY: -999999 });
110
+ (0, vitest_1.expect)(calls).toEqual([
111
+ ['move'],
112
+ ['wheel', 10000, -10000],
113
+ ]);
114
+ // type with too-long text rejected silently.
115
+ calls.length = 0;
116
+ await handleInput(mockSession, { type: 'type', text: 'x'.repeat(2000) });
117
+ (0, vitest_1.expect)(calls).toEqual([]);
118
+ // type with normal text works.
119
+ calls.length = 0;
120
+ await handleInput(mockSession, { type: 'type', text: 'hello' });
121
+ (0, vitest_1.expect)(calls).toEqual([['type', 'hello']]);
122
+ // resize clamps to bounds.
123
+ calls.length = 0;
124
+ await handleInput(mockSession, { type: 'resize', w: 50, h: 100000 });
125
+ (0, vitest_1.expect)(calls).toEqual([['vp', 200, 2160]]);
126
+ (0, vitest_1.expect)(mockSession.viewport).toEqual({ w: 200, h: 2160 });
127
+ });
128
+ (0, vitest_1.it)('key event uses press by default and releases modifiers in reverse', async () => {
129
+ const calls = [];
130
+ const mockPage = {
131
+ mouse: { click: async () => { }, move: async () => { }, wheel: async () => { } },
132
+ keyboard: {
133
+ down: async (k) => { calls.push(`d:${k}`); },
134
+ up: async (k) => { calls.push(`u:${k}`); },
135
+ press: async (k) => { calls.push(`p:${k}`); },
136
+ type: async () => { },
137
+ },
138
+ setViewportSize: async () => { },
139
+ };
140
+ const mockSession = {
141
+ sid: 's', username: 'u', browser: {}, context: {},
142
+ page: mockPage, cdp: {},
143
+ createdAt: 0, lastActivityAt: 0,
144
+ viewport: { w: 1280, h: 800 }, url: '',
145
+ };
146
+ const { handleInput } = await Promise.resolve().then(() => __importStar(require('../browser-chrome/input-forwarder')));
147
+ await handleInput(mockSession, { type: 'key', action: 'press', key: 'a', modifiers: ['Control', 'Shift'] });
148
+ (0, vitest_1.expect)(calls).toEqual(['d:Control', 'd:Shift', 'p:a', 'u:Shift', 'u:Control']);
149
+ });
150
+ (0, vitest_1.it)('drops key event when key is empty or too long', async () => {
151
+ const calls = [];
152
+ const mockPage = {
153
+ mouse: { click: async () => { }, move: async () => { }, wheel: async () => { } },
154
+ keyboard: { down: async () => { }, up: async () => { }, press: async (k) => { calls.push(k); }, type: async () => { } },
155
+ setViewportSize: async () => { },
156
+ };
157
+ const mockSession = {
158
+ sid: 's', username: 'u', browser: {}, context: {},
159
+ page: mockPage, cdp: {},
160
+ createdAt: 0, lastActivityAt: 0,
161
+ viewport: { w: 1280, h: 800 }, url: '',
162
+ };
163
+ const { handleInput } = await Promise.resolve().then(() => __importStar(require('../browser-chrome/input-forwarder')));
164
+ await handleInput(mockSession, { type: 'key', action: 'press', key: '' });
165
+ await handleInput(mockSession, { type: 'key', action: 'press', key: 'x'.repeat(100) });
166
+ (0, vitest_1.expect)(calls).toEqual([]);
167
+ });
168
+ });
169
+ //# sourceMappingURL=browser-chrome.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-chrome.test.js","sourceRoot":"","sources":["../../src/__tests__/browser-chrome.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Session } from './session-manager';
2
+ export type InputMsg = {
3
+ type: 'click';
4
+ x: number;
5
+ y: number;
6
+ button?: string;
7
+ modifiers?: string[];
8
+ } | {
9
+ type: 'mousemove';
10
+ x: number;
11
+ y: number;
12
+ } | {
13
+ type: 'scroll';
14
+ x: number;
15
+ y: number;
16
+ deltaX: number;
17
+ deltaY: number;
18
+ } | {
19
+ type: 'key';
20
+ action: 'down' | 'up' | 'press';
21
+ key: string;
22
+ modifiers?: string[];
23
+ } | {
24
+ type: 'type';
25
+ text: string;
26
+ } | {
27
+ type: 'resize';
28
+ w: number;
29
+ h: number;
30
+ };
31
+ export declare function handleInput(session: Session, msg: InputMsg): Promise<void>;
32
+ //# sourceMappingURL=input-forwarder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-forwarder.d.ts","sourceRoot":"","sources":["../../src/browser-chrome/input-forwarder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAajD,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACnF;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAgB7C,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DhF"}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleInput = handleInput;
4
+ const logger_1 = require("../logger");
5
+ const log = (0, logger_1.modLogger)('browser-chrome:input');
6
+ // Whitelist of modifier names accepted from the client. Anything else is
7
+ // silently dropped — defends against bogus values being passed straight
8
+ // to playwright's keyboard API.
9
+ const VALID_MODIFIERS = ['Shift', 'Control', 'Alt', 'Meta'];
10
+ const VALID_BUTTONS = ['left', 'right', 'middle'];
11
+ function clamp(n, min, max) {
12
+ if (!Number.isFinite(n))
13
+ return min;
14
+ return Math.max(min, Math.min(max, Math.round(n)));
15
+ }
16
+ function sanitizeModifiers(arr) {
17
+ if (!Array.isArray(arr))
18
+ return [];
19
+ return arr.filter((m) => VALID_MODIFIERS.includes(m));
20
+ }
21
+ function sanitizeButton(b) {
22
+ return VALID_BUTTONS.includes(b ?? '') ? b : 'left';
23
+ }
24
+ async function handleInput(session, msg) {
25
+ session.lastActivityAt = Date.now();
26
+ switch (msg.type) {
27
+ case 'click': {
28
+ const x = clamp(msg.x, 0, session.viewport.w);
29
+ const y = clamp(msg.y, 0, session.viewport.h);
30
+ const mods = sanitizeModifiers(msg.modifiers);
31
+ for (const m of mods)
32
+ await session.page.keyboard.down(m);
33
+ try {
34
+ await session.page.mouse.click(x, y, { button: sanitizeButton(msg.button) });
35
+ }
36
+ finally {
37
+ for (const m of [...mods].reverse())
38
+ await session.page.keyboard.up(m).catch(() => { });
39
+ }
40
+ break;
41
+ }
42
+ case 'mousemove': {
43
+ const x = clamp(msg.x, 0, session.viewport.w);
44
+ const y = clamp(msg.y, 0, session.viewport.h);
45
+ await session.page.mouse.move(x, y);
46
+ break;
47
+ }
48
+ case 'scroll': {
49
+ const x = clamp(msg.x, 0, session.viewport.w);
50
+ const y = clamp(msg.y, 0, session.viewport.h);
51
+ await session.page.mouse.move(x, y);
52
+ await session.page.mouse.wheel(clamp(msg.deltaX, -10000, 10000), clamp(msg.deltaY, -10000, 10000));
53
+ break;
54
+ }
55
+ case 'key': {
56
+ if (typeof msg.key !== 'string' || msg.key.length === 0 || msg.key.length > 32)
57
+ return;
58
+ const mods = sanitizeModifiers(msg.modifiers);
59
+ // Hold modifiers, perform key action, release modifiers (in reverse).
60
+ for (const m of mods)
61
+ await session.page.keyboard.down(m);
62
+ try {
63
+ if (msg.action === 'down')
64
+ await session.page.keyboard.down(msg.key);
65
+ else if (msg.action === 'up')
66
+ await session.page.keyboard.up(msg.key);
67
+ else
68
+ await session.page.keyboard.press(msg.key);
69
+ }
70
+ finally {
71
+ for (const m of [...mods].reverse())
72
+ await session.page.keyboard.up(m).catch(() => { });
73
+ }
74
+ break;
75
+ }
76
+ case 'type': {
77
+ if (typeof msg.text !== 'string' || msg.text.length === 0 || msg.text.length > 1000)
78
+ return;
79
+ await session.page.keyboard.type(msg.text);
80
+ break;
81
+ }
82
+ case 'resize': {
83
+ const w = clamp(msg.w, 200, 3840);
84
+ const h = clamp(msg.h, 200, 2160);
85
+ await session.page.setViewportSize({ width: w, height: h });
86
+ session.viewport = { w, h };
87
+ log.info({ sid: session.sid, w, h }, 'viewport resized');
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ //# sourceMappingURL=input-forwarder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-forwarder.js","sourceRoot":"","sources":["../../src/browser-chrome/input-forwarder.ts"],"names":[],"mappings":";;AAmCA,kCA2DC;AA7FD,sCAAsC;AAEtC,MAAM,GAAG,GAAG,IAAA,kBAAS,EAAC,sBAAsB,CAAC,CAAC;AAE9C,yEAAyE;AACzE,wEAAwE;AACxE,gCAAgC;AAChC,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAU,CAAC;AAErE,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAW3D,SAAS,KAAK,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW;IAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAc;IACvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAiB,EAAE,CAAE,eAAqC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9F,CAAC;AAED,SAAS,cAAc,CAAC,CAAU;IAChC,OAAQ,aAAmC,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,CAAY,CAAC,CAAC,CAAC,MAAM,CAAC;AACzF,CAAC;AAEM,KAAK,UAAU,WAAW,CAAC,OAAgB,EAAE,GAAa;IAC/D,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC9C,KAAK,MAAM,CAAC,IAAI,IAAI;gBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/E,CAAC;oBAAS,CAAC;gBACT,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE;oBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACzF,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpC,MAAM;QACR,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAC5B,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAChC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CACjC,CAAC;YACF,MAAM;QACR,CAAC;QACD,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE;gBAAE,OAAO;YACvF,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC9C,sEAAsE;YACtE,KAAK,MAAM,CAAC,IAAI,IAAI;gBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAC;gBACH,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM;oBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;qBAChE,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;oBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;;oBACjE,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClD,CAAC;oBAAS,CAAC;gBACT,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE;oBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACzF,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI;gBAAE,OAAO;YAC5F,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM;QACR,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAClC,MAAM,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YAC5D,OAAO,CAAC,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;YACzD,MAAM;QACR,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type WebSocket from 'ws';
2
+ import type { Session } from './session-manager';
3
+ export interface ScreencastConfig {
4
+ format: 'jpeg' | 'png';
5
+ quality: number;
6
+ maxWidth: number;
7
+ maxHeight: number;
8
+ everyNthFrame: number;
9
+ }
10
+ /**
11
+ * Start CDP screencast on the given session, forwarding base64 frames to the
12
+ * WebSocket as JSON messages. Returns a stopper that detaches the listener
13
+ * and stops the upstream screencast.
14
+ *
15
+ * Backpressure: if ws.bufferedAmount exceeds the ceiling we skip sending the
16
+ * frame to the client BUT still ack to chromium so it keeps producing.
17
+ * Dropping the frame is preferable to letting daemon memory balloon when
18
+ * a slow client falls behind.
19
+ */
20
+ export declare function startScreencast(session: Session, ws: WebSocket, cfg?: Partial<ScreencastConfig>): Promise<() => Promise<void>>;
21
+ //# sourceMappingURL=screencast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screencast.d.ts","sourceRoot":"","sources":["../../src/browser-chrome/screencast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAmBD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,SAAS,EACb,GAAG,GAAE,OAAO,CAAC,gBAAgB,CAAM,GAClC,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAqD9B"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startScreencast = startScreencast;
4
+ const logger_1 = require("../logger");
5
+ const log = (0, logger_1.modLogger)('browser-chrome:screencast');
6
+ const DEFAULT = {
7
+ format: 'jpeg',
8
+ quality: 70,
9
+ maxWidth: 1280,
10
+ maxHeight: 800,
11
+ // 30fps source / 3 → ~10fps. Research/PoC confirm sweet spot.
12
+ everyNthFrame: 3,
13
+ };
14
+ const WS_BUFFER_CEILING_BYTES = 4 * 1024 * 1024;
15
+ /**
16
+ * Start CDP screencast on the given session, forwarding base64 frames to the
17
+ * WebSocket as JSON messages. Returns a stopper that detaches the listener
18
+ * and stops the upstream screencast.
19
+ *
20
+ * Backpressure: if ws.bufferedAmount exceeds the ceiling we skip sending the
21
+ * frame to the client BUT still ack to chromium so it keeps producing.
22
+ * Dropping the frame is preferable to letting daemon memory balloon when
23
+ * a slow client falls behind.
24
+ */
25
+ async function startScreencast(session, ws, cfg = {}) {
26
+ const config = { ...DEFAULT, ...cfg };
27
+ const onFrame = async (params) => {
28
+ if (ws.readyState !== 1 /* OPEN */)
29
+ return;
30
+ const dropForBackpressure = ws.bufferedAmount > WS_BUFFER_CEILING_BYTES;
31
+ if (!dropForBackpressure) {
32
+ try {
33
+ ws.send(JSON.stringify({
34
+ type: 'frame',
35
+ data: params.data,
36
+ format: config.format,
37
+ ts: Date.now(),
38
+ }));
39
+ }
40
+ catch (err) {
41
+ log.warn({ err, sid: session.sid }, 'frame send failed');
42
+ }
43
+ }
44
+ else {
45
+ log.warn({ sid: session.sid, buf: ws.bufferedAmount }, 'WS backlog, dropping frame');
46
+ }
47
+ // Always ack upstream — not acking would stall chromium for ALL clients
48
+ // sharing the page (we're single-client per page, but still hygienic).
49
+ try {
50
+ await session.cdp.send('Page.screencastFrameAck', { sessionId: params.sessionId });
51
+ }
52
+ catch (err) {
53
+ // CDP may already be detached during teardown — not an error.
54
+ }
55
+ };
56
+ session.cdp.on('Page.screencastFrame', onFrame);
57
+ await session.cdp.send('Page.startScreencast', {
58
+ format: config.format,
59
+ quality: config.quality,
60
+ maxWidth: config.maxWidth,
61
+ maxHeight: config.maxHeight,
62
+ everyNthFrame: config.everyNthFrame,
63
+ });
64
+ log.info({ sid: session.sid, config }, 'screencast started');
65
+ let stopped = false;
66
+ return async () => {
67
+ if (stopped)
68
+ return;
69
+ stopped = true;
70
+ session.cdp.off('Page.screencastFrame', onFrame);
71
+ try {
72
+ await session.cdp.send('Page.stopScreencast');
73
+ }
74
+ catch { /* session may already be dead */ }
75
+ log.info({ sid: session.sid }, 'screencast stopped');
76
+ };
77
+ }
78
+ //# sourceMappingURL=screencast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screencast.js","sourceRoot":"","sources":["../../src/browser-chrome/screencast.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type Browser, type BrowserContext, type Page, type CDPSession } from 'playwright';
2
+ import { EventEmitter } from 'events';
3
+ export interface Session {
4
+ sid: string;
5
+ username: string;
6
+ browser: Browser;
7
+ context: BrowserContext;
8
+ page: Page;
9
+ cdp: CDPSession;
10
+ createdAt: number;
11
+ lastActivityAt: number;
12
+ viewport: {
13
+ w: number;
14
+ h: number;
15
+ };
16
+ url: string;
17
+ }
18
+ declare class SessionManager extends EventEmitter {
19
+ private sessions;
20
+ private idleTimer;
21
+ private started;
22
+ start(): void;
23
+ /** Return existing session for this user (reuse) or create a new one. */
24
+ getOrCreate(username: string): Promise<Session>;
25
+ get(sid: string, username: string): Session | null;
26
+ destroy(sid: string): Promise<void>;
27
+ destroyAll(): Promise<void>;
28
+ size(): number;
29
+ private sweepIdle;
30
+ }
31
+ export declare const browserChromeSessions: SessionManager;
32
+ export declare function mintSessionToken(sid: string, username: string): string;
33
+ export declare function verifySessionToken(token: string): {
34
+ sid: string;
35
+ username: string;
36
+ } | null;
37
+ export {};
38
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/browser-chrome/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAErG,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAOtC,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,UAAU,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;CACb;AAMD,cAAM,cAAe,SAAQ,YAAY;IACvC,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,OAAO,CAAS;IAExB,KAAK,IAAI,IAAI;IAMb,yEAAyE;IACnE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiDrD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAQ5C,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAanC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,SAAS;CASlB;AAED,eAAO,MAAM,qBAAqB,gBAAuB,CAAC;AAO1D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOtE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAU1F"}