@ceki/n8n-nodes-ceki 0.2.8 → 0.2.10

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Rent real human browsers inside your n8n workflows.**
4
4
 
5
- [Ceki](https://browser.ceki.me) lets AI agents and automations rent live, human-operated browsers by the minute — real fingerprints, real IPs, real humans solving captchas. This package brings Ceki into n8n as native nodes: drive a rented browser, scrape anti-bot pages, screenshot from any geo, and orchestrate Ceki's contract system where a workflow can hire agents and people.
5
+ [Ceki](https://ceki.me) lets AI agents and automations rent live, human-operated browsers by the minute — real fingerprints, real IPs, real humans solving captchas. This package brings Ceki into n8n as native nodes: drive a rented browser, scrape anti-bot pages, screenshot from any geo, and orchestrate Ceki's contract system where a workflow can hire agents and people.
6
6
 
7
7
  - **Real human browsers** — not headless, not emulation. Actual Chrome sessions with genuine fingerprints that pass anti-bot checks.
8
8
  - **Geo-targeting** — appear from RU, EE, US, or wherever a human host is online.
@@ -10,7 +10,7 @@
10
10
  - **Pay-as-you-go** — from **$0.01/min**. Pay only for the minutes you use; close the session and billing stops.
11
11
  - **Hire from a workflow** — the Ceki Contract node lets your automation create tasks, assign them to agents or humans, and escalate when it's stuck.
12
12
 
13
- All of the logic lives in [`@ceki/sdk`](https://browser.ceki.me/docs) — these nodes are a thin, typed UI on top.
13
+ All of the logic lives in [`@ceki/sdk`](https://github.com/Ceki-me/js-sdk) — these nodes are a thin, typed UI on top.
14
14
 
15
15
  ## Install
16
16
 
@@ -23,7 +23,7 @@ npm install n8n-nodes-ceki
23
23
 
24
24
  ## Credential
25
25
 
26
- Create it once: **Ceki API** → set `token` to your agent token (`ag_...`) from the [Ceki panel](https://browser.ceki.me). One credential powers every node.
26
+ Create it once: **Ceki API** → set `token` to your agent token (`ag_...`) from the [Ceki panel](https://ceki.me/dashboard/agents). One credential powers every node.
27
27
 
28
28
  ## Nodes
29
29
 
@@ -111,9 +111,9 @@ To use locally in n8n, link `dist/` via `N8N_CUSTOM_EXTENSIONS` or `NODE_PATH`.
111
111
 
112
112
  - [browser.ceki.me](https://browser.ceki.me) — rent a browser or become a host
113
113
  - [Docs](https://browser.ceki.me/docs) — API key, SDK reference, recipes
114
- - [`@ceki/sdk`](https://browser.ceki.me/docs) — the engine behind these nodes
115
- - [MCP](https://browser.ceki.me/mcp) — drive Ceki from any MCP-compatible agent
114
+ - [`@ceki/sdk`](https://github.com/Ceki-me/js-sdk) — the engine behind these nodes
115
+ - [MCP](https://ceki.me/mcp) — drive Ceki from any MCP-compatible agent
116
116
 
117
117
  ## License
118
118
 
119
- MIT. Depends on [`@ceki/sdk`](https://browser.ceki.me/docs).
119
+ MIT. Depends on [`@ceki/sdk`](https://github.com/Ceki-me/js-sdk).
package/dist/index.js CHANGED
@@ -473,7 +473,9 @@ var BrowserCeki = class {
473
473
  { name: "Wait for Selector", value: "waitForSelector" },
474
474
  { name: "Upload", value: "upload" },
475
475
  { name: "Close", value: "close" },
476
- { name: "Full: Rent \u2192 Navigate \u2192 Screenshot", value: "full" }
476
+ { name: "Full: Rent \u2192 Navigate \u2192 Screenshot", value: "full" },
477
+ { name: "My Sessions", value: "my_sessions" },
478
+ { name: "Stop Session", value: "stop_session" }
477
479
  ]
478
480
  },
479
481
  // === Rent: rental parameters ===
@@ -545,7 +547,7 @@ var BrowserCeki = class {
545
547
  required: true,
546
548
  displayOptions: {
547
549
  show: {
548
- operation: ["navigate", "click", "type", "scroll", "screenshot", "snapshot", "wait", "waitForSelector", "upload", "close"]
550
+ operation: ["navigate", "click", "type", "scroll", "screenshot", "snapshot", "wait", "waitForSelector", "upload", "close", "stop_session"]
549
551
  }
550
552
  }
551
553
  },
@@ -702,6 +704,56 @@ var BrowserCeki = class {
702
704
  }
703
705
  continue;
704
706
  }
707
+ if (op === "my_sessions") {
708
+ try {
709
+ const resp = await fetch("https://api.ceki.me/api/agent/sessions", {
710
+ headers: { Authorization: `Bearer ${token}` }
711
+ });
712
+ if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
713
+ const body = await resp.json();
714
+ const sessions = body.data ?? [];
715
+ out.push({ json: { sessions, count: sessions.length } });
716
+ } catch (e) {
717
+ throw new Error(`My sessions failed: ${e.message}`);
718
+ }
719
+ continue;
720
+ }
721
+ if (op === "stop_session") {
722
+ const sessionId2 = this.getNodeParameter("sessionId", i);
723
+ try {
724
+ await new Promise((resolve, reject) => {
725
+ const ws = new WebSocket("wss://browser.ceki.me/ws/agent", [`bearer.${token}`]);
726
+ const t = AbortSignal.timeout(15e3);
727
+ t.addEventListener("abort", () => {
728
+ try {
729
+ ws.close();
730
+ } catch {
731
+ }
732
+ reject(new Error("Stop session timed out"));
733
+ }, { once: true });
734
+ ws.onopen = () => {
735
+ ws.send(JSON.stringify({ type: "stop", session_id: sessionId2, reason: "n8n stop_session" }));
736
+ };
737
+ ws.onmessage = (ev) => {
738
+ const msg = JSON.parse(ev.data);
739
+ if (msg.type === "session_ended" || msg.type === "pong") {
740
+ try {
741
+ ws.close();
742
+ } catch {
743
+ }
744
+ resolve();
745
+ }
746
+ };
747
+ ws.onerror = () => {
748
+ reject(new Error("WebSocket connection failed"));
749
+ };
750
+ });
751
+ out.push({ json: { stopped: true, session_id: sessionId2 } });
752
+ } catch (e) {
753
+ throw new Error(`Stop session failed: ${e.message}`);
754
+ }
755
+ continue;
756
+ }
705
757
  if (op === "full") {
706
758
  const demoMode = this.getNodeParameter("demoMode", i);
707
759
  let sid2;
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../index.ts", "../lib/ceki-client.ts", "../nodes/BrowserCeki/BrowserCeki.node.ts", "../lib/contract-client.ts", "../nodes/CekiContract/CekiContract.node.ts", "../nodes/recipes/CekiCaptchaScrape/CekiCaptchaScrape.node.ts", "../nodes/recipes/CekiScreenshotGeo/CekiScreenshotGeo.node.ts", "../credentials/CekiApi.credentials.ts"],
4
- "sourcesContent": ["import { BrowserCeki } from './nodes/BrowserCeki/BrowserCeki.node';\nimport { CekiContract } from './nodes/CekiContract/CekiContract.node';\nimport { CekiCaptchaScrape } from './nodes/recipes/CekiCaptchaScrape/CekiCaptchaScrape.node';\nimport { CekiScreenshotGeo } from './nodes/recipes/CekiScreenshotGeo/CekiScreenshotGeo.node';\nimport { CekiApi } from './credentials/CekiApi.credentials';\n\nexport const nodes = [\n\tBrowserCeki,\n\tCekiContract,\n\tCekiCaptchaScrape,\n\tCekiScreenshotGeo,\n];\n\nexport const credentials = [\n\tCekiApi,\n];\n", "/**\n * Minimal Ceki browser client \u2014 uses only native WebSocket + fetch (Node 22 globals).\n * Zero npm imports (no ws, no mime-types, no node built-in modules).\n *\n * Timeout management: uses AbortSignal.timeout() instead of restricted\n * setTimeout/clearTimeout globals to satisfy the n8n community-nodes\n * package scanner (no-restricted-globals rule).\n */\n\n// \u2500\u2500 types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserOption {\n\tschedule_id: number;\n\tgeo?: string;\n\tprice_per_min: number;\n\tonline: boolean;\n\trating?: number | null;\n}\n\nexport interface Match {\n\tsession_id: string;\n\tschedule_id: number;\n\tevent_id?: string | null;\n\tchat_topic_id?: string | null;\n\tprovider_user_id?: number | null;\n\tbrowser_info?: Record<string, unknown>;\n}\n\nexport interface RentOptions {\n\tmode?: 'main' | 'incognito';\n}\n\nexport interface ScreenshotOptions {\n\tformat?: 'png' | 'base64';\n\tfullPage?: boolean;\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction jsonParse(raw: string): unknown {\n\ttry { return JSON.parse(raw); } catch { return null; }\n}\n\n// \u2500\u2500 Client \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiClient {\n\tprivate _ws: WebSocket | null = null;\n\tprivate _connected = false;\n\tprivate _pendingRents = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingResumes = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingCdp = new Map<number, {\n\t\tresolve: (v: unknown) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _cdpCounter = 1;\n\t_activeSessions = new Map<string, CekiBrowser>();\n\tprivate _connectReject: ((e: Error) => void) | null = null;\n\tprivate _closed = false;\n\n\tconstructor(\n\t\tprivate _token: string,\n\t\tprivate _relayUrl = 'wss://browser.ceki.me/ws/agent',\n\t\tprivate _apiUrl = 'https://api.ceki.me',\n\t) {}\n\n\t/** Connect to the relay WebSocket. */\n\tasync connect(): Promise<void> {\n\t\tif (this._connected) return;\n\t\tconst protocols = [`bearer.${this._token}`];\n\t\tthis._ws = new WebSocket(this._relayUrl, protocols);\n\t\tthis._ws.onopen = () => {\n\t\t\tthis._connected = true;\n\t\t};\n\t\tthis._ws.onmessage = (ev: MessageEvent) => {\n\t\t\tthis._handleMessage(ev.data);\n\t\t};\n\t\tthis._ws.onclose = (ev: CloseEvent) => {\n\t\t\tthis._connected = false;\n\t\t\tif ((ev.code === 4401 || ev.code === 4403) && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error(`Auth failed: ${ev.reason || String(ev.code)}`));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tthis._ws.onerror = () => {\n\t\t\tif (!this._connected && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error('WebSocket connection failed'));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tif (this._ws.readyState === WebSocket.CONNECTING) {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tif (!this._ws) { reject(new Error('No WebSocket')); return; }\n\t\t\t\tthis._connectReject = reject;\n\t\t\t\tthis._ws!.onopen = () => {\n\t\t\t\t\tthis._connected = true;\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n\n\t_sendRaw(msg: Record<string, unknown>): void {\n\t\tif (!this._ws || this._ws.readyState !== WebSocket.OPEN) {\n\t\t\tthrow new Error('WebSocket not connected');\n\t\t}\n\t\tthis._ws.send(JSON.stringify(msg));\n\t}\n\n\t/** Search for available browser providers (HTTP GET). */\n\tasync search(filters?: Record<string, unknown>, limit?: number): Promise<BrowserOption[]> {\n\t\tconst params = new URLSearchParams();\n\t\tif (limit != null) params.set('limit', String(limit));\n\t\tif (filters) {\n\t\t\tfor (const [k, v] of Object.entries(filters)) {\n\t\t\t\tif (v != null) params.set(k, String(v));\n\t\t\t}\n\t\t}\n\t\tconst resp = await fetch(`${this._apiUrl}/api/browsers/search?${params}`, {\n\t\t\theaders: { Authorization: `Bearer ${this._token}` },\n\t\t});\n\t\tif (!resp.ok) throw new Error(`Search failed: ${resp.status}`);\n\t\tconst body = (await resp.json()) as Record<string, unknown>;\n\t\tconst data = (body.data ?? body) as unknown[];\n\t\treturn Array.isArray(data) ? data as BrowserOption[] : [];\n\t}\n\n\t/** Rent a browser by schedule_id. */\n\tasync rent(scheduleId: number, opts?: RentOptions): Promise<CekiBrowser> {\n\t\tconst msg: Record<string, unknown> = { type: 'rent', browser_id: scheduleId };\n\t\tif (opts?.mode) msg.mode = opts.mode;\n\t\tthis._sendRaw(msg);\n\t\treturn this._awaitRent(`rent:${scheduleId}`, scheduleId, 90000);\n\t}\n\n\t/** Resume an existing session. */\n\tasync resume(sessionId: string): Promise<CekiBrowser> {\n\t\tthis._sendRaw({ type: 'resume', session_id: sessionId });\n\t\treturn this._awaitResume(sessionId);\n\t}\n\n\t/** Close the WS connection \u2014 session stays alive in grace.\n\t * Waits for the close handshake so the relay processes the close\n\t * before a new connection with the same renterId is established\n\t * (avoids the close-handler race condition).\n\t */\n\tasync disconnect(): Promise<void> {\n\t\tthis._closed = true;\n\t\tthis._activeSessions.clear();\n\t\tthis._pendingRents.clear();\n\t\tthis._pendingResumes.clear();\n\t\tif (!this._ws) return;\n\t\tconst ws = this._ws;\n\t\tif (ws.readyState === WebSocket.CLOSED) {\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\tif (ws.readyState === WebSocket.CLOSING) {\n\t\t\tawait new Promise<void>(r => { ws.onclose = () => { this._connected = false; r(); }; });\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\t// OPEN \u2192 initiate close and wait for handshake (up to 5s safety timeout)\n\t\tawait new Promise<void>(r => {\n\t\t\tconst t = setTimeout(() => { r(); }, 5000);\n\t\t\tws.onclose = () => { this._connected = false; clearTimeout(t); r(); };\n\t\t\ttry { ws.close(); } catch { clearTimeout(t); r(); }\n\t\t});\n\t\tthis._ws = null;\n\t}\n\n\t/** Close everything. */\n\tasync close(): Promise<void> {\n\t\tawait this.disconnect();\n\t}\n\n\t// \u2500\u2500 private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate _awaitRent(key: string, scheduleId: number, timeoutMs: number): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingRents.delete(key);\n\t\t\t\treject(new Error('Rent timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingRents.set(key, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _awaitResume(sessionId: string): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(60000);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\t\treject(new Error('Resume timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingResumes.set(sessionId, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _closeWs(): void {\n\t\tif (this._ws) {\n\t\t\ttry { this._ws.onopen = null; this._ws.onmessage = null; this._ws.onclose = null; this._ws.onerror = null; this._ws.close(); } catch { /* ignore */ }\n\t\t\tthis._ws = null;\n\t\t}\n\t}\n\n\tprivate _handleMessage(data: unknown): void {\n\t\tconst msg = jsonParse(String(data)) as Record<string, unknown> | null;\n\t\tif (!msg || typeof msg !== 'object') return;\n\t\tconst type = String(msg.type ?? '');\n\t\tconst sid = msg.session_id ? String(msg.session_id) : null;\n\n\t\tswitch (type) {\n\t\t\tcase 'pong':\n\t\t\tcase 'rent_pending':\n\t\t\t\tbreak;\n\t\t\tcase 'match':\n\t\t\t\tthis._onMatch(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'rent.error':\n\t\t\t\tthis._onRentError(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_ok':\n\t\t\t\tthis._onResumeOk(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_failed':\n\t\t\t\tthis._onResumeFailed(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'cdp_response':\n\t\t\t\tif (sid) this._onCdpResponse(sid, msg);\n\t\t\t\tbreak;\n\t\t\tcase 'session.ended':\n\t\t\t\tif (sid) {\n\t\t\t\t\tthis._activeSessions.delete(sid);\n\t\t\t\t\tconst b = this._activeSessions.get(sid);\n\t\t\t\t\tif (b) (b as any)._ended = String(msg.reason ?? 'ended');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate _onMatch(msg: Record<string, unknown>): void {\n\t\tconst scheduleId = Number(msg.schedule_id ?? 0);\n\t\tconst eventId = msg.event_id ? String(msg.event_id) : null;\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\t// Send match_ack to transition session from ACCEPTED to ACTIVE.\n\t\t// Without this, subsequent resume from other n8n nodes would receive\n\t\t// \"match\" instead of \"resume_ok\" (session stays ACCEPTED).\n\t\tif (sessionId && this._ws?.readyState === WebSocket.OPEN) {\n\t\t\ttry { this._ws.send(JSON.stringify({ type: 'match_ack', session_id: sessionId })); } catch { /* ignore */ }\n\t\t}\n\t\t// Check pending rents (normal rent flow)\n\t\tlet pending = this._pendingRents.get(`event:${eventId}`);\n\t\tif (!pending) pending = this._pendingRents.get(`rent:${scheduleId}`);\n\t\tif (pending) {\n\t\t\tthis._pendingRents.delete(`event:${eventId}`);\n\t\t\tthis._pendingRents.delete(`rent:${scheduleId}`);\n\t\t\tpending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\t// Fallback: relay may send \"match\" during resume if session is ACCEPTED\n\t\t// (e.g. when rent node finished without sending match_ack).\n\t\t// Treat it like resume_ok so the next node doesn't hang.\n\t\tconst resumePending = sessionId ? this._pendingResumes.get(sessionId) : null;\n\t\tif (resumePending) {\n\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\tresumePending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _onRentError(msg: Record<string, unknown>): void {\n\t\tconst code = String(msg.code ?? '');\n\t\tconst message = String(msg.message ?? '');\n\t\tfor (const [key, pending] of this._pendingRents) {\n\t\t\tthis._pendingRents.delete(key);\n\t\t\tpending.reject(new Error(message || `Rent error: ${code}`));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate _onResumeOk(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.resolve({\n\t\t\tsession_id: sessionId,\n\t\t\tschedule_id: Number(msg.schedule_id ?? 0),\n\t\t\tevent_id: msg.event_id ? String(msg.event_id) : null,\n\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t});\n\t}\n\n\tprivate _onResumeFailed(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.reject(new Error(String(msg.reason ?? 'Resume failed')));\n\t}\n\n\tprivate _onCdpResponse(sessionId: string, msg: Record<string, unknown>): void {\n\t\tconst browser = this._activeSessions.get(sessionId);\n\t\tif (!browser) return;\n\t\tconst id = Number(msg.id ?? 0);\n\t\t// NOTE: pending CDP is stored on CekiBrowser._pendingCdp (set by CekiBrowser.send()),\n\t\t// NOT on CekiClient._pendingCdp \u2014 they are different maps.\n\t\tconst pending = browser._pendingCdp.get(id);\n\t\tif (!pending) return;\n\t\tbrowser._pendingCdp.delete(id);\n\t\tif (msg.error) {\n\t\t\tpending.reject(new Error(String((msg.error as Record<string, unknown>).message ?? 'CDP error')));\n\t\t} else {\n\t\t\tpending.resolve(msg.result);\n\t\t}\n\t}\n}\n\n// \u2500\u2500 Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiBrowser {\n\treadonly sessionId: string;\n\treadonly scheduleId: number;\n\treadonly chatTopicId: string | null;\n\treadonly browserInfo: Record<string, unknown>;\n\treadonly providerUserId: number | null;\n\n\tprivate _client: CekiClient;\n\tprivate _cdpId = 1;\n\t_pendingCdp = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n\n\tconstructor(client: CekiClient, match: Match) {\n\t\tthis._client = client;\n\t\tthis.sessionId = match.session_id;\n\t\tthis.scheduleId = match.schedule_id;\n\t\tthis.chatTopicId = match.chat_topic_id ?? null;\n\t\tthis.browserInfo = match.browser_info ?? {};\n\t\tthis.providerUserId = match.provider_user_id ?? null;\n\t}\n\n\t/** Send a CDP command. Uses AbortSignal.timeout() (no restricted setTimeout global). */\n\tasync send(method: string, params?: Record<string, unknown>, timeoutMs = 30000): Promise<unknown> {\n\t\tconst id = this._cdpId++;\n\t\tconst msg = { type: 'cdp', session_id: this.sessionId, id, method, params: params ?? {} };\n\t\tthis._client._sendRaw(msg);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingCdp.delete(id);\n\t\t\t\treject(new Error(`CDP ${method} timed out after ${timeoutMs}ms`));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingCdp.set(id, {\n\t\t\t\tresolve: (v) => { resolve(v); },\n\t\t\t\treject: (e) => { reject(e); },\n\t\t\t});\n\t\t});\n\t}\n\n\tasync navigate(url: string, timeoutMs?: number): Promise<void> {\n\t\tawait this.send('Page.navigate', { url }, timeoutMs);\n\t}\n\n\tasync click(x: number, y: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 });\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });\n\t}\n\n\tasync type(text: string): Promise<void> {\n\t\tawait this.send('Ceki.typeText', { text });\n\t}\n\n\tasync scroll(deltaY: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseWheel', x: 0, y: 0, deltaX: 0, deltaY });\n\t}\n\n\tasync screenshot(opts?: ScreenshotOptions): Promise<{ data: string } | Buffer> {\n\t\tconst format = opts?.format ?? 'base64';\n\t\tconst fullPage = opts?.fullPage ?? false;\n\t\tlet clip: Record<string, number> | undefined;\n\t\tif (fullPage) {\n\t\t\tconst metrics = await this.send('Page.getLayoutMetrics') as Record<string, unknown> | null;\n\t\t\tconst contentSize = metrics?.contentSize as Record<string, number> | undefined;\n\t\t\tif (contentSize) {\n\t\t\t\tclip = { x: 0, y: 0, width: Number(contentSize.width ?? 1920), height: Math.min(Number(contentSize.height ?? 1080), 16384), scale: 1 };\n\t\t\t}\n\t\t}\n\t\tconst result = await this.send('Page.captureScreenshot', { format: 'png', ...(clip ? { clip } : {}) }) as Record<string, unknown> | null;\n\t\tconst data = String(result?.data ?? '');\n\t\tif (format === 'png') {\n\t\t\treturn Buffer.from(data, 'base64');\n\t\t}\n\t\treturn { data };\n\t}\n\n\tasync snapshot(): Promise<{ screenshot: string; ts: Date }> {\n\t\tconst ssResult = await this.screenshot({ format: 'base64' }) as { data: string };\n\t\treturn { screenshot: ssResult.data, ts: new Date() };\n\t}\n\n\tasync upload(selector: string, buf: Buffer, filename = 'file'): Promise<Record<string, unknown>> {\n\t\tconst b64 = buf.toString('base64');\n\t\tconst size = buf.length;\n\t\tconst mime = 'application/octet-stream';\n\t\tconst expression = `(function(){\n\t\t\tvar input = document.querySelector(${JSON.stringify(selector)});\n\t\t\tif (!input) return JSON.stringify({ok:false,error:'Element not found'});\n\t\t\tvar b = atob(${JSON.stringify(b64)});\n\t\t\tvar u = new Uint8Array(b.length);\n\t\t\tfor (var i = 0; i < b.length; i++) u[i] = b.charCodeAt(i);\n\t\t\tvar f = new File([u], ${JSON.stringify(filename)}, {type: ${JSON.stringify(mime)}});\n\t\t\tvar dt = new DataTransfer(); dt.items.add(f);\n\t\t\tinput.files = dt.files;\n\t\t\tinput.dispatchEvent(new Event('change',{bubbles:true}));\n\t\t\treturn JSON.stringify({ok:true,filename:${JSON.stringify(filename)},size:${size}});\n\t\t})()`;\n\t\tconst result = await this.send('Runtime.evaluate', { expression, returnByValue: true }) as Record<string, unknown> | null;\n\t\ttry {\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t} catch { /* ignore */ }\n\t\tconst resultObj = result?.result as Record<string, unknown> | undefined;\n\t\tif (resultObj?.value) return JSON.parse(String(resultObj.value)) as Record<string, unknown>;\n\t\treturn { ok: true, filename, size };\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.send('Ceki.close', {}).catch(() => {});\n\t\tthis._client._activeSessions.delete(this.sessionId);\n\t}\n}\n", "import type {\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { CekiClient } from '../../lib/ceki-client';\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => {\n\tAbortSignal.timeout(ms).addEventListener('abort', () => resolve(), { once: true });\n});\n\n/**\n * Browser Ceki \u2014 one node, many operations.\n * Uses native WebSocket (not the ws library) \u2014 zero external runtime deps.\n *\n * Resume flow:\n * 1. Rent \u2192 browser session created, client disconnects (session in grace).\n * 2. Navigate/Screenshot/etc \u2192 new client, connect, resume(sessionId) \u2192 server\n * responds with resume_ok, do the op, disconnect.\n * 3. Close \u2192 same, sends Ceki.close, client.close().\n *\n * This works because the server supports session resume across different\n * WebSocket connections (same auth token). Each n8n node independently\n * creates a fresh WS connection and resumes the session by ID.\n */\nexport class BrowserCeki implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki',\n\t\tname: 'browserCeki',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '={{ \"Ceki: \" + $parameter.operation }}',\n\t\tdescription: 'Rent a real human browser and control it: rent, navigate, click, type, screenshot, solve captchas, and more',\n\t\tdefaults: { name: 'Browser Ceki' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'search',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Search', value: 'search' },\n\t\t\t\t\t{ name: 'Rent', value: 'rent' },\n\t\t\t\t\t{ name: 'Navigate', value: 'navigate' },\n\t\t\t\t\t{ name: 'Click', value: 'click' },\n\t\t\t\t\t{ name: 'Type', value: 'type' },\n\t\t\t\t\t{ name: 'Scroll', value: 'scroll' },\n\t\t\t\t\t{ name: 'Screenshot', value: 'screenshot' },\n\t\t\t\t\t{ name: 'Snapshot', value: 'snapshot' },\n\t\t\t\t\t{ name: 'Wait', value: 'wait' },\n\t\t\t\t\t{ name: 'Wait for Selector', value: 'waitForSelector' },\n\t\t\t\t\t{ name: 'Upload', value: 'upload' },\n\t\t\t\t\t{ name: 'Close', value: 'close' },\n\t\t\t\t\t{ name: 'Full: Rent \u2192 Navigate \u2192 Screenshot', value: 'full' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t// === Rent: rental parameters ===\n\t\t\t{\n\t\t\t\tdisplayName: 'Schedule ID',\n\t\t\t\tname: 'scheduleId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: '0 \u2014 search by the filters below',\n\t\t\t\tdisplayOptions: { show: { operation: ['rent'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Geo',\n\t\t\t\tname: 'geo',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'RU, EE, US\u2026',\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max $/min',\n\t\t\t\tname: 'maxPrice',\n\t\t\t\ttype: 'number',\n\t\t\t\ttypeOptions: { numberPrecision: 4 },\n\t\t\t\tdefault: 0.02,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Min rating',\n\t\t\t\tname: 'minRating',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Profile mode',\n\t\t\t\tname: 'mode',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'incognito',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'main', value: 'main' },\n\t\t\t\t\t{ name: 'incognito', value: 'incognito' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['rent', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://example.com',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Demo mode (no browser needed)',\n\t\t\t\tname: 'demoMode',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription: 'Skip actual browser rent and generate demo output',\n\t\t\t\tdisplayOptions: { show: { operation: ['full'] } },\n\t\t\t},\n\t\t\t// === Operations: session_id ===\n\n\n\t\t\t{\n\t\t\t\tdisplayName: 'Session ID',\n\t\t\t\tname: 'sessionId',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'From the Rent operation',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\toperation: ['navigate', 'click', 'type', 'scroll', 'screenshot', 'snapshot', 'wait', 'waitForSelector', 'upload', 'close'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'X',\n\t\t\t\tname: 'x',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Y',\n\t\t\t\tname: 'y',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Text',\n\t\t\t\tname: 'text',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: { show: { operation: ['type'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Delta Y',\n\t\t\t\tname: 'deltaY',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: -300,\n\t\t\t\tdisplayOptions: { show: { operation: ['scroll'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Format',\n\t\t\t\tname: 'format',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'png',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'PNG (binary)', value: 'png' },\n\t\t\t\t\t{ name: 'Base64', value: 'base64' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Full page',\n\t\t\t\tname: 'fullPage',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: false,\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Milliseconds',\n\t\t\t\tname: 'ms',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 1000,\n\t\t\t\ttypeOptions: { minValue: 0 },\n\t\t\t\tdescription: 'Fixed delay on the active session',\n\t\t\t\tdisplayOptions: { show: { operation: ['wait', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'waitSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tplaceholder: 'e.g. .results, #content, table tr',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Timeout (ms)',\n\t\t\t\tname: 'waitTimeout',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 30000,\n\t\t\t\tdescription: 'Waits until the selector appears in the DOM',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'selector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Binary Property',\n\t\t\t\tname: 'binaryPropertyName',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'data',\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\t\tconst token = creds.token as string;\n\n\t\tconst resolveSid = async (i: number, client: CekiClient) => {\n\t\t\tconst scheduleId = this.getNodeParameter('scheduleId', i) as number;\n\t\t\tif (scheduleId) return scheduleId;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\tconst list = await client.search({\n\t\t\t\tgeo: geo || undefined,\n\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t});\n\t\t\tif (!list.length) throw new Error('No browsers found by filters');\n\t\t\treturn list[0].schedule_id;\n\t\t};\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst op = this.getNodeParameter('operation', i) as string;\n\t\t\tconst client = new CekiClient(token);\n\t\t\tlet browser: any;\n\t\t\tlet needFullClose = false;\n\t\t\ttry {\n\t\t\t\tawait client.connect();\n\n\t\t\t\tif (op === 'rent') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst sid = await resolveSid(i, client);\n\t\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: browser.sessionId, schedule_id: sid, mode },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Rent failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'search') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\t\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\t\t\t\tconst list = await client.search({\n\t\t\t\t\t\t\tgeo: geo || undefined,\n\t\t\t\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tout.push({ json: { browsers: list, count: list.length } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Search failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t\n\t\t\t\tif (op === 'full') {\n\t\t\t\t\tconst demoMode = this.getNodeParameter('demoMode', i) as boolean;\n\t\t\t\t\tlet sid: number;\n\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsid = 99999; // mock\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tsid = await resolveSid(i, client);\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full: resolve schedule failed: ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\n\t\t\t\t\tlet session_id: string;\n\t\t\t\t\tlet binary: any;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsession_id = 'demo-' + Date.now();\n\t\t\t\t\t\tconst demoPng = Buffer.from('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', 'base64');\n\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(demoPng, 'screenshot.png', 'image/png');\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\t\tsession_id = browser.sessionId;\n\t\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\t\t\tconst shot = await browser.screenshot({ format: 'png', fullPage: true }) as any;\n\t\t\t\t\t\t\tconst data = (shot as Buffer).toString('base64');\n\t\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(Buffer.from(data, 'base64'), 'screenshot.png', 'image/png');\n\t\t\t\t\t\t\tawait browser.close();\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full op failed at step \"${(browser?.sessionId ? 'navigate/screenshot' : 'rent')}\": ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\tsession_id,\n\t\t\t\t\t\t\tschedule_id: sid,\n\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\twaited: ms,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbinary: { data: binary },\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tawait client.close().catch(() => {});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// All remaining operations: navigate, click, type, scroll, screenshot,\n\t\t\t// snapshot, wait, waitForSelector, upload, close.\n\t\t\t// Each creates a fresh WS connection and resumes the existing\n\t\t\t// browser session by sessionId (server supports cross-WS resume).\n\t\t\tconst sessionId = this.getNodeParameter('sessionId', i) as string;\n\t\t\ttry {\n\t\t\t\tbrowser = await client.resume(sessionId);\n\t\t\t} catch (e) {\n\t\t\t\tthrow new Error(`Resume session \"${sessionId}\" failed: ${(e as Error).message}. Session may have expired or still be in grace.`);\n\t\t\t}\n\t\t\tconst sid = browser.sessionId;\n\n\t\t\tswitch (op) {\n\t\t\t\tcase 'navigate': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, url } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Navigate failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'click': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst x = this.getNodeParameter('x', i) as number;\n\t\t\t\t\t\tconst y = this.getNodeParameter('y', i) as number;\n\t\t\t\t\t\tawait browser.click(x, y);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, clicked: [x, y] } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Click at (${x},${y}) failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'type': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst text = this.getNodeParameter('text', i) as string;\n\t\t\t\t\t\tawait browser.type(text);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, typed: text } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Type failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'scroll': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst deltaY = this.getNodeParameter('deltaY', i) as number;\n\t\t\t\t\t\tawait browser.scroll(deltaY);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, scrolled: deltaY } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Scroll failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'screenshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst format = this.getNodeParameter('format', i) as 'png' | 'base64';\n\t\t\t\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\t\t\t\t\t\tconst shot = await browser.screenshot({ format, fullPage }) as any;\n\t\t\t\t\t\tconst data = format === 'base64' ? shot.data : (shot as Buffer).toString('base64');\n\t\t\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\t\t\tBuffer.from(data, 'base64'),\n\t\t\t\t\t\t\t'screenshot.png',\n\t\t\t\t\t\t\t'image/png',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tout.push({ json: { session_id: sid }, binary: { data: binary } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Screenshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'snapshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst snap = await browser.snapshot();\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: sid, screenshot: snap.screenshot },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Snapshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'wait': {\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\tout.push({ json: { session_id: sid, waited: ms } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'waitForSelector': {\n\t\t\t\t\tconst selector = this.getNodeParameter('waitSelector', i) as string;\n\t\t\t\t\tconst timeout = this.getNodeParameter('waitTimeout', i) as number;\n\t\t\t\t\tconst expr = `!!document.querySelector(${JSON.stringify(selector)})`;\n\t\t\t\t\tconst deadline = Date.now() + timeout;\n\t\t\t\t\tlet ok = false;\n\t\t\t\t\tlet lastErr: unknown = null;\n\t\t\t\t\twhile (Date.now() < deadline) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\t\t\t\t\t\t\tif (res?.result?.value === true) {\n\t\t\t\t\t\t\t\tok = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tlastErr = e;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait sleep(500);\n\t\t\t\t\t}\n\t\t\t\t\tif (!ok) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`waitForSelector(\"${selector}\") timed out after ${timeout}ms${lastErr ? `: ${(lastErr as Error).message}` : ''}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tout.push({ json: { session_id: sid, selector, found: true } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'upload': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst selector = this.getNodeParameter('selector', i) as string;\n\t\t\t\t\t\tconst bpn = this.getNodeParameter('binaryPropertyName', i) as string;\n\t\t\t\t\t\tconst bin = items[i].binary?.[bpn];\n\t\t\t\t\t\tif (!bin) throw new Error(`Binary property \"${bpn}\" not found on input`);\n\t\t\t\t\t\tconst stream = await this.helpers.getBinaryStream(bin.id as string);\n\t\t\t\t\t\tconst chunks: Buffer[] = [];\n\t\t\t\t\t\tfor await (const c of stream) chunks.push(c as Buffer);\n\t\t\t\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\t\t\t\tconst res = await browser.upload(selector, buf);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, uploaded: res } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Upload failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'close': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try graceful CDP close first (best-effort)\n\t\t\t\t\t\tawait browser.close().catch(() => {});\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore CDP close errors\n\t\t\t\t\t}\n\t\t\t\t\t// Always send relay stop (force-end session) \u2014 CDP can silently fail\n\t\t\t\t\t// eslint-disable-next-line no-async-promise-executor\n\t\t\t\t\tawait new Promise((resolve) => {\n\t\t\t\t\t\tconst stopWs = new WebSocket('wss://browser.ceki.me/ws/agent', [`bearer.${token}`]);\n\t\t\t\t\t\tconst abortTimer = AbortSignal.timeout(10000);\n\t\t\t\t\tconst onTimer = () => { try { stopWs.close(); } catch {} resolve(); };\n\t\t\t\t\tabortTimer.addEventListener(\"abort\", onTimer, { once: true });\n\t\t\t\t\t\tstopWs.onopen = () => {\n\t\t\t\t\t\t\tstopWs.send(JSON.stringify({ type: 'stop', session_id: sessionId, reason: 'n8n close' }));\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onmessage = (ev) => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst msg = JSON.parse(ev.data);\n\t\t\t\t\t\t\t\tif (msg.type === 'session_ended') {\n\t\t\t\t\t\t\t\t\tabortTimer.removeEventListener(\"abort\", onTimer);\n\t\t\t\t\t\t\t\t\ttry { stopWs.close(); } catch {}\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onerror = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t\tstopWs.onclose = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t});\n\t\t\t\t\tout.push({ json: { closed: true, session_id: sessionId } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tneedFullClose = op === 'close';\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (needFullClose) {\n\t\t\t\t\t\tawait client.close();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// swallow cleanup errors\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "/**\n * Minimal Ceki contract client \u2014 uses only native fetch (Node 22 global).\n * Zero npm imports (no ws, no axios, no node built-in modules beyond globals).\n *\n * Communicates with Ceki's MCP endpoint via JSON-RPC 2.0 over HTTP POST.\n */\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction cleanArgs<T extends Record<string, unknown>>(o: T): Partial<T> {\n\tconst out = { ...o };\n\tfor (const k of Object.keys(out)) {\n\t\tif ((out as any)[k] === undefined || (out as any)[k] === null) delete (out as any)[k];\n\t}\n\treturn out;\n}\n\nfunction parseBenefitable(value: string | null | undefined): { type: string; value: number } | null {\n\tif (!value) return null;\n\tconst m = /^(agent|user):(\\d+)$/.exec(value);\n\tif (!m) return null;\n\treturn { type: m[1], value: Number(m[2]) };\n}\n\ninterface ParticipantSpec {\n\tparticipable_id: number;\n\ttype: string;\n\trole_id: number;\n}\n\nfunction parseParticipant(value: string | null | undefined, roleId: number): ParticipantSpec | null {\n\tconst b = parseBenefitable(value);\n\tif (!b) return null;\n\treturn { participable_id: b.value, type: b.type, role_id: roleId };\n}\n\nfunction deriveLabel(desc: string | null | undefined): string {\n\tif (!desc) return '';\n\tconst line = desc.split('\\n')[0].trim();\n\treturn line.length > 60 ? line.slice(0, 57) + '...' : line;\n}\n\nconst ROLE_REVIEWER = 5;\nconst ROLE_QA = 6;\n\n// \u2500\u2500 types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface CreateOptions {\n\tlabel: string;\n\ttype?: number;\n\tstatus?: number;\n\tdescription?: string;\n\tbenefitable?: string;\n\treviewer?: string;\n\tqa?: string;\n}\n\nexport interface ProposeOptions {\n\tstatus?: number;\n\tlabel?: string;\n\tdescription?: string;\n\tbenefitable?: string;\n}\n\nexport interface CommentOptions {\n\tlabel?: string;\n\tdescription?: string;\n}\n\nexport interface ProgressOptions {\n\tstatus?: number;\n\tdesc: string;\n}\n\n// \u2500\u2500 client \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ContractClient {\n\tprivate _endpoint: string;\n\tprivate _apiBase: string;\n\tprivate _token: string;\n\n\tconstructor(token: string, endpoint?: string, apiBase?: string) {\n\t\tthis._endpoint = (endpoint ?? 'https://api.ceki.me/mcp').replace(/\\/+$/, '');\n\t\tthis._apiBase = (apiBase ?? 'https://api.ceki.me').replace(/\\/+$/, '');\n\t\tthis._token = token;\n\t}\n\n\tprivate _headers(): Record<string, string> {\n\t\treturn {\n\t\t\t'Content-Type': 'application/json',\n\t\t\tAccept: 'application/json',\n\t\t\tAuthorization: `Bearer ${this._token}`,\n\t\t};\n\t}\n\n\tprivate async _rpc(method: string, params: Record<string, unknown>): Promise<any> {\n\t\tconst body = JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params });\n\t\tconst resp = await fetch(this._endpoint, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: this._headers(),\n\t\t\tbody,\n\t\t});\n\t\tif (!resp.ok) {\n\t\t\tconst text = await resp.text().catch(() => '');\n\t\t\tthrow new Error(`HTTP ${resp.status}: ${text.slice(0, 400)}`);\n\t\t}\n\t\treturn resp.json();\n\t}\n\n\tprivate async _call(tool: string, args?: Record<string, unknown>): Promise<any> {\n\t\tconst body = await this._rpc('tools/call', { name: tool, arguments: args ?? {} });\n\t\tif (body.error) throw new Error(`${tool} \u2192 ${JSON.stringify(body.error).slice(0, 400)}`);\n\t\tconst result = body.result ?? {};\n\t\tconst content = result.content;\n\t\tif (Array.isArray(content)) {\n\t\t\tconst texts = content.filter((c: any) => c.type === 'text').map((c: any) => String(c.text ?? ''));\n\t\t\tconst joined = texts.join('\\n');\n\t\t\ttry { return JSON.parse(joined); } catch { return joined; }\n\t\t}\n\t\tif (result.structuredContent !== undefined) return result.structuredContent;\n\t\treturn result;\n\t}\n\n\t// \u2500\u2500 domain methods \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tasync listContracts(): Promise<any> {\n\t\treturn this._call('list-contracts');\n\t}\n\n\tasync members(contractId: number): Promise<any> {\n\t\treturn this._call('contract-members', { contract_id: contractId });\n\t}\n\n\tasync tasks(contractId: number): Promise<any> {\n\t\treturn this._call('contract-tasks', { contract_id: contractId });\n\t}\n\n\tasync myEvents(): Promise<any> {\n\t\treturn this._call('get-my-events');\n\t}\n\n\tasync task(eventId: number): Promise<any> {\n\t\treturn this._call('get-event', { event_id: eventId });\n\t}\n\n\tasync create(contractId: number, opts: CreateOptions): Promise<any> {\n\t\tconst args = cleanArgs({\n\t\t\tcontract_id: contractId,\n\t\t\tlabel: opts.label,\n\t\t\ttype_id: opts.type,\n\t\t\tstatus_id: opts.status,\n\t\t\tdescription: opts.description,\n\t\t\tbenefitable: opts.benefitable ? parseBenefitable(opts.benefitable) : undefined,\n\t\t});\n\t\tconst users: ParticipantSpec[] = [];\n\t\tconst rev = parseParticipant(opts.reviewer, ROLE_REVIEWER);\n\t\tif (rev) users.push(rev);\n\t\tconst qa = parseParticipant(opts.qa, ROLE_QA);\n\t\tif (qa) users.push(qa);\n\t\tif (users.length) (args as any).users = users;\n\t\treturn this._call('create-contract-event', args);\n\t}\n\n\tasync propose(eventId: number, opts: ProposeOptions): Promise<any> {\n\t\treturn this._call('propose-correction', cleanArgs({\n\t\t\tevent_id: eventId,\n\t\t\tstatus_id: opts.status,\n\t\t\tlabel: opts.label,\n\t\t\tdescription: opts.description,\n\t\t\tbenefitable: opts.benefitable ? parseBenefitable(opts.benefitable) : undefined,\n\t\t}));\n\t}\n\n\tasync comment(eventId: number, opts?: CommentOptions): Promise<any> {\n\t\treturn this._call('comment', cleanArgs({\n\t\t\tevent_id: eventId,\n\t\t\tlabel: opts?.label,\n\t\t\tdescription: opts?.description,\n\t\t}));\n\t}\n\n\tasync progress(eventId: number, opts: ProgressOptions): Promise<any> {\n\t\tlet statusResult: any = null;\n\t\tif (opts.status != null) {\n\t\t\tstatusResult = await this.propose(eventId, { status: opts.status });\n\t\t}\n\t\tconst commentResult = await this.comment(eventId, { label: deriveLabel(opts.desc), description: opts.desc });\n\t\treturn { status_correction: statusResult, comment: commentResult };\n\t}\n\n\tasync callHuman(eventId: number, kind: 'input' | 'review' | 'stuck', desc: string): Promise<any> {\n\t\tif (!['input', 'review', 'stuck'].includes(kind)) throw new Error(`kind must be input|review|stuck, got ${kind}`);\n\t\treturn this._call('call-human', { event_id: eventId, kind, desc });\n\t}\n\n\t/** GET /agent/polling. Returns [] on 429. */\n\tasync poll(): Promise<any[]> {\n\t\tconst resp = await fetch(`${this._apiBase}/agent/polling`, {\n\t\t\theaders: { Accept: 'application/json', Authorization: `Bearer ${this._token}` },\n\t\t});\n\t\tif (resp.status === 429) return [];\n\t\tif (!resp.ok) {\n\t\t\tconst text = await resp.text().catch(() => '');\n\t\t\tthrow new Error(`poll HTTP ${resp.status}: ${text.slice(0, 300)}`);\n\t\t}\n\t\tconst body = (await resp.json()) as Record<string, unknown>;\n\t\tif (Array.isArray(body)) return body;\n\t\tif (body && typeof body === 'object') {\n\t\t\tfor (const k of ['notifications', 'data', 'items']) {\n\t\t\t\tif (Array.isArray(body[k])) return body[k] as any[];\n\t\t\t}\n\t\t}\n\t\treturn [];\n\t}\n}\n", "import type {\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { ContractClient } from '../../lib/contract-client';\n\nconst STATUS_OPTIONS = [\n\t{ name: '100 \u00B7 Backlog', value: 100 },\n\t{ name: '200 \u00B7 Hand (assigned)', value: 200 },\n\t{ name: '222 \u00B7 Hand done', value: 222 },\n\t{ name: '300 \u00B7 QA', value: 300 },\n\t{ name: '350 \u00B7 QA done', value: 350 },\n\t{ name: '499 \u00B7 Reviewer', value: 499 },\n];\n\n/**\n * Ceki Contract \u2014 operation node for the Ceki contract system (tasks/events).\n * Uses native fetch() \u2014 zero external runtime deps.\n */\nexport class CekiContract implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Ceki Contract',\n\t\tname: 'cekiContract',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '={{ \"Contract: \" + $operation }}',\n\t\tdescription: 'Work with Ceki contract tasks: list, create, assign, update status, comment, report progress, escalate to a human, and poll',\n\t\tdefaults: { name: 'Ceki Contract' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'myEvents',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'List My Contracts', value: 'listContracts' },\n\t\t\t\t\t{ name: 'List Tasks in Contract', value: 'listTasks' },\n\t\t\t\t\t{ name: 'Get Task', value: 'getTask' },\n\t\t\t\t\t{ name: 'My Assigned Events', value: 'myEvents' },\n\t\t\t\t\t{ name: 'Create Task', value: 'createTask' },\n\t\t\t\t\t{ name: 'Assign Executor', value: 'assign' },\n\t\t\t\t\t{ name: 'Update Status', value: 'setStatus' },\n\t\t\t\t\t{ name: 'Comment', value: 'comment' },\n\t\t\t\t\t{ name: 'Progress Report', value: 'progress' },\n\t\t\t\t\t{ name: 'Call Human', value: 'callHuman' },\n\t\t\t\t\t{ name: 'Poll Notifications', value: 'poll' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t// --- contractId / eventId ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Contract ID',\n\t\t\t\tname: 'contractId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: 'ceki contract id',\n\t\t\t\tdisplayOptions: { show: { operation: ['listTasks', 'createTask'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Event ID',\n\t\t\t\tname: 'eventId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: 'Task / event id (KalEvent)',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: { operation: ['getTask', 'assign', 'setStatus', 'comment', 'progress', 'callHuman'] },\n\t\t\t\t},\n\t\t\t},\n\t\t\t// --- createTask fields ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Label',\n\t\t\t\tname: 'label',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Description',\n\t\t\t\tname: 'description',\n\t\t\t\ttype: 'string',\n\t\t\t\ttypeOptions: { rows: 4 },\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'comment'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Executor (benefitable)',\n\t\t\t\tname: 'benefitableType',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'agent',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Agent', value: 'agent' },\n\t\t\t\t\t{ name: 'User (human)', value: 'user' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'assign'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Executor ID',\n\t\t\t\tname: 'benefitableValue',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: 'Agent ID or user ID of the executor',\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'assign'] } },\n\t\t\t},\n\t\t\t// --- status ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Status',\n\t\t\t\tname: 'status',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: STATUS_OPTIONS,\n\t\t\t\tdefault: 200,\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'setStatus', 'progress'] } },\n\t\t\t},\n\t\t\t// --- progress desc ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Progress Description',\n\t\t\t\tname: 'progressDesc',\n\t\t\t\ttype: 'string',\n\t\t\t\ttypeOptions: { rows: 4 },\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'Body of the progress comment (does not overwrite the task spec)',\n\t\t\t\tdisplayOptions: { show: { operation: ['progress'] } },\n\t\t\t},\n\t\t\t// --- call human (escalate) ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Call Kind',\n\t\t\t\tname: 'callKind',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'review',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Input (need clarification)', value: 'input' },\n\t\t\t\t\t{ name: 'Review (done, take a look)', value: 'review' },\n\t\t\t\t\t{ name: 'Stuck (blocked)', value: 'stuck' },\n\t\t\t\t],\n\t\t\t\tdescription: 'Type of escalation to a human (the call-human action)',\n\t\t\t\tdisplayOptions: { show: { operation: ['callHuman'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Message',\n\t\t\t\tname: 'callDesc',\n\t\t\t\ttype: 'string',\n\t\t\t\ttypeOptions: { rows: 4 },\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'What to tell the human \u2014 context, question, or what was done',\n\t\t\t\tdisplayOptions: { show: { operation: ['callHuman'] } },\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\t\tconst token = creds.token as string;\n\t\tconst client = new ContractClient(token);\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst op = this.getNodeParameter('operation', i) as string;\n\t\t\tlet result: unknown;\n\n\t\t\tswitch (op) {\n\t\t\t\tcase 'listContracts':\n\t\t\t\t\tresult = await client.listContracts();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'listTasks': {\n\t\t\t\t\tconst contractId = this.getNodeParameter('contractId', i) as number;\n\t\t\t\t\tresult = await client.tasks(contractId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'getTask': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tresult = await client.task(eventId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'myEvents':\n\t\t\t\t\tresult = await client.myEvents();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'createTask': {\n\t\t\t\t\tconst contractId = this.getNodeParameter('contractId', i) as number;\n\t\t\t\t\tconst label = this.getNodeParameter('label', i) as string;\n\t\t\t\t\tconst description = (this.getNodeParameter('description', i) as string) || '';\n\t\t\t\t\tconst status = this.getNodeParameter('status', i) as number;\n\t\t\t\t\tconst bType = this.getNodeParameter('benefitableType', i) as string;\n\t\t\t\t\tconst bValue = this.getNodeParameter('benefitableValue', i) as number;\n\t\t\t\t\tresult = await client.create(contractId, {\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\tdescription: description || undefined,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t\tbenefitable: bValue ? `${bType}:${bValue}` : undefined,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'assign': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst bType = this.getNodeParameter('benefitableType', i) as string;\n\t\t\t\t\tconst bValue = this.getNodeParameter('benefitableValue', i) as number;\n\t\t\t\t\tif (!bValue) throw new Error('Executor ID is required for Assign');\n\t\t\t\t\tresult = await client.propose(eventId, { benefitable: `${bType}:${bValue}` });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'setStatus': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst status = this.getNodeParameter('status', i) as number;\n\t\t\t\t\tresult = await client.propose(eventId, { status });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'comment': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst description = (this.getNodeParameter('description', i) as string) || '';\n\t\t\t\t\tif (!description) throw new Error('Comment text is required');\n\t\t\t\t\tresult = await client.comment(eventId, { description });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'progress': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst status = this.getNodeParameter('status', i) as number;\n\t\t\t\t\tconst desc = this.getNodeParameter('progressDesc', i) as string;\n\t\t\t\t\tresult = await client.progress(eventId, { status, desc });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'callHuman': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst kind = this.getNodeParameter('callKind', i) as 'input' | 'review' | 'stuck';\n\t\t\t\t\tconst desc = this.getNodeParameter('callDesc', i) as string;\n\t\t\t\t\tif (!desc) throw new Error('Message is required for Call Human');\n\t\t\t\t\tresult = await client.callHuman(eventId, kind, desc);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'poll':\n\t\t\t\t\tresult = await client.poll();\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unknown operation: ${op}`);\n\t\t\t}\n\n\t\t\tout.push({ json: { op, result: result as any } });\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "import type { IExecuteFunctions, INodeType, INodeTypeDescription, INodeExecutionData } from 'n8n-workflow';\nimport { CekiClient } from '../../../lib/ceki-client';\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => {\n\tAbortSignal.timeout(ms).addEventListener('abort', () => resolve(), { once: true });\n});\n\nasync function waitForSelector(browser: any, selector: string, timeoutMs: number, intervalMs = 500) {\n\tconst expr = `!!document.querySelector(${JSON.stringify(selector)})`;\n\tconst deadline = Date.now() + timeoutMs;\n\tlet lastErr: unknown = null;\n\twhile (Date.now() < deadline) {\n\t\ttry {\n\t\t\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\t\t\tif (res?.result?.value === true) return true;\n\t\t} catch (e) {\n\t\t\tlastErr = e;\n\t\t}\n\t\tawait sleep(intervalMs);\n\t}\n\tthrow new Error(\n\t\t`waitForSelector(\"${selector}\") timed out after ${timeoutMs}ms${lastErr ? `: ${(lastErr as Error).message}` : ''}`,\n\t);\n}\n\nasync function extractHtml(browser: any, selector: string): Promise<string> {\n\tconst expr =\n\t\tselector.trim() === '' || selector === 'body'\n\t\t\t? `document.body ? document.body.outerHTML : ''`\n\t\t\t: `(function(){ var el = document.querySelector(${JSON.stringify(selector)}); return el ? el.outerHTML : ''; })()`;\n\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\treturn (res?.result?.value as string) ?? '';\n}\n\n/**\n * Recipe: Captcha-protected Scrape.\n * Rent a human browser \u2192 open a URL \u2192 (optional) wait for a selector \u2192\n * snapshot/HTML \u2192 release.\n *\n * The real human fingerprint bypasses anti-bot protection.\n */\nexport class CekiCaptchaScrape implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki: Captcha-protected Scrape',\n\t\tname: 'cekiCaptchaScrape',\n\t\tdescription: 'Rent a human browser, wait, screenshot/HTML, release',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '=rent in {{ $geo }} \u2192 snapshot',\n\t\tdefaults: { name: 'Browser Ceki: Captcha-protected Scrape' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://example.com',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'Page protected by anti-bot / captcha',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Geo',\n\t\t\t\tname: 'geo',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'RU',\n\t\t\t\tplaceholder: 'RU, EE, US\u2026',\n\t\t\t},\n\t\t\t{ displayName: 'Max $/min', name: 'maxPrice', type: 'number', typeOptions: { numberPrecision: 4 }, default: 0.02 },\n\t\t\t{\n\t\t\t\tdisplayName: 'Wait for Selector',\n\t\t\t\tname: 'waitSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'CSS selector (optional)',\n\t\t\t\tdescription: 'Wait until this selector appears in the DOM',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Wait Timeout (ms)',\n\t\t\t\tname: 'waitTimeout',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 30000,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Extract HTML',\n\t\t\t\tname: 'extractHtml',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'HTML Selector',\n\t\t\t\tname: 'htmlSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'body',\n\t\t\t\tplaceholder: 'CSS selector or \"body\"',\n\t\t\t\tdescription: 'outerHTML of this selector is returned as `html`',\n\t\t\t\tdisplayOptions: { show: { extractHtml: [true] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Full Page Screenshot',\n\t\t\t\tname: 'fullPage',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\tconst waitSelector = (this.getNodeParameter('waitSelector', i) as string) || '';\n\t\t\tconst waitTimeout = this.getNodeParameter('waitTimeout', i) as number;\n\t\t\tconst extractHtmlFlag = this.getNodeParameter('extractHtml', i) as boolean;\n\t\t\tconst htmlSelector = (this.getNodeParameter('htmlSelector', i) as string) || 'body';\n\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\n\t\t\tconst client = new CekiClient(creds.token as string);\n\t\t\tawait client.connect();\n\t\t\tlet browser: any;\n\t\t\tlet scheduleId = 0;\n\t\t\ttry {\n\t\t\t\tconst list = await client.search({ geo: geo || undefined, max_price_per_min: maxPrice });\n\t\t\t\tif (!list.length) throw new Error(`No browsers in geo ${geo || '*'}`);\n\t\t\t\tscheduleId = list[0].schedule_id;\n\t\t\t\tbrowser = await client.rent(scheduleId);\n\n\t\t\t\tawait browser.navigate(url);\n\n\t\t\t\tif (waitSelector) {\n\t\t\t\t\tawait waitForSelector(browser, waitSelector, waitTimeout);\n\t\t\t\t}\n\n\t\t\t\tconst shot = await browser.screenshot({ format: 'base64', fullPage }) as any;\n\t\t\t\tconst data = shot.data ?? (shot instanceof Buffer ? shot.toString('base64') : '');\n\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\tBuffer.from(data, 'base64'),\n\t\t\t\t\t'captcha-scrape.png',\n\t\t\t\t\t'image/png',\n\t\t\t\t);\n\n\t\t\t\tconst json: Record<string, unknown> = {\n\t\t\t\t\turl,\n\t\t\t\t\tgeo,\n\t\t\t\t\tschedule_id: scheduleId,\n\t\t\t\t};\n\t\t\t\tif (extractHtmlFlag) {\n\t\t\t\t\tjson.html = await extractHtml(browser, htmlSelector);\n\t\t\t\t}\n\n\t\t\t\tout.push({ json: json as any, binary: { data: binary } });\n\t\t\t} finally {\n\t\t\t\tif (browser) {\n\t\t\t\t\ttry { await browser.close(); } catch { /* ignore */ }\n\t\t\t\t}\n\t\t\t\ttry { await client.close(); } catch { /* ignore */ }\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "import type { IExecuteFunctions, INodeType, INodeTypeDescription, INodeExecutionData } from 'n8n-workflow';\nimport { CekiClient } from '../../../lib/ceki-client';\n\n/**\n * Recipe: Screenshot in Geo.\n * One call \u2014 rent a browser in the requested geo, open a URL, take a screenshot, release.\n */\nexport class CekiScreenshotGeo implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki: Screenshot in Geo',\n\t\tname: 'cekiScreenshotGeo',\n\t\tdescription: 'Rent a browser in a given geo, screenshot a page, release',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '=rent in {{ $geo }} \u2192 screenshot \u2192 release',\n\t\tdefaults: { name: 'Browser Ceki: Screenshot in Geo' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://ifconfig.me',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{ displayName: 'Geo', name: 'geo', type: 'string', default: 'RU', placeholder: 'RU, EE, US\u2026' },\n\t\t\t{ displayName: 'Full page', name: 'fullPage', type: 'boolean', default: false },\n\t\t\t{ displayName: 'Max $/min', name: 'maxPrice', type: 'number', default: 0.02 },\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\n\t\t\tconst client = new CekiClient(creds.token as string);\n\t\t\tawait client.connect();\n\t\t\tlet browser: any;\n\t\t\ttry {\n\t\t\t\tconst list = await client.search({ geo, max_price_per_min: maxPrice });\n\t\t\t\tif (!list.length) throw new Error(`No browsers in geo ${geo}`);\n\t\t\t\tbrowser = await client.rent(list[0].schedule_id);\n\t\t\t\tawait browser.navigate(url);\n\t\t\t\tconst shot = await browser.screenshot({ format: 'base64', fullPage }) as any;\n\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\tBuffer.from(shot.data, 'base64'),\n\t\t\t\t\t'screenshot.png',\n\t\t\t\t\t'image/png',\n\t\t\t\t);\n\t\t\t\tout.push({\n\t\t\t\t\tjson: { url, geo, schedule_id: list[0].schedule_id },\n\t\t\t\t\tbinary: { data: binary },\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tif (browser) { try { await browser.close(); } catch {} }\n\t\t\t\ttry { await client.close(); } catch {}\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "import type {\n\tIAuthenticateGeneric,\n\tICredentialTestRequest,\n\tICredentialType,\n\tINodeProperties,\n} from 'n8n-workflow';\n\n/**\n * Ceki agent token (ag_...). Authorizes every Ceki node.\n * Get it from the Ceki panel \u2192 agent profile \u2192 API key.\n */\nexport class CekiApi implements ICredentialType {\n\tname = 'cekiApi';\n\tdisplayName = 'Ceki API';\n\tdocumentationUrl = 'https://browser.ceki.me/docs#api-key';\n\tproperties: INodeProperties[] = [\n\t\t{\n\t\t\tdisplayName: 'API Key',\n\t\t\tname: 'token',\n\t\t\ttype: 'string',\n\t\t\ttypeOptions: { password: true },\n\t\t\tdefault: '',\n\t\t\tdescription:\n\t\t\t\t'Agent token (ag_...). [Get your API key \u2192](https://browser.ceki.me/docs#api-key)',\n\t\t\trequired: true,\n\t\t},\n\t];\n\n\tauthenticate: IAuthenticateGeneric = {\n\t\ttype: 'generic',\n\t\tproperties: {\n\t\t\theaders: {\n\t\t\t\tAuthorization: '=Bearer {{$credentials?.token}}',\n\t\t\t},\n\t\t},\n\t};\n\n\ttest: ICredentialTestRequest = {\n\t\trequest: {\n\t\t\tbaseURL: 'https://api.ceki.me',\n\t\t\turl: '/api/browsers/search',\n\t\t\tmethod: 'GET',\n\t\t},\n\t};\n}\n"],
5
- "mappings": "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",
6
- "names": ["x", "y", "sid", "x", "y", "sleep"]
4
+ "sourcesContent": ["import { BrowserCeki } from './nodes/BrowserCeki/BrowserCeki.node';\nimport { CekiContract } from './nodes/CekiContract/CekiContract.node';\nimport { CekiCaptchaScrape } from './nodes/recipes/CekiCaptchaScrape/CekiCaptchaScrape.node';\nimport { CekiScreenshotGeo } from './nodes/recipes/CekiScreenshotGeo/CekiScreenshotGeo.node';\nimport { CekiApi } from './credentials/CekiApi.credentials';\n\nexport const nodes = [\n\tBrowserCeki,\n\tCekiContract,\n\tCekiCaptchaScrape,\n\tCekiScreenshotGeo,\n];\n\nexport const credentials = [\n\tCekiApi,\n];\n", "/**\n * Minimal Ceki browser client \u2014 uses only native WebSocket + fetch (Node 22 globals).\n * Zero npm imports (no ws, no mime-types, no node built-in modules).\n *\n * Timeout management: uses AbortSignal.timeout() instead of restricted\n * setTimeout/clearTimeout globals to satisfy the n8n community-nodes\n * package scanner (no-restricted-globals rule).\n */\n\n// \u2500\u2500 types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserOption {\n\tschedule_id: number;\n\tgeo?: string;\n\tprice_per_min: number;\n\tonline: boolean;\n\trating?: number | null;\n}\n\nexport interface Match {\n\tsession_id: string;\n\tschedule_id: number;\n\tevent_id?: string | null;\n\tchat_topic_id?: string | null;\n\tprovider_user_id?: number | null;\n\tbrowser_info?: Record<string, unknown>;\n}\n\nexport interface RentOptions {\n\tmode?: 'main' | 'incognito';\n}\n\nexport interface ScreenshotOptions {\n\tformat?: 'png' | 'base64';\n\tfullPage?: boolean;\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction jsonParse(raw: string): unknown {\n\ttry { return JSON.parse(raw); } catch { return null; }\n}\n\n// \u2500\u2500 Client \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiClient {\n\tprivate _ws: WebSocket | null = null;\n\tprivate _connected = false;\n\tprivate _pendingRents = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingResumes = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingCdp = new Map<number, {\n\t\tresolve: (v: unknown) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _cdpCounter = 1;\n\t_activeSessions = new Map<string, CekiBrowser>();\n\tprivate _connectReject: ((e: Error) => void) | null = null;\n\tprivate _closed = false;\n\n\tconstructor(\n\t\tprivate _token: string,\n\t\tprivate _relayUrl = 'wss://browser.ceki.me/ws/agent',\n\t\tprivate _apiUrl = 'https://api.ceki.me',\n\t) {}\n\n\t/** Connect to the relay WebSocket. */\n\tasync connect(): Promise<void> {\n\t\tif (this._connected) return;\n\t\tconst protocols = [`bearer.${this._token}`];\n\t\tthis._ws = new WebSocket(this._relayUrl, protocols);\n\t\tthis._ws.onopen = () => {\n\t\t\tthis._connected = true;\n\t\t};\n\t\tthis._ws.onmessage = (ev: MessageEvent) => {\n\t\t\tthis._handleMessage(ev.data);\n\t\t};\n\t\tthis._ws.onclose = (ev: CloseEvent) => {\n\t\t\tthis._connected = false;\n\t\t\tif ((ev.code === 4401 || ev.code === 4403) && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error(`Auth failed: ${ev.reason || String(ev.code)}`));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tthis._ws.onerror = () => {\n\t\t\tif (!this._connected && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error('WebSocket connection failed'));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tif (this._ws.readyState === WebSocket.CONNECTING) {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tif (!this._ws) { reject(new Error('No WebSocket')); return; }\n\t\t\t\tthis._connectReject = reject;\n\t\t\t\tthis._ws!.onopen = () => {\n\t\t\t\t\tthis._connected = true;\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n\n\t_sendRaw(msg: Record<string, unknown>): void {\n\t\tif (!this._ws || this._ws.readyState !== WebSocket.OPEN) {\n\t\t\tthrow new Error('WebSocket not connected');\n\t\t}\n\t\tthis._ws.send(JSON.stringify(msg));\n\t}\n\n\t/** Search for available browser providers (HTTP GET). */\n\tasync search(filters?: Record<string, unknown>, limit?: number): Promise<BrowserOption[]> {\n\t\tconst params = new URLSearchParams();\n\t\tif (limit != null) params.set('limit', String(limit));\n\t\tif (filters) {\n\t\t\tfor (const [k, v] of Object.entries(filters)) {\n\t\t\t\tif (v != null) params.set(k, String(v));\n\t\t\t}\n\t\t}\n\t\tconst resp = await fetch(`${this._apiUrl}/api/browsers/search?${params}`, {\n\t\t\theaders: { Authorization: `Bearer ${this._token}` },\n\t\t});\n\t\tif (!resp.ok) throw new Error(`Search failed: ${resp.status}`);\n\t\tconst body = (await resp.json()) as Record<string, unknown>;\n\t\tconst data = (body.data ?? body) as unknown[];\n\t\treturn Array.isArray(data) ? data as BrowserOption[] : [];\n\t}\n\n\t/** Rent a browser by schedule_id. */\n\tasync rent(scheduleId: number, opts?: RentOptions): Promise<CekiBrowser> {\n\t\tconst msg: Record<string, unknown> = { type: 'rent', browser_id: scheduleId };\n\t\tif (opts?.mode) msg.mode = opts.mode;\n\t\tthis._sendRaw(msg);\n\t\treturn this._awaitRent(`rent:${scheduleId}`, scheduleId, 90000);\n\t}\n\n\t/** Resume an existing session. */\n\tasync resume(sessionId: string): Promise<CekiBrowser> {\n\t\tthis._sendRaw({ type: 'resume', session_id: sessionId });\n\t\treturn this._awaitResume(sessionId);\n\t}\n\n\t/** Close the WS connection \u2014 session stays alive in grace.\n\t * Waits for the close handshake so the relay processes the close\n\t * before a new connection with the same renterId is established\n\t * (avoids the close-handler race condition).\n\t */\n\tasync disconnect(): Promise<void> {\n\t\tthis._closed = true;\n\t\tthis._activeSessions.clear();\n\t\tthis._pendingRents.clear();\n\t\tthis._pendingResumes.clear();\n\t\tif (!this._ws) return;\n\t\tconst ws = this._ws;\n\t\tif (ws.readyState === WebSocket.CLOSED) {\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\tif (ws.readyState === WebSocket.CLOSING) {\n\t\t\tawait new Promise<void>(r => { ws.onclose = () => { this._connected = false; r(); }; });\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\t// OPEN \u2192 initiate close and wait for handshake (up to 5s safety timeout)\n\t\tawait new Promise<void>(r => {\n\t\t\tconst t = setTimeout(() => { r(); }, 5000);\n\t\t\tws.onclose = () => { this._connected = false; clearTimeout(t); r(); };\n\t\t\ttry { ws.close(); } catch { clearTimeout(t); r(); }\n\t\t});\n\t\tthis._ws = null;\n\t}\n\n\t/** Close everything. */\n\tasync close(): Promise<void> {\n\t\tawait this.disconnect();\n\t}\n\n\t// \u2500\u2500 private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate _awaitRent(key: string, scheduleId: number, timeoutMs: number): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingRents.delete(key);\n\t\t\t\treject(new Error('Rent timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingRents.set(key, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _awaitResume(sessionId: string): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(60000);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\t\treject(new Error('Resume timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingResumes.set(sessionId, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _closeWs(): void {\n\t\tif (this._ws) {\n\t\t\ttry { this._ws.onopen = null; this._ws.onmessage = null; this._ws.onclose = null; this._ws.onerror = null; this._ws.close(); } catch { /* ignore */ }\n\t\t\tthis._ws = null;\n\t\t}\n\t}\n\n\tprivate _handleMessage(data: unknown): void {\n\t\tconst msg = jsonParse(String(data)) as Record<string, unknown> | null;\n\t\tif (!msg || typeof msg !== 'object') return;\n\t\tconst type = String(msg.type ?? '');\n\t\tconst sid = msg.session_id ? String(msg.session_id) : null;\n\n\t\tswitch (type) {\n\t\t\tcase 'pong':\n\t\t\tcase 'rent_pending':\n\t\t\t\tbreak;\n\t\t\tcase 'match':\n\t\t\t\tthis._onMatch(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'rent.error':\n\t\t\t\tthis._onRentError(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_ok':\n\t\t\t\tthis._onResumeOk(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_failed':\n\t\t\t\tthis._onResumeFailed(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'cdp_response':\n\t\t\t\tif (sid) this._onCdpResponse(sid, msg);\n\t\t\t\tbreak;\n\t\t\tcase 'session.ended':\n\t\t\t\tif (sid) {\n\t\t\t\t\tthis._activeSessions.delete(sid);\n\t\t\t\t\tconst b = this._activeSessions.get(sid);\n\t\t\t\t\tif (b) (b as any)._ended = String(msg.reason ?? 'ended');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate _onMatch(msg: Record<string, unknown>): void {\n\t\tconst scheduleId = Number(msg.schedule_id ?? 0);\n\t\tconst eventId = msg.event_id ? String(msg.event_id) : null;\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\t// Send match_ack to transition session from ACCEPTED to ACTIVE.\n\t\t// Without this, subsequent resume from other n8n nodes would receive\n\t\t// \"match\" instead of \"resume_ok\" (session stays ACCEPTED).\n\t\tif (sessionId && this._ws?.readyState === WebSocket.OPEN) {\n\t\t\ttry { this._ws.send(JSON.stringify({ type: 'match_ack', session_id: sessionId })); } catch { /* ignore */ }\n\t\t}\n\t\t// Check pending rents (normal rent flow)\n\t\tlet pending = this._pendingRents.get(`event:${eventId}`);\n\t\tif (!pending) pending = this._pendingRents.get(`rent:${scheduleId}`);\n\t\tif (pending) {\n\t\t\tthis._pendingRents.delete(`event:${eventId}`);\n\t\t\tthis._pendingRents.delete(`rent:${scheduleId}`);\n\t\t\tpending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\t// Fallback: relay may send \"match\" during resume if session is ACCEPTED\n\t\t// (e.g. when rent node finished without sending match_ack).\n\t\t// Treat it like resume_ok so the next node doesn't hang.\n\t\tconst resumePending = sessionId ? this._pendingResumes.get(sessionId) : null;\n\t\tif (resumePending) {\n\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\tresumePending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _onRentError(msg: Record<string, unknown>): void {\n\t\tconst code = String(msg.code ?? '');\n\t\tconst message = String(msg.message ?? '');\n\t\tfor (const [key, pending] of this._pendingRents) {\n\t\t\tthis._pendingRents.delete(key);\n\t\t\tpending.reject(new Error(message || `Rent error: ${code}`));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate _onResumeOk(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.resolve({\n\t\t\tsession_id: sessionId,\n\t\t\tschedule_id: Number(msg.schedule_id ?? 0),\n\t\t\tevent_id: msg.event_id ? String(msg.event_id) : null,\n\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t});\n\t}\n\n\tprivate _onResumeFailed(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.reject(new Error(String(msg.reason ?? 'Resume failed')));\n\t}\n\n\tprivate _onCdpResponse(sessionId: string, msg: Record<string, unknown>): void {\n\t\tconst browser = this._activeSessions.get(sessionId);\n\t\tif (!browser) return;\n\t\tconst id = Number(msg.id ?? 0);\n\t\t// NOTE: pending CDP is stored on CekiBrowser._pendingCdp (set by CekiBrowser.send()),\n\t\t// NOT on CekiClient._pendingCdp \u2014 they are different maps.\n\t\tconst pending = browser._pendingCdp.get(id);\n\t\tif (!pending) return;\n\t\tbrowser._pendingCdp.delete(id);\n\t\tif (msg.error) {\n\t\t\tpending.reject(new Error(String((msg.error as Record<string, unknown>).message ?? 'CDP error')));\n\t\t} else {\n\t\t\tpending.resolve(msg.result);\n\t\t}\n\t}\n}\n\n// \u2500\u2500 Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiBrowser {\n\treadonly sessionId: string;\n\treadonly scheduleId: number;\n\treadonly chatTopicId: string | null;\n\treadonly browserInfo: Record<string, unknown>;\n\treadonly providerUserId: number | null;\n\n\tprivate _client: CekiClient;\n\tprivate _cdpId = 1;\n\t_pendingCdp = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n\n\tconstructor(client: CekiClient, match: Match) {\n\t\tthis._client = client;\n\t\tthis.sessionId = match.session_id;\n\t\tthis.scheduleId = match.schedule_id;\n\t\tthis.chatTopicId = match.chat_topic_id ?? null;\n\t\tthis.browserInfo = match.browser_info ?? {};\n\t\tthis.providerUserId = match.provider_user_id ?? null;\n\t}\n\n\t/** Send a CDP command. Uses AbortSignal.timeout() (no restricted setTimeout global). */\n\tasync send(method: string, params?: Record<string, unknown>, timeoutMs = 30000): Promise<unknown> {\n\t\tconst id = this._cdpId++;\n\t\tconst msg = { type: 'cdp', session_id: this.sessionId, id, method, params: params ?? {} };\n\t\tthis._client._sendRaw(msg);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingCdp.delete(id);\n\t\t\t\treject(new Error(`CDP ${method} timed out after ${timeoutMs}ms`));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingCdp.set(id, {\n\t\t\t\tresolve: (v) => { resolve(v); },\n\t\t\t\treject: (e) => { reject(e); },\n\t\t\t});\n\t\t});\n\t}\n\n\tasync navigate(url: string, timeoutMs?: number): Promise<void> {\n\t\tawait this.send('Page.navigate', { url }, timeoutMs);\n\t}\n\n\tasync click(x: number, y: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 });\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });\n\t}\n\n\tasync type(text: string): Promise<void> {\n\t\tawait this.send('Ceki.typeText', { text });\n\t}\n\n\tasync scroll(deltaY: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseWheel', x: 0, y: 0, deltaX: 0, deltaY });\n\t}\n\n\tasync screenshot(opts?: ScreenshotOptions): Promise<{ data: string } | Buffer> {\n\t\tconst format = opts?.format ?? 'base64';\n\t\tconst fullPage = opts?.fullPage ?? false;\n\t\tlet clip: Record<string, number> | undefined;\n\t\tif (fullPage) {\n\t\t\tconst metrics = await this.send('Page.getLayoutMetrics') as Record<string, unknown> | null;\n\t\t\tconst contentSize = metrics?.contentSize as Record<string, number> | undefined;\n\t\t\tif (contentSize) {\n\t\t\t\tclip = { x: 0, y: 0, width: Number(contentSize.width ?? 1920), height: Math.min(Number(contentSize.height ?? 1080), 16384), scale: 1 };\n\t\t\t}\n\t\t}\n\t\tconst result = await this.send('Page.captureScreenshot', { format: 'png', ...(clip ? { clip } : {}) }) as Record<string, unknown> | null;\n\t\tconst data = String(result?.data ?? '');\n\t\tif (format === 'png') {\n\t\t\treturn Buffer.from(data, 'base64');\n\t\t}\n\t\treturn { data };\n\t}\n\n\tasync snapshot(): Promise<{ screenshot: string; ts: Date }> {\n\t\tconst ssResult = await this.screenshot({ format: 'base64' }) as { data: string };\n\t\treturn { screenshot: ssResult.data, ts: new Date() };\n\t}\n\n\tasync upload(selector: string, buf: Buffer, filename = 'file'): Promise<Record<string, unknown>> {\n\t\tconst b64 = buf.toString('base64');\n\t\tconst size = buf.length;\n\t\tconst mime = 'application/octet-stream';\n\t\tconst expression = `(function(){\n\t\t\tvar input = document.querySelector(${JSON.stringify(selector)});\n\t\t\tif (!input) return JSON.stringify({ok:false,error:'Element not found'});\n\t\t\tvar b = atob(${JSON.stringify(b64)});\n\t\t\tvar u = new Uint8Array(b.length);\n\t\t\tfor (var i = 0; i < b.length; i++) u[i] = b.charCodeAt(i);\n\t\t\tvar f = new File([u], ${JSON.stringify(filename)}, {type: ${JSON.stringify(mime)}});\n\t\t\tvar dt = new DataTransfer(); dt.items.add(f);\n\t\t\tinput.files = dt.files;\n\t\t\tinput.dispatchEvent(new Event('change',{bubbles:true}));\n\t\t\treturn JSON.stringify({ok:true,filename:${JSON.stringify(filename)},size:${size}});\n\t\t})()`;\n\t\tconst result = await this.send('Runtime.evaluate', { expression, returnByValue: true }) as Record<string, unknown> | null;\n\t\ttry {\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t} catch { /* ignore */ }\n\t\tconst resultObj = result?.result as Record<string, unknown> | undefined;\n\t\tif (resultObj?.value) return JSON.parse(String(resultObj.value)) as Record<string, unknown>;\n\t\treturn { ok: true, filename, size };\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.send('Ceki.close', {}).catch(() => {});\n\t\tthis._client._activeSessions.delete(this.sessionId);\n\t}\n}\n", "import type {\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { CekiClient } from '../../lib/ceki-client';\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => {\n\tAbortSignal.timeout(ms).addEventListener('abort', () => resolve(), { once: true });\n});\n\n/**\n * Browser Ceki \u2014 one node, many operations.\n * Uses native WebSocket (not the ws library) \u2014 zero external runtime deps.\n *\n * Resume flow:\n * 1. Rent \u2192 browser session created, client disconnects (session in grace).\n * 2. Navigate/Screenshot/etc \u2192 new client, connect, resume(sessionId) \u2192 server\n * responds with resume_ok, do the op, disconnect.\n * 3. Close \u2192 same, sends Ceki.close, client.close().\n *\n * This works because the server supports session resume across different\n * WebSocket connections (same auth token). Each n8n node independently\n * creates a fresh WS connection and resumes the session by ID.\n */\nexport class BrowserCeki implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki',\n\t\tname: 'browserCeki',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '={{ \"Ceki: \" + $parameter.operation }}',\n\t\tdescription: 'Rent a real human browser and control it: rent, navigate, click, type, screenshot, solve captchas, and more',\n\t\tdefaults: { name: 'Browser Ceki' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'search',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Search', value: 'search' },\n\t\t\t\t\t{ name: 'Rent', value: 'rent' },\n\t\t\t\t\t{ name: 'Navigate', value: 'navigate' },\n\t\t\t\t\t{ name: 'Click', value: 'click' },\n\t\t\t\t\t{ name: 'Type', value: 'type' },\n\t\t\t\t\t{ name: 'Scroll', value: 'scroll' },\n\t\t\t\t\t{ name: 'Screenshot', value: 'screenshot' },\n\t\t\t\t\t{ name: 'Snapshot', value: 'snapshot' },\n\t\t\t\t\t{ name: 'Wait', value: 'wait' },\n\t\t\t\t\t{ name: 'Wait for Selector', value: 'waitForSelector' },\n\t\t\t\t\t{ name: 'Upload', value: 'upload' },\n\t\t\t\t\t{ name: 'Close', value: 'close' },\n\t\t\t\t\t{ name: 'Full: Rent \u2192 Navigate \u2192 Screenshot', value: 'full' },\n { name: 'My Sessions', value: 'my_sessions' },\n { name: 'Stop Session', value: 'stop_session' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t// === Rent: rental parameters ===\n\t\t\t{\n\t\t\t\tdisplayName: 'Schedule ID',\n\t\t\t\tname: 'scheduleId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: '0 \u2014 search by the filters below',\n\t\t\t\tdisplayOptions: { show: { operation: ['rent'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Geo',\n\t\t\t\tname: 'geo',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'RU, EE, US\u2026',\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max $/min',\n\t\t\t\tname: 'maxPrice',\n\t\t\t\ttype: 'number',\n\t\t\t\ttypeOptions: { numberPrecision: 4 },\n\t\t\t\tdefault: 0.02,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Min rating',\n\t\t\t\tname: 'minRating',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Profile mode',\n\t\t\t\tname: 'mode',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'incognito',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'main', value: 'main' },\n\t\t\t\t\t{ name: 'incognito', value: 'incognito' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['rent', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://example.com',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Demo mode (no browser needed)',\n\t\t\t\tname: 'demoMode',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription: 'Skip actual browser rent and generate demo output',\n\t\t\t\tdisplayOptions: { show: { operation: ['full'] } },\n\t\t\t},\n\t\t\t// === Operations: session_id ===\n\n\n\t\t\t{\n\t\t\t\tdisplayName: 'Session ID',\n\t\t\t\tname: 'sessionId',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'From the Rent operation',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\toperation: ['navigate', 'click', 'type', 'scroll', 'screenshot', 'snapshot', 'wait', 'waitForSelector', 'upload', 'close', 'stop_session'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'X',\n\t\t\t\tname: 'x',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Y',\n\t\t\t\tname: 'y',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Text',\n\t\t\t\tname: 'text',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: { show: { operation: ['type'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Delta Y',\n\t\t\t\tname: 'deltaY',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: -300,\n\t\t\t\tdisplayOptions: { show: { operation: ['scroll'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Format',\n\t\t\t\tname: 'format',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'png',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'PNG (binary)', value: 'png' },\n\t\t\t\t\t{ name: 'Base64', value: 'base64' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Full page',\n\t\t\t\tname: 'fullPage',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: false,\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Milliseconds',\n\t\t\t\tname: 'ms',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 1000,\n\t\t\t\ttypeOptions: { minValue: 0 },\n\t\t\t\tdescription: 'Fixed delay on the active session',\n\t\t\t\tdisplayOptions: { show: { operation: ['wait', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'waitSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tplaceholder: 'e.g. .results, #content, table tr',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Timeout (ms)',\n\t\t\t\tname: 'waitTimeout',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 30000,\n\t\t\t\tdescription: 'Waits until the selector appears in the DOM',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'selector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Binary Property',\n\t\t\t\tname: 'binaryPropertyName',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'data',\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\t\tconst token = creds.token as string;\n\n\t\tconst resolveSid = async (i: number, client: CekiClient) => {\n\t\t\tconst scheduleId = this.getNodeParameter('scheduleId', i) as number;\n\t\t\tif (scheduleId) return scheduleId;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\tconst list = await client.search({\n\t\t\t\tgeo: geo || undefined,\n\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t});\n\t\t\tif (!list.length) throw new Error('No browsers found by filters');\n\t\t\treturn list[0].schedule_id;\n\t\t};\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst op = this.getNodeParameter('operation', i) as string;\n\t\t\tconst client = new CekiClient(token);\n\t\t\tlet browser: any;\n\t\t\tlet needFullClose = false;\n\t\t\ttry {\n\t\t\t\tawait client.connect();\n\n\t\t\t\tif (op === 'rent') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst sid = await resolveSid(i, client);\n\t\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: browser.sessionId, schedule_id: sid, mode },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Rent failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'search') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\t\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\t\t\t\tconst list = await client.search({\n\t\t\t\t\t\t\tgeo: geo || undefined,\n\t\t\t\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tout.push({ json: { browsers: list, count: list.length } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Search failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'my_sessions') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst resp = await fetch(\"https://api.ceki.me/api/agent/sessions\", {\n\t\t\t\t\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!resp.ok) throw new Error(`HTTP ${resp.status}`);\n\t\t\t\t\t\tconst body = await resp.json() as any;\n\t\t\t\t\t\tconst sessions = body.data ?? [];\n\t\t\t\t\t\tout.push({ json: { sessions, count: sessions.length } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`My sessions failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (op === 'stop_session') {\n\t\t\t\t\tconst sessionId = this.getNodeParameter(\"sessionId\", i) as string;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\t\tconst ws = new WebSocket(\"wss://browser.ceki.me/ws/agent\", [`bearer.${token}`]);\n\t\t\t\t\t\t\tconst t = AbortSignal.timeout(15000);\n\t\t\t\t\t\t\tt.addEventListener(\"abort\", () => { try { ws.close(); } catch {} reject(new Error(\"Stop session timed out\")); }, { once: true });\n\t\t\t\t\t\t\tws.onopen = () => {\n\t\t\t\t\t\t\t\tws.send(JSON.stringify({ type: \"stop\", session_id: sessionId, reason: \"n8n stop_session\" }));\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tws.onmessage = (ev) => {\n\t\t\t\t\t\t\t\tconst msg = JSON.parse(ev.data as string);\n\t\t\t\t\t\t\t\tif (msg.type === \"session_ended\" || msg.type === \"pong\") {\n\t\t\t\t\t\t\t\t\ttry { ws.close(); } catch {}\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tws.onerror = () => { reject(new Error(\"WebSocket connection failed\")); };\n\t\t\t\t\t\t});\n\t\t\t\t\t\tout.push({ json: { stopped: true, session_id: sessionId } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Stop session failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'full') {\n\t\t\t\t\tconst demoMode = this.getNodeParameter('demoMode', i) as boolean;\n\t\t\t\t\tlet sid: number;\n\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsid = 99999; // mock\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tsid = await resolveSid(i, client);\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full: resolve schedule failed: ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\n\t\t\t\t\tlet session_id: string;\n\t\t\t\t\tlet binary: any;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsession_id = 'demo-' + Date.now();\n\t\t\t\t\t\tconst demoPng = Buffer.from('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', 'base64');\n\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(demoPng, 'screenshot.png', 'image/png');\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\t\tsession_id = browser.sessionId;\n\t\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\t\t\tconst shot = await browser.screenshot({ format: 'png', fullPage: true }) as any;\n\t\t\t\t\t\t\tconst data = (shot as Buffer).toString('base64');\n\t\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(Buffer.from(data, 'base64'), 'screenshot.png', 'image/png');\n\t\t\t\t\t\t\tawait browser.close();\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full op failed at step \"${(browser?.sessionId ? 'navigate/screenshot' : 'rent')}\": ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\tsession_id,\n\t\t\t\t\t\t\tschedule_id: sid,\n\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\twaited: ms,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbinary: { data: binary },\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tawait client.close().catch(() => {});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// All remaining operations: navigate, click, type, scroll, screenshot,\n\t\t\t// snapshot, wait, waitForSelector, upload, close.\n\t\t\t// Each creates a fresh WS connection and resumes the existing\n\t\t\t// browser session by sessionId (server supports cross-WS resume).\n\t\t\tconst sessionId = this.getNodeParameter('sessionId', i) as string;\n\t\t\ttry {\n\t\t\t\tbrowser = await client.resume(sessionId);\n\t\t\t} catch (e) {\n\t\t\t\tthrow new Error(`Resume session \"${sessionId}\" failed: ${(e as Error).message}. Session may have expired or still be in grace.`);\n\t\t\t}\n\t\t\tconst sid = browser.sessionId;\n\n\t\t\tswitch (op) {\n\t\t\t\tcase 'navigate': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, url } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Navigate failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'click': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst x = this.getNodeParameter('x', i) as number;\n\t\t\t\t\t\tconst y = this.getNodeParameter('y', i) as number;\n\t\t\t\t\t\tawait browser.click(x, y);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, clicked: [x, y] } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Click at (${x},${y}) failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'type': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst text = this.getNodeParameter('text', i) as string;\n\t\t\t\t\t\tawait browser.type(text);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, typed: text } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Type failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'scroll': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst deltaY = this.getNodeParameter('deltaY', i) as number;\n\t\t\t\t\t\tawait browser.scroll(deltaY);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, scrolled: deltaY } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Scroll failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'screenshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst format = this.getNodeParameter('format', i) as 'png' | 'base64';\n\t\t\t\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\t\t\t\t\t\tconst shot = await browser.screenshot({ format, fullPage }) as any;\n\t\t\t\t\t\tconst data = format === 'base64' ? shot.data : (shot as Buffer).toString('base64');\n\t\t\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\t\t\tBuffer.from(data, 'base64'),\n\t\t\t\t\t\t\t'screenshot.png',\n\t\t\t\t\t\t\t'image/png',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tout.push({ json: { session_id: sid }, binary: { data: binary } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Screenshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'snapshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst snap = await browser.snapshot();\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: sid, screenshot: snap.screenshot },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Snapshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'wait': {\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\tout.push({ json: { session_id: sid, waited: ms } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'waitForSelector': {\n\t\t\t\t\tconst selector = this.getNodeParameter('waitSelector', i) as string;\n\t\t\t\t\tconst timeout = this.getNodeParameter('waitTimeout', i) as number;\n\t\t\t\t\tconst expr = `!!document.querySelector(${JSON.stringify(selector)})`;\n\t\t\t\t\tconst deadline = Date.now() + timeout;\n\t\t\t\t\tlet ok = false;\n\t\t\t\t\tlet lastErr: unknown = null;\n\t\t\t\t\twhile (Date.now() < deadline) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\t\t\t\t\t\t\tif (res?.result?.value === true) {\n\t\t\t\t\t\t\t\tok = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tlastErr = e;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait sleep(500);\n\t\t\t\t\t}\n\t\t\t\t\tif (!ok) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`waitForSelector(\"${selector}\") timed out after ${timeout}ms${lastErr ? `: ${(lastErr as Error).message}` : ''}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tout.push({ json: { session_id: sid, selector, found: true } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'upload': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst selector = this.getNodeParameter('selector', i) as string;\n\t\t\t\t\t\tconst bpn = this.getNodeParameter('binaryPropertyName', i) as string;\n\t\t\t\t\t\tconst bin = items[i].binary?.[bpn];\n\t\t\t\t\t\tif (!bin) throw new Error(`Binary property \"${bpn}\" not found on input`);\n\t\t\t\t\t\tconst stream = await this.helpers.getBinaryStream(bin.id as string);\n\t\t\t\t\t\tconst chunks: Buffer[] = [];\n\t\t\t\t\t\tfor await (const c of stream) chunks.push(c as Buffer);\n\t\t\t\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\t\t\t\tconst res = await browser.upload(selector, buf);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, uploaded: res } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Upload failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'close': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try graceful CDP close first (best-effort)\n\t\t\t\t\t\tawait browser.close().catch(() => {});\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore CDP close errors\n\t\t\t\t\t}\n\t\t\t\t\t// Always send relay stop (force-end session) \u2014 CDP can silently fail\n\t\t\t\t\t// eslint-disable-next-line no-async-promise-executor\n\t\t\t\t\tawait new Promise((resolve) => {\n\t\t\t\t\t\tconst stopWs = new WebSocket('wss://browser.ceki.me/ws/agent', [`bearer.${token}`]);\n\t\t\t\t\t\tconst abortTimer = AbortSignal.timeout(10000);\n\t\t\t\t\tconst onTimer = () => { try { stopWs.close(); } catch {} resolve(); };\n\t\t\t\t\tabortTimer.addEventListener(\"abort\", onTimer, { once: true });\n\t\t\t\t\t\tstopWs.onopen = () => {\n\t\t\t\t\t\t\tstopWs.send(JSON.stringify({ type: 'stop', session_id: sessionId, reason: 'n8n close' }));\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onmessage = (ev) => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst msg = JSON.parse(ev.data);\n\t\t\t\t\t\t\t\tif (msg.type === 'session_ended') {\n\t\t\t\t\t\t\t\t\tabortTimer.removeEventListener(\"abort\", onTimer);\n\t\t\t\t\t\t\t\t\ttry { stopWs.close(); } catch {}\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onerror = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t\tstopWs.onclose = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t});\n\t\t\t\t\tout.push({ json: { closed: true, session_id: sessionId } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tneedFullClose = op === 'close';\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (needFullClose) {\n\t\t\t\t\t\tawait client.close();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// swallow cleanup errors\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "/**\n * Minimal Ceki contract client \u2014 uses only native fetch (Node 22 global).\n * Zero npm imports (no ws, no axios, no node built-in modules beyond globals).\n *\n * Communicates with Ceki's MCP endpoint via JSON-RPC 2.0 over HTTP POST.\n */\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction cleanArgs<T extends Record<string, unknown>>(o: T): Partial<T> {\n\tconst out = { ...o };\n\tfor (const k of Object.keys(out)) {\n\t\tif ((out as any)[k] === undefined || (out as any)[k] === null) delete (out as any)[k];\n\t}\n\treturn out;\n}\n\nfunction parseBenefitable(value: string | null | undefined): { type: string; value: number } | null {\n\tif (!value) return null;\n\tconst m = /^(agent|user):(\\d+)$/.exec(value);\n\tif (!m) return null;\n\treturn { type: m[1], value: Number(m[2]) };\n}\n\ninterface ParticipantSpec {\n\tparticipable_id: number;\n\ttype: string;\n\trole_id: number;\n}\n\nfunction parseParticipant(value: string | null | undefined, roleId: number): ParticipantSpec | null {\n\tconst b = parseBenefitable(value);\n\tif (!b) return null;\n\treturn { participable_id: b.value, type: b.type, role_id: roleId };\n}\n\nfunction deriveLabel(desc: string | null | undefined): string {\n\tif (!desc) return '';\n\tconst line = desc.split('\\n')[0].trim();\n\treturn line.length > 60 ? line.slice(0, 57) + '...' : line;\n}\n\nconst ROLE_REVIEWER = 5;\nconst ROLE_QA = 6;\n\n// \u2500\u2500 types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface CreateOptions {\n\tlabel: string;\n\ttype?: number;\n\tstatus?: number;\n\tdescription?: string;\n\tbenefitable?: string;\n\treviewer?: string;\n\tqa?: string;\n}\n\nexport interface ProposeOptions {\n\tstatus?: number;\n\tlabel?: string;\n\tdescription?: string;\n\tbenefitable?: string;\n}\n\nexport interface CommentOptions {\n\tlabel?: string;\n\tdescription?: string;\n}\n\nexport interface ProgressOptions {\n\tstatus?: number;\n\tdesc: string;\n}\n\n// \u2500\u2500 client \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ContractClient {\n\tprivate _endpoint: string;\n\tprivate _apiBase: string;\n\tprivate _token: string;\n\n\tconstructor(token: string, endpoint?: string, apiBase?: string) {\n\t\tthis._endpoint = (endpoint ?? 'https://api.ceki.me/mcp').replace(/\\/+$/, '');\n\t\tthis._apiBase = (apiBase ?? 'https://api.ceki.me').replace(/\\/+$/, '');\n\t\tthis._token = token;\n\t}\n\n\tprivate _headers(): Record<string, string> {\n\t\treturn {\n\t\t\t'Content-Type': 'application/json',\n\t\t\tAccept: 'application/json',\n\t\t\tAuthorization: `Bearer ${this._token}`,\n\t\t};\n\t}\n\n\tprivate async _rpc(method: string, params: Record<string, unknown>): Promise<any> {\n\t\tconst body = JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params });\n\t\tconst resp = await fetch(this._endpoint, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: this._headers(),\n\t\t\tbody,\n\t\t});\n\t\tif (!resp.ok) {\n\t\t\tconst text = await resp.text().catch(() => '');\n\t\t\tthrow new Error(`HTTP ${resp.status}: ${text.slice(0, 400)}`);\n\t\t}\n\t\treturn resp.json();\n\t}\n\n\tprivate async _call(tool: string, args?: Record<string, unknown>): Promise<any> {\n\t\tconst body = await this._rpc('tools/call', { name: tool, arguments: args ?? {} });\n\t\tif (body.error) throw new Error(`${tool} \u2192 ${JSON.stringify(body.error).slice(0, 400)}`);\n\t\tconst result = body.result ?? {};\n\t\tconst content = result.content;\n\t\tif (Array.isArray(content)) {\n\t\t\tconst texts = content.filter((c: any) => c.type === 'text').map((c: any) => String(c.text ?? ''));\n\t\t\tconst joined = texts.join('\\n');\n\t\t\ttry { return JSON.parse(joined); } catch { return joined; }\n\t\t}\n\t\tif (result.structuredContent !== undefined) return result.structuredContent;\n\t\treturn result;\n\t}\n\n\t// \u2500\u2500 domain methods \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tasync listContracts(): Promise<any> {\n\t\treturn this._call('list-contracts');\n\t}\n\n\tasync members(contractId: number): Promise<any> {\n\t\treturn this._call('contract-members', { contract_id: contractId });\n\t}\n\n\tasync tasks(contractId: number): Promise<any> {\n\t\treturn this._call('contract-tasks', { contract_id: contractId });\n\t}\n\n\tasync myEvents(): Promise<any> {\n\t\treturn this._call('get-my-events');\n\t}\n\n\tasync task(eventId: number): Promise<any> {\n\t\treturn this._call('get-event', { event_id: eventId });\n\t}\n\n\tasync create(contractId: number, opts: CreateOptions): Promise<any> {\n\t\tconst args = cleanArgs({\n\t\t\tcontract_id: contractId,\n\t\t\tlabel: opts.label,\n\t\t\ttype_id: opts.type,\n\t\t\tstatus_id: opts.status,\n\t\t\tdescription: opts.description,\n\t\t\tbenefitable: opts.benefitable ? parseBenefitable(opts.benefitable) : undefined,\n\t\t});\n\t\tconst users: ParticipantSpec[] = [];\n\t\tconst rev = parseParticipant(opts.reviewer, ROLE_REVIEWER);\n\t\tif (rev) users.push(rev);\n\t\tconst qa = parseParticipant(opts.qa, ROLE_QA);\n\t\tif (qa) users.push(qa);\n\t\tif (users.length) (args as any).users = users;\n\t\treturn this._call('create-contract-event', args);\n\t}\n\n\tasync propose(eventId: number, opts: ProposeOptions): Promise<any> {\n\t\treturn this._call('propose-correction', cleanArgs({\n\t\t\tevent_id: eventId,\n\t\t\tstatus_id: opts.status,\n\t\t\tlabel: opts.label,\n\t\t\tdescription: opts.description,\n\t\t\tbenefitable: opts.benefitable ? parseBenefitable(opts.benefitable) : undefined,\n\t\t}));\n\t}\n\n\tasync comment(eventId: number, opts?: CommentOptions): Promise<any> {\n\t\treturn this._call('comment', cleanArgs({\n\t\t\tevent_id: eventId,\n\t\t\tlabel: opts?.label,\n\t\t\tdescription: opts?.description,\n\t\t}));\n\t}\n\n\tasync progress(eventId: number, opts: ProgressOptions): Promise<any> {\n\t\tlet statusResult: any = null;\n\t\tif (opts.status != null) {\n\t\t\tstatusResult = await this.propose(eventId, { status: opts.status });\n\t\t}\n\t\tconst commentResult = await this.comment(eventId, { label: deriveLabel(opts.desc), description: opts.desc });\n\t\treturn { status_correction: statusResult, comment: commentResult };\n\t}\n\n\tasync callHuman(eventId: number, kind: 'input' | 'review' | 'stuck', desc: string): Promise<any> {\n\t\tif (!['input', 'review', 'stuck'].includes(kind)) throw new Error(`kind must be input|review|stuck, got ${kind}`);\n\t\treturn this._call('call-human', { event_id: eventId, kind, desc });\n\t}\n\n\t/** GET /agent/polling. Returns [] on 429. */\n\tasync poll(): Promise<any[]> {\n\t\tconst resp = await fetch(`${this._apiBase}/agent/polling`, {\n\t\t\theaders: { Accept: 'application/json', Authorization: `Bearer ${this._token}` },\n\t\t});\n\t\tif (resp.status === 429) return [];\n\t\tif (!resp.ok) {\n\t\t\tconst text = await resp.text().catch(() => '');\n\t\t\tthrow new Error(`poll HTTP ${resp.status}: ${text.slice(0, 300)}`);\n\t\t}\n\t\tconst body = (await resp.json()) as Record<string, unknown>;\n\t\tif (Array.isArray(body)) return body;\n\t\tif (body && typeof body === 'object') {\n\t\t\tfor (const k of ['notifications', 'data', 'items']) {\n\t\t\t\tif (Array.isArray(body[k])) return body[k] as any[];\n\t\t\t}\n\t\t}\n\t\treturn [];\n\t}\n}\n", "import type {\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { ContractClient } from '../../lib/contract-client';\n\nconst STATUS_OPTIONS = [\n\t{ name: '100 \u00B7 Backlog', value: 100 },\n\t{ name: '200 \u00B7 Hand (assigned)', value: 200 },\n\t{ name: '222 \u00B7 Hand done', value: 222 },\n\t{ name: '300 \u00B7 QA', value: 300 },\n\t{ name: '350 \u00B7 QA done', value: 350 },\n\t{ name: '499 \u00B7 Reviewer', value: 499 },\n];\n\n/**\n * Ceki Contract \u2014 operation node for the Ceki contract system (tasks/events).\n * Uses native fetch() \u2014 zero external runtime deps.\n */\nexport class CekiContract implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Ceki Contract',\n\t\tname: 'cekiContract',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '={{ \"Contract: \" + $operation }}',\n\t\tdescription: 'Work with Ceki contract tasks: list, create, assign, update status, comment, report progress, escalate to a human, and poll',\n\t\tdefaults: { name: 'Ceki Contract' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'myEvents',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'List My Contracts', value: 'listContracts' },\n\t\t\t\t\t{ name: 'List Tasks in Contract', value: 'listTasks' },\n\t\t\t\t\t{ name: 'Get Task', value: 'getTask' },\n\t\t\t\t\t{ name: 'My Assigned Events', value: 'myEvents' },\n\t\t\t\t\t{ name: 'Create Task', value: 'createTask' },\n\t\t\t\t\t{ name: 'Assign Executor', value: 'assign' },\n\t\t\t\t\t{ name: 'Update Status', value: 'setStatus' },\n\t\t\t\t\t{ name: 'Comment', value: 'comment' },\n\t\t\t\t\t{ name: 'Progress Report', value: 'progress' },\n\t\t\t\t\t{ name: 'Call Human', value: 'callHuman' },\n\t\t\t\t\t{ name: 'Poll Notifications', value: 'poll' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t// --- contractId / eventId ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Contract ID',\n\t\t\t\tname: 'contractId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: 'ceki contract id',\n\t\t\t\tdisplayOptions: { show: { operation: ['listTasks', 'createTask'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Event ID',\n\t\t\t\tname: 'eventId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: 'Task / event id (KalEvent)',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: { operation: ['getTask', 'assign', 'setStatus', 'comment', 'progress', 'callHuman'] },\n\t\t\t\t},\n\t\t\t},\n\t\t\t// --- createTask fields ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Label',\n\t\t\t\tname: 'label',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Description',\n\t\t\t\tname: 'description',\n\t\t\t\ttype: 'string',\n\t\t\t\ttypeOptions: { rows: 4 },\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'comment'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Executor (benefitable)',\n\t\t\t\tname: 'benefitableType',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'agent',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Agent', value: 'agent' },\n\t\t\t\t\t{ name: 'User (human)', value: 'user' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'assign'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Executor ID',\n\t\t\t\tname: 'benefitableValue',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: 'Agent ID or user ID of the executor',\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'assign'] } },\n\t\t\t},\n\t\t\t// --- status ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Status',\n\t\t\t\tname: 'status',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: STATUS_OPTIONS,\n\t\t\t\tdefault: 200,\n\t\t\t\tdisplayOptions: { show: { operation: ['createTask', 'setStatus', 'progress'] } },\n\t\t\t},\n\t\t\t// --- progress desc ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Progress Description',\n\t\t\t\tname: 'progressDesc',\n\t\t\t\ttype: 'string',\n\t\t\t\ttypeOptions: { rows: 4 },\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'Body of the progress comment (does not overwrite the task spec)',\n\t\t\t\tdisplayOptions: { show: { operation: ['progress'] } },\n\t\t\t},\n\t\t\t// --- call human (escalate) ---\n\t\t\t{\n\t\t\t\tdisplayName: 'Call Kind',\n\t\t\t\tname: 'callKind',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'review',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Input (need clarification)', value: 'input' },\n\t\t\t\t\t{ name: 'Review (done, take a look)', value: 'review' },\n\t\t\t\t\t{ name: 'Stuck (blocked)', value: 'stuck' },\n\t\t\t\t],\n\t\t\t\tdescription: 'Type of escalation to a human (the call-human action)',\n\t\t\t\tdisplayOptions: { show: { operation: ['callHuman'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Message',\n\t\t\t\tname: 'callDesc',\n\t\t\t\ttype: 'string',\n\t\t\t\ttypeOptions: { rows: 4 },\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'What to tell the human \u2014 context, question, or what was done',\n\t\t\t\tdisplayOptions: { show: { operation: ['callHuman'] } },\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\t\tconst token = creds.token as string;\n\t\tconst client = new ContractClient(token);\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst op = this.getNodeParameter('operation', i) as string;\n\t\t\tlet result: unknown;\n\n\t\t\tswitch (op) {\n\t\t\t\tcase 'listContracts':\n\t\t\t\t\tresult = await client.listContracts();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'listTasks': {\n\t\t\t\t\tconst contractId = this.getNodeParameter('contractId', i) as number;\n\t\t\t\t\tresult = await client.tasks(contractId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'getTask': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tresult = await client.task(eventId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'myEvents':\n\t\t\t\t\tresult = await client.myEvents();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'createTask': {\n\t\t\t\t\tconst contractId = this.getNodeParameter('contractId', i) as number;\n\t\t\t\t\tconst label = this.getNodeParameter('label', i) as string;\n\t\t\t\t\tconst description = (this.getNodeParameter('description', i) as string) || '';\n\t\t\t\t\tconst status = this.getNodeParameter('status', i) as number;\n\t\t\t\t\tconst bType = this.getNodeParameter('benefitableType', i) as string;\n\t\t\t\t\tconst bValue = this.getNodeParameter('benefitableValue', i) as number;\n\t\t\t\t\tresult = await client.create(contractId, {\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\tdescription: description || undefined,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t\tbenefitable: bValue ? `${bType}:${bValue}` : undefined,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'assign': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst bType = this.getNodeParameter('benefitableType', i) as string;\n\t\t\t\t\tconst bValue = this.getNodeParameter('benefitableValue', i) as number;\n\t\t\t\t\tif (!bValue) throw new Error('Executor ID is required for Assign');\n\t\t\t\t\tresult = await client.propose(eventId, { benefitable: `${bType}:${bValue}` });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'setStatus': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst status = this.getNodeParameter('status', i) as number;\n\t\t\t\t\tresult = await client.propose(eventId, { status });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'comment': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst description = (this.getNodeParameter('description', i) as string) || '';\n\t\t\t\t\tif (!description) throw new Error('Comment text is required');\n\t\t\t\t\tresult = await client.comment(eventId, { description });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'progress': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst status = this.getNodeParameter('status', i) as number;\n\t\t\t\t\tconst desc = this.getNodeParameter('progressDesc', i) as string;\n\t\t\t\t\tresult = await client.progress(eventId, { status, desc });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'callHuman': {\n\t\t\t\t\tconst eventId = this.getNodeParameter('eventId', i) as number;\n\t\t\t\t\tconst kind = this.getNodeParameter('callKind', i) as 'input' | 'review' | 'stuck';\n\t\t\t\t\tconst desc = this.getNodeParameter('callDesc', i) as string;\n\t\t\t\t\tif (!desc) throw new Error('Message is required for Call Human');\n\t\t\t\t\tresult = await client.callHuman(eventId, kind, desc);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'poll':\n\t\t\t\t\tresult = await client.poll();\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unknown operation: ${op}`);\n\t\t\t}\n\n\t\t\tout.push({ json: { op, result: result as any } });\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "import type { IExecuteFunctions, INodeType, INodeTypeDescription, INodeExecutionData } from 'n8n-workflow';\nimport { CekiClient } from '../../../lib/ceki-client';\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => {\n\tAbortSignal.timeout(ms).addEventListener('abort', () => resolve(), { once: true });\n});\n\nasync function waitForSelector(browser: any, selector: string, timeoutMs: number, intervalMs = 500) {\n\tconst expr = `!!document.querySelector(${JSON.stringify(selector)})`;\n\tconst deadline = Date.now() + timeoutMs;\n\tlet lastErr: unknown = null;\n\twhile (Date.now() < deadline) {\n\t\ttry {\n\t\t\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\t\t\tif (res?.result?.value === true) return true;\n\t\t} catch (e) {\n\t\t\tlastErr = e;\n\t\t}\n\t\tawait sleep(intervalMs);\n\t}\n\tthrow new Error(\n\t\t`waitForSelector(\"${selector}\") timed out after ${timeoutMs}ms${lastErr ? `: ${(lastErr as Error).message}` : ''}`,\n\t);\n}\n\nasync function extractHtml(browser: any, selector: string): Promise<string> {\n\tconst expr =\n\t\tselector.trim() === '' || selector === 'body'\n\t\t\t? `document.body ? document.body.outerHTML : ''`\n\t\t\t: `(function(){ var el = document.querySelector(${JSON.stringify(selector)}); return el ? el.outerHTML : ''; })()`;\n\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\treturn (res?.result?.value as string) ?? '';\n}\n\n/**\n * Recipe: Captcha-protected Scrape.\n * Rent a human browser \u2192 open a URL \u2192 (optional) wait for a selector \u2192\n * snapshot/HTML \u2192 release.\n *\n * The real human fingerprint bypasses anti-bot protection.\n */\nexport class CekiCaptchaScrape implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki: Captcha-protected Scrape',\n\t\tname: 'cekiCaptchaScrape',\n\t\tdescription: 'Rent a human browser, wait, screenshot/HTML, release',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '=rent in {{ $geo }} \u2192 snapshot',\n\t\tdefaults: { name: 'Browser Ceki: Captcha-protected Scrape' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://example.com',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'Page protected by anti-bot / captcha',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Geo',\n\t\t\t\tname: 'geo',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'RU',\n\t\t\t\tplaceholder: 'RU, EE, US\u2026',\n\t\t\t},\n\t\t\t{ displayName: 'Max $/min', name: 'maxPrice', type: 'number', typeOptions: { numberPrecision: 4 }, default: 0.02 },\n\t\t\t{\n\t\t\t\tdisplayName: 'Wait for Selector',\n\t\t\t\tname: 'waitSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'CSS selector (optional)',\n\t\t\t\tdescription: 'Wait until this selector appears in the DOM',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Wait Timeout (ms)',\n\t\t\t\tname: 'waitTimeout',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 30000,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Extract HTML',\n\t\t\t\tname: 'extractHtml',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'HTML Selector',\n\t\t\t\tname: 'htmlSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'body',\n\t\t\t\tplaceholder: 'CSS selector or \"body\"',\n\t\t\t\tdescription: 'outerHTML of this selector is returned as `html`',\n\t\t\t\tdisplayOptions: { show: { extractHtml: [true] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Full Page Screenshot',\n\t\t\t\tname: 'fullPage',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\tconst waitSelector = (this.getNodeParameter('waitSelector', i) as string) || '';\n\t\t\tconst waitTimeout = this.getNodeParameter('waitTimeout', i) as number;\n\t\t\tconst extractHtmlFlag = this.getNodeParameter('extractHtml', i) as boolean;\n\t\t\tconst htmlSelector = (this.getNodeParameter('htmlSelector', i) as string) || 'body';\n\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\n\t\t\tconst client = new CekiClient(creds.token as string);\n\t\t\tawait client.connect();\n\t\t\tlet browser: any;\n\t\t\tlet scheduleId = 0;\n\t\t\ttry {\n\t\t\t\tconst list = await client.search({ geo: geo || undefined, max_price_per_min: maxPrice });\n\t\t\t\tif (!list.length) throw new Error(`No browsers in geo ${geo || '*'}`);\n\t\t\t\tscheduleId = list[0].schedule_id;\n\t\t\t\tbrowser = await client.rent(scheduleId);\n\n\t\t\t\tawait browser.navigate(url);\n\n\t\t\t\tif (waitSelector) {\n\t\t\t\t\tawait waitForSelector(browser, waitSelector, waitTimeout);\n\t\t\t\t}\n\n\t\t\t\tconst shot = await browser.screenshot({ format: 'base64', fullPage }) as any;\n\t\t\t\tconst data = shot.data ?? (shot instanceof Buffer ? shot.toString('base64') : '');\n\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\tBuffer.from(data, 'base64'),\n\t\t\t\t\t'captcha-scrape.png',\n\t\t\t\t\t'image/png',\n\t\t\t\t);\n\n\t\t\t\tconst json: Record<string, unknown> = {\n\t\t\t\t\turl,\n\t\t\t\t\tgeo,\n\t\t\t\t\tschedule_id: scheduleId,\n\t\t\t\t};\n\t\t\t\tif (extractHtmlFlag) {\n\t\t\t\t\tjson.html = await extractHtml(browser, htmlSelector);\n\t\t\t\t}\n\n\t\t\t\tout.push({ json: json as any, binary: { data: binary } });\n\t\t\t} finally {\n\t\t\t\tif (browser) {\n\t\t\t\t\ttry { await browser.close(); } catch { /* ignore */ }\n\t\t\t\t}\n\t\t\t\ttry { await client.close(); } catch { /* ignore */ }\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "import type { IExecuteFunctions, INodeType, INodeTypeDescription, INodeExecutionData } from 'n8n-workflow';\nimport { CekiClient } from '../../../lib/ceki-client';\n\n/**\n * Recipe: Screenshot in Geo.\n * One call \u2014 rent a browser in the requested geo, open a URL, take a screenshot, release.\n */\nexport class CekiScreenshotGeo implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki: Screenshot in Geo',\n\t\tname: 'cekiScreenshotGeo',\n\t\tdescription: 'Rent a browser in a given geo, screenshot a page, release',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '=rent in {{ $geo }} \u2192 screenshot \u2192 release',\n\t\tdefaults: { name: 'Browser Ceki: Screenshot in Geo' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://ifconfig.me',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{ displayName: 'Geo', name: 'geo', type: 'string', default: 'RU', placeholder: 'RU, EE, US\u2026' },\n\t\t\t{ displayName: 'Full page', name: 'fullPage', type: 'boolean', default: false },\n\t\t\t{ displayName: 'Max $/min', name: 'maxPrice', type: 'number', default: 0.02 },\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\n\t\t\tconst client = new CekiClient(creds.token as string);\n\t\t\tawait client.connect();\n\t\t\tlet browser: any;\n\t\t\ttry {\n\t\t\t\tconst list = await client.search({ geo, max_price_per_min: maxPrice });\n\t\t\t\tif (!list.length) throw new Error(`No browsers in geo ${geo}`);\n\t\t\t\tbrowser = await client.rent(list[0].schedule_id);\n\t\t\t\tawait browser.navigate(url);\n\t\t\t\tconst shot = await browser.screenshot({ format: 'base64', fullPage }) as any;\n\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\tBuffer.from(shot.data, 'base64'),\n\t\t\t\t\t'screenshot.png',\n\t\t\t\t\t'image/png',\n\t\t\t\t);\n\t\t\t\tout.push({\n\t\t\t\t\tjson: { url, geo, schedule_id: list[0].schedule_id },\n\t\t\t\t\tbinary: { data: binary },\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tif (browser) { try { await browser.close(); } catch {} }\n\t\t\t\ttry { await client.close(); } catch {}\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "import type {\n\tIAuthenticateGeneric,\n\tICredentialTestRequest,\n\tICredentialType,\n\tINodeProperties,\n} from 'n8n-workflow';\n\n/**\n * Ceki agent token (ag_...). Authorizes every Ceki node.\n * Get it from the Ceki panel \u2192 agent profile \u2192 API key.\n */\nexport class CekiApi implements ICredentialType {\n\tname = 'cekiApi';\n\tdisplayName = 'Ceki API';\n\tdocumentationUrl = 'https://browser.ceki.me/docs#api-key';\n\tproperties: INodeProperties[] = [\n\t\t{\n\t\t\tdisplayName: 'API Key',\n\t\t\tname: 'token',\n\t\t\ttype: 'string',\n\t\t\ttypeOptions: { password: true },\n\t\t\tdefault: '',\n\t\t\tdescription:\n\t\t\t\t'Agent token (ag_...). [Get your API key \u2192](https://browser.ceki.me/docs#api-key)',\n\t\t\trequired: true,\n\t\t},\n\t];\n\n\tauthenticate: IAuthenticateGeneric = {\n\t\ttype: 'generic',\n\t\tproperties: {\n\t\t\theaders: {\n\t\t\t\tAuthorization: '=Bearer {{$credentials?.token}}',\n\t\t\t},\n\t\t},\n\t};\n\n\ttest: ICredentialTestRequest = {\n\t\trequest: {\n\t\t\tbaseURL: 'https://api.ceki.me',\n\t\t\turl: '/api/browsers/search',\n\t\t\tmethod: 'GET',\n\t\t},\n\t};\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["x", "y", "sid", "sessionId", "x", "y", "sleep"]
7
7
  }
@@ -472,7 +472,9 @@ var BrowserCeki = class {
472
472
  { name: "Wait for Selector", value: "waitForSelector" },
473
473
  { name: "Upload", value: "upload" },
474
474
  { name: "Close", value: "close" },
475
- { name: "Full: Rent \u2192 Navigate \u2192 Screenshot", value: "full" }
475
+ { name: "Full: Rent \u2192 Navigate \u2192 Screenshot", value: "full" },
476
+ { name: "My Sessions", value: "my_sessions" },
477
+ { name: "Stop Session", value: "stop_session" }
476
478
  ]
477
479
  },
478
480
  // === Rent: rental parameters ===
@@ -544,7 +546,7 @@ var BrowserCeki = class {
544
546
  required: true,
545
547
  displayOptions: {
546
548
  show: {
547
- operation: ["navigate", "click", "type", "scroll", "screenshot", "snapshot", "wait", "waitForSelector", "upload", "close"]
549
+ operation: ["navigate", "click", "type", "scroll", "screenshot", "snapshot", "wait", "waitForSelector", "upload", "close", "stop_session"]
548
550
  }
549
551
  }
550
552
  },
@@ -701,6 +703,56 @@ var BrowserCeki = class {
701
703
  }
702
704
  continue;
703
705
  }
706
+ if (op === "my_sessions") {
707
+ try {
708
+ const resp = await fetch("https://api.ceki.me/api/agent/sessions", {
709
+ headers: { Authorization: `Bearer ${token}` }
710
+ });
711
+ if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
712
+ const body = await resp.json();
713
+ const sessions = body.data ?? [];
714
+ out.push({ json: { sessions, count: sessions.length } });
715
+ } catch (e) {
716
+ throw new Error(`My sessions failed: ${e.message}`);
717
+ }
718
+ continue;
719
+ }
720
+ if (op === "stop_session") {
721
+ const sessionId2 = this.getNodeParameter("sessionId", i);
722
+ try {
723
+ await new Promise((resolve, reject) => {
724
+ const ws = new WebSocket("wss://browser.ceki.me/ws/agent", [`bearer.${token}`]);
725
+ const t = AbortSignal.timeout(15e3);
726
+ t.addEventListener("abort", () => {
727
+ try {
728
+ ws.close();
729
+ } catch {
730
+ }
731
+ reject(new Error("Stop session timed out"));
732
+ }, { once: true });
733
+ ws.onopen = () => {
734
+ ws.send(JSON.stringify({ type: "stop", session_id: sessionId2, reason: "n8n stop_session" }));
735
+ };
736
+ ws.onmessage = (ev) => {
737
+ const msg = JSON.parse(ev.data);
738
+ if (msg.type === "session_ended" || msg.type === "pong") {
739
+ try {
740
+ ws.close();
741
+ } catch {
742
+ }
743
+ resolve();
744
+ }
745
+ };
746
+ ws.onerror = () => {
747
+ reject(new Error("WebSocket connection failed"));
748
+ };
749
+ });
750
+ out.push({ json: { stopped: true, session_id: sessionId2 } });
751
+ } catch (e) {
752
+ throw new Error(`Stop session failed: ${e.message}`);
753
+ }
754
+ continue;
755
+ }
704
756
  if (op === "full") {
705
757
  const demoMode = this.getNodeParameter("demoMode", i);
706
758
  let sid2;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../nodes/BrowserCeki/BrowserCeki.node.ts", "../../../lib/ceki-client.ts"],
4
- "sourcesContent": ["import type {\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { CekiClient } from '../../lib/ceki-client';\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => {\n\tAbortSignal.timeout(ms).addEventListener('abort', () => resolve(), { once: true });\n});\n\n/**\n * Browser Ceki \u2014 one node, many operations.\n * Uses native WebSocket (not the ws library) \u2014 zero external runtime deps.\n *\n * Resume flow:\n * 1. Rent \u2192 browser session created, client disconnects (session in grace).\n * 2. Navigate/Screenshot/etc \u2192 new client, connect, resume(sessionId) \u2192 server\n * responds with resume_ok, do the op, disconnect.\n * 3. Close \u2192 same, sends Ceki.close, client.close().\n *\n * This works because the server supports session resume across different\n * WebSocket connections (same auth token). Each n8n node independently\n * creates a fresh WS connection and resumes the session by ID.\n */\nexport class BrowserCeki implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki',\n\t\tname: 'browserCeki',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '={{ \"Ceki: \" + $parameter.operation }}',\n\t\tdescription: 'Rent a real human browser and control it: rent, navigate, click, type, screenshot, solve captchas, and more',\n\t\tdefaults: { name: 'Browser Ceki' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'search',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Search', value: 'search' },\n\t\t\t\t\t{ name: 'Rent', value: 'rent' },\n\t\t\t\t\t{ name: 'Navigate', value: 'navigate' },\n\t\t\t\t\t{ name: 'Click', value: 'click' },\n\t\t\t\t\t{ name: 'Type', value: 'type' },\n\t\t\t\t\t{ name: 'Scroll', value: 'scroll' },\n\t\t\t\t\t{ name: 'Screenshot', value: 'screenshot' },\n\t\t\t\t\t{ name: 'Snapshot', value: 'snapshot' },\n\t\t\t\t\t{ name: 'Wait', value: 'wait' },\n\t\t\t\t\t{ name: 'Wait for Selector', value: 'waitForSelector' },\n\t\t\t\t\t{ name: 'Upload', value: 'upload' },\n\t\t\t\t\t{ name: 'Close', value: 'close' },\n\t\t\t\t\t{ name: 'Full: Rent \u2192 Navigate \u2192 Screenshot', value: 'full' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t// === Rent: rental parameters ===\n\t\t\t{\n\t\t\t\tdisplayName: 'Schedule ID',\n\t\t\t\tname: 'scheduleId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: '0 \u2014 search by the filters below',\n\t\t\t\tdisplayOptions: { show: { operation: ['rent'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Geo',\n\t\t\t\tname: 'geo',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'RU, EE, US\u2026',\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max $/min',\n\t\t\t\tname: 'maxPrice',\n\t\t\t\ttype: 'number',\n\t\t\t\ttypeOptions: { numberPrecision: 4 },\n\t\t\t\tdefault: 0.02,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Min rating',\n\t\t\t\tname: 'minRating',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Profile mode',\n\t\t\t\tname: 'mode',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'incognito',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'main', value: 'main' },\n\t\t\t\t\t{ name: 'incognito', value: 'incognito' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['rent', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://example.com',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Demo mode (no browser needed)',\n\t\t\t\tname: 'demoMode',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription: 'Skip actual browser rent and generate demo output',\n\t\t\t\tdisplayOptions: { show: { operation: ['full'] } },\n\t\t\t},\n\t\t\t// === Operations: session_id ===\n\n\n\t\t\t{\n\t\t\t\tdisplayName: 'Session ID',\n\t\t\t\tname: 'sessionId',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'From the Rent operation',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\toperation: ['navigate', 'click', 'type', 'scroll', 'screenshot', 'snapshot', 'wait', 'waitForSelector', 'upload', 'close'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'X',\n\t\t\t\tname: 'x',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Y',\n\t\t\t\tname: 'y',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Text',\n\t\t\t\tname: 'text',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: { show: { operation: ['type'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Delta Y',\n\t\t\t\tname: 'deltaY',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: -300,\n\t\t\t\tdisplayOptions: { show: { operation: ['scroll'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Format',\n\t\t\t\tname: 'format',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'png',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'PNG (binary)', value: 'png' },\n\t\t\t\t\t{ name: 'Base64', value: 'base64' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Full page',\n\t\t\t\tname: 'fullPage',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: false,\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Milliseconds',\n\t\t\t\tname: 'ms',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 1000,\n\t\t\t\ttypeOptions: { minValue: 0 },\n\t\t\t\tdescription: 'Fixed delay on the active session',\n\t\t\t\tdisplayOptions: { show: { operation: ['wait', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'waitSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tplaceholder: 'e.g. .results, #content, table tr',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Timeout (ms)',\n\t\t\t\tname: 'waitTimeout',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 30000,\n\t\t\t\tdescription: 'Waits until the selector appears in the DOM',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'selector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Binary Property',\n\t\t\t\tname: 'binaryPropertyName',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'data',\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\t\tconst token = creds.token as string;\n\n\t\tconst resolveSid = async (i: number, client: CekiClient) => {\n\t\t\tconst scheduleId = this.getNodeParameter('scheduleId', i) as number;\n\t\t\tif (scheduleId) return scheduleId;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\tconst list = await client.search({\n\t\t\t\tgeo: geo || undefined,\n\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t});\n\t\t\tif (!list.length) throw new Error('No browsers found by filters');\n\t\t\treturn list[0].schedule_id;\n\t\t};\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst op = this.getNodeParameter('operation', i) as string;\n\t\t\tconst client = new CekiClient(token);\n\t\t\tlet browser: any;\n\t\t\tlet needFullClose = false;\n\t\t\ttry {\n\t\t\t\tawait client.connect();\n\n\t\t\t\tif (op === 'rent') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst sid = await resolveSid(i, client);\n\t\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: browser.sessionId, schedule_id: sid, mode },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Rent failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'search') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\t\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\t\t\t\tconst list = await client.search({\n\t\t\t\t\t\t\tgeo: geo || undefined,\n\t\t\t\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tout.push({ json: { browsers: list, count: list.length } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Search failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t\n\t\t\t\tif (op === 'full') {\n\t\t\t\t\tconst demoMode = this.getNodeParameter('demoMode', i) as boolean;\n\t\t\t\t\tlet sid: number;\n\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsid = 99999; // mock\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tsid = await resolveSid(i, client);\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full: resolve schedule failed: ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\n\t\t\t\t\tlet session_id: string;\n\t\t\t\t\tlet binary: any;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsession_id = 'demo-' + Date.now();\n\t\t\t\t\t\tconst demoPng = Buffer.from('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', 'base64');\n\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(demoPng, 'screenshot.png', 'image/png');\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\t\tsession_id = browser.sessionId;\n\t\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\t\t\tconst shot = await browser.screenshot({ format: 'png', fullPage: true }) as any;\n\t\t\t\t\t\t\tconst data = (shot as Buffer).toString('base64');\n\t\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(Buffer.from(data, 'base64'), 'screenshot.png', 'image/png');\n\t\t\t\t\t\t\tawait browser.close();\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full op failed at step \"${(browser?.sessionId ? 'navigate/screenshot' : 'rent')}\": ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\tsession_id,\n\t\t\t\t\t\t\tschedule_id: sid,\n\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\twaited: ms,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbinary: { data: binary },\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tawait client.close().catch(() => {});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// All remaining operations: navigate, click, type, scroll, screenshot,\n\t\t\t// snapshot, wait, waitForSelector, upload, close.\n\t\t\t// Each creates a fresh WS connection and resumes the existing\n\t\t\t// browser session by sessionId (server supports cross-WS resume).\n\t\t\tconst sessionId = this.getNodeParameter('sessionId', i) as string;\n\t\t\ttry {\n\t\t\t\tbrowser = await client.resume(sessionId);\n\t\t\t} catch (e) {\n\t\t\t\tthrow new Error(`Resume session \"${sessionId}\" failed: ${(e as Error).message}. Session may have expired or still be in grace.`);\n\t\t\t}\n\t\t\tconst sid = browser.sessionId;\n\n\t\t\tswitch (op) {\n\t\t\t\tcase 'navigate': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, url } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Navigate failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'click': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst x = this.getNodeParameter('x', i) as number;\n\t\t\t\t\t\tconst y = this.getNodeParameter('y', i) as number;\n\t\t\t\t\t\tawait browser.click(x, y);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, clicked: [x, y] } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Click at (${x},${y}) failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'type': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst text = this.getNodeParameter('text', i) as string;\n\t\t\t\t\t\tawait browser.type(text);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, typed: text } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Type failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'scroll': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst deltaY = this.getNodeParameter('deltaY', i) as number;\n\t\t\t\t\t\tawait browser.scroll(deltaY);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, scrolled: deltaY } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Scroll failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'screenshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst format = this.getNodeParameter('format', i) as 'png' | 'base64';\n\t\t\t\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\t\t\t\t\t\tconst shot = await browser.screenshot({ format, fullPage }) as any;\n\t\t\t\t\t\tconst data = format === 'base64' ? shot.data : (shot as Buffer).toString('base64');\n\t\t\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\t\t\tBuffer.from(data, 'base64'),\n\t\t\t\t\t\t\t'screenshot.png',\n\t\t\t\t\t\t\t'image/png',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tout.push({ json: { session_id: sid }, binary: { data: binary } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Screenshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'snapshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst snap = await browser.snapshot();\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: sid, screenshot: snap.screenshot },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Snapshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'wait': {\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\tout.push({ json: { session_id: sid, waited: ms } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'waitForSelector': {\n\t\t\t\t\tconst selector = this.getNodeParameter('waitSelector', i) as string;\n\t\t\t\t\tconst timeout = this.getNodeParameter('waitTimeout', i) as number;\n\t\t\t\t\tconst expr = `!!document.querySelector(${JSON.stringify(selector)})`;\n\t\t\t\t\tconst deadline = Date.now() + timeout;\n\t\t\t\t\tlet ok = false;\n\t\t\t\t\tlet lastErr: unknown = null;\n\t\t\t\t\twhile (Date.now() < deadline) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\t\t\t\t\t\t\tif (res?.result?.value === true) {\n\t\t\t\t\t\t\t\tok = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tlastErr = e;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait sleep(500);\n\t\t\t\t\t}\n\t\t\t\t\tif (!ok) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`waitForSelector(\"${selector}\") timed out after ${timeout}ms${lastErr ? `: ${(lastErr as Error).message}` : ''}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tout.push({ json: { session_id: sid, selector, found: true } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'upload': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst selector = this.getNodeParameter('selector', i) as string;\n\t\t\t\t\t\tconst bpn = this.getNodeParameter('binaryPropertyName', i) as string;\n\t\t\t\t\t\tconst bin = items[i].binary?.[bpn];\n\t\t\t\t\t\tif (!bin) throw new Error(`Binary property \"${bpn}\" not found on input`);\n\t\t\t\t\t\tconst stream = await this.helpers.getBinaryStream(bin.id as string);\n\t\t\t\t\t\tconst chunks: Buffer[] = [];\n\t\t\t\t\t\tfor await (const c of stream) chunks.push(c as Buffer);\n\t\t\t\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\t\t\t\tconst res = await browser.upload(selector, buf);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, uploaded: res } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Upload failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'close': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try graceful CDP close first (best-effort)\n\t\t\t\t\t\tawait browser.close().catch(() => {});\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore CDP close errors\n\t\t\t\t\t}\n\t\t\t\t\t// Always send relay stop (force-end session) \u2014 CDP can silently fail\n\t\t\t\t\t// eslint-disable-next-line no-async-promise-executor\n\t\t\t\t\tawait new Promise((resolve) => {\n\t\t\t\t\t\tconst stopWs = new WebSocket('wss://browser.ceki.me/ws/agent', [`bearer.${token}`]);\n\t\t\t\t\t\tconst abortTimer = AbortSignal.timeout(10000);\n\t\t\t\t\tconst onTimer = () => { try { stopWs.close(); } catch {} resolve(); };\n\t\t\t\t\tabortTimer.addEventListener(\"abort\", onTimer, { once: true });\n\t\t\t\t\t\tstopWs.onopen = () => {\n\t\t\t\t\t\t\tstopWs.send(JSON.stringify({ type: 'stop', session_id: sessionId, reason: 'n8n close' }));\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onmessage = (ev) => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst msg = JSON.parse(ev.data);\n\t\t\t\t\t\t\t\tif (msg.type === 'session_ended') {\n\t\t\t\t\t\t\t\t\tabortTimer.removeEventListener(\"abort\", onTimer);\n\t\t\t\t\t\t\t\t\ttry { stopWs.close(); } catch {}\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onerror = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t\tstopWs.onclose = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t});\n\t\t\t\t\tout.push({ json: { closed: true, session_id: sessionId } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tneedFullClose = op === 'close';\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (needFullClose) {\n\t\t\t\t\t\tawait client.close();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// swallow cleanup errors\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "/**\n * Minimal Ceki browser client \u2014 uses only native WebSocket + fetch (Node 22 globals).\n * Zero npm imports (no ws, no mime-types, no node built-in modules).\n *\n * Timeout management: uses AbortSignal.timeout() instead of restricted\n * setTimeout/clearTimeout globals to satisfy the n8n community-nodes\n * package scanner (no-restricted-globals rule).\n */\n\n// \u2500\u2500 types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserOption {\n\tschedule_id: number;\n\tgeo?: string;\n\tprice_per_min: number;\n\tonline: boolean;\n\trating?: number | null;\n}\n\nexport interface Match {\n\tsession_id: string;\n\tschedule_id: number;\n\tevent_id?: string | null;\n\tchat_topic_id?: string | null;\n\tprovider_user_id?: number | null;\n\tbrowser_info?: Record<string, unknown>;\n}\n\nexport interface RentOptions {\n\tmode?: 'main' | 'incognito';\n}\n\nexport interface ScreenshotOptions {\n\tformat?: 'png' | 'base64';\n\tfullPage?: boolean;\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction jsonParse(raw: string): unknown {\n\ttry { return JSON.parse(raw); } catch { return null; }\n}\n\n// \u2500\u2500 Client \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiClient {\n\tprivate _ws: WebSocket | null = null;\n\tprivate _connected = false;\n\tprivate _pendingRents = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingResumes = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingCdp = new Map<number, {\n\t\tresolve: (v: unknown) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _cdpCounter = 1;\n\t_activeSessions = new Map<string, CekiBrowser>();\n\tprivate _connectReject: ((e: Error) => void) | null = null;\n\tprivate _closed = false;\n\n\tconstructor(\n\t\tprivate _token: string,\n\t\tprivate _relayUrl = 'wss://browser.ceki.me/ws/agent',\n\t\tprivate _apiUrl = 'https://api.ceki.me',\n\t) {}\n\n\t/** Connect to the relay WebSocket. */\n\tasync connect(): Promise<void> {\n\t\tif (this._connected) return;\n\t\tconst protocols = [`bearer.${this._token}`];\n\t\tthis._ws = new WebSocket(this._relayUrl, protocols);\n\t\tthis._ws.onopen = () => {\n\t\t\tthis._connected = true;\n\t\t};\n\t\tthis._ws.onmessage = (ev: MessageEvent) => {\n\t\t\tthis._handleMessage(ev.data);\n\t\t};\n\t\tthis._ws.onclose = (ev: CloseEvent) => {\n\t\t\tthis._connected = false;\n\t\t\tif ((ev.code === 4401 || ev.code === 4403) && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error(`Auth failed: ${ev.reason || String(ev.code)}`));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tthis._ws.onerror = () => {\n\t\t\tif (!this._connected && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error('WebSocket connection failed'));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tif (this._ws.readyState === WebSocket.CONNECTING) {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tif (!this._ws) { reject(new Error('No WebSocket')); return; }\n\t\t\t\tthis._connectReject = reject;\n\t\t\t\tthis._ws!.onopen = () => {\n\t\t\t\t\tthis._connected = true;\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n\n\t_sendRaw(msg: Record<string, unknown>): void {\n\t\tif (!this._ws || this._ws.readyState !== WebSocket.OPEN) {\n\t\t\tthrow new Error('WebSocket not connected');\n\t\t}\n\t\tthis._ws.send(JSON.stringify(msg));\n\t}\n\n\t/** Search for available browser providers (HTTP GET). */\n\tasync search(filters?: Record<string, unknown>, limit?: number): Promise<BrowserOption[]> {\n\t\tconst params = new URLSearchParams();\n\t\tif (limit != null) params.set('limit', String(limit));\n\t\tif (filters) {\n\t\t\tfor (const [k, v] of Object.entries(filters)) {\n\t\t\t\tif (v != null) params.set(k, String(v));\n\t\t\t}\n\t\t}\n\t\tconst resp = await fetch(`${this._apiUrl}/api/browsers/search?${params}`, {\n\t\t\theaders: { Authorization: `Bearer ${this._token}` },\n\t\t});\n\t\tif (!resp.ok) throw new Error(`Search failed: ${resp.status}`);\n\t\tconst body = (await resp.json()) as Record<string, unknown>;\n\t\tconst data = (body.data ?? body) as unknown[];\n\t\treturn Array.isArray(data) ? data as BrowserOption[] : [];\n\t}\n\n\t/** Rent a browser by schedule_id. */\n\tasync rent(scheduleId: number, opts?: RentOptions): Promise<CekiBrowser> {\n\t\tconst msg: Record<string, unknown> = { type: 'rent', browser_id: scheduleId };\n\t\tif (opts?.mode) msg.mode = opts.mode;\n\t\tthis._sendRaw(msg);\n\t\treturn this._awaitRent(`rent:${scheduleId}`, scheduleId, 90000);\n\t}\n\n\t/** Resume an existing session. */\n\tasync resume(sessionId: string): Promise<CekiBrowser> {\n\t\tthis._sendRaw({ type: 'resume', session_id: sessionId });\n\t\treturn this._awaitResume(sessionId);\n\t}\n\n\t/** Close the WS connection \u2014 session stays alive in grace.\n\t * Waits for the close handshake so the relay processes the close\n\t * before a new connection with the same renterId is established\n\t * (avoids the close-handler race condition).\n\t */\n\tasync disconnect(): Promise<void> {\n\t\tthis._closed = true;\n\t\tthis._activeSessions.clear();\n\t\tthis._pendingRents.clear();\n\t\tthis._pendingResumes.clear();\n\t\tif (!this._ws) return;\n\t\tconst ws = this._ws;\n\t\tif (ws.readyState === WebSocket.CLOSED) {\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\tif (ws.readyState === WebSocket.CLOSING) {\n\t\t\tawait new Promise<void>(r => { ws.onclose = () => { this._connected = false; r(); }; });\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\t// OPEN \u2192 initiate close and wait for handshake (up to 5s safety timeout)\n\t\tawait new Promise<void>(r => {\n\t\t\tconst t = setTimeout(() => { r(); }, 5000);\n\t\t\tws.onclose = () => { this._connected = false; clearTimeout(t); r(); };\n\t\t\ttry { ws.close(); } catch { clearTimeout(t); r(); }\n\t\t});\n\t\tthis._ws = null;\n\t}\n\n\t/** Close everything. */\n\tasync close(): Promise<void> {\n\t\tawait this.disconnect();\n\t}\n\n\t// \u2500\u2500 private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate _awaitRent(key: string, scheduleId: number, timeoutMs: number): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingRents.delete(key);\n\t\t\t\treject(new Error('Rent timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingRents.set(key, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _awaitResume(sessionId: string): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(60000);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\t\treject(new Error('Resume timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingResumes.set(sessionId, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _closeWs(): void {\n\t\tif (this._ws) {\n\t\t\ttry { this._ws.onopen = null; this._ws.onmessage = null; this._ws.onclose = null; this._ws.onerror = null; this._ws.close(); } catch { /* ignore */ }\n\t\t\tthis._ws = null;\n\t\t}\n\t}\n\n\tprivate _handleMessage(data: unknown): void {\n\t\tconst msg = jsonParse(String(data)) as Record<string, unknown> | null;\n\t\tif (!msg || typeof msg !== 'object') return;\n\t\tconst type = String(msg.type ?? '');\n\t\tconst sid = msg.session_id ? String(msg.session_id) : null;\n\n\t\tswitch (type) {\n\t\t\tcase 'pong':\n\t\t\tcase 'rent_pending':\n\t\t\t\tbreak;\n\t\t\tcase 'match':\n\t\t\t\tthis._onMatch(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'rent.error':\n\t\t\t\tthis._onRentError(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_ok':\n\t\t\t\tthis._onResumeOk(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_failed':\n\t\t\t\tthis._onResumeFailed(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'cdp_response':\n\t\t\t\tif (sid) this._onCdpResponse(sid, msg);\n\t\t\t\tbreak;\n\t\t\tcase 'session.ended':\n\t\t\t\tif (sid) {\n\t\t\t\t\tthis._activeSessions.delete(sid);\n\t\t\t\t\tconst b = this._activeSessions.get(sid);\n\t\t\t\t\tif (b) (b as any)._ended = String(msg.reason ?? 'ended');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate _onMatch(msg: Record<string, unknown>): void {\n\t\tconst scheduleId = Number(msg.schedule_id ?? 0);\n\t\tconst eventId = msg.event_id ? String(msg.event_id) : null;\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\t// Send match_ack to transition session from ACCEPTED to ACTIVE.\n\t\t// Without this, subsequent resume from other n8n nodes would receive\n\t\t// \"match\" instead of \"resume_ok\" (session stays ACCEPTED).\n\t\tif (sessionId && this._ws?.readyState === WebSocket.OPEN) {\n\t\t\ttry { this._ws.send(JSON.stringify({ type: 'match_ack', session_id: sessionId })); } catch { /* ignore */ }\n\t\t}\n\t\t// Check pending rents (normal rent flow)\n\t\tlet pending = this._pendingRents.get(`event:${eventId}`);\n\t\tif (!pending) pending = this._pendingRents.get(`rent:${scheduleId}`);\n\t\tif (pending) {\n\t\t\tthis._pendingRents.delete(`event:${eventId}`);\n\t\t\tthis._pendingRents.delete(`rent:${scheduleId}`);\n\t\t\tpending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\t// Fallback: relay may send \"match\" during resume if session is ACCEPTED\n\t\t// (e.g. when rent node finished without sending match_ack).\n\t\t// Treat it like resume_ok so the next node doesn't hang.\n\t\tconst resumePending = sessionId ? this._pendingResumes.get(sessionId) : null;\n\t\tif (resumePending) {\n\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\tresumePending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _onRentError(msg: Record<string, unknown>): void {\n\t\tconst code = String(msg.code ?? '');\n\t\tconst message = String(msg.message ?? '');\n\t\tfor (const [key, pending] of this._pendingRents) {\n\t\t\tthis._pendingRents.delete(key);\n\t\t\tpending.reject(new Error(message || `Rent error: ${code}`));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate _onResumeOk(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.resolve({\n\t\t\tsession_id: sessionId,\n\t\t\tschedule_id: Number(msg.schedule_id ?? 0),\n\t\t\tevent_id: msg.event_id ? String(msg.event_id) : null,\n\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t});\n\t}\n\n\tprivate _onResumeFailed(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.reject(new Error(String(msg.reason ?? 'Resume failed')));\n\t}\n\n\tprivate _onCdpResponse(sessionId: string, msg: Record<string, unknown>): void {\n\t\tconst browser = this._activeSessions.get(sessionId);\n\t\tif (!browser) return;\n\t\tconst id = Number(msg.id ?? 0);\n\t\t// NOTE: pending CDP is stored on CekiBrowser._pendingCdp (set by CekiBrowser.send()),\n\t\t// NOT on CekiClient._pendingCdp \u2014 they are different maps.\n\t\tconst pending = browser._pendingCdp.get(id);\n\t\tif (!pending) return;\n\t\tbrowser._pendingCdp.delete(id);\n\t\tif (msg.error) {\n\t\t\tpending.reject(new Error(String((msg.error as Record<string, unknown>).message ?? 'CDP error')));\n\t\t} else {\n\t\t\tpending.resolve(msg.result);\n\t\t}\n\t}\n}\n\n// \u2500\u2500 Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiBrowser {\n\treadonly sessionId: string;\n\treadonly scheduleId: number;\n\treadonly chatTopicId: string | null;\n\treadonly browserInfo: Record<string, unknown>;\n\treadonly providerUserId: number | null;\n\n\tprivate _client: CekiClient;\n\tprivate _cdpId = 1;\n\t_pendingCdp = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n\n\tconstructor(client: CekiClient, match: Match) {\n\t\tthis._client = client;\n\t\tthis.sessionId = match.session_id;\n\t\tthis.scheduleId = match.schedule_id;\n\t\tthis.chatTopicId = match.chat_topic_id ?? null;\n\t\tthis.browserInfo = match.browser_info ?? {};\n\t\tthis.providerUserId = match.provider_user_id ?? null;\n\t}\n\n\t/** Send a CDP command. Uses AbortSignal.timeout() (no restricted setTimeout global). */\n\tasync send(method: string, params?: Record<string, unknown>, timeoutMs = 30000): Promise<unknown> {\n\t\tconst id = this._cdpId++;\n\t\tconst msg = { type: 'cdp', session_id: this.sessionId, id, method, params: params ?? {} };\n\t\tthis._client._sendRaw(msg);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingCdp.delete(id);\n\t\t\t\treject(new Error(`CDP ${method} timed out after ${timeoutMs}ms`));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingCdp.set(id, {\n\t\t\t\tresolve: (v) => { resolve(v); },\n\t\t\t\treject: (e) => { reject(e); },\n\t\t\t});\n\t\t});\n\t}\n\n\tasync navigate(url: string, timeoutMs?: number): Promise<void> {\n\t\tawait this.send('Page.navigate', { url }, timeoutMs);\n\t}\n\n\tasync click(x: number, y: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 });\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });\n\t}\n\n\tasync type(text: string): Promise<void> {\n\t\tawait this.send('Ceki.typeText', { text });\n\t}\n\n\tasync scroll(deltaY: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseWheel', x: 0, y: 0, deltaX: 0, deltaY });\n\t}\n\n\tasync screenshot(opts?: ScreenshotOptions): Promise<{ data: string } | Buffer> {\n\t\tconst format = opts?.format ?? 'base64';\n\t\tconst fullPage = opts?.fullPage ?? false;\n\t\tlet clip: Record<string, number> | undefined;\n\t\tif (fullPage) {\n\t\t\tconst metrics = await this.send('Page.getLayoutMetrics') as Record<string, unknown> | null;\n\t\t\tconst contentSize = metrics?.contentSize as Record<string, number> | undefined;\n\t\t\tif (contentSize) {\n\t\t\t\tclip = { x: 0, y: 0, width: Number(contentSize.width ?? 1920), height: Math.min(Number(contentSize.height ?? 1080), 16384), scale: 1 };\n\t\t\t}\n\t\t}\n\t\tconst result = await this.send('Page.captureScreenshot', { format: 'png', ...(clip ? { clip } : {}) }) as Record<string, unknown> | null;\n\t\tconst data = String(result?.data ?? '');\n\t\tif (format === 'png') {\n\t\t\treturn Buffer.from(data, 'base64');\n\t\t}\n\t\treturn { data };\n\t}\n\n\tasync snapshot(): Promise<{ screenshot: string; ts: Date }> {\n\t\tconst ssResult = await this.screenshot({ format: 'base64' }) as { data: string };\n\t\treturn { screenshot: ssResult.data, ts: new Date() };\n\t}\n\n\tasync upload(selector: string, buf: Buffer, filename = 'file'): Promise<Record<string, unknown>> {\n\t\tconst b64 = buf.toString('base64');\n\t\tconst size = buf.length;\n\t\tconst mime = 'application/octet-stream';\n\t\tconst expression = `(function(){\n\t\t\tvar input = document.querySelector(${JSON.stringify(selector)});\n\t\t\tif (!input) return JSON.stringify({ok:false,error:'Element not found'});\n\t\t\tvar b = atob(${JSON.stringify(b64)});\n\t\t\tvar u = new Uint8Array(b.length);\n\t\t\tfor (var i = 0; i < b.length; i++) u[i] = b.charCodeAt(i);\n\t\t\tvar f = new File([u], ${JSON.stringify(filename)}, {type: ${JSON.stringify(mime)}});\n\t\t\tvar dt = new DataTransfer(); dt.items.add(f);\n\t\t\tinput.files = dt.files;\n\t\t\tinput.dispatchEvent(new Event('change',{bubbles:true}));\n\t\t\treturn JSON.stringify({ok:true,filename:${JSON.stringify(filename)},size:${size}});\n\t\t})()`;\n\t\tconst result = await this.send('Runtime.evaluate', { expression, returnByValue: true }) as Record<string, unknown> | null;\n\t\ttry {\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t} catch { /* ignore */ }\n\t\tconst resultObj = result?.result as Record<string, unknown> | undefined;\n\t\tif (resultObj?.value) return JSON.parse(String(resultObj.value)) as Record<string, unknown>;\n\t\treturn { ok: true, filename, size };\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.send('Ceki.close', {}).catch(() => {});\n\t\tthis._client._activeSessions.delete(this.sessionId);\n\t}\n}\n"],
5
- "mappings": "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",
6
- "names": ["x", "y", "sid", "x", "y"]
4
+ "sourcesContent": ["import type {\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { CekiClient } from '../../lib/ceki-client';\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => {\n\tAbortSignal.timeout(ms).addEventListener('abort', () => resolve(), { once: true });\n});\n\n/**\n * Browser Ceki \u2014 one node, many operations.\n * Uses native WebSocket (not the ws library) \u2014 zero external runtime deps.\n *\n * Resume flow:\n * 1. Rent \u2192 browser session created, client disconnects (session in grace).\n * 2. Navigate/Screenshot/etc \u2192 new client, connect, resume(sessionId) \u2192 server\n * responds with resume_ok, do the op, disconnect.\n * 3. Close \u2192 same, sends Ceki.close, client.close().\n *\n * This works because the server supports session resume across different\n * WebSocket connections (same auth token). Each n8n node independently\n * creates a fresh WS connection and resumes the session by ID.\n */\nexport class BrowserCeki implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Ceki',\n\t\tname: 'browserCeki',\n\t\ticon: 'file:ceki.png',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tsubtitle: '={{ \"Ceki: \" + $parameter.operation }}',\n\t\tdescription: 'Rent a real human browser and control it: rent, navigate, click, type, screenshot, solve captchas, and more',\n\t\tdefaults: { name: 'Browser Ceki' },\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [{ name: 'cekiApi', required: true }],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'search',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Search', value: 'search' },\n\t\t\t\t\t{ name: 'Rent', value: 'rent' },\n\t\t\t\t\t{ name: 'Navigate', value: 'navigate' },\n\t\t\t\t\t{ name: 'Click', value: 'click' },\n\t\t\t\t\t{ name: 'Type', value: 'type' },\n\t\t\t\t\t{ name: 'Scroll', value: 'scroll' },\n\t\t\t\t\t{ name: 'Screenshot', value: 'screenshot' },\n\t\t\t\t\t{ name: 'Snapshot', value: 'snapshot' },\n\t\t\t\t\t{ name: 'Wait', value: 'wait' },\n\t\t\t\t\t{ name: 'Wait for Selector', value: 'waitForSelector' },\n\t\t\t\t\t{ name: 'Upload', value: 'upload' },\n\t\t\t\t\t{ name: 'Close', value: 'close' },\n\t\t\t\t\t{ name: 'Full: Rent \u2192 Navigate \u2192 Screenshot', value: 'full' },\n { name: 'My Sessions', value: 'my_sessions' },\n { name: 'Stop Session', value: 'stop_session' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t// === Rent: rental parameters ===\n\t\t\t{\n\t\t\t\tdisplayName: 'Schedule ID',\n\t\t\t\tname: 'scheduleId',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdescription: '0 \u2014 search by the filters below',\n\t\t\t\tdisplayOptions: { show: { operation: ['rent'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Geo',\n\t\t\t\tname: 'geo',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'RU, EE, US\u2026',\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max $/min',\n\t\t\t\tname: 'maxPrice',\n\t\t\t\ttype: 'number',\n\t\t\t\ttypeOptions: { numberPrecision: 4 },\n\t\t\t\tdefault: 0.02,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Min rating',\n\t\t\t\tname: 'minRating',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['search'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Profile mode',\n\t\t\t\tname: 'mode',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'incognito',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'main', value: 'main' },\n\t\t\t\t\t{ name: 'incognito', value: 'incognito' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['rent', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'https://example.com',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Demo mode (no browser needed)',\n\t\t\t\tname: 'demoMode',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription: 'Skip actual browser rent and generate demo output',\n\t\t\t\tdisplayOptions: { show: { operation: ['full'] } },\n\t\t\t},\n\t\t\t// === Operations: session_id ===\n\n\n\t\t\t{\n\t\t\t\tdisplayName: 'Session ID',\n\t\t\t\tname: 'sessionId',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'From the Rent operation',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\toperation: ['navigate', 'click', 'type', 'scroll', 'screenshot', 'snapshot', 'wait', 'waitForSelector', 'upload', 'close', 'stop_session'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'URL',\n\t\t\t\tname: 'url',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['navigate'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'X',\n\t\t\t\tname: 'x',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Y',\n\t\t\t\tname: 'y',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 0,\n\t\t\t\tdisplayOptions: { show: { operation: ['click'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Text',\n\t\t\t\tname: 'text',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: { show: { operation: ['type'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Delta Y',\n\t\t\t\tname: 'deltaY',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: -300,\n\t\t\t\tdisplayOptions: { show: { operation: ['scroll'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Format',\n\t\t\t\tname: 'format',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'png',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'PNG (binary)', value: 'png' },\n\t\t\t\t\t{ name: 'Base64', value: 'base64' },\n\t\t\t\t],\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Full page',\n\t\t\t\tname: 'fullPage',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: false,\n\t\t\t\tdisplayOptions: { show: { operation: ['screenshot'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Milliseconds',\n\t\t\t\tname: 'ms',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 1000,\n\t\t\t\ttypeOptions: { minValue: 0 },\n\t\t\t\tdescription: 'Fixed delay on the active session',\n\t\t\t\tdisplayOptions: { show: { operation: ['wait', 'full'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'waitSelector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tplaceholder: 'e.g. .results, #content, table tr',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Timeout (ms)',\n\t\t\t\tname: 'waitTimeout',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 30000,\n\t\t\t\tdescription: 'Waits until the selector appears in the DOM',\n\t\t\t\tdisplayOptions: { show: { operation: ['waitForSelector'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'CSS Selector',\n\t\t\t\tname: 'selector',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Binary Property',\n\t\t\t\tname: 'binaryPropertyName',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'data',\n\t\t\t\tdisplayOptions: { show: { operation: ['upload'] } },\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst out: INodeExecutionData[] = [];\n\t\tconst creds = await this.getCredentials('cekiApi');\n\t\tconst token = creds.token as string;\n\n\t\tconst resolveSid = async (i: number, client: CekiClient) => {\n\t\t\tconst scheduleId = this.getNodeParameter('scheduleId', i) as number;\n\t\t\tif (scheduleId) return scheduleId;\n\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\tconst list = await client.search({\n\t\t\t\tgeo: geo || undefined,\n\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t});\n\t\t\tif (!list.length) throw new Error('No browsers found by filters');\n\t\t\treturn list[0].schedule_id;\n\t\t};\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst op = this.getNodeParameter('operation', i) as string;\n\t\t\tconst client = new CekiClient(token);\n\t\t\tlet browser: any;\n\t\t\tlet needFullClose = false;\n\t\t\ttry {\n\t\t\t\tawait client.connect();\n\n\t\t\t\tif (op === 'rent') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst sid = await resolveSid(i, client);\n\t\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: browser.sessionId, schedule_id: sid, mode },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Rent failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'search') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst geo = this.getNodeParameter('geo', i) as string;\n\t\t\t\t\t\tconst maxPrice = this.getNodeParameter('maxPrice', i) as number;\n\t\t\t\t\t\tconst list = await client.search({\n\t\t\t\t\t\t\tgeo: geo || undefined,\n\t\t\t\t\t\t\tmax_price_per_min: maxPrice,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tout.push({ json: { browsers: list, count: list.length } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Search failed: ${(e as Error).message}`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'my_sessions') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst resp = await fetch(\"https://api.ceki.me/api/agent/sessions\", {\n\t\t\t\t\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!resp.ok) throw new Error(`HTTP ${resp.status}`);\n\t\t\t\t\t\tconst body = await resp.json() as any;\n\t\t\t\t\t\tconst sessions = body.data ?? [];\n\t\t\t\t\t\tout.push({ json: { sessions, count: sessions.length } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`My sessions failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (op === 'stop_session') {\n\t\t\t\t\tconst sessionId = this.getNodeParameter(\"sessionId\", i) as string;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\t\tconst ws = new WebSocket(\"wss://browser.ceki.me/ws/agent\", [`bearer.${token}`]);\n\t\t\t\t\t\t\tconst t = AbortSignal.timeout(15000);\n\t\t\t\t\t\t\tt.addEventListener(\"abort\", () => { try { ws.close(); } catch {} reject(new Error(\"Stop session timed out\")); }, { once: true });\n\t\t\t\t\t\t\tws.onopen = () => {\n\t\t\t\t\t\t\t\tws.send(JSON.stringify({ type: \"stop\", session_id: sessionId, reason: \"n8n stop_session\" }));\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tws.onmessage = (ev) => {\n\t\t\t\t\t\t\t\tconst msg = JSON.parse(ev.data as string);\n\t\t\t\t\t\t\t\tif (msg.type === \"session_ended\" || msg.type === \"pong\") {\n\t\t\t\t\t\t\t\t\ttry { ws.close(); } catch {}\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tws.onerror = () => { reject(new Error(\"WebSocket connection failed\")); };\n\t\t\t\t\t\t});\n\t\t\t\t\t\tout.push({ json: { stopped: true, session_id: sessionId } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Stop session failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (op === 'full') {\n\t\t\t\t\tconst demoMode = this.getNodeParameter('demoMode', i) as boolean;\n\t\t\t\t\tlet sid: number;\n\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsid = 99999; // mock\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tsid = await resolveSid(i, client);\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full: resolve schedule failed: ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst mode = this.getNodeParameter('mode', i) as 'main' | 'incognito';\n\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\n\t\t\t\t\tlet session_id: string;\n\t\t\t\t\tlet binary: any;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (demoMode) {\n\t\t\t\t\t\tsession_id = 'demo-' + Date.now();\n\t\t\t\t\t\tconst demoPng = Buffer.from('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', 'base64');\n\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(demoPng, 'screenshot.png', 'image/png');\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tbrowser = await client.rent(sid, { mode });\n\t\t\t\t\t\t\tsession_id = browser.sessionId;\n\t\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\t\t\tconst shot = await browser.screenshot({ format: 'png', fullPage: true }) as any;\n\t\t\t\t\t\t\tconst data = (shot as Buffer).toString('base64');\n\t\t\t\t\t\t\tbinary = await this.helpers.prepareBinaryData(Buffer.from(data, 'base64'), 'screenshot.png', 'image/png');\n\t\t\t\t\t\t\tawait browser.close();\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow new Error(`Full op failed at step \"${(browser?.sessionId ? 'navigate/screenshot' : 'rent')}\": ${(e as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\tsession_id,\n\t\t\t\t\t\t\tschedule_id: sid,\n\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\twaited: ms,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbinary: { data: binary },\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tawait client.close().catch(() => {});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// All remaining operations: navigate, click, type, scroll, screenshot,\n\t\t\t// snapshot, wait, waitForSelector, upload, close.\n\t\t\t// Each creates a fresh WS connection and resumes the existing\n\t\t\t// browser session by sessionId (server supports cross-WS resume).\n\t\t\tconst sessionId = this.getNodeParameter('sessionId', i) as string;\n\t\t\ttry {\n\t\t\t\tbrowser = await client.resume(sessionId);\n\t\t\t} catch (e) {\n\t\t\t\tthrow new Error(`Resume session \"${sessionId}\" failed: ${(e as Error).message}. Session may have expired or still be in grace.`);\n\t\t\t}\n\t\t\tconst sid = browser.sessionId;\n\n\t\t\tswitch (op) {\n\t\t\t\tcase 'navigate': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst url = this.getNodeParameter('url', i) as string;\n\t\t\t\t\t\tawait browser.navigate(url);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, url } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Navigate failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'click': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst x = this.getNodeParameter('x', i) as number;\n\t\t\t\t\t\tconst y = this.getNodeParameter('y', i) as number;\n\t\t\t\t\t\tawait browser.click(x, y);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, clicked: [x, y] } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Click at (${x},${y}) failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'type': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst text = this.getNodeParameter('text', i) as string;\n\t\t\t\t\t\tawait browser.type(text);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, typed: text } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Type failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'scroll': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst deltaY = this.getNodeParameter('deltaY', i) as number;\n\t\t\t\t\t\tawait browser.scroll(deltaY);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, scrolled: deltaY } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Scroll failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'screenshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst format = this.getNodeParameter('format', i) as 'png' | 'base64';\n\t\t\t\t\t\tconst fullPage = this.getNodeParameter('fullPage', i) as boolean;\n\t\t\t\t\t\tconst shot = await browser.screenshot({ format, fullPage }) as any;\n\t\t\t\t\t\tconst data = format === 'base64' ? shot.data : (shot as Buffer).toString('base64');\n\t\t\t\t\t\tconst binary = await this.helpers.prepareBinaryData(\n\t\t\t\t\t\t\tBuffer.from(data, 'base64'),\n\t\t\t\t\t\t\t'screenshot.png',\n\t\t\t\t\t\t\t'image/png',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tout.push({ json: { session_id: sid }, binary: { data: binary } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Screenshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'snapshot': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst snap = await browser.snapshot();\n\t\t\t\t\t\tout.push({\n\t\t\t\t\t\t\tjson: { session_id: sid, screenshot: snap.screenshot },\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Snapshot failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'wait': {\n\t\t\t\t\tconst ms = this.getNodeParameter('ms', i) as number;\n\t\t\t\t\tawait sleep(ms);\n\t\t\t\t\tout.push({ json: { session_id: sid, waited: ms } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'waitForSelector': {\n\t\t\t\t\tconst selector = this.getNodeParameter('waitSelector', i) as string;\n\t\t\t\t\tconst timeout = this.getNodeParameter('waitTimeout', i) as number;\n\t\t\t\t\tconst expr = `!!document.querySelector(${JSON.stringify(selector)})`;\n\t\t\t\t\tconst deadline = Date.now() + timeout;\n\t\t\t\t\tlet ok = false;\n\t\t\t\t\tlet lastErr: unknown = null;\n\t\t\t\t\twhile (Date.now() < deadline) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst res = await browser.send('Runtime.evaluate', { expression: expr, returnByValue: true }) as any;\n\t\t\t\t\t\t\tif (res?.result?.value === true) {\n\t\t\t\t\t\t\t\tok = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tlastErr = e;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait sleep(500);\n\t\t\t\t\t}\n\t\t\t\t\tif (!ok) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`waitForSelector(\"${selector}\") timed out after ${timeout}ms${lastErr ? `: ${(lastErr as Error).message}` : ''}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tout.push({ json: { session_id: sid, selector, found: true } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'upload': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst selector = this.getNodeParameter('selector', i) as string;\n\t\t\t\t\t\tconst bpn = this.getNodeParameter('binaryPropertyName', i) as string;\n\t\t\t\t\t\tconst bin = items[i].binary?.[bpn];\n\t\t\t\t\t\tif (!bin) throw new Error(`Binary property \"${bpn}\" not found on input`);\n\t\t\t\t\t\tconst stream = await this.helpers.getBinaryStream(bin.id as string);\n\t\t\t\t\t\tconst chunks: Buffer[] = [];\n\t\t\t\t\t\tfor await (const c of stream) chunks.push(c as Buffer);\n\t\t\t\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\t\t\t\tconst res = await browser.upload(selector, buf);\n\t\t\t\t\t\tout.push({ json: { session_id: sid, uploaded: res } });\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthrow new Error(`Upload failed: ${(e as Error).message}`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'close': {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try graceful CDP close first (best-effort)\n\t\t\t\t\t\tawait browser.close().catch(() => {});\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore CDP close errors\n\t\t\t\t\t}\n\t\t\t\t\t// Always send relay stop (force-end session) \u2014 CDP can silently fail\n\t\t\t\t\t// eslint-disable-next-line no-async-promise-executor\n\t\t\t\t\tawait new Promise((resolve) => {\n\t\t\t\t\t\tconst stopWs = new WebSocket('wss://browser.ceki.me/ws/agent', [`bearer.${token}`]);\n\t\t\t\t\t\tconst abortTimer = AbortSignal.timeout(10000);\n\t\t\t\t\tconst onTimer = () => { try { stopWs.close(); } catch {} resolve(); };\n\t\t\t\t\tabortTimer.addEventListener(\"abort\", onTimer, { once: true });\n\t\t\t\t\t\tstopWs.onopen = () => {\n\t\t\t\t\t\t\tstopWs.send(JSON.stringify({ type: 'stop', session_id: sessionId, reason: 'n8n close' }));\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onmessage = (ev) => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst msg = JSON.parse(ev.data);\n\t\t\t\t\t\t\t\tif (msg.type === 'session_ended') {\n\t\t\t\t\t\t\t\t\tabortTimer.removeEventListener(\"abort\", onTimer);\n\t\t\t\t\t\t\t\t\ttry { stopWs.close(); } catch {}\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstopWs.onerror = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t\tstopWs.onclose = () => { abortTimer.removeEventListener(\"abort\", onTimer); resolve(); };\n\t\t\t\t\t});\n\t\t\t\t\tout.push({ json: { closed: true, session_id: sessionId } });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tneedFullClose = op === 'close';\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (needFullClose) {\n\t\t\t\t\t\tawait client.close();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait client.disconnect();\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// swallow cleanup errors\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn [out];\n\t}\n}\n", "/**\n * Minimal Ceki browser client \u2014 uses only native WebSocket + fetch (Node 22 globals).\n * Zero npm imports (no ws, no mime-types, no node built-in modules).\n *\n * Timeout management: uses AbortSignal.timeout() instead of restricted\n * setTimeout/clearTimeout globals to satisfy the n8n community-nodes\n * package scanner (no-restricted-globals rule).\n */\n\n// \u2500\u2500 types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserOption {\n\tschedule_id: number;\n\tgeo?: string;\n\tprice_per_min: number;\n\tonline: boolean;\n\trating?: number | null;\n}\n\nexport interface Match {\n\tsession_id: string;\n\tschedule_id: number;\n\tevent_id?: string | null;\n\tchat_topic_id?: string | null;\n\tprovider_user_id?: number | null;\n\tbrowser_info?: Record<string, unknown>;\n}\n\nexport interface RentOptions {\n\tmode?: 'main' | 'incognito';\n}\n\nexport interface ScreenshotOptions {\n\tformat?: 'png' | 'base64';\n\tfullPage?: boolean;\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction jsonParse(raw: string): unknown {\n\ttry { return JSON.parse(raw); } catch { return null; }\n}\n\n// \u2500\u2500 Client \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiClient {\n\tprivate _ws: WebSocket | null = null;\n\tprivate _connected = false;\n\tprivate _pendingRents = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingResumes = new Map<string, {\n\t\tresolve: (m: Match) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _pendingCdp = new Map<number, {\n\t\tresolve: (v: unknown) => void;\n\t\treject: (e: Error) => void;\n\t}>();\n\tprivate _cdpCounter = 1;\n\t_activeSessions = new Map<string, CekiBrowser>();\n\tprivate _connectReject: ((e: Error) => void) | null = null;\n\tprivate _closed = false;\n\n\tconstructor(\n\t\tprivate _token: string,\n\t\tprivate _relayUrl = 'wss://browser.ceki.me/ws/agent',\n\t\tprivate _apiUrl = 'https://api.ceki.me',\n\t) {}\n\n\t/** Connect to the relay WebSocket. */\n\tasync connect(): Promise<void> {\n\t\tif (this._connected) return;\n\t\tconst protocols = [`bearer.${this._token}`];\n\t\tthis._ws = new WebSocket(this._relayUrl, protocols);\n\t\tthis._ws.onopen = () => {\n\t\t\tthis._connected = true;\n\t\t};\n\t\tthis._ws.onmessage = (ev: MessageEvent) => {\n\t\t\tthis._handleMessage(ev.data);\n\t\t};\n\t\tthis._ws.onclose = (ev: CloseEvent) => {\n\t\t\tthis._connected = false;\n\t\t\tif ((ev.code === 4401 || ev.code === 4403) && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error(`Auth failed: ${ev.reason || String(ev.code)}`));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tthis._ws.onerror = () => {\n\t\t\tif (!this._connected && this._connectReject) {\n\t\t\t\tthis._connectReject(new Error('WebSocket connection failed'));\n\t\t\t\tthis._connectReject = null;\n\t\t\t}\n\t\t};\n\t\tif (this._ws.readyState === WebSocket.CONNECTING) {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tif (!this._ws) { reject(new Error('No WebSocket')); return; }\n\t\t\t\tthis._connectReject = reject;\n\t\t\t\tthis._ws!.onopen = () => {\n\t\t\t\t\tthis._connected = true;\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n\n\t_sendRaw(msg: Record<string, unknown>): void {\n\t\tif (!this._ws || this._ws.readyState !== WebSocket.OPEN) {\n\t\t\tthrow new Error('WebSocket not connected');\n\t\t}\n\t\tthis._ws.send(JSON.stringify(msg));\n\t}\n\n\t/** Search for available browser providers (HTTP GET). */\n\tasync search(filters?: Record<string, unknown>, limit?: number): Promise<BrowserOption[]> {\n\t\tconst params = new URLSearchParams();\n\t\tif (limit != null) params.set('limit', String(limit));\n\t\tif (filters) {\n\t\t\tfor (const [k, v] of Object.entries(filters)) {\n\t\t\t\tif (v != null) params.set(k, String(v));\n\t\t\t}\n\t\t}\n\t\tconst resp = await fetch(`${this._apiUrl}/api/browsers/search?${params}`, {\n\t\t\theaders: { Authorization: `Bearer ${this._token}` },\n\t\t});\n\t\tif (!resp.ok) throw new Error(`Search failed: ${resp.status}`);\n\t\tconst body = (await resp.json()) as Record<string, unknown>;\n\t\tconst data = (body.data ?? body) as unknown[];\n\t\treturn Array.isArray(data) ? data as BrowserOption[] : [];\n\t}\n\n\t/** Rent a browser by schedule_id. */\n\tasync rent(scheduleId: number, opts?: RentOptions): Promise<CekiBrowser> {\n\t\tconst msg: Record<string, unknown> = { type: 'rent', browser_id: scheduleId };\n\t\tif (opts?.mode) msg.mode = opts.mode;\n\t\tthis._sendRaw(msg);\n\t\treturn this._awaitRent(`rent:${scheduleId}`, scheduleId, 90000);\n\t}\n\n\t/** Resume an existing session. */\n\tasync resume(sessionId: string): Promise<CekiBrowser> {\n\t\tthis._sendRaw({ type: 'resume', session_id: sessionId });\n\t\treturn this._awaitResume(sessionId);\n\t}\n\n\t/** Close the WS connection \u2014 session stays alive in grace.\n\t * Waits for the close handshake so the relay processes the close\n\t * before a new connection with the same renterId is established\n\t * (avoids the close-handler race condition).\n\t */\n\tasync disconnect(): Promise<void> {\n\t\tthis._closed = true;\n\t\tthis._activeSessions.clear();\n\t\tthis._pendingRents.clear();\n\t\tthis._pendingResumes.clear();\n\t\tif (!this._ws) return;\n\t\tconst ws = this._ws;\n\t\tif (ws.readyState === WebSocket.CLOSED) {\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\tif (ws.readyState === WebSocket.CLOSING) {\n\t\t\tawait new Promise<void>(r => { ws.onclose = () => { this._connected = false; r(); }; });\n\t\t\tthis._ws = null;\n\t\t\treturn;\n\t\t}\n\t\t// OPEN \u2192 initiate close and wait for handshake (up to 5s safety timeout)\n\t\tawait new Promise<void>(r => {\n\t\t\tconst t = setTimeout(() => { r(); }, 5000);\n\t\t\tws.onclose = () => { this._connected = false; clearTimeout(t); r(); };\n\t\t\ttry { ws.close(); } catch { clearTimeout(t); r(); }\n\t\t});\n\t\tthis._ws = null;\n\t}\n\n\t/** Close everything. */\n\tasync close(): Promise<void> {\n\t\tawait this.disconnect();\n\t}\n\n\t// \u2500\u2500 private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate _awaitRent(key: string, scheduleId: number, timeoutMs: number): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingRents.delete(key);\n\t\t\t\treject(new Error('Rent timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingRents.set(key, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _awaitResume(sessionId: string): Promise<CekiBrowser> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(60000);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\t\treject(new Error('Resume timed out'));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingResumes.set(sessionId, {\n\t\t\t\tresolve: (match: Match) => {\n\t\t\t\t\tconst browser = new CekiBrowser(this, match);\n\t\t\t\t\tthis._activeSessions.set(browser.sessionId, browser);\n\t\t\t\t\tresolve(browser);\n\t\t\t\t},\n\t\t\t\treject: (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _closeWs(): void {\n\t\tif (this._ws) {\n\t\t\ttry { this._ws.onopen = null; this._ws.onmessage = null; this._ws.onclose = null; this._ws.onerror = null; this._ws.close(); } catch { /* ignore */ }\n\t\t\tthis._ws = null;\n\t\t}\n\t}\n\n\tprivate _handleMessage(data: unknown): void {\n\t\tconst msg = jsonParse(String(data)) as Record<string, unknown> | null;\n\t\tif (!msg || typeof msg !== 'object') return;\n\t\tconst type = String(msg.type ?? '');\n\t\tconst sid = msg.session_id ? String(msg.session_id) : null;\n\n\t\tswitch (type) {\n\t\t\tcase 'pong':\n\t\t\tcase 'rent_pending':\n\t\t\t\tbreak;\n\t\t\tcase 'match':\n\t\t\t\tthis._onMatch(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'rent.error':\n\t\t\t\tthis._onRentError(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_ok':\n\t\t\t\tthis._onResumeOk(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'resume_failed':\n\t\t\t\tthis._onResumeFailed(msg);\n\t\t\t\tbreak;\n\t\t\tcase 'cdp_response':\n\t\t\t\tif (sid) this._onCdpResponse(sid, msg);\n\t\t\t\tbreak;\n\t\t\tcase 'session.ended':\n\t\t\t\tif (sid) {\n\t\t\t\t\tthis._activeSessions.delete(sid);\n\t\t\t\t\tconst b = this._activeSessions.get(sid);\n\t\t\t\t\tif (b) (b as any)._ended = String(msg.reason ?? 'ended');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate _onMatch(msg: Record<string, unknown>): void {\n\t\tconst scheduleId = Number(msg.schedule_id ?? 0);\n\t\tconst eventId = msg.event_id ? String(msg.event_id) : null;\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\t// Send match_ack to transition session from ACCEPTED to ACTIVE.\n\t\t// Without this, subsequent resume from other n8n nodes would receive\n\t\t// \"match\" instead of \"resume_ok\" (session stays ACCEPTED).\n\t\tif (sessionId && this._ws?.readyState === WebSocket.OPEN) {\n\t\t\ttry { this._ws.send(JSON.stringify({ type: 'match_ack', session_id: sessionId })); } catch { /* ignore */ }\n\t\t}\n\t\t// Check pending rents (normal rent flow)\n\t\tlet pending = this._pendingRents.get(`event:${eventId}`);\n\t\tif (!pending) pending = this._pendingRents.get(`rent:${scheduleId}`);\n\t\tif (pending) {\n\t\t\tthis._pendingRents.delete(`event:${eventId}`);\n\t\t\tthis._pendingRents.delete(`rent:${scheduleId}`);\n\t\t\tpending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\t// Fallback: relay may send \"match\" during resume if session is ACCEPTED\n\t\t// (e.g. when rent node finished without sending match_ack).\n\t\t// Treat it like resume_ok so the next node doesn't hang.\n\t\tconst resumePending = sessionId ? this._pendingResumes.get(sessionId) : null;\n\t\tif (resumePending) {\n\t\t\tthis._pendingResumes.delete(sessionId);\n\t\t\tresumePending.resolve({\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tschedule_id: scheduleId,\n\t\t\t\tevent_id: eventId,\n\t\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _onRentError(msg: Record<string, unknown>): void {\n\t\tconst code = String(msg.code ?? '');\n\t\tconst message = String(msg.message ?? '');\n\t\tfor (const [key, pending] of this._pendingRents) {\n\t\t\tthis._pendingRents.delete(key);\n\t\t\tpending.reject(new Error(message || `Rent error: ${code}`));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate _onResumeOk(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.resolve({\n\t\t\tsession_id: sessionId,\n\t\t\tschedule_id: Number(msg.schedule_id ?? 0),\n\t\t\tevent_id: msg.event_id ? String(msg.event_id) : null,\n\t\t\tchat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,\n\t\t\tprovider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,\n\t\t\tbrowser_info: (msg.browser_info ?? {}) as Record<string, unknown>,\n\t\t});\n\t}\n\n\tprivate _onResumeFailed(msg: Record<string, unknown>): void {\n\t\tconst sessionId = String(msg.session_id ?? '');\n\t\tconst pending = this._pendingResumes.get(sessionId);\n\t\tif (!pending) return;\n\t\tthis._pendingResumes.delete(sessionId);\n\t\tpending.reject(new Error(String(msg.reason ?? 'Resume failed')));\n\t}\n\n\tprivate _onCdpResponse(sessionId: string, msg: Record<string, unknown>): void {\n\t\tconst browser = this._activeSessions.get(sessionId);\n\t\tif (!browser) return;\n\t\tconst id = Number(msg.id ?? 0);\n\t\t// NOTE: pending CDP is stored on CekiBrowser._pendingCdp (set by CekiBrowser.send()),\n\t\t// NOT on CekiClient._pendingCdp \u2014 they are different maps.\n\t\tconst pending = browser._pendingCdp.get(id);\n\t\tif (!pending) return;\n\t\tbrowser._pendingCdp.delete(id);\n\t\tif (msg.error) {\n\t\t\tpending.reject(new Error(String((msg.error as Record<string, unknown>).message ?? 'CDP error')));\n\t\t} else {\n\t\t\tpending.resolve(msg.result);\n\t\t}\n\t}\n}\n\n// \u2500\u2500 Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class CekiBrowser {\n\treadonly sessionId: string;\n\treadonly scheduleId: number;\n\treadonly chatTopicId: string | null;\n\treadonly browserInfo: Record<string, unknown>;\n\treadonly providerUserId: number | null;\n\n\tprivate _client: CekiClient;\n\tprivate _cdpId = 1;\n\t_pendingCdp = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n\n\tconstructor(client: CekiClient, match: Match) {\n\t\tthis._client = client;\n\t\tthis.sessionId = match.session_id;\n\t\tthis.scheduleId = match.schedule_id;\n\t\tthis.chatTopicId = match.chat_topic_id ?? null;\n\t\tthis.browserInfo = match.browser_info ?? {};\n\t\tthis.providerUserId = match.provider_user_id ?? null;\n\t}\n\n\t/** Send a CDP command. Uses AbortSignal.timeout() (no restricted setTimeout global). */\n\tasync send(method: string, params?: Record<string, unknown>, timeoutMs = 30000): Promise<unknown> {\n\t\tconst id = this._cdpId++;\n\t\tconst msg = { type: 'cdp', session_id: this.sessionId, id, method, params: params ?? {} };\n\t\tthis._client._sendRaw(msg);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\ttimeoutSignal.addEventListener('abort', () => {\n\t\t\t\tthis._pendingCdp.delete(id);\n\t\t\t\treject(new Error(`CDP ${method} timed out after ${timeoutMs}ms`));\n\t\t\t}, { once: true });\n\t\t\tthis._pendingCdp.set(id, {\n\t\t\t\tresolve: (v) => { resolve(v); },\n\t\t\t\treject: (e) => { reject(e); },\n\t\t\t});\n\t\t});\n\t}\n\n\tasync navigate(url: string, timeoutMs?: number): Promise<void> {\n\t\tawait this.send('Page.navigate', { url }, timeoutMs);\n\t}\n\n\tasync click(x: number, y: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 });\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });\n\t}\n\n\tasync type(text: string): Promise<void> {\n\t\tawait this.send('Ceki.typeText', { text });\n\t}\n\n\tasync scroll(deltaY: number): Promise<void> {\n\t\tawait this.send('Input.dispatchMouseEvent', { type: 'mouseWheel', x: 0, y: 0, deltaX: 0, deltaY });\n\t}\n\n\tasync screenshot(opts?: ScreenshotOptions): Promise<{ data: string } | Buffer> {\n\t\tconst format = opts?.format ?? 'base64';\n\t\tconst fullPage = opts?.fullPage ?? false;\n\t\tlet clip: Record<string, number> | undefined;\n\t\tif (fullPage) {\n\t\t\tconst metrics = await this.send('Page.getLayoutMetrics') as Record<string, unknown> | null;\n\t\t\tconst contentSize = metrics?.contentSize as Record<string, number> | undefined;\n\t\t\tif (contentSize) {\n\t\t\t\tclip = { x: 0, y: 0, width: Number(contentSize.width ?? 1920), height: Math.min(Number(contentSize.height ?? 1080), 16384), scale: 1 };\n\t\t\t}\n\t\t}\n\t\tconst result = await this.send('Page.captureScreenshot', { format: 'png', ...(clip ? { clip } : {}) }) as Record<string, unknown> | null;\n\t\tconst data = String(result?.data ?? '');\n\t\tif (format === 'png') {\n\t\t\treturn Buffer.from(data, 'base64');\n\t\t}\n\t\treturn { data };\n\t}\n\n\tasync snapshot(): Promise<{ screenshot: string; ts: Date }> {\n\t\tconst ssResult = await this.screenshot({ format: 'base64' }) as { data: string };\n\t\treturn { screenshot: ssResult.data, ts: new Date() };\n\t}\n\n\tasync upload(selector: string, buf: Buffer, filename = 'file'): Promise<Record<string, unknown>> {\n\t\tconst b64 = buf.toString('base64');\n\t\tconst size = buf.length;\n\t\tconst mime = 'application/octet-stream';\n\t\tconst expression = `(function(){\n\t\t\tvar input = document.querySelector(${JSON.stringify(selector)});\n\t\t\tif (!input) return JSON.stringify({ok:false,error:'Element not found'});\n\t\t\tvar b = atob(${JSON.stringify(b64)});\n\t\t\tvar u = new Uint8Array(b.length);\n\t\t\tfor (var i = 0; i < b.length; i++) u[i] = b.charCodeAt(i);\n\t\t\tvar f = new File([u], ${JSON.stringify(filename)}, {type: ${JSON.stringify(mime)}});\n\t\t\tvar dt = new DataTransfer(); dt.items.add(f);\n\t\t\tinput.files = dt.files;\n\t\t\tinput.dispatchEvent(new Event('change',{bubbles:true}));\n\t\t\treturn JSON.stringify({ok:true,filename:${JSON.stringify(filename)},size:${size}});\n\t\t})()`;\n\t\tconst result = await this.send('Runtime.evaluate', { expression, returnByValue: true }) as Record<string, unknown> | null;\n\t\ttry {\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t\tawait this.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });\n\t\t} catch { /* ignore */ }\n\t\tconst resultObj = result?.result as Record<string, unknown> | undefined;\n\t\tif (resultObj?.value) return JSON.parse(String(resultObj.value)) as Record<string, unknown>;\n\t\treturn { ok: true, filename, size };\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.send('Ceki.close', {}).catch(() => {});\n\t\tthis._client._activeSessions.delete(this.sessionId);\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["x", "y", "sid", "sessionId", "x", "y"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ceki/n8n-nodes-ceki",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Rent real human browsers in n8n — anti-bot scraping, human-solved captchas, geo-targeting, and contract-based hiring of agents and humans. Powered by Ceki.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",