@hasna/browser 0.4.3 → 0.4.4
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/commands/tools.d.ts.map +1 -1
- package/dist/cli/index.js +45953 -13754
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/index.js +63 -25
- package/dist/lib/screenshot.d.ts.map +1 -1
- package/dist/mcp/index.js +47058 -15936
- package/dist/server/index.js +63 -25
- package/package.json +1 -1
- package/dist/lib/login-scripts.d.ts +0 -89
- package/dist/lib/login-scripts.d.ts.map +0 -1
package/dist/server/index.js
CHANGED
|
@@ -5,39 +5,60 @@ var __defProp = Object.defineProperty;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
8
13
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
9
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
23
|
for (let key of __getOwnPropNames(mod))
|
|
12
24
|
if (!__hasOwnProp.call(to, key))
|
|
13
25
|
__defProp(to, key, {
|
|
14
|
-
get: (
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
15
27
|
enumerable: true
|
|
16
28
|
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
17
31
|
return to;
|
|
18
32
|
};
|
|
19
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
20
33
|
var __toCommonJS = (from) => {
|
|
21
|
-
var entry = __moduleCache.get(from), desc;
|
|
34
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
22
35
|
if (entry)
|
|
23
36
|
return entry;
|
|
24
37
|
entry = __defProp({}, "__esModule", { value: true });
|
|
25
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
39
|
+
for (var key of __getOwnPropNames(from))
|
|
40
|
+
if (!__hasOwnProp.call(entry, key))
|
|
41
|
+
__defProp(entry, key, {
|
|
42
|
+
get: __accessProp.bind(from, key),
|
|
43
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
44
|
+
});
|
|
45
|
+
}
|
|
30
46
|
__moduleCache.set(from, entry);
|
|
31
47
|
return entry;
|
|
32
48
|
};
|
|
49
|
+
var __moduleCache;
|
|
33
50
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
51
|
+
var __returnValue = (v) => v;
|
|
52
|
+
function __exportSetter(name, newValue) {
|
|
53
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
54
|
+
}
|
|
34
55
|
var __export = (target, all) => {
|
|
35
56
|
for (var name in all)
|
|
36
57
|
__defProp(target, name, {
|
|
37
58
|
get: all[name],
|
|
38
59
|
enumerable: true,
|
|
39
60
|
configurable: true,
|
|
40
|
-
set: (
|
|
61
|
+
set: __exportSetter.bind(all, name)
|
|
41
62
|
});
|
|
42
63
|
};
|
|
43
64
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -121,11 +142,11 @@ import { homedir as homedir4 } from "os";
|
|
|
121
142
|
import { join as join4 } from "path";
|
|
122
143
|
import { join as join6, dirname } from "path";
|
|
123
144
|
import { homedir as homedir5, platform } from "os";
|
|
124
|
-
function
|
|
145
|
+
function __accessProp2(key) {
|
|
125
146
|
return this[key];
|
|
126
147
|
}
|
|
127
|
-
function
|
|
128
|
-
this[name] =
|
|
148
|
+
function __exportSetter2(name, newValue) {
|
|
149
|
+
this[name] = __returnValue2.bind(null, newValue);
|
|
129
150
|
}
|
|
130
151
|
function translateSql(sql, dialect) {
|
|
131
152
|
if (dialect === "sqlite")
|
|
@@ -1155,10 +1176,10 @@ class SyncProgressTracker {
|
|
|
1155
1176
|
}
|
|
1156
1177
|
}
|
|
1157
1178
|
}
|
|
1158
|
-
var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2,
|
|
1179
|
+
var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node2, __toESMCache_esm2, __toESM2 = (mod, isNodeMode, target) => {
|
|
1159
1180
|
var canCache = mod != null && typeof mod === "object";
|
|
1160
1181
|
if (canCache) {
|
|
1161
|
-
var cache = isNodeMode ?
|
|
1182
|
+
var cache = isNodeMode ? __toESMCache_node2 ??= new WeakMap : __toESMCache_esm2 ??= new WeakMap;
|
|
1162
1183
|
var cached = cache.get(mod);
|
|
1163
1184
|
if (cached)
|
|
1164
1185
|
return cached;
|
|
@@ -1168,19 +1189,19 @@ var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __t
|
|
|
1168
1189
|
for (let key of __getOwnPropNames2(mod))
|
|
1169
1190
|
if (!__hasOwnProp2.call(to, key))
|
|
1170
1191
|
__defProp2(to, key, {
|
|
1171
|
-
get:
|
|
1192
|
+
get: __accessProp2.bind(mod, key),
|
|
1172
1193
|
enumerable: true
|
|
1173
1194
|
});
|
|
1174
1195
|
if (canCache)
|
|
1175
1196
|
cache.set(mod, to);
|
|
1176
1197
|
return to;
|
|
1177
|
-
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports),
|
|
1198
|
+
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue2 = (v) => v, __export2 = (target, all) => {
|
|
1178
1199
|
for (var name in all)
|
|
1179
1200
|
__defProp2(target, name, {
|
|
1180
1201
|
get: all[name],
|
|
1181
1202
|
enumerable: true,
|
|
1182
1203
|
configurable: true,
|
|
1183
|
-
set:
|
|
1204
|
+
set: __exportSetter2.bind(all, name)
|
|
1184
1205
|
});
|
|
1185
1206
|
}, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), __require2, require_postgres_array, require_arrayParser, require_postgres_date, require_mutable, require_postgres_interval, require_postgres_bytea, require_textParsers, require_pg_int8, require_binaryParsers, require_builtins, require_pg_types, require_defaults, require_utils, require_utils_legacy, require_utils_webcrypto, require_utils2, require_cert_signatures, require_sasl, require_type_overrides, require_pg_connection_string, require_connection_parameters, require_result, require_query, require_messages, require_buffer_writer, require_serializer, require_buffer_reader, require_parser, require_dist, require_empty, require_stream, require_connection, require_split2, require_helper, require_lib, require_client, require_pg_pool, require_query2, require_client2, require_lib2, import_lib, Client, Pool, Connection, types, Query, DatabaseError, escapeIdentifier, escapeLiteral, Result, TypeOverrides, defaults, esm_default, init_esm, init_adapter, util, objectUtil, ZodParsedType, getParsedType = (data) => {
|
|
1186
1207
|
const t = typeof data;
|
|
@@ -9532,6 +9553,12 @@ function getDatabase(path) {
|
|
|
9532
9553
|
_db.exec("PRAGMA journal_mode=WAL;");
|
|
9533
9554
|
_db.exec("PRAGMA foreign_keys=ON;");
|
|
9534
9555
|
runMigrations(_db);
|
|
9556
|
+
try {
|
|
9557
|
+
const cols = _db.query("PRAGMA table_info(feedback)").all().map((c) => c.name);
|
|
9558
|
+
if (cols.length > 0 && !cols.includes("service")) {
|
|
9559
|
+
_db.exec("ALTER TABLE feedback ADD COLUMN service TEXT NOT NULL DEFAULT 'browser'");
|
|
9560
|
+
}
|
|
9561
|
+
} catch {}
|
|
9535
9562
|
return _db;
|
|
9536
9563
|
}
|
|
9537
9564
|
function resetDatabase() {
|
|
@@ -9837,12 +9864,12 @@ function runMigrations(db) {
|
|
|
9837
9864
|
version: 10,
|
|
9838
9865
|
sql: `
|
|
9839
9866
|
CREATE TABLE IF NOT EXISTS feedback (
|
|
9840
|
-
id TEXT PRIMARY KEY
|
|
9867
|
+
id TEXT PRIMARY KEY,
|
|
9868
|
+
service TEXT NOT NULL DEFAULT 'browser',
|
|
9869
|
+
version TEXT DEFAULT '',
|
|
9841
9870
|
message TEXT NOT NULL,
|
|
9842
|
-
email TEXT,
|
|
9843
|
-
|
|
9844
|
-
version TEXT,
|
|
9845
|
-
machine_id TEXT,
|
|
9871
|
+
email TEXT DEFAULT '',
|
|
9872
|
+
machine_id TEXT DEFAULT '',
|
|
9846
9873
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
9847
9874
|
);
|
|
9848
9875
|
`
|
|
@@ -19074,8 +19101,8 @@ async function takeScreenshot(page, opts) {
|
|
|
19074
19101
|
const timestamp = Date.now();
|
|
19075
19102
|
const format = opts?.format ?? "webp";
|
|
19076
19103
|
const compress = opts?.compress ?? true;
|
|
19077
|
-
const maxWidth = opts?.maxWidth ??
|
|
19078
|
-
const quality = opts?.quality ?? (format === "webp" ?
|
|
19104
|
+
const maxWidth = opts?.maxWidth ?? 1200;
|
|
19105
|
+
const quality = opts?.quality ?? (format === "webp" ? 80 : format === "jpeg" ? 70 : undefined);
|
|
19079
19106
|
const stem = String(timestamp);
|
|
19080
19107
|
const rawOpts = {
|
|
19081
19108
|
fullPage: opts?.fullPage ?? false,
|
|
@@ -19100,12 +19127,23 @@ async function takeScreenshot(page, opts) {
|
|
|
19100
19127
|
rawBuffer = await page.screenshot(rawOpts);
|
|
19101
19128
|
}
|
|
19102
19129
|
const originalSizeBytes = rawBuffer.length;
|
|
19130
|
+
const MAX_SIZE_BYTES = 500 * 1024;
|
|
19103
19131
|
let finalBuffer;
|
|
19104
19132
|
let compressed = true;
|
|
19105
19133
|
let fallback = false;
|
|
19106
19134
|
try {
|
|
19107
19135
|
if (compress && format !== "png") {
|
|
19108
|
-
finalBuffer = await compressBuffer(rawBuffer, format, quality ??
|
|
19136
|
+
finalBuffer = await compressBuffer(rawBuffer, format, quality ?? 70, maxWidth);
|
|
19137
|
+
if (finalBuffer.length > MAX_SIZE_BYTES) {
|
|
19138
|
+
const reducedFormat = format === "webp" ? "webp" : "jpeg";
|
|
19139
|
+
for (const q of [60, 50, 40, 30]) {
|
|
19140
|
+
const attempt = await compressBuffer(rawBuffer, reducedFormat, q, maxWidth);
|
|
19141
|
+
if (attempt.length <= MAX_SIZE_BYTES) {
|
|
19142
|
+
finalBuffer = attempt;
|
|
19143
|
+
break;
|
|
19144
|
+
}
|
|
19145
|
+
}
|
|
19146
|
+
}
|
|
19109
19147
|
} else if (compress && format === "png") {
|
|
19110
19148
|
finalBuffer = await compressBuffer(rawBuffer, "png", quality ?? 9, maxWidth);
|
|
19111
19149
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/browser",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
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",
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Login scripts — multi-step workflows that combine browser actions + connector calls.
|
|
3
|
-
* Supports variable interpolation, regex extraction, conditions, and state saving.
|
|
4
|
-
*
|
|
5
|
-
* Usage: save a script once, replay with `browser login-script <name>`
|
|
6
|
-
*/
|
|
7
|
-
import type { Page } from "playwright";
|
|
8
|
-
export type StepType = "browser" | "connector" | "extract" | "wait" | "condition" | "save_state" | "ai";
|
|
9
|
-
export interface ScriptStep {
|
|
10
|
-
type: StepType;
|
|
11
|
-
description?: string;
|
|
12
|
-
action?: "navigate" | "type" | "click" | "click_text" | "wait_for_navigation" | "wait_for_text" | "snapshot";
|
|
13
|
-
url?: string;
|
|
14
|
-
selector?: string;
|
|
15
|
-
text?: string;
|
|
16
|
-
value?: string;
|
|
17
|
-
timeout?: number;
|
|
18
|
-
connector?: string;
|
|
19
|
-
operation?: string;
|
|
20
|
-
args?: string[];
|
|
21
|
-
format?: string;
|
|
22
|
-
pattern?: string;
|
|
23
|
-
json_path?: string;
|
|
24
|
-
save_as?: string;
|
|
25
|
-
prompt?: string;
|
|
26
|
-
model?: string;
|
|
27
|
-
response_format?: "text" | "json";
|
|
28
|
-
seconds?: number;
|
|
29
|
-
check?: string;
|
|
30
|
-
equals?: string;
|
|
31
|
-
contains?: string;
|
|
32
|
-
skip_to?: number;
|
|
33
|
-
name?: string;
|
|
34
|
-
}
|
|
35
|
-
export interface LoginScript {
|
|
36
|
-
name: string;
|
|
37
|
-
domain: string;
|
|
38
|
-
description?: string;
|
|
39
|
-
variables: Record<string, string>;
|
|
40
|
-
steps: ScriptStep[];
|
|
41
|
-
created_at: string;
|
|
42
|
-
updated_at: string;
|
|
43
|
-
}
|
|
44
|
-
export interface ScriptRunResult {
|
|
45
|
-
success: boolean;
|
|
46
|
-
steps_executed: number;
|
|
47
|
-
steps_failed: number;
|
|
48
|
-
variables: Record<string, string>;
|
|
49
|
-
errors: string[];
|
|
50
|
-
duration_ms: number;
|
|
51
|
-
}
|
|
52
|
-
export interface ScriptJob {
|
|
53
|
-
id: string;
|
|
54
|
-
script_name: string;
|
|
55
|
-
status: "running" | "completed" | "failed";
|
|
56
|
-
current_step: number;
|
|
57
|
-
total_steps: number;
|
|
58
|
-
current_step_description: string;
|
|
59
|
-
steps_log: Array<{
|
|
60
|
-
step: number;
|
|
61
|
-
type: string;
|
|
62
|
-
description: string;
|
|
63
|
-
status: "ok" | "failed" | "running";
|
|
64
|
-
duration_ms?: number;
|
|
65
|
-
error?: string;
|
|
66
|
-
}>;
|
|
67
|
-
result?: ScriptRunResult;
|
|
68
|
-
started_at: string;
|
|
69
|
-
}
|
|
70
|
-
export declare function getJob(jobId: string): ScriptJob | null;
|
|
71
|
-
export declare function listJobs(): ScriptJob[];
|
|
72
|
-
export declare function saveScript(script: LoginScript): string;
|
|
73
|
-
export declare function loadScript(name: string): LoginScript | null;
|
|
74
|
-
export declare function listScripts(): Array<{
|
|
75
|
-
name: string;
|
|
76
|
-
domain: string;
|
|
77
|
-
description?: string;
|
|
78
|
-
steps: number;
|
|
79
|
-
}>;
|
|
80
|
-
export declare function deleteScript(name: string): boolean;
|
|
81
|
-
export declare function runScript(script: LoginScript, page: Page, overrides?: Record<string, string>, jobId?: string): Promise<ScriptRunResult>;
|
|
82
|
-
/**
|
|
83
|
-
* Run a script asynchronously — returns immediately with a job ID.
|
|
84
|
-
* Poll with getJob(jobId) for progress.
|
|
85
|
-
*/
|
|
86
|
-
export declare function runScriptAsync(script: LoginScript, page: Page, overrides?: Record<string, string>): string;
|
|
87
|
-
export declare function createScriptFromJSON(jsonStr: string): LoginScript;
|
|
88
|
-
export declare function createScriptFromFile(filePath: string): LoginScript;
|
|
89
|
-
//# sourceMappingURL=login-scripts.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/login-scripts.ts"],"names":[],"mappings":"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"}
|