@ceki/n8n-nodes-ceki 0.2.6 → 0.2.8
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/dist/credentials/CekiApi.credentials.js +15 -0
- package/dist/credentials/CekiApi.credentials.js.map +2 -2
- package/dist/index.js +313 -73
- package/dist/index.js.map +3 -3
- package/dist/nodes/BrowserCeki/BrowserCeki.node.js +298 -73
- package/dist/nodes/BrowserCeki/BrowserCeki.node.js.map +3 -3
- package/dist/nodes/CekiContract/CekiContract.node.js.map +2 -2
- package/dist/nodes/recipes/CekiCaptchaScrape/CekiCaptchaScrape.node.js +65 -9
- package/dist/nodes/recipes/CekiCaptchaScrape/CekiCaptchaScrape.node.js.map +2 -2
- package/dist/nodes/recipes/CekiScreenshotGeo/CekiScreenshotGeo.node.js +65 -9
- package/dist/nodes/recipes/CekiScreenshotGeo/CekiScreenshotGeo.node.js.map +2 -2
- package/package.json +1 -1
|
@@ -39,6 +39,21 @@ var CekiApi = class {
|
|
|
39
39
|
required: true
|
|
40
40
|
}
|
|
41
41
|
];
|
|
42
|
+
this.authenticate = {
|
|
43
|
+
type: "generic",
|
|
44
|
+
properties: {
|
|
45
|
+
headers: {
|
|
46
|
+
Authorization: "=Bearer {{$credentials?.token}}"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
this.test = {
|
|
51
|
+
request: {
|
|
52
|
+
baseURL: "https://api.ceki.me",
|
|
53
|
+
url: "/api/browsers/search",
|
|
54
|
+
method: "GET"
|
|
55
|
+
}
|
|
56
|
+
};
|
|
42
57
|
}
|
|
43
58
|
};
|
|
44
59
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../credentials/CekiApi.credentials.ts"],
|
|
4
|
-
"sourcesContent": ["import type {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["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": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWO,IAAM,UAAN,MAAyC;AAAA,EAAzC;AACN,gBAAO;AACP,uBAAc;AACd,4BAAmB;AACnB,sBAAgC;AAAA,MAC/B;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,MAAM;AAAA,QACN,aAAa,EAAE,UAAU,KAAK;AAAA,QAC9B,SAAS;AAAA,QACT,aACC;AAAA,QACD,UAAU;AAAA,MACX;AAAA,IACD;AAEA,wBAAqC;AAAA,MACpC,MAAM;AAAA,MACN,YAAY;AAAA,QACX,SAAS;AAAA,UACR,eAAe;AAAA,QAChB;AAAA,MACD;AAAA,IACD;AAEA,gBAA+B;AAAA,MAC9B,SAAS;AAAA,QACR,SAAS;AAAA,QACT,KAAK;AAAA,QACL,QAAQ;AAAA,MACT;AAAA,IACD;AAAA;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -121,17 +121,53 @@ var CekiClient = class {
|
|
|
121
121
|
this._sendRaw({ type: "resume", session_id: sessionId });
|
|
122
122
|
return this._awaitResume(sessionId);
|
|
123
123
|
}
|
|
124
|
-
/** Close the WS connection — session stays alive in grace.
|
|
125
|
-
|
|
124
|
+
/** Close the WS connection — session stays alive in grace.
|
|
125
|
+
* Waits for the close handshake so the relay processes the close
|
|
126
|
+
* before a new connection with the same renterId is established
|
|
127
|
+
* (avoids the close-handler race condition).
|
|
128
|
+
*/
|
|
129
|
+
async disconnect() {
|
|
126
130
|
this._closed = true;
|
|
127
131
|
this._activeSessions.clear();
|
|
128
132
|
this._pendingRents.clear();
|
|
129
133
|
this._pendingResumes.clear();
|
|
130
|
-
this.
|
|
134
|
+
if (!this._ws) return;
|
|
135
|
+
const ws = this._ws;
|
|
136
|
+
if (ws.readyState === WebSocket.CLOSED) {
|
|
137
|
+
this._ws = null;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (ws.readyState === WebSocket.CLOSING) {
|
|
141
|
+
await new Promise((r) => {
|
|
142
|
+
ws.onclose = () => {
|
|
143
|
+
this._connected = false;
|
|
144
|
+
r();
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
this._ws = null;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
await new Promise((r) => {
|
|
151
|
+
const t = setTimeout(() => {
|
|
152
|
+
r();
|
|
153
|
+
}, 5e3);
|
|
154
|
+
ws.onclose = () => {
|
|
155
|
+
this._connected = false;
|
|
156
|
+
clearTimeout(t);
|
|
157
|
+
r();
|
|
158
|
+
};
|
|
159
|
+
try {
|
|
160
|
+
ws.close();
|
|
161
|
+
} catch {
|
|
162
|
+
clearTimeout(t);
|
|
163
|
+
r();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
this._ws = null;
|
|
131
167
|
}
|
|
132
168
|
/** Close everything. */
|
|
133
|
-
close() {
|
|
134
|
-
this.disconnect();
|
|
169
|
+
async close() {
|
|
170
|
+
await this.disconnect();
|
|
135
171
|
}
|
|
136
172
|
// ── private ────────────────────────────────────────────────
|
|
137
173
|
_awaitRent(key, scheduleId, timeoutMs) {
|
|
@@ -155,7 +191,7 @@ var CekiClient = class {
|
|
|
155
191
|
}
|
|
156
192
|
_awaitResume(sessionId) {
|
|
157
193
|
return new Promise((resolve, reject) => {
|
|
158
|
-
const timeoutSignal = AbortSignal.timeout(
|
|
194
|
+
const timeoutSignal = AbortSignal.timeout(6e4);
|
|
159
195
|
timeoutSignal.addEventListener("abort", () => {
|
|
160
196
|
this._pendingResumes.delete(sessionId);
|
|
161
197
|
reject(new Error("Resume timed out"));
|
|
@@ -221,13 +257,33 @@ var CekiClient = class {
|
|
|
221
257
|
_onMatch(msg) {
|
|
222
258
|
const scheduleId = Number(msg.schedule_id ?? 0);
|
|
223
259
|
const eventId = msg.event_id ? String(msg.event_id) : null;
|
|
260
|
+
const sessionId = String(msg.session_id ?? "");
|
|
261
|
+
if (sessionId && this._ws?.readyState === WebSocket.OPEN) {
|
|
262
|
+
try {
|
|
263
|
+
this._ws.send(JSON.stringify({ type: "match_ack", session_id: sessionId }));
|
|
264
|
+
} catch {
|
|
265
|
+
}
|
|
266
|
+
}
|
|
224
267
|
let pending = this._pendingRents.get(`event:${eventId}`);
|
|
225
268
|
if (!pending) pending = this._pendingRents.get(`rent:${scheduleId}`);
|
|
226
269
|
if (pending) {
|
|
227
270
|
this._pendingRents.delete(`event:${eventId}`);
|
|
228
271
|
this._pendingRents.delete(`rent:${scheduleId}`);
|
|
229
272
|
pending.resolve({
|
|
230
|
-
session_id:
|
|
273
|
+
session_id: sessionId,
|
|
274
|
+
schedule_id: scheduleId,
|
|
275
|
+
event_id: eventId,
|
|
276
|
+
chat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,
|
|
277
|
+
provider_user_id: msg.provider_user_id != null ? Number(msg.provider_user_id) : null,
|
|
278
|
+
browser_info: msg.browser_info ?? {}
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const resumePending = sessionId ? this._pendingResumes.get(sessionId) : null;
|
|
283
|
+
if (resumePending) {
|
|
284
|
+
this._pendingResumes.delete(sessionId);
|
|
285
|
+
resumePending.resolve({
|
|
286
|
+
session_id: sessionId,
|
|
231
287
|
schedule_id: scheduleId,
|
|
232
288
|
event_id: eventId,
|
|
233
289
|
chat_topic_id: msg.chat_topic_id ? String(msg.chat_topic_id) : null,
|
|
@@ -270,9 +326,9 @@ var CekiClient = class {
|
|
|
270
326
|
const browser = this._activeSessions.get(sessionId);
|
|
271
327
|
if (!browser) return;
|
|
272
328
|
const id = Number(msg.id ?? 0);
|
|
273
|
-
const pending =
|
|
329
|
+
const pending = browser._pendingCdp.get(id);
|
|
274
330
|
if (!pending) return;
|
|
275
|
-
|
|
331
|
+
browser._pendingCdp.delete(id);
|
|
276
332
|
if (msg.error) {
|
|
277
333
|
pending.reject(new Error(String(msg.error.message ?? "CDP error")));
|
|
278
334
|
} else {
|
|
@@ -315,9 +371,9 @@ var CekiBrowser = class {
|
|
|
315
371
|
async navigate(url, timeoutMs) {
|
|
316
372
|
await this.send("Page.navigate", { url }, timeoutMs);
|
|
317
373
|
}
|
|
318
|
-
async click(
|
|
319
|
-
await this.send("Input.dispatchMouseEvent", { type: "mousePressed", x, y, button: "left", clickCount: 1 });
|
|
320
|
-
await this.send("Input.dispatchMouseEvent", { type: "mouseReleased", x, y, button: "left", clickCount: 1 });
|
|
374
|
+
async click(x2, y2) {
|
|
375
|
+
await this.send("Input.dispatchMouseEvent", { type: "mousePressed", x: x2, y: y2, button: "left", clickCount: 1 });
|
|
376
|
+
await this.send("Input.dispatchMouseEvent", { type: "mouseReleased", x: x2, y: y2, button: "left", clickCount: 1 });
|
|
321
377
|
}
|
|
322
378
|
async type(text) {
|
|
323
379
|
await this.send("Ceki.typeText", { text });
|
|
@@ -392,7 +448,7 @@ var BrowserCeki = class {
|
|
|
392
448
|
icon: "file:ceki.png",
|
|
393
449
|
group: ["transform"],
|
|
394
450
|
version: 1,
|
|
395
|
-
subtitle: '={{ "Ceki: " + $operation }}',
|
|
451
|
+
subtitle: '={{ "Ceki: " + $parameter.operation }}',
|
|
396
452
|
description: "Rent a real human browser and control it: rent, navigate, click, type, screenshot, solve captchas, and more",
|
|
397
453
|
defaults: { name: "Browser Ceki" },
|
|
398
454
|
inputs: ["main"],
|
|
@@ -403,8 +459,9 @@ var BrowserCeki = class {
|
|
|
403
459
|
displayName: "Operation",
|
|
404
460
|
name: "operation",
|
|
405
461
|
type: "options",
|
|
406
|
-
default: "
|
|
462
|
+
default: "search",
|
|
407
463
|
options: [
|
|
464
|
+
{ name: "Search", value: "search" },
|
|
408
465
|
{ name: "Rent", value: "rent" },
|
|
409
466
|
{ name: "Navigate", value: "navigate" },
|
|
410
467
|
{ name: "Click", value: "click" },
|
|
@@ -415,7 +472,8 @@ var BrowserCeki = class {
|
|
|
415
472
|
{ name: "Wait", value: "wait" },
|
|
416
473
|
{ name: "Wait for Selector", value: "waitForSelector" },
|
|
417
474
|
{ name: "Upload", value: "upload" },
|
|
418
|
-
{ name: "Close", value: "close" }
|
|
475
|
+
{ name: "Close", value: "close" },
|
|
476
|
+
{ name: "Full: Rent \u2192 Navigate \u2192 Screenshot", value: "full" }
|
|
419
477
|
]
|
|
420
478
|
},
|
|
421
479
|
// === Rent: rental parameters ===
|
|
@@ -433,7 +491,7 @@ var BrowserCeki = class {
|
|
|
433
491
|
type: "string",
|
|
434
492
|
default: "",
|
|
435
493
|
placeholder: "RU, EE, US\u2026",
|
|
436
|
-
displayOptions: { show: { operation: ["
|
|
494
|
+
displayOptions: { show: { operation: ["search"] } }
|
|
437
495
|
},
|
|
438
496
|
{
|
|
439
497
|
displayName: "Max $/min",
|
|
@@ -441,32 +499,48 @@ var BrowserCeki = class {
|
|
|
441
499
|
type: "number",
|
|
442
500
|
typeOptions: { numberPrecision: 4 },
|
|
443
501
|
default: 0.02,
|
|
444
|
-
displayOptions: { show: { operation: ["
|
|
502
|
+
displayOptions: { show: { operation: ["search"] } }
|
|
445
503
|
},
|
|
446
504
|
{
|
|
447
505
|
displayName: "Min rating",
|
|
448
506
|
name: "minRating",
|
|
449
507
|
type: "number",
|
|
450
508
|
default: 0,
|
|
451
|
-
displayOptions: { show: { operation: ["
|
|
509
|
+
displayOptions: { show: { operation: ["search"] } }
|
|
452
510
|
},
|
|
453
511
|
{
|
|
454
512
|
displayName: "Profile mode",
|
|
455
513
|
name: "mode",
|
|
456
514
|
type: "options",
|
|
457
|
-
default: "
|
|
515
|
+
default: "incognito",
|
|
458
516
|
options: [
|
|
459
517
|
{ name: "main", value: "main" },
|
|
460
518
|
{ name: "incognito", value: "incognito" }
|
|
461
519
|
],
|
|
462
|
-
displayOptions: { show: { operation: ["rent"] } }
|
|
520
|
+
displayOptions: { show: { operation: ["rent", "full"] } }
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
displayName: "URL",
|
|
524
|
+
name: "url",
|
|
525
|
+
type: "string",
|
|
526
|
+
default: "https://example.com",
|
|
527
|
+
required: true,
|
|
528
|
+
displayOptions: { show: { operation: ["navigate", "full"] } }
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
displayName: "Demo mode (no browser needed)",
|
|
532
|
+
name: "demoMode",
|
|
533
|
+
type: "boolean",
|
|
534
|
+
default: true,
|
|
535
|
+
description: "Skip actual browser rent and generate demo output",
|
|
536
|
+
displayOptions: { show: { operation: ["full"] } }
|
|
463
537
|
},
|
|
464
538
|
// === Operations: session_id ===
|
|
465
539
|
{
|
|
466
540
|
displayName: "Session ID",
|
|
467
541
|
name: "sessionId",
|
|
468
542
|
type: "string",
|
|
469
|
-
default: "
|
|
543
|
+
default: "",
|
|
470
544
|
description: "From the Rent operation",
|
|
471
545
|
required: true,
|
|
472
546
|
displayOptions: {
|
|
@@ -536,7 +610,7 @@ var BrowserCeki = class {
|
|
|
536
610
|
default: 1e3,
|
|
537
611
|
typeOptions: { minValue: 0 },
|
|
538
612
|
description: "Fixed delay on the active session",
|
|
539
|
-
displayOptions: { show: { operation: ["wait"] } }
|
|
613
|
+
displayOptions: { show: { operation: ["wait", "full"] } }
|
|
540
614
|
},
|
|
541
615
|
{
|
|
542
616
|
displayName: "CSS Selector",
|
|
@@ -593,66 +667,168 @@ var BrowserCeki = class {
|
|
|
593
667
|
for (let i = 0; i < items.length; i++) {
|
|
594
668
|
const op = this.getNodeParameter("operation", i);
|
|
595
669
|
const client = new CekiClient(token);
|
|
596
|
-
await client.connect();
|
|
597
670
|
let browser;
|
|
671
|
+
let needFullClose = false;
|
|
598
672
|
try {
|
|
673
|
+
await client.connect();
|
|
599
674
|
if (op === "rent") {
|
|
600
|
-
|
|
675
|
+
try {
|
|
676
|
+
const sid2 = await resolveSid(i, client);
|
|
677
|
+
const mode = this.getNodeParameter("mode", i);
|
|
678
|
+
browser = await client.rent(sid2, { mode });
|
|
679
|
+
out.push({
|
|
680
|
+
json: { session_id: browser.sessionId, schedule_id: sid2, mode }
|
|
681
|
+
});
|
|
682
|
+
} catch (e) {
|
|
683
|
+
throw new Error(`Rent failed: ${e.message}`);
|
|
684
|
+
} finally {
|
|
685
|
+
await client.disconnect();
|
|
686
|
+
}
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
if (op === "search") {
|
|
690
|
+
try {
|
|
691
|
+
const geo = this.getNodeParameter("geo", i);
|
|
692
|
+
const maxPrice = this.getNodeParameter("maxPrice", i);
|
|
693
|
+
const list = await client.search({
|
|
694
|
+
geo: geo || void 0,
|
|
695
|
+
max_price_per_min: maxPrice
|
|
696
|
+
});
|
|
697
|
+
out.push({ json: { browsers: list, count: list.length } });
|
|
698
|
+
} catch (e) {
|
|
699
|
+
throw new Error(`Search failed: ${e.message}`);
|
|
700
|
+
} finally {
|
|
701
|
+
await client.disconnect();
|
|
702
|
+
}
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
if (op === "full") {
|
|
706
|
+
const demoMode = this.getNodeParameter("demoMode", i);
|
|
707
|
+
let sid2;
|
|
708
|
+
if (demoMode) {
|
|
709
|
+
sid2 = 99999;
|
|
710
|
+
} else {
|
|
711
|
+
try {
|
|
712
|
+
sid2 = await resolveSid(i, client);
|
|
713
|
+
} catch (e) {
|
|
714
|
+
throw new Error(`Full: resolve schedule failed: ${e.message}`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
601
717
|
const mode = this.getNodeParameter("mode", i);
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
718
|
+
const url = this.getNodeParameter("url", i);
|
|
719
|
+
const ms = this.getNodeParameter("ms", i);
|
|
720
|
+
let session_id;
|
|
721
|
+
let binary;
|
|
722
|
+
try {
|
|
723
|
+
if (demoMode) {
|
|
724
|
+
session_id = "demo-" + Date.now();
|
|
725
|
+
const demoPng = Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAIAAAD9V4nPAAAnuElEQVR4nO3ceVxU9f748feZhU0RxRUTXEEWFXG3Rc3MJb3mUlrueivzVvebVre+38ql7d5bqZmZlZV4UUvLUtPUUtOKUAREBRVkEVQQxQ2UdWbO74+p+XGZAWlBqs/r+ddhOJ/lHHrw6sCIFhDQRQAAUJWhrjcAAEBdIoQAAKURQgCA0gghAEBphBAAoDRCCABQGiEEACiNEAIAlEYIAQBKI4QAAKURQgCA0gghAEBphBAAoDRCCABQGiEEACiNEAIAlEYIAQBKI4QAAKURQgCA0gghAEBphBAAoDRCCABQGiEEACiNEAIAlEYIAQBKI4QAAKURQgCA0gghAEBphBAAoDRCCABQGiEEACjNVKuzD1odeyXtiGiaybN+2rpl5+P31upydq3uGOs/eJyl5Jq1pOjoey+VXDjr8rSBkdG7p93i+LC+f/tGId1PfbXe8Yp987ouBpPp9K7PcvZsqvWtAwBuuNoNoc1SfmD+X0XEu3XHiKeX3IAQNu7St8Wtw/Y/P8VWVtok4tZOj7wY98KDNRl49VT61VPpFV9xbN7o7hnx9JvW0uK8mK9qZdMAgLpTuyF0KMxO1a1WERkYGX0udldB5vG8mK/CZi0wenhZS4qSl8/rueDD+JdmFp/P7f7sO9dyMo+v/LdvWI9Wg+69nJp40+2jRddT175RkJYcPOMZ94ZNNJM5NWrhlbSkihNmb1srIm3+MvXE2jdtZaUikn/w+2a9BmpGk8nDy3mgnZuPb4/n3zu85Omrp9IrPSM6WEuLU1cvDp7+9MXD+1xuIG//Tt/QHic3RzYMjmjYsWv2to+ytka5N2xS8QJLL+ffmFsNAPhZblAIfTv1Oh75qogYzObc6O0XDv3Q+e//PBu9LefbLS37jQiaPCc/MbpRSPeS/C/FoHm36SgijUK65yd+HzT5ie8fG+7u26zt6Ada9B2Svf2jKyeOeDTxi3h6ScxT4ypOaF+ovn/7wpPHHeseffcFEQmaPMd5oIgYTOYuj796PPLVSs+CzgqzUr1a+Lucx2B2O73z0/RP3um3bNv+Zyelfby010urs7ZGBU15ouIFHln6f7/9bQUA/Gq1G0KDydxz/gcGs1uD9p0uJu0/H79Xt9kuHt4nIr5hPZOXzxORszFfBU58PPmd+c173VGYlVqYedy7dUeTZ71GId1Pff2pb6denR596dSO9UlvPdtv+VdeLfztMxvdPTWDQbfZHBP+tKSLt/80Dr/ZeaCIhPz1/3K/23oxKfa6F6IZjTaLxfU8ul6QnqzbbDZLeUH6UV23Gd09nC/wF99DAECtukG/I6wfENjrhUgR0a1WXbeJiIhW8cyLyQcCJ/y9YVD4peMHrWWljUJ7GMxuZVcuJC17vlFI99bDJ/ndOkwzGuNf/putvFTTDA2DI+wxqzChiEhRbpZ3m45XThwREdG0Tn97MWnZcy4HGszm+gEdROTM7s+veyE+HTpfzT7h3TbYeR6bpfzHg/KyijupdIEAgN+nG/TPJ8oLLxflnar4ysXk2OZ97hSR5n3uvJh8wFZWWnb5QrPed1xOSbx8/GDrEVMuHo0zedXvueDDy6mHjiz9vyYRt11OSWzWa6CINIm4pe3ov7pc6NSOdR3ue9RgdhORFjcPtR+4HGgrL499bqpHs5at7hhb/ebN9RoETXz85OaVNdlAVRd4/XsEAKgLN+JHo7qui8jR916s+KnUqEVhsxa0GnSPtbQ4eflcEclPjL7pjrHlhZevnDjcKKRb2rq3LEVXz8d/2/uV1ZpmyNjw3rkD34TOnOs/+F7dak1+d4HLFc/+sMPLr3Wff31cVnCprODisfdfFpGUyNdcDtR125Elz/R+eXVhVkrFd9D89+bFYDJlbvrwYnJc0dnT191ANRcIAPgd0gICutT1HgAAqDP8ZRkAgNIIIQBAaYQQAKA0QggAUBohBAAojRACAJRGCAEASiOEAAClEUIAgNIIIQBAaYQQAKA0QggAUBohBAAojRACAJRGCAEASiOEAAClEUIAgNIIIQBAaYQQAKA0QggAUBohBAAojRACAJRGCAEASiOEAAClEUIAgNIIIQBAaYQQAKA0QggAUBohBAAojRACAJRGCAEASiOEAAClEUIAgNIIIQBAaYQQAKA0QggAUBohBAAojRACAJRGCAEASiOEAAClEUIAgNIIIQBAaYQQAKC0Wg3hypXLP/305Q0b3l+1atn48Q9169YlJKRbevrJTz9d9cknpfv3i8gvvZzde++9lJZ2UtM0o9HYpUuHL7/8+meN+vTTl1esWKppmtFo7NSp/aefrvq5o/r163P11BlZ5Omnn7pwoXDkyDsNBkPFl2JiYtLTs0SkbdsAg8GQnX1m6tR7R49+8LqjFiyYn5iYLCMmCdf3AAAPyElEQVT3f+DAwZ07v922bZeI3HZbnyeffFi3nU40Xb165dy5Tw4ePBiP7wDwc1MHhFA87LbbQ0S6du3YteufFi58d+3az444+QcPHszNPZeami4izZo1iYlJEBGTyZiTU/rrrwz86QoCAr7//vvffOVeImI0Gnx8GtTWcgAQd7/fI5mYxZEjaUVFRX369GjSpLGIZGZmP/XUI4sXz69mQu2+l+Cdd17+4IM14h7Q6MmXl2/fvnvMmIfsL3333cHMzFMiYjabd+3aLyJ9+nR7660PIiIi3n33lYiIro88cn1iYlJqapr9Fy+/vDgp6Yj9OCkpafbsGfv2JYjIV1/tFZEBA/rExe1v0KC+yWTy8HAvKCgUkccee3DWrKfsyz3++IMi0qCB99tvf/TCC88dOJB4332jHn10prgH/Pe//3z44T/X1h0DgD+EWguhplmGDbvdYrHk5+cnJma4uzfw8/Np1KjhnXf+yc/PR9O0s2fP7tuX4HJCl0+EmzZ9euzYsT17Ymy21/Ly/n/s3XlYU9f+B/BvQhISloAsYVEQkEURQVktiB2XqlZbq+217VufttV6az989T219vq01k5r62Wq1qXa1qcWByqj4gIqyCqLIIggEFaBsCRk+f3hO0eHSSAO1Pm9nn9w8n3OPfckhPNhOZyT3KNHj/v2HQgIGDppUo2mnT6deetbSssriouVpjxNT09PTq0fPHhQe7rOzs78+PHe+/btv+22oICA4e7u7pGRkUql0sPDY+TIQBERXl5eUVExIuLo6CgizZqeys7ONQwVEe3adTwtTbspIi2tFhEx5M+f//f48eOEQhYA1F/nhXDRok9///3wypU/CgiY/PLLi0TELyRkSk5Orqj0PDwmy5YtHjly+px5HzUOV3shiUSiUqk2bvzH2bMXZkyYOG3aLBMTE01XZpc4ObV6ltMq/2xHtNtaW5vv2rXX1ta2Z8+e8+cvs7GxUSgU+/cfMTE28etlL6bt5ua2Y8f/REQlMo/M/K2ZmeXvvycfO3a8cUumUHe2TwBwczQ2m6VnV4lCoaisVFdXV1dUKCsrKysrq66vN1lfX2dpaSkibHhYLJZd3ctXk9lsnnYlEon8/PiPH3761Km/Nm36JiPjT2dn53379nfu3HnFiu91e2ZmntX9WCajjUQiSUhI1Oo4IiLo9/0EADdMo4tD165dPX/+YlpaRufOnboSEYnI2bMXvbw8e/XqXlhY+OOPO/r27T158qiGhgalUq26du3atWtX/fz6i0hBQcHly5ddXbkmJib3W6+2trbW1lYREYvFEhNbc3MLEWlublapVA0NDY6Ojvt+P5iVlTU7a9Z8G5v2IpKZmUlEXl4eIpKRkVlaWhYSMsXFxcXUtJmpqamHh4etrZ2RkVGXLl3u2Z6ISOXlVxoaGkRkyZJFmzZtNzMza2hoyM09EBAQoC1n+fLQo0eP7927f8uWLZ6eHkQ0YMCAsLCf0tLSfH199+7df/nyFXNz82++Wd+5c+dbLgcA0Ag0R8R4RE+dmmAiY+gbG3Xr1iUl5aj2o5GRkY2NjYODQ3Z29syZ0/LzC+7ZZkZG5pQpE4cOHaJSqRITkxYsSFBVVUVExOubmNUq5fj4CT4+3hER4Q0NDUlJqUuWLPrii4QR6voeHh5hYWG9e/e6fPny1q3fh4VN++yzz42MjD5b99nmzVu3bv3e27uXiLBYLBMTk6NHj3355ZezZ88SEXd3d19fXz4/tKio6OjRY8OG+R0/frK6unrlyuX/+9/eF198MTl5v7Oz8/bte955562oqCiNxiI+ft6GDT8FBAR4e/M8PT26des2fHhAXV1dWlraLbf0pkIhRESjocLCQh42bPhvv+3p3bv3lStX0tJ03+Tq1r9//3feeaewsKhXr16pqWmXLl3Ky8srKioODQ01MTHZtu37xMRES0tLLy/PoUOH6o6h4XoBoAVojiAxHu8wGnXLls0/+eQjfWO7dOn0zz93d8nYGB4Z6ddfd/zzn1+o1dd5Y8IMe/bFf/MaBoPh4eFeWVl5C5cdHh5uYmLKMNzevb+amJhIpdJvv/0vEURF3b1hww+TJ0/64Ydt8fGJs2d/lpCQEBcXN3PmTO0SdXVqR0en0NApInL48JH169dv377d39+/qurql1+upN/XEQBoeYxuWSAo/t6nT5+JiopydnY+ePBQWlp6u38X7gMA6hYhBFjx8bELFizm8XhE9MEH78+dG3NnVwEAf1t4RwgAIH/7NQIAALcDIQQAkEIIIQCEEDI+QggAIYQAEEIIACCEEABC2BwYAAAQEEIACCGEABBCAAAJIQQAkEIIASCEAABCCCEEgBACQEL3WAUAAAKEEABCCAEghBAAQggBIYQAEEIIACGEABBCAAAJIYQAEEIIACGEAABCCCEEgBBCAAghhAAAAYQQAEIIASCEEABACCEEgBBCAAghBIAQQgAIIQQAIYQAEEIIACGEAABCCCEEgBBCAAghBIAQQgAIIQQAIYQAEEIIACGEABBCAAAJIYQAEEIIACGEAABCCCEEgBBCAAghBIAQQgAIIQQAIYQAEEIIACGEABBCAAAJIYQAEEIIACGEAABCCCEEgBBCAAghBIAQQgAIIQQAIYQAEEIIACGEABBCAAAJIYQAEEIIACGEAABCCCEEgBBCAAghBIAQQgAIIQQAIYQAEEIIACGEABBCAAAJIYQAEEIIACGEAABCCCEEgBBCAAghBIAQQgAIIQQAIYQAEEIIACGEABBCAAAJIYQAEEIIACGEAABCCCEEgBBCAAghBIAQQgAIIQQAIYQAEEIIACGEABBCAAAJIYSIEHHBggXdunWLiYk5f/78naxl27aYb7/9loho+vTp77//PpPJvPWl2rVr19DQoE8tk8l0d3d//PHHXVxc9KkNAODe1CofER48ePDChQsODg4LFy5kMpmXL1/esGGDnZ3dmjVrbq2Wy5cvE5GLi4s+NenU4Ovr26NHjxMnsg4ePKBPbQAA96zWO0d44cIFNze3119/3c/Pj8ViiUhVVdXjjz9eU1NzC7Xs2LFDJpMJBILy8nJ9yiouLq6srGQymT/99FN2djYAADzaWohIJBIJBAJPT0+VStXS9Rw9elStVs+ZM8fCwkJfQQsWLJgxY4aentovvvhi586d58+f15mZmZk5atQoJycnIpJKpXFxcRqNZtu2bZ07dx40aJBIJNq3b19AQMDly5f3798/bNgwgUDwzTffFBcXBwcHp6SkHDhwYP/+/U5OTmZmZl999VVNTU1wcPCiRYuOHDkSFhZ25MiRFStWhIeHZ2dnL1y4sLq6ms/n9+7de9WqVVwut6GhIT4+Pjo6+rXXXhs9evTZs2d//PHHV1555Y6+OQCAv52ndl+/fi0iREQajcbGxmbHjh3Dhg2rqKj44IMPrK2te/XqtXv3bn1Keuihhw4dOpScnNyrVy99jpiYmOjoaGMjYy6XS0RqtVomkxUWFkokEg8PDyaTmZ6evmfPHoFAIJPJJk+e/Oabb1706Lx9+/b//Oc/iYmJpqamubm5Fy9efPPNN9euXbtq1ar58+f37dv3wIEDNBpNqVQyGAwiyszMnDx5cnFxsZWVVbdu3XJzc4nowIEDOTk5n376KRGpVKq8vLyvvvoqLy/v1KlTq1evjo+PLy4ufvbZZ8vLy+/0+wMA+FtonTlCgUCwb98+lUp19uzZTz75pKamJi4ubsCAAUePHvXy8rp06VJJSYk+Jen2b7e3txcIBLrDWCwWhUIpKSkRCARyuVx3RG1tbXV1tbW1NRFxuVwigUKhMBiMoqKiX3755ZVXXhGLxUS0cePGkSNHOjk5tWvXTluf7nP0/2tqarKzs4lo0qRJGzZsMDY2Xrt2bUBAQHFxMRG5uLgcPnxYLpcvXrz4mWee+fbbb2NjY59//vnBgwc3e4sAAOQ+Yjx9glZUVJSUlBw6dOjSpUv9+vXbt2/fDz/8sH///nfffTcqKqpVq1bTp09vrsl+v5WUlJCSkkJEFRUVUqlUJBIZGRkRUUlJCZfL7dq1K4vFcnFx6dq1K5PJ7NKlS2RkZEBAQFhYGBFJpdLNmze//vrra9euzcnJISLd5f+oOTY2NjU1NSYmJjg4+NixY9bW1hqN5tChQ2PGjPH3928wclxM0w1VqVTJyclvv/22bqG2trZFRUVarbdv3/7UU0+1adOGz+f37duXiGJjY6dOnerp6Xnul1NiYuL3338/efJkR0fHxYsXS6XSbdu2LViwYP78+Z6enn/X7xAAQJ9a70+EYrH4448/NjU1Xbt27fvvv9+7d28Oh+Po6FhUVDRq1Kh169bNmDGD7jN9+PDhDz74gIjuueee9957j8/nazSaUaNGhYWFZWZmzps3LzQ09KWXXiIiFovl5+dnbGzcr1+/rKysRx99VKVSzZgxo7y83MTE5JNPPqHT6UQkFAr9/f3Nzc1XrlzZ0NBw/PjxHj16+Pv7u7u7d+/e3d3d3cPD49y5c2KxuLKy8urVq05OTn369MnPzzczM7ty5YqTk9PAgQOzsrKISLdHmZmZ06dPnzZtmi7DlpaW48ePz8jI+Pbbb0ePHl1cXMxisQICAi5cuMDn8zMyMhob3oxGI51O1+01NjbGZDKnTp168ODB2bNnr1mzpn///hkZGT/99NPo0aPPnz/f3I2j0WhEwwMIAO5VGIIiIiIajebi4pKbm7ty5crQ0NCffvpp9uzZb7/9dlhYmFgsXrlyJYVCeeyxx0JCQmbMmJGRkXHp0iXlj+G/MAAAHONJREFU2RIrK6u//OUvCoVCIpE8/vjjfD6/oqIiLCzMwcGBx+MRUZ8+fVasWBEYGDh+/Phr1649/vjjp0+fjo+P79mzZ3h4eFJSkpmZ2e7duxmN/xD1b7/9xmazg4KCRowY8cILL0yfPj0lJaW2tnbz5s3du3fXarVpaWm1tbVcLvfw4cOPPPLIBx98sGvXLi6XK5FIUlJS0tLSOnToUFZWNnTo0H//+99ExOFw4uLiampqJkyYUFZWRkT5+flisVgsFj/xxBMCgaChoeHy5csSicTc3DwsLIzFYhERjUYrKChISkqaM2eOp6cnnU4nIpVK1bt3706dOq1bt27dunWEH90D4N6GjggR0aRJk4hIqVSKRCIzM7OysjI3NzeJREJEubm5EyZMGDRo0Jtvvvn+++8vX768Xbt2Tz75ZHh4+IIFC2g0mkgk6tmzJ5vNzs/Pd3Fxqa2tbdu2rVar7d+/v6en57Rp0/h8PhHJ5XI7O7sFCxY4Ojq+9NJL5ubm9vb2QqHwkUceOX/+fEFBQW5u7vr162NjY3Uvs99fOp3OZDJ79uzZqVOn4uJiCwuLxx9/nMlkHjp0qLi4WFcGl8utqanp0KGDQqFISUnR1WFkZGRnZ3fgwIH58+enpKQIpjI++eQTIpLL5ZWVlVu2bCktLS0rK0tOTlYsXRIeHi4SiYiopqbmo48+2rlzZ0ZGBofD6dKli5+fX0lJyTfffLN48eIuXbpIpVI+n9+tWzerxq48AACPAouI8IKK6Nq1a9euXXUqeOeddxYvXvzYY4+dP39eX2k7O7vk5OTOnTsfOXJk+/btCxYsIKINGzZ88skn48eP7y9on5aWNn/+fN3QefPmHTp0KDU1dc6cOc2VT6fTN2/e/NJLL+krGwAAPu05Qh5PKBaLjx071rFjx/bt2xORQqGQy+UCgaC6urq6unrz5s1E5O7u3rdv3+rq6ps3b2q12o4dO546dUokEu3bt8/KyuqTTz4hIk9PzwcffLC+vh7vhQCAFqd9R4iUBn+LKBQKCoWSlJSk0Whqa2vPnDlTVlZ26NChkJAQlUp18+bN5OTk3NxcLpd769GlS5dSqVQ6nd69e/cXX3zR19f3ypUrmzZtKioq6tOnT3x8PIPBICYGAAC8IzxtsFmssLCwgIAAHo8nkUguXLiQnZ1tZ2e3cuXKqVOfpv+PYzQajUb70/8vFyIqKiqKjIycMmVKbW1tRUVFbm6uWq32xv8LBQB4tGkUwtmzZxMTE/FPCQHgd/7OS5QAAEA3Vqs/ESEAAIDeEEIAABmEEABABiEEAJBBCAEAZBBCAAAZhBAAQKaNTQfcbwIAQAhCCAAghiEEABBDCAEAxBBCAIBbhhACAOT/xDcAAMB/hj8RAgDI/H+J3gYgOqnyVQAAAABJRU5ErkJggg==", "base64");
|
|
726
|
+
binary = await this.helpers.prepareBinaryData(demoPng, "screenshot.png", "image/png");
|
|
727
|
+
} else {
|
|
728
|
+
try {
|
|
729
|
+
browser = await client.rent(sid2, { mode });
|
|
730
|
+
session_id = browser.sessionId;
|
|
731
|
+
await browser.navigate(url);
|
|
732
|
+
await sleep(ms);
|
|
733
|
+
const shot = await browser.screenshot({ format: "png", fullPage: true });
|
|
734
|
+
const data = shot.toString("base64");
|
|
735
|
+
binary = await this.helpers.prepareBinaryData(Buffer.from(data, "base64"), "screenshot.png", "image/png");
|
|
736
|
+
await browser.close();
|
|
737
|
+
} catch (e) {
|
|
738
|
+
throw new Error(`Full op failed at step "${browser?.sessionId ? "navigate/screenshot" : "rent"}": ${e.message}`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
out.push({
|
|
742
|
+
json: {
|
|
743
|
+
session_id,
|
|
744
|
+
schedule_id: sid2,
|
|
745
|
+
mode,
|
|
746
|
+
url,
|
|
747
|
+
waited: ms
|
|
748
|
+
},
|
|
749
|
+
binary: { data: binary }
|
|
750
|
+
});
|
|
751
|
+
} finally {
|
|
752
|
+
await client.close().catch(() => {
|
|
753
|
+
});
|
|
754
|
+
}
|
|
607
755
|
continue;
|
|
608
756
|
}
|
|
609
757
|
const sessionId = this.getNodeParameter("sessionId", i);
|
|
610
|
-
|
|
758
|
+
try {
|
|
759
|
+
browser = await client.resume(sessionId);
|
|
760
|
+
} catch (e) {
|
|
761
|
+
throw new Error(`Resume session "${sessionId}" failed: ${e.message}. Session may have expired or still be in grace.`);
|
|
762
|
+
}
|
|
611
763
|
const sid = browser.sessionId;
|
|
612
764
|
switch (op) {
|
|
613
765
|
case "navigate": {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
766
|
+
try {
|
|
767
|
+
const url = this.getNodeParameter("url", i);
|
|
768
|
+
await browser.navigate(url);
|
|
769
|
+
out.push({ json: { session_id: sid, url } });
|
|
770
|
+
} catch (e) {
|
|
771
|
+
throw new Error(`Navigate failed: ${e.message}`);
|
|
772
|
+
}
|
|
617
773
|
break;
|
|
618
774
|
}
|
|
619
775
|
case "click": {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
776
|
+
try {
|
|
777
|
+
const x2 = this.getNodeParameter("x", i);
|
|
778
|
+
const y2 = this.getNodeParameter("y", i);
|
|
779
|
+
await browser.click(x2, y2);
|
|
780
|
+
out.push({ json: { session_id: sid, clicked: [x2, y2] } });
|
|
781
|
+
} catch (e) {
|
|
782
|
+
throw new Error(`Click at (${x},${y}) failed: ${e.message}`);
|
|
783
|
+
}
|
|
624
784
|
break;
|
|
625
785
|
}
|
|
626
786
|
case "type": {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
787
|
+
try {
|
|
788
|
+
const text = this.getNodeParameter("text", i);
|
|
789
|
+
await browser.type(text);
|
|
790
|
+
out.push({ json: { session_id: sid, typed: text } });
|
|
791
|
+
} catch (e) {
|
|
792
|
+
throw new Error(`Type failed: ${e.message}`);
|
|
793
|
+
}
|
|
630
794
|
break;
|
|
631
795
|
}
|
|
632
796
|
case "scroll": {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
797
|
+
try {
|
|
798
|
+
const deltaY = this.getNodeParameter("deltaY", i);
|
|
799
|
+
await browser.scroll(deltaY);
|
|
800
|
+
out.push({ json: { session_id: sid, scrolled: deltaY } });
|
|
801
|
+
} catch (e) {
|
|
802
|
+
throw new Error(`Scroll failed: ${e.message}`);
|
|
803
|
+
}
|
|
636
804
|
break;
|
|
637
805
|
}
|
|
638
806
|
case "screenshot": {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
807
|
+
try {
|
|
808
|
+
const format = this.getNodeParameter("format", i);
|
|
809
|
+
const fullPage = this.getNodeParameter("fullPage", i);
|
|
810
|
+
const shot = await browser.screenshot({ format, fullPage });
|
|
811
|
+
const data = format === "base64" ? shot.data : shot.toString("base64");
|
|
812
|
+
const binary = await this.helpers.prepareBinaryData(
|
|
813
|
+
Buffer.from(data, "base64"),
|
|
814
|
+
"screenshot.png",
|
|
815
|
+
"image/png"
|
|
816
|
+
);
|
|
817
|
+
out.push({ json: { session_id: sid }, binary: { data: binary } });
|
|
818
|
+
} catch (e) {
|
|
819
|
+
throw new Error(`Screenshot failed: ${e.message}`);
|
|
820
|
+
}
|
|
649
821
|
break;
|
|
650
822
|
}
|
|
651
823
|
case "snapshot": {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
824
|
+
try {
|
|
825
|
+
const snap = await browser.snapshot();
|
|
826
|
+
out.push({
|
|
827
|
+
json: { session_id: sid, screenshot: snap.screenshot }
|
|
828
|
+
});
|
|
829
|
+
} catch (e) {
|
|
830
|
+
throw new Error(`Snapshot failed: ${e.message}`);
|
|
831
|
+
}
|
|
656
832
|
break;
|
|
657
833
|
}
|
|
658
834
|
case "wait": {
|
|
@@ -689,30 +865,79 @@ var BrowserCeki = class {
|
|
|
689
865
|
break;
|
|
690
866
|
}
|
|
691
867
|
case "upload": {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
868
|
+
try {
|
|
869
|
+
const selector = this.getNodeParameter("selector", i);
|
|
870
|
+
const bpn = this.getNodeParameter("binaryPropertyName", i);
|
|
871
|
+
const bin = items[i].binary?.[bpn];
|
|
872
|
+
if (!bin) throw new Error(`Binary property "${bpn}" not found on input`);
|
|
873
|
+
const stream = await this.helpers.getBinaryStream(bin.id);
|
|
874
|
+
const chunks = [];
|
|
875
|
+
for await (const c of stream) chunks.push(c);
|
|
876
|
+
const buf = Buffer.concat(chunks);
|
|
877
|
+
const res = await browser.upload(selector, buf);
|
|
878
|
+
out.push({ json: { session_id: sid, uploaded: res } });
|
|
879
|
+
} catch (e) {
|
|
880
|
+
throw new Error(`Upload failed: ${e.message}`);
|
|
881
|
+
}
|
|
702
882
|
break;
|
|
703
883
|
}
|
|
704
884
|
case "close": {
|
|
705
|
-
|
|
885
|
+
try {
|
|
886
|
+
await browser.close().catch(() => {
|
|
887
|
+
});
|
|
888
|
+
} catch {
|
|
889
|
+
}
|
|
890
|
+
await new Promise((resolve) => {
|
|
891
|
+
const stopWs = new WebSocket("wss://browser.ceki.me/ws/agent", [`bearer.${token}`]);
|
|
892
|
+
const abortTimer = AbortSignal.timeout(1e4);
|
|
893
|
+
const onTimer = () => {
|
|
894
|
+
try {
|
|
895
|
+
stopWs.close();
|
|
896
|
+
} catch {
|
|
897
|
+
}
|
|
898
|
+
resolve();
|
|
899
|
+
};
|
|
900
|
+
abortTimer.addEventListener("abort", onTimer, { once: true });
|
|
901
|
+
stopWs.onopen = () => {
|
|
902
|
+
stopWs.send(JSON.stringify({ type: "stop", session_id: sessionId, reason: "n8n close" }));
|
|
903
|
+
};
|
|
904
|
+
stopWs.onmessage = (ev) => {
|
|
905
|
+
try {
|
|
906
|
+
const msg = JSON.parse(ev.data);
|
|
907
|
+
if (msg.type === "session_ended") {
|
|
908
|
+
abortTimer.removeEventListener("abort", onTimer);
|
|
909
|
+
try {
|
|
910
|
+
stopWs.close();
|
|
911
|
+
} catch {
|
|
912
|
+
}
|
|
913
|
+
resolve();
|
|
914
|
+
}
|
|
915
|
+
} catch {
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
stopWs.onerror = () => {
|
|
919
|
+
abortTimer.removeEventListener("abort", onTimer);
|
|
920
|
+
resolve();
|
|
921
|
+
};
|
|
922
|
+
stopWs.onclose = () => {
|
|
923
|
+
abortTimer.removeEventListener("abort", onTimer);
|
|
924
|
+
resolve();
|
|
925
|
+
};
|
|
926
|
+
});
|
|
706
927
|
out.push({ json: { closed: true, session_id: sessionId } });
|
|
707
928
|
break;
|
|
708
929
|
}
|
|
709
930
|
}
|
|
710
|
-
|
|
711
|
-
await client.close();
|
|
712
|
-
} else {
|
|
713
|
-
await client.disconnect();
|
|
714
|
-
}
|
|
931
|
+
needFullClose = op === "close";
|
|
715
932
|
} finally {
|
|
933
|
+
try {
|
|
934
|
+
if (needFullClose) {
|
|
935
|
+
await client.close();
|
|
936
|
+
} else {
|
|
937
|
+
await client.disconnect();
|
|
938
|
+
}
|
|
939
|
+
} catch {
|
|
940
|
+
}
|
|
716
941
|
}
|
|
717
942
|
}
|
|
718
943
|
return [out];
|
|
@@ -1348,6 +1573,21 @@ var CekiApi = class {
|
|
|
1348
1573
|
required: true
|
|
1349
1574
|
}
|
|
1350
1575
|
];
|
|
1576
|
+
this.authenticate = {
|
|
1577
|
+
type: "generic",
|
|
1578
|
+
properties: {
|
|
1579
|
+
headers: {
|
|
1580
|
+
Authorization: "=Bearer {{$credentials?.token}}"
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
this.test = {
|
|
1585
|
+
request: {
|
|
1586
|
+
baseURL: "https://api.ceki.me",
|
|
1587
|
+
url: "/api/browsers/search",
|
|
1588
|
+
method: "GET"
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1351
1591
|
}
|
|
1352
1592
|
};
|
|
1353
1593
|
|