@hasna/browser 0.2.1 → 0.2.3
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/cli/index.js +108 -28
- package/dist/lib/login-scripts.d.ts +26 -1
- package/dist/lib/login-scripts.d.ts.map +1 -1
- package/dist/mcp/index.js +102 -22
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -19363,14 +19363,24 @@ var init_dist = __esm(() => {
|
|
|
19363
19363
|
var exports_login_scripts = {};
|
|
19364
19364
|
__export(exports_login_scripts, {
|
|
19365
19365
|
saveScript: () => saveScript,
|
|
19366
|
+
runScriptAsync: () => runScriptAsync,
|
|
19366
19367
|
runScript: () => runScript,
|
|
19367
19368
|
loadScript: () => loadScript,
|
|
19368
19369
|
listScripts: () => listScripts,
|
|
19370
|
+
listJobs: () => listJobs,
|
|
19371
|
+
getJob: () => getJob,
|
|
19369
19372
|
deleteScript: () => deleteScript,
|
|
19370
19373
|
createUsestableScript: () => createUsestableScript
|
|
19371
19374
|
});
|
|
19375
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
19372
19376
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync8, readdirSync as readdirSync4 } from "fs";
|
|
19373
19377
|
import { join as join9 } from "path";
|
|
19378
|
+
function getJob(jobId) {
|
|
19379
|
+
return activeJobs.get(jobId) ?? null;
|
|
19380
|
+
}
|
|
19381
|
+
function listJobs() {
|
|
19382
|
+
return Array.from(activeJobs.values());
|
|
19383
|
+
}
|
|
19374
19384
|
function getScriptsDir() {
|
|
19375
19385
|
const dir = join9(getDataDir(), "scripts");
|
|
19376
19386
|
mkdirSync8(dir, { recursive: true });
|
|
@@ -19417,15 +19427,34 @@ function interpolate(template, vars) {
|
|
|
19417
19427
|
return vars[key] ?? match;
|
|
19418
19428
|
});
|
|
19419
19429
|
}
|
|
19420
|
-
|
|
19430
|
+
function stepDescription(step) {
|
|
19431
|
+
return step.description ?? `${step.type}${step.action ? `:${step.action}` : ""}${step.connector ? `:${step.connector}` : ""}`;
|
|
19432
|
+
}
|
|
19433
|
+
async function runScript(script, page, overrides = {}, jobId) {
|
|
19421
19434
|
const t0 = Date.now();
|
|
19422
19435
|
const vars = { ...script.variables, ...overrides };
|
|
19423
19436
|
const errors = [];
|
|
19424
19437
|
let executed = 0;
|
|
19425
19438
|
let failed = 0;
|
|
19439
|
+
const job = jobId && activeJobs.has(jobId) ? activeJobs.get(jobId) : {
|
|
19440
|
+
id: jobId ?? randomUUID10(),
|
|
19441
|
+
script_name: script.name,
|
|
19442
|
+
status: "running",
|
|
19443
|
+
current_step: 0,
|
|
19444
|
+
total_steps: script.steps.length,
|
|
19445
|
+
current_step_description: "Starting...",
|
|
19446
|
+
steps_log: [],
|
|
19447
|
+
started_at: new Date().toISOString()
|
|
19448
|
+
};
|
|
19449
|
+
activeJobs.set(job.id, job);
|
|
19426
19450
|
for (let i = 0;i < script.steps.length; i++) {
|
|
19427
19451
|
const step = script.steps[i];
|
|
19452
|
+
const desc = stepDescription(step);
|
|
19428
19453
|
executed++;
|
|
19454
|
+
job.current_step = i + 1;
|
|
19455
|
+
job.current_step_description = desc;
|
|
19456
|
+
job.steps_log.push({ step: i + 1, type: step.type, description: desc, status: "running" });
|
|
19457
|
+
const stepStart = Date.now();
|
|
19429
19458
|
try {
|
|
19430
19459
|
switch (step.type) {
|
|
19431
19460
|
case "browser":
|
|
@@ -19462,15 +19491,22 @@ async function runScript(script, page, overrides = {}) {
|
|
|
19462
19491
|
break;
|
|
19463
19492
|
}
|
|
19464
19493
|
}
|
|
19494
|
+
const logEntry = job.steps_log[job.steps_log.length - 1];
|
|
19495
|
+
logEntry.status = "ok";
|
|
19496
|
+
logEntry.duration_ms = Date.now() - stepStart;
|
|
19465
19497
|
} catch (err) {
|
|
19466
19498
|
failed++;
|
|
19467
19499
|
const msg = `Step ${i + 1} (${step.type}/${step.action ?? step.connector ?? ""}): ${err instanceof Error ? err.message : String(err)}`;
|
|
19468
19500
|
errors.push(msg);
|
|
19501
|
+
const logEntry = job.steps_log[job.steps_log.length - 1];
|
|
19502
|
+
logEntry.status = "failed";
|
|
19503
|
+
logEntry.error = err instanceof Error ? err.message : String(err);
|
|
19504
|
+
logEntry.duration_ms = Date.now() - stepStart;
|
|
19469
19505
|
if (step.type === "browser" && step.action === "navigate")
|
|
19470
19506
|
break;
|
|
19471
19507
|
}
|
|
19472
19508
|
}
|
|
19473
|
-
|
|
19509
|
+
const result = {
|
|
19474
19510
|
success: failed === 0,
|
|
19475
19511
|
steps_executed: executed,
|
|
19476
19512
|
steps_failed: failed,
|
|
@@ -19478,6 +19514,28 @@ async function runScript(script, page, overrides = {}) {
|
|
|
19478
19514
|
errors,
|
|
19479
19515
|
duration_ms: Date.now() - t0
|
|
19480
19516
|
};
|
|
19517
|
+
job.status = failed === 0 ? "completed" : "failed";
|
|
19518
|
+
job.result = result;
|
|
19519
|
+
return result;
|
|
19520
|
+
}
|
|
19521
|
+
function runScriptAsync(script, page, overrides = {}) {
|
|
19522
|
+
const jobId = randomUUID10();
|
|
19523
|
+
const job = {
|
|
19524
|
+
id: jobId,
|
|
19525
|
+
script_name: script.name,
|
|
19526
|
+
status: "running",
|
|
19527
|
+
current_step: 0,
|
|
19528
|
+
total_steps: script.steps.length,
|
|
19529
|
+
current_step_description: "Starting...",
|
|
19530
|
+
steps_log: [],
|
|
19531
|
+
started_at: new Date().toISOString()
|
|
19532
|
+
};
|
|
19533
|
+
activeJobs.set(jobId, job);
|
|
19534
|
+
runScript(script, page, overrides, jobId).catch((err) => {
|
|
19535
|
+
job.status = "failed";
|
|
19536
|
+
job.current_step_description = `Fatal error: ${err instanceof Error ? err.message : String(err)}`;
|
|
19537
|
+
});
|
|
19538
|
+
return jobId;
|
|
19481
19539
|
}
|
|
19482
19540
|
async function runBrowserStep(step, page, vars) {
|
|
19483
19541
|
const action = step.action;
|
|
@@ -19565,6 +19623,9 @@ async function runConnectorStep(step, vars) {
|
|
|
19565
19623
|
vars[step.save_as] = result.stdout;
|
|
19566
19624
|
}
|
|
19567
19625
|
}
|
|
19626
|
+
function decodeHtmlEntities(str) {
|
|
19627
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'");
|
|
19628
|
+
}
|
|
19568
19629
|
function runExtractStep(step, vars) {
|
|
19569
19630
|
const saveTo = step.save_as ?? "extracted";
|
|
19570
19631
|
if (step.pattern) {
|
|
@@ -19572,7 +19633,7 @@ function runExtractStep(step, vars) {
|
|
|
19572
19633
|
const regex = new RegExp(step.pattern);
|
|
19573
19634
|
const match = regex.exec(source);
|
|
19574
19635
|
if (match) {
|
|
19575
|
-
vars[saveTo] = match[1] ?? match[0];
|
|
19636
|
+
vars[saveTo] = decodeHtmlEntities(match[1] ?? match[0]);
|
|
19576
19637
|
}
|
|
19577
19638
|
}
|
|
19578
19639
|
if (step.json_path) {
|
|
@@ -19637,8 +19698,10 @@ function createUsestableScript(email) {
|
|
|
19637
19698
|
updated_at: new Date().toISOString()
|
|
19638
19699
|
};
|
|
19639
19700
|
}
|
|
19701
|
+
var activeJobs;
|
|
19640
19702
|
var init_login_scripts = __esm(() => {
|
|
19641
19703
|
init_schema();
|
|
19704
|
+
activeJobs = new Map;
|
|
19642
19705
|
});
|
|
19643
19706
|
|
|
19644
19707
|
// src/lib/daemon-client.ts
|
|
@@ -23767,7 +23830,7 @@ __export(exports_downloads, {
|
|
|
23767
23830
|
deleteDownload: () => deleteDownload,
|
|
23768
23831
|
cleanStaleDownloads: () => cleanStaleDownloads
|
|
23769
23832
|
});
|
|
23770
|
-
import { randomUUID as
|
|
23833
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
23771
23834
|
import { join as join11, basename, extname } from "path";
|
|
23772
23835
|
import { mkdirSync as mkdirSync9, existsSync as existsSync8, readdirSync as readdirSync5, statSync as statSync2, unlinkSync as unlinkSync2, copyFileSync, writeFileSync as writeFileSync4, readFileSync as readFileSync6 } from "fs";
|
|
23773
23836
|
import { homedir as homedir10 } from "os";
|
|
@@ -23788,7 +23851,7 @@ function metaPath(filePath) {
|
|
|
23788
23851
|
}
|
|
23789
23852
|
function saveToDownloads(buffer, filename, opts) {
|
|
23790
23853
|
const dir = getDownloadsDir(opts?.sessionId);
|
|
23791
|
-
const id =
|
|
23854
|
+
const id = randomUUID11();
|
|
23792
23855
|
const ext = extname(filename) || "";
|
|
23793
23856
|
const stem = basename(filename, ext);
|
|
23794
23857
|
const uniqueName = `${stem}-${id.slice(0, 8)}${ext}`;
|
|
@@ -24196,10 +24259,10 @@ __export(exports_workflows, {
|
|
|
24196
24259
|
getWorkflow: () => getWorkflow,
|
|
24197
24260
|
deleteWorkflow: () => deleteWorkflow
|
|
24198
24261
|
});
|
|
24199
|
-
import { randomUUID as
|
|
24262
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
24200
24263
|
function saveWorkflow(data) {
|
|
24201
24264
|
const db = getDatabase();
|
|
24202
|
-
const id =
|
|
24265
|
+
const id = randomUUID12();
|
|
24203
24266
|
db.prepare("INSERT OR REPLACE INTO workflows (id, name, description, steps, start_url) VALUES (?, ?, ?, ?, ?)").run(id, data.name, data.description ?? null, JSON.stringify(data.steps), data.startUrl ?? null);
|
|
24204
24267
|
return getWorkflow(id);
|
|
24205
24268
|
}
|
|
@@ -24359,10 +24422,10 @@ __export(exports_auth_flow, {
|
|
|
24359
24422
|
getAuthFlow: () => getAuthFlow,
|
|
24360
24423
|
deleteAuthFlow: () => deleteAuthFlow
|
|
24361
24424
|
});
|
|
24362
|
-
import { randomUUID as
|
|
24425
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
24363
24426
|
function saveAuthFlow(data) {
|
|
24364
24427
|
const db = getDatabase();
|
|
24365
|
-
const id =
|
|
24428
|
+
const id = randomUUID13();
|
|
24366
24429
|
db.prepare("INSERT OR REPLACE INTO auth_flows (id, name, domain, recording_id, storage_state_path) VALUES (?, ?, ?, ?, ?)").run(id, data.name, data.domain, data.recordingId ?? null, data.storageStatePath ?? null);
|
|
24367
24430
|
return getAuthFlow(id);
|
|
24368
24431
|
}
|
|
@@ -24542,13 +24605,13 @@ __export(exports_datasets, {
|
|
|
24542
24605
|
exportDataset: () => exportDataset,
|
|
24543
24606
|
deleteDataset: () => deleteDataset
|
|
24544
24607
|
});
|
|
24545
|
-
import { randomUUID as
|
|
24608
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
24546
24609
|
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync11 } from "fs";
|
|
24547
24610
|
import { join as join13 } from "path";
|
|
24548
24611
|
import { homedir as homedir12 } from "os";
|
|
24549
24612
|
function saveDataset(data) {
|
|
24550
24613
|
const db = getDatabase();
|
|
24551
|
-
const id =
|
|
24614
|
+
const id = randomUUID14();
|
|
24552
24615
|
const existing = db.query("SELECT id FROM datasets WHERE name = ?").get(data.name);
|
|
24553
24616
|
if (existing) {
|
|
24554
24617
|
db.prepare("UPDATE datasets SET data = ?, row_count = ?, source_url = ?, schema = ?, last_refresh = datetime('now'), updated_at = datetime('now') WHERE name = ?").run(JSON.stringify(data.rows), data.rows.length, data.sourceUrl ?? null, data.schema ? JSON.stringify(data.schema) : null, data.name);
|
|
@@ -29349,7 +29412,7 @@ import { Database as Database3 } from "bun:sqlite";
|
|
|
29349
29412
|
import { mkdirSync as mkdirSync13 } from "fs";
|
|
29350
29413
|
import { join as join15, dirname as dirname6 } from "path";
|
|
29351
29414
|
import { homedir as homedir14 } from "os";
|
|
29352
|
-
import { randomUUID as
|
|
29415
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
29353
29416
|
import { mkdirSync as mkdirSync23, copyFileSync as copyFileSync3, statSync as statSync3 } from "fs";
|
|
29354
29417
|
import { join as join34 } from "path";
|
|
29355
29418
|
import { homedir as homedir33 } from "os";
|
|
@@ -29729,7 +29792,7 @@ function guessMimeType(name) {
|
|
|
29729
29792
|
function sendMessage(opts) {
|
|
29730
29793
|
const db2 = getDb();
|
|
29731
29794
|
const explicitSession = opts.session_id && opts.session_id.trim().length > 0 ? opts.session_id : undefined;
|
|
29732
|
-
const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${
|
|
29795
|
+
const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${randomUUID15().slice(0, 8)}`);
|
|
29733
29796
|
const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
|
|
29734
29797
|
const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
|
|
29735
29798
|
const blocking = opts.blocking ? 1 : 0;
|
|
@@ -41418,7 +41481,7 @@ __export(exports_cron_manager, {
|
|
|
41418
41481
|
deleteCronJob: () => deleteCronJob,
|
|
41419
41482
|
createCronJob: () => createCronJob
|
|
41420
41483
|
});
|
|
41421
|
-
import { randomUUID as
|
|
41484
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
41422
41485
|
function ensureCronTable() {
|
|
41423
41486
|
const db2 = getDatabase();
|
|
41424
41487
|
db2.exec(`
|
|
@@ -41447,7 +41510,7 @@ function ensureCronTable() {
|
|
|
41447
41510
|
function createCronJob(schedule, task, name) {
|
|
41448
41511
|
ensureCronTable();
|
|
41449
41512
|
const db2 = getDatabase();
|
|
41450
|
-
const id =
|
|
41513
|
+
const id = randomUUID16();
|
|
41451
41514
|
db2.prepare(`
|
|
41452
41515
|
INSERT INTO cron_jobs (id, name, schedule, task_json, enabled)
|
|
41453
41516
|
VALUES (?, ?, ?, ?, 1)
|
|
@@ -41505,7 +41568,7 @@ function getCronEvents(jobId, limit = 10) {
|
|
|
41505
41568
|
async function executeCronJob(job) {
|
|
41506
41569
|
ensureCronTable();
|
|
41507
41570
|
const db2 = getDatabase();
|
|
41508
|
-
const eventId =
|
|
41571
|
+
const eventId = randomUUID16();
|
|
41509
41572
|
const startedAt = new Date().toISOString();
|
|
41510
41573
|
db2.prepare("INSERT INTO cron_events (id, job_id, started_at) VALUES (?, ?, ?)").run(eventId, job.id, startedAt);
|
|
41511
41574
|
try {
|
|
@@ -41596,7 +41659,7 @@ __export(exports_url_watcher, {
|
|
|
41596
41659
|
deleteWatchJob: () => deleteWatchJob,
|
|
41597
41660
|
createWatchJob: () => createWatchJob
|
|
41598
41661
|
});
|
|
41599
|
-
import { randomUUID as
|
|
41662
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
41600
41663
|
import { createHash } from "crypto";
|
|
41601
41664
|
function ensureWatchTables() {
|
|
41602
41665
|
const db2 = getDatabase();
|
|
@@ -41628,7 +41691,7 @@ function ensureWatchTables() {
|
|
|
41628
41691
|
function createWatchJob(url, schedule, opts) {
|
|
41629
41692
|
ensureWatchTables();
|
|
41630
41693
|
const db2 = getDatabase();
|
|
41631
|
-
const id =
|
|
41694
|
+
const id = randomUUID17();
|
|
41632
41695
|
db2.prepare(`
|
|
41633
41696
|
INSERT INTO watch_jobs (id, name, url, schedule, selector, extract_schema, enabled)
|
|
41634
41697
|
VALUES (?, ?, ?, ?, ?, ?, 1)
|
|
@@ -41664,7 +41727,7 @@ function getWatchEvents(watchId, limit = 20) {
|
|
|
41664
41727
|
async function checkWatchJob(job) {
|
|
41665
41728
|
ensureWatchTables();
|
|
41666
41729
|
const db2 = getDatabase();
|
|
41667
|
-
const eventId =
|
|
41730
|
+
const eventId = randomUUID17();
|
|
41668
41731
|
const checkedAt = new Date().toISOString();
|
|
41669
41732
|
let newContent = "";
|
|
41670
41733
|
try {
|
|
@@ -43571,13 +43634,13 @@ var init_mcp = __esm(async () => {
|
|
|
43571
43634
|
return err(e);
|
|
43572
43635
|
}
|
|
43573
43636
|
});
|
|
43574
|
-
server.tool("browser_script_run", "Run a saved login script \u2014
|
|
43637
|
+
server.tool("browser_script_run", "Run a saved login script asynchronously. Returns a job_id immediately \u2014 poll with browser_script_status for step-by-step progress. Combines browser actions + connector calls (e.g. magic link login via Gmail).", {
|
|
43575
43638
|
name: exports_external.string().describe("Script name (e.g. 'usestable')"),
|
|
43576
43639
|
session_id: exports_external.string().optional(),
|
|
43577
43640
|
variables: exports_external.record(exports_external.string()).optional().describe("Override script variables (e.g. {email: 'foo@bar.com'})")
|
|
43578
43641
|
}, async ({ name, session_id, variables }) => {
|
|
43579
43642
|
try {
|
|
43580
|
-
const { loadScript: loadScript2,
|
|
43643
|
+
const { loadScript: loadScript2, runScriptAsync: runScriptAsync2 } = await Promise.resolve().then(() => (init_login_scripts(), exports_login_scripts));
|
|
43581
43644
|
const script = loadScript2(name);
|
|
43582
43645
|
if (!script)
|
|
43583
43646
|
return err(new Error(`Script '${name}' not found. Use browser_script_list to see available scripts.`));
|
|
@@ -43587,12 +43650,29 @@ var init_mcp = __esm(async () => {
|
|
|
43587
43650
|
sid = resolveSessionId(session_id);
|
|
43588
43651
|
page = getSessionPage(sid);
|
|
43589
43652
|
} else {
|
|
43590
|
-
const
|
|
43591
|
-
sid =
|
|
43592
|
-
page =
|
|
43653
|
+
const result = await createSession2({ headless: true });
|
|
43654
|
+
sid = result.session.id;
|
|
43655
|
+
page = result.page;
|
|
43593
43656
|
}
|
|
43594
|
-
const
|
|
43595
|
-
return json({
|
|
43657
|
+
const jobId = runScriptAsync2(script, page, variables ?? {});
|
|
43658
|
+
return json({ job_id: jobId, session_id: sid, script: name, total_steps: script.steps.length, message: "Script running in background. Poll with browser_script_status for progress." });
|
|
43659
|
+
} catch (e) {
|
|
43660
|
+
return err(e);
|
|
43661
|
+
}
|
|
43662
|
+
});
|
|
43663
|
+
server.tool("browser_script_status", "Check the progress of a running login script. Shows current step, step-by-step log with durations, and final result when complete.", { job_id: exports_external.string() }, async ({ job_id }) => {
|
|
43664
|
+
try {
|
|
43665
|
+
const { getJob: getJob2 } = await Promise.resolve().then(() => (init_login_scripts(), exports_login_scripts));
|
|
43666
|
+
const job = getJob2(job_id);
|
|
43667
|
+
if (!job)
|
|
43668
|
+
return err(new Error(`Job '${job_id}' not found`));
|
|
43669
|
+
return json({
|
|
43670
|
+
status: job.status,
|
|
43671
|
+
progress: `${job.current_step}/${job.total_steps}`,
|
|
43672
|
+
current_step: job.current_step_description,
|
|
43673
|
+
steps_log: job.steps_log,
|
|
43674
|
+
result: job.result ?? undefined
|
|
43675
|
+
});
|
|
43596
43676
|
} catch (e) {
|
|
43597
43677
|
return err(e);
|
|
43598
43678
|
}
|
|
@@ -44362,10 +44442,10 @@ __export(exports_snapshots, {
|
|
|
44362
44442
|
deleteSnapshot: () => deleteSnapshot,
|
|
44363
44443
|
createSnapshot: () => createSnapshot
|
|
44364
44444
|
});
|
|
44365
|
-
import { randomUUID as
|
|
44445
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
44366
44446
|
function createSnapshot(data) {
|
|
44367
44447
|
const db2 = getDatabase();
|
|
44368
|
-
const id =
|
|
44448
|
+
const id = randomUUID18();
|
|
44369
44449
|
db2.prepare("INSERT INTO snapshots (id, session_id, url, title, html, screenshot_path) VALUES (?, ?, ?, ?, ?, ?)").run(id, data.session_id, data.url, data.title ?? null, data.html ?? null, data.screenshot_path ?? null);
|
|
44370
44450
|
return getSnapshot(id);
|
|
44371
44451
|
}
|
|
@@ -45,6 +45,26 @@ export interface ScriptRunResult {
|
|
|
45
45
|
errors: string[];
|
|
46
46
|
duration_ms: number;
|
|
47
47
|
}
|
|
48
|
+
export interface ScriptJob {
|
|
49
|
+
id: string;
|
|
50
|
+
script_name: string;
|
|
51
|
+
status: "running" | "completed" | "failed";
|
|
52
|
+
current_step: number;
|
|
53
|
+
total_steps: number;
|
|
54
|
+
current_step_description: string;
|
|
55
|
+
steps_log: Array<{
|
|
56
|
+
step: number;
|
|
57
|
+
type: string;
|
|
58
|
+
description: string;
|
|
59
|
+
status: "ok" | "failed" | "running";
|
|
60
|
+
duration_ms?: number;
|
|
61
|
+
error?: string;
|
|
62
|
+
}>;
|
|
63
|
+
result?: ScriptRunResult;
|
|
64
|
+
started_at: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function getJob(jobId: string): ScriptJob | null;
|
|
67
|
+
export declare function listJobs(): ScriptJob[];
|
|
48
68
|
export declare function saveScript(script: LoginScript): string;
|
|
49
69
|
export declare function loadScript(name: string): LoginScript | null;
|
|
50
70
|
export declare function listScripts(): Array<{
|
|
@@ -54,6 +74,11 @@ export declare function listScripts(): Array<{
|
|
|
54
74
|
steps: number;
|
|
55
75
|
}>;
|
|
56
76
|
export declare function deleteScript(name: string): boolean;
|
|
57
|
-
export declare function runScript(script: LoginScript, page: Page, overrides?: Record<string, string
|
|
77
|
+
export declare function runScript(script: LoginScript, page: Page, overrides?: Record<string, string>, jobId?: string): Promise<ScriptRunResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Run a script asynchronously — returns immediately with a job ID.
|
|
80
|
+
* Poll with getJob(jobId) for progress.
|
|
81
|
+
*/
|
|
82
|
+
export declare function runScriptAsync(script: LoginScript, page: Page, overrides?: Record<string, string>): string;
|
|
58
83
|
export declare function createUsestableScript(email: string): LoginScript;
|
|
59
84
|
//# sourceMappingURL=login-scripts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/login-scripts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,CAAC;AAEjG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,YAAY,GAAG,qBAAqB,GAAG,eAAe,GAAG,UAAU,CAAC;IAC7G,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAUD,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAOtD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAI3D;AAED,wBAAgB,WAAW,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAY1G;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMlD;
|
|
1
|
+
{"version":3,"file":"login-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/login-scripts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,CAAC;AAEjG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,YAAY,GAAG,qBAAqB,GAAG,eAAe,GAAG,UAAU,CAAC;IAC7G,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB,EAAE,MAAM,CAAC;IACjC,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjJ,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAEtD;AAED,wBAAgB,QAAQ,IAAI,SAAS,EAAE,CAEtC;AAUD,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAOtD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAI3D;AAED,wBAAgB,WAAW,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAY1G;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMlD;AAgBD,wBAAsB,SAAS,CAC7B,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,IAAI,EACV,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACtC,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,CA0G1B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,IAAI,EACV,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,MAAM,CAqBR;AA8ID,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CA2ChE"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -17120,14 +17120,24 @@ var init_dist = __esm(() => {
|
|
|
17120
17120
|
var exports_login_scripts = {};
|
|
17121
17121
|
__export(exports_login_scripts, {
|
|
17122
17122
|
saveScript: () => saveScript,
|
|
17123
|
+
runScriptAsync: () => runScriptAsync,
|
|
17123
17124
|
runScript: () => runScript,
|
|
17124
17125
|
loadScript: () => loadScript,
|
|
17125
17126
|
listScripts: () => listScripts,
|
|
17127
|
+
listJobs: () => listJobs,
|
|
17128
|
+
getJob: () => getJob,
|
|
17126
17129
|
deleteScript: () => deleteScript,
|
|
17127
17130
|
createUsestableScript: () => createUsestableScript
|
|
17128
17131
|
});
|
|
17132
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
17129
17133
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync10, readdirSync as readdirSync5 } from "fs";
|
|
17130
17134
|
import { join as join10 } from "path";
|
|
17135
|
+
function getJob(jobId) {
|
|
17136
|
+
return activeJobs.get(jobId) ?? null;
|
|
17137
|
+
}
|
|
17138
|
+
function listJobs() {
|
|
17139
|
+
return Array.from(activeJobs.values());
|
|
17140
|
+
}
|
|
17131
17141
|
function getScriptsDir() {
|
|
17132
17142
|
const dir = join10(getDataDir(), "scripts");
|
|
17133
17143
|
mkdirSync10(dir, { recursive: true });
|
|
@@ -17174,15 +17184,34 @@ function interpolate(template, vars) {
|
|
|
17174
17184
|
return vars[key] ?? match;
|
|
17175
17185
|
});
|
|
17176
17186
|
}
|
|
17177
|
-
|
|
17187
|
+
function stepDescription(step) {
|
|
17188
|
+
return step.description ?? `${step.type}${step.action ? `:${step.action}` : ""}${step.connector ? `:${step.connector}` : ""}`;
|
|
17189
|
+
}
|
|
17190
|
+
async function runScript(script, page, overrides = {}, jobId) {
|
|
17178
17191
|
const t0 = Date.now();
|
|
17179
17192
|
const vars = { ...script.variables, ...overrides };
|
|
17180
17193
|
const errors2 = [];
|
|
17181
17194
|
let executed = 0;
|
|
17182
17195
|
let failed = 0;
|
|
17196
|
+
const job = jobId && activeJobs.has(jobId) ? activeJobs.get(jobId) : {
|
|
17197
|
+
id: jobId ?? randomUUID12(),
|
|
17198
|
+
script_name: script.name,
|
|
17199
|
+
status: "running",
|
|
17200
|
+
current_step: 0,
|
|
17201
|
+
total_steps: script.steps.length,
|
|
17202
|
+
current_step_description: "Starting...",
|
|
17203
|
+
steps_log: [],
|
|
17204
|
+
started_at: new Date().toISOString()
|
|
17205
|
+
};
|
|
17206
|
+
activeJobs.set(job.id, job);
|
|
17183
17207
|
for (let i = 0;i < script.steps.length; i++) {
|
|
17184
17208
|
const step = script.steps[i];
|
|
17209
|
+
const desc = stepDescription(step);
|
|
17185
17210
|
executed++;
|
|
17211
|
+
job.current_step = i + 1;
|
|
17212
|
+
job.current_step_description = desc;
|
|
17213
|
+
job.steps_log.push({ step: i + 1, type: step.type, description: desc, status: "running" });
|
|
17214
|
+
const stepStart = Date.now();
|
|
17186
17215
|
try {
|
|
17187
17216
|
switch (step.type) {
|
|
17188
17217
|
case "browser":
|
|
@@ -17219,15 +17248,22 @@ async function runScript(script, page, overrides = {}) {
|
|
|
17219
17248
|
break;
|
|
17220
17249
|
}
|
|
17221
17250
|
}
|
|
17251
|
+
const logEntry = job.steps_log[job.steps_log.length - 1];
|
|
17252
|
+
logEntry.status = "ok";
|
|
17253
|
+
logEntry.duration_ms = Date.now() - stepStart;
|
|
17222
17254
|
} catch (err) {
|
|
17223
17255
|
failed++;
|
|
17224
17256
|
const msg = `Step ${i + 1} (${step.type}/${step.action ?? step.connector ?? ""}): ${err instanceof Error ? err.message : String(err)}`;
|
|
17225
17257
|
errors2.push(msg);
|
|
17258
|
+
const logEntry = job.steps_log[job.steps_log.length - 1];
|
|
17259
|
+
logEntry.status = "failed";
|
|
17260
|
+
logEntry.error = err instanceof Error ? err.message : String(err);
|
|
17261
|
+
logEntry.duration_ms = Date.now() - stepStart;
|
|
17226
17262
|
if (step.type === "browser" && step.action === "navigate")
|
|
17227
17263
|
break;
|
|
17228
17264
|
}
|
|
17229
17265
|
}
|
|
17230
|
-
|
|
17266
|
+
const result = {
|
|
17231
17267
|
success: failed === 0,
|
|
17232
17268
|
steps_executed: executed,
|
|
17233
17269
|
steps_failed: failed,
|
|
@@ -17235,6 +17271,28 @@ async function runScript(script, page, overrides = {}) {
|
|
|
17235
17271
|
errors: errors2,
|
|
17236
17272
|
duration_ms: Date.now() - t0
|
|
17237
17273
|
};
|
|
17274
|
+
job.status = failed === 0 ? "completed" : "failed";
|
|
17275
|
+
job.result = result;
|
|
17276
|
+
return result;
|
|
17277
|
+
}
|
|
17278
|
+
function runScriptAsync(script, page, overrides = {}) {
|
|
17279
|
+
const jobId = randomUUID12();
|
|
17280
|
+
const job = {
|
|
17281
|
+
id: jobId,
|
|
17282
|
+
script_name: script.name,
|
|
17283
|
+
status: "running",
|
|
17284
|
+
current_step: 0,
|
|
17285
|
+
total_steps: script.steps.length,
|
|
17286
|
+
current_step_description: "Starting...",
|
|
17287
|
+
steps_log: [],
|
|
17288
|
+
started_at: new Date().toISOString()
|
|
17289
|
+
};
|
|
17290
|
+
activeJobs.set(jobId, job);
|
|
17291
|
+
runScript(script, page, overrides, jobId).catch((err) => {
|
|
17292
|
+
job.status = "failed";
|
|
17293
|
+
job.current_step_description = `Fatal error: ${err instanceof Error ? err.message : String(err)}`;
|
|
17294
|
+
});
|
|
17295
|
+
return jobId;
|
|
17238
17296
|
}
|
|
17239
17297
|
async function runBrowserStep(step, page, vars) {
|
|
17240
17298
|
const action = step.action;
|
|
@@ -17322,6 +17380,9 @@ async function runConnectorStep(step, vars) {
|
|
|
17322
17380
|
vars[step.save_as] = result.stdout;
|
|
17323
17381
|
}
|
|
17324
17382
|
}
|
|
17383
|
+
function decodeHtmlEntities(str) {
|
|
17384
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'");
|
|
17385
|
+
}
|
|
17325
17386
|
function runExtractStep(step, vars) {
|
|
17326
17387
|
const saveTo = step.save_as ?? "extracted";
|
|
17327
17388
|
if (step.pattern) {
|
|
@@ -17329,7 +17390,7 @@ function runExtractStep(step, vars) {
|
|
|
17329
17390
|
const regex = new RegExp(step.pattern);
|
|
17330
17391
|
const match = regex.exec(source);
|
|
17331
17392
|
if (match) {
|
|
17332
|
-
vars[saveTo] = match[1] ?? match[0];
|
|
17393
|
+
vars[saveTo] = decodeHtmlEntities(match[1] ?? match[0]);
|
|
17333
17394
|
}
|
|
17334
17395
|
}
|
|
17335
17396
|
if (step.json_path) {
|
|
@@ -17394,8 +17455,10 @@ function createUsestableScript(email) {
|
|
|
17394
17455
|
updated_at: new Date().toISOString()
|
|
17395
17456
|
};
|
|
17396
17457
|
}
|
|
17458
|
+
var activeJobs;
|
|
17397
17459
|
var init_login_scripts = __esm(() => {
|
|
17398
17460
|
init_schema();
|
|
17461
|
+
activeJobs = new Map;
|
|
17399
17462
|
});
|
|
17400
17463
|
|
|
17401
17464
|
// src/lib/api-detector.ts
|
|
@@ -17404,7 +17467,7 @@ __export(exports_api_detector, {
|
|
|
17404
17467
|
listDiscoveredAPIs: () => listDiscoveredAPIs,
|
|
17405
17468
|
detectAPIs: () => detectAPIs
|
|
17406
17469
|
});
|
|
17407
|
-
import { randomUUID as
|
|
17470
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
17408
17471
|
function detectAPIs(sessionId) {
|
|
17409
17472
|
const db = getDatabase();
|
|
17410
17473
|
const requests = db.query(`SELECT method, url, status_code, response_headers, body_size
|
|
@@ -17440,7 +17503,7 @@ function detectAPIs(sessionId) {
|
|
|
17440
17503
|
}
|
|
17441
17504
|
const apis = Array.from(seen.values());
|
|
17442
17505
|
for (const api of apis) {
|
|
17443
|
-
const id =
|
|
17506
|
+
const id = randomUUID13();
|
|
17444
17507
|
db.prepare("INSERT OR IGNORE INTO api_endpoints (id, session_id, url, method, status_code, content_type) VALUES (?, ?, ?, ?, ?, ?)").run(id, sessionId, api.url, api.method, api.status_code, api.content_type);
|
|
17445
17508
|
}
|
|
17446
17509
|
return apis;
|
|
@@ -17545,13 +17608,13 @@ __export(exports_datasets, {
|
|
|
17545
17608
|
exportDataset: () => exportDataset,
|
|
17546
17609
|
deleteDataset: () => deleteDataset
|
|
17547
17610
|
});
|
|
17548
|
-
import { randomUUID as
|
|
17611
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
17549
17612
|
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync11 } from "fs";
|
|
17550
17613
|
import { join as join11 } from "path";
|
|
17551
17614
|
import { homedir as homedir10 } from "os";
|
|
17552
17615
|
function saveDataset(data) {
|
|
17553
17616
|
const db = getDatabase();
|
|
17554
|
-
const id =
|
|
17617
|
+
const id = randomUUID14();
|
|
17555
17618
|
const existing = db.query("SELECT id FROM datasets WHERE name = ?").get(data.name);
|
|
17556
17619
|
if (existing) {
|
|
17557
17620
|
db.prepare("UPDATE datasets SET data = ?, row_count = ?, source_url = ?, schema = ?, last_refresh = datetime('now'), updated_at = datetime('now') WHERE name = ?").run(JSON.stringify(data.rows), data.rows.length, data.sourceUrl ?? null, data.schema ? JSON.stringify(data.schema) : null, data.name);
|
|
@@ -22442,7 +22505,7 @@ import { Database as Database3 } from "bun:sqlite";
|
|
|
22442
22505
|
import { mkdirSync as mkdirSync13 } from "fs";
|
|
22443
22506
|
import { join as join14, dirname as dirname6 } from "path";
|
|
22444
22507
|
import { homedir as homedir13 } from "os";
|
|
22445
|
-
import { randomUUID as
|
|
22508
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
22446
22509
|
import { mkdirSync as mkdirSync23, copyFileSync as copyFileSync3, statSync as statSync3 } from "fs";
|
|
22447
22510
|
import { join as join34 } from "path";
|
|
22448
22511
|
import { homedir as homedir33 } from "os";
|
|
@@ -22822,7 +22885,7 @@ function guessMimeType(name) {
|
|
|
22822
22885
|
function sendMessage(opts) {
|
|
22823
22886
|
const db2 = getDb();
|
|
22824
22887
|
const explicitSession = opts.session_id && opts.session_id.trim().length > 0 ? opts.session_id : undefined;
|
|
22825
|
-
const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${
|
|
22888
|
+
const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${randomUUID15().slice(0, 8)}`);
|
|
22826
22889
|
const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
|
|
22827
22890
|
const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
|
|
22828
22891
|
const blocking = opts.blocking ? 1 : 0;
|
|
@@ -34511,7 +34574,7 @@ __export(exports_cron_manager, {
|
|
|
34511
34574
|
deleteCronJob: () => deleteCronJob,
|
|
34512
34575
|
createCronJob: () => createCronJob
|
|
34513
34576
|
});
|
|
34514
|
-
import { randomUUID as
|
|
34577
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
34515
34578
|
function ensureCronTable() {
|
|
34516
34579
|
const db2 = getDatabase();
|
|
34517
34580
|
db2.exec(`
|
|
@@ -34540,7 +34603,7 @@ function ensureCronTable() {
|
|
|
34540
34603
|
function createCronJob(schedule, task, name) {
|
|
34541
34604
|
ensureCronTable();
|
|
34542
34605
|
const db2 = getDatabase();
|
|
34543
|
-
const id =
|
|
34606
|
+
const id = randomUUID16();
|
|
34544
34607
|
db2.prepare(`
|
|
34545
34608
|
INSERT INTO cron_jobs (id, name, schedule, task_json, enabled)
|
|
34546
34609
|
VALUES (?, ?, ?, ?, 1)
|
|
@@ -34598,7 +34661,7 @@ function getCronEvents(jobId, limit = 10) {
|
|
|
34598
34661
|
async function executeCronJob(job) {
|
|
34599
34662
|
ensureCronTable();
|
|
34600
34663
|
const db2 = getDatabase();
|
|
34601
|
-
const eventId =
|
|
34664
|
+
const eventId = randomUUID16();
|
|
34602
34665
|
const startedAt = new Date().toISOString();
|
|
34603
34666
|
db2.prepare("INSERT INTO cron_events (id, job_id, started_at) VALUES (?, ?, ?)").run(eventId, job.id, startedAt);
|
|
34604
34667
|
try {
|
|
@@ -34689,7 +34752,7 @@ __export(exports_url_watcher, {
|
|
|
34689
34752
|
deleteWatchJob: () => deleteWatchJob,
|
|
34690
34753
|
createWatchJob: () => createWatchJob
|
|
34691
34754
|
});
|
|
34692
|
-
import { randomUUID as
|
|
34755
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
34693
34756
|
import { createHash } from "crypto";
|
|
34694
34757
|
function ensureWatchTables() {
|
|
34695
34758
|
const db2 = getDatabase();
|
|
@@ -34721,7 +34784,7 @@ function ensureWatchTables() {
|
|
|
34721
34784
|
function createWatchJob(url, schedule, opts) {
|
|
34722
34785
|
ensureWatchTables();
|
|
34723
34786
|
const db2 = getDatabase();
|
|
34724
|
-
const id =
|
|
34787
|
+
const id = randomUUID17();
|
|
34725
34788
|
db2.prepare(`
|
|
34726
34789
|
INSERT INTO watch_jobs (id, name, url, schedule, selector, extract_schema, enabled)
|
|
34727
34790
|
VALUES (?, ?, ?, ?, ?, ?, 1)
|
|
@@ -34757,7 +34820,7 @@ function getWatchEvents(watchId, limit = 20) {
|
|
|
34757
34820
|
async function checkWatchJob(job) {
|
|
34758
34821
|
ensureWatchTables();
|
|
34759
34822
|
const db2 = getDatabase();
|
|
34760
|
-
const eventId =
|
|
34823
|
+
const eventId = randomUUID17();
|
|
34761
34824
|
const checkedAt = new Date().toISOString();
|
|
34762
34825
|
let newContent = "";
|
|
34763
34826
|
try {
|
|
@@ -41384,13 +41447,13 @@ server.tool("browser_profile_delete", "Delete a saved browser profile", { name:
|
|
|
41384
41447
|
return err(e);
|
|
41385
41448
|
}
|
|
41386
41449
|
});
|
|
41387
|
-
server.tool("browser_script_run", "Run a saved login script \u2014
|
|
41450
|
+
server.tool("browser_script_run", "Run a saved login script asynchronously. Returns a job_id immediately \u2014 poll with browser_script_status for step-by-step progress. Combines browser actions + connector calls (e.g. magic link login via Gmail).", {
|
|
41388
41451
|
name: exports_external.string().describe("Script name (e.g. 'usestable')"),
|
|
41389
41452
|
session_id: exports_external.string().optional(),
|
|
41390
41453
|
variables: exports_external.record(exports_external.string()).optional().describe("Override script variables (e.g. {email: 'foo@bar.com'})")
|
|
41391
41454
|
}, async ({ name, session_id, variables }) => {
|
|
41392
41455
|
try {
|
|
41393
|
-
const { loadScript: loadScript2,
|
|
41456
|
+
const { loadScript: loadScript2, runScriptAsync: runScriptAsync2 } = await Promise.resolve().then(() => (init_login_scripts(), exports_login_scripts));
|
|
41394
41457
|
const script = loadScript2(name);
|
|
41395
41458
|
if (!script)
|
|
41396
41459
|
return err(new Error(`Script '${name}' not found. Use browser_script_list to see available scripts.`));
|
|
@@ -41400,12 +41463,29 @@ server.tool("browser_script_run", "Run a saved login script \u2014 multi-step wo
|
|
|
41400
41463
|
sid = resolveSessionId(session_id);
|
|
41401
41464
|
page = getSessionPage(sid);
|
|
41402
41465
|
} else {
|
|
41403
|
-
const
|
|
41404
|
-
sid =
|
|
41405
|
-
page =
|
|
41466
|
+
const result = await createSession2({ headless: true });
|
|
41467
|
+
sid = result.session.id;
|
|
41468
|
+
page = result.page;
|
|
41406
41469
|
}
|
|
41407
|
-
const
|
|
41408
|
-
return json({
|
|
41470
|
+
const jobId = runScriptAsync2(script, page, variables ?? {});
|
|
41471
|
+
return json({ job_id: jobId, session_id: sid, script: name, total_steps: script.steps.length, message: "Script running in background. Poll with browser_script_status for progress." });
|
|
41472
|
+
} catch (e) {
|
|
41473
|
+
return err(e);
|
|
41474
|
+
}
|
|
41475
|
+
});
|
|
41476
|
+
server.tool("browser_script_status", "Check the progress of a running login script. Shows current step, step-by-step log with durations, and final result when complete.", { job_id: exports_external.string() }, async ({ job_id }) => {
|
|
41477
|
+
try {
|
|
41478
|
+
const { getJob: getJob2 } = await Promise.resolve().then(() => (init_login_scripts(), exports_login_scripts));
|
|
41479
|
+
const job = getJob2(job_id);
|
|
41480
|
+
if (!job)
|
|
41481
|
+
return err(new Error(`Job '${job_id}' not found`));
|
|
41482
|
+
return json({
|
|
41483
|
+
status: job.status,
|
|
41484
|
+
progress: `${job.current_step}/${job.total_steps}`,
|
|
41485
|
+
current_step: job.current_step_description,
|
|
41486
|
+
steps_log: job.steps_log,
|
|
41487
|
+
result: job.result ?? undefined
|
|
41488
|
+
});
|
|
41409
41489
|
} catch (e) {
|
|
41410
41490
|
return err(e);
|
|
41411
41491
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/browser",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "General-purpose browser agent toolkit — Playwright, Chrome DevTools Protocol, Lightpanda with auto engine selection. CLI + MCP + REST + SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|