@hasna/browser 0.2.2 → 0.2.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/index.js CHANGED
@@ -19370,7 +19370,8 @@ __export(exports_login_scripts, {
19370
19370
  listJobs: () => listJobs,
19371
19371
  getJob: () => getJob,
19372
19372
  deleteScript: () => deleteScript,
19373
- createUsestableScript: () => createUsestableScript
19373
+ createScriptFromJSON: () => createScriptFromJSON,
19374
+ createScriptFromFile: () => createScriptFromFile
19374
19375
  });
19375
19376
  import { randomUUID as randomUUID10 } from "crypto";
19376
19377
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync8, readdirSync as readdirSync4 } from "fs";
@@ -19623,6 +19624,9 @@ async function runConnectorStep(step, vars) {
19623
19624
  vars[step.save_as] = result.stdout;
19624
19625
  }
19625
19626
  }
19627
+ function decodeHtmlEntities(str) {
19628
+ return str.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&#x27;/g, "'");
19629
+ }
19626
19630
  function runExtractStep(step, vars) {
19627
19631
  const saveTo = step.save_as ?? "extracted";
19628
19632
  if (step.pattern) {
@@ -19630,7 +19634,7 @@ function runExtractStep(step, vars) {
19630
19634
  const regex = new RegExp(step.pattern);
19631
19635
  const match = regex.exec(source);
19632
19636
  if (match) {
19633
- vars[saveTo] = match[1] ?? match[0];
19637
+ vars[saveTo] = decodeHtmlEntities(match[1] ?? match[0]);
19634
19638
  }
19635
19639
  }
19636
19640
  if (step.json_path) {
@@ -19645,56 +19649,30 @@ function runExtractStep(step, vars) {
19645
19649
  } catch {}
19646
19650
  }
19647
19651
  }
19648
- function createUsestableScript(email) {
19652
+ function createScriptFromJSON(jsonStr) {
19653
+ const parsed = JSON.parse(jsonStr);
19654
+ if (!parsed.name)
19655
+ throw new Error("Script must have a 'name' field");
19656
+ if (!parsed.domain)
19657
+ throw new Error("Script must have a 'domain' field");
19658
+ if (!parsed.steps || !Array.isArray(parsed.steps) || parsed.steps.length === 0) {
19659
+ throw new Error("Script must have a non-empty 'steps' array");
19660
+ }
19649
19661
  return {
19650
- name: "usestable",
19651
- domain: "dashboard.usestable.com",
19652
- description: "Login to Stable via magic link (email \u2192 Gmail \u2192 click link)",
19653
- variables: { email },
19654
- steps: [
19655
- { type: "browser", action: "navigate", url: "https://dashboard.usestable.com/login", description: "Go to login page" },
19656
- { type: "browser", action: "type", selector: "input", value: "{{email}}", description: "Enter email" },
19657
- { type: "browser", action: "click_text", text: "Continue", description: "Click Continue" },
19658
- { type: "wait", seconds: 1, description: "Wait for login options" },
19659
- { type: "browser", action: "click_text", text: "Send login link", description: "Request magic link" },
19660
- { type: "wait", seconds: 5, description: "Wait for email delivery" },
19661
- {
19662
- type: "connector",
19663
- connector: "gmail",
19664
- args: ["search", "from:authenticate.usestable.com newer_than:5m", "-n", "1"],
19665
- description: "Search Gmail for magic link email"
19666
- },
19667
- {
19668
- type: "extract",
19669
- pattern: "id:\\s*([a-f0-9]+)",
19670
- save_as: "email_id",
19671
- description: "Extract email ID from search results"
19672
- },
19673
- {
19674
- type: "connector",
19675
- connector: "gmail",
19676
- args: ["messages", "read", "{{email_id}}", "--body", "--html"],
19677
- save_as: "email_body",
19678
- description: "Read the magic link email"
19679
- },
19680
- {
19681
- type: "extract",
19682
- pattern: "href='(https://dashboard\\.usestable\\.com/login\\?[^']+)'",
19683
- check: "email_body",
19684
- save_as: "magic_link",
19685
- description: "Extract magic link URL from email HTML"
19686
- },
19687
- { type: "browser", action: "navigate", url: "{{magic_link}}", description: "Open magic link" },
19688
- { type: "wait", seconds: 2, description: "Wait for page to load" },
19689
- { type: "browser", action: "type", selector: "input", value: "{{email}}", description: "Re-enter email" },
19690
- { type: "browser", action: "click_text", text: "Login", description: "Click Login" },
19691
- { type: "browser", action: "wait_for_navigation", timeout: 15000, description: "Wait for redirect to dashboard" },
19692
- { type: "save_state", name: "usestable", description: "Save auth state" }
19693
- ],
19662
+ name: parsed.name,
19663
+ domain: parsed.domain,
19664
+ description: parsed.description ?? "",
19665
+ variables: parsed.variables ?? {},
19666
+ steps: parsed.steps,
19694
19667
  created_at: new Date().toISOString(),
19695
19668
  updated_at: new Date().toISOString()
19696
19669
  };
19697
19670
  }
19671
+ function createScriptFromFile(filePath) {
19672
+ if (!existsSync6(filePath))
19673
+ throw new Error(`File not found: ${filePath}`);
19674
+ return createScriptFromJSON(readFileSync4(filePath, "utf8"));
19675
+ }
19698
19676
  var activeJobs;
19699
19677
  var init_login_scripts = __esm(() => {
19700
19678
  init_schema();
@@ -45328,14 +45306,19 @@ scriptCmd.command("list").description("List saved login scripts").option("--json
45328
45306
  });
45329
45307
  }
45330
45308
  });
45331
- scriptCmd.command("create-usestable").description("Create the usestable.com login script (magic link via Gmail)").option("--email <email>", "Email address", "andrei@hasna.com").action(async (opts) => {
45332
- const { createUsestableScript: createUsestableScript2, saveScript: saveScript2 } = await Promise.resolve().then(() => (init_login_scripts(), exports_login_scripts));
45333
- const script = createUsestableScript2(opts.email);
45334
- const path = saveScript2(script);
45335
- console.log(chalk.green(`\u2713 Script saved: ${script.name}`));
45336
- console.log(chalk.gray(` Path: ${path}`));
45337
- console.log(chalk.gray(` Steps: ${script.steps.length}`));
45338
- console.log(chalk.gray(` Run with: browser script run usestable`));
45309
+ scriptCmd.command("create <file>").description("Create a script from a JSON file (see docs for schema)").action(async (file) => {
45310
+ const { createScriptFromFile: createScriptFromFile2, saveScript: saveScript2 } = await Promise.resolve().then(() => (init_login_scripts(), exports_login_scripts));
45311
+ try {
45312
+ const script = createScriptFromFile2(file);
45313
+ const path = saveScript2(script);
45314
+ console.log(chalk.green(`\u2713 Script saved: ${script.name}`));
45315
+ console.log(chalk.gray(` Domain: ${script.domain}`));
45316
+ console.log(chalk.gray(` Steps: ${script.steps.length}`));
45317
+ console.log(chalk.gray(` Path: ${path}`));
45318
+ console.log(chalk.gray(` Run with: browser script run ${script.name}`));
45319
+ } catch (err2) {
45320
+ console.log(chalk.red(`Error: ${err2 instanceof Error ? err2.message : String(err2)}`));
45321
+ }
45339
45322
  });
45340
45323
  scriptCmd.command("show <name>").description("Show script details").action(async (name) => {
45341
45324
  const { loadScript: loadScript2 } = await Promise.resolve().then(() => (init_login_scripts(), exports_login_scripts));
@@ -80,5 +80,6 @@ export declare function runScript(script: LoginScript, page: Page, overrides?: R
80
80
  * Poll with getJob(jobId) for progress.
81
81
  */
82
82
  export declare function runScriptAsync(script: LoginScript, page: Page, overrides?: Record<string, string>): string;
83
- export declare function createUsestableScript(email: string): LoginScript;
83
+ export declare function createScriptFromJSON(jsonStr: string): LoginScript;
84
+ export declare function createScriptFromFile(filePath: string): LoginScript;
84
85
  //# 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":"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"}
1
+ {"version":3,"file":"login-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/login-scripts.ts"],"names":[],"mappings":"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"}
package/dist/mcp/index.js CHANGED
@@ -17127,7 +17127,8 @@ __export(exports_login_scripts, {
17127
17127
  listJobs: () => listJobs,
17128
17128
  getJob: () => getJob,
17129
17129
  deleteScript: () => deleteScript,
17130
- createUsestableScript: () => createUsestableScript
17130
+ createScriptFromJSON: () => createScriptFromJSON,
17131
+ createScriptFromFile: () => createScriptFromFile
17131
17132
  });
17132
17133
  import { randomUUID as randomUUID12 } from "crypto";
17133
17134
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync10, readdirSync as readdirSync5 } from "fs";
@@ -17380,6 +17381,9 @@ async function runConnectorStep(step, vars) {
17380
17381
  vars[step.save_as] = result.stdout;
17381
17382
  }
17382
17383
  }
17384
+ function decodeHtmlEntities(str) {
17385
+ return str.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&#x27;/g, "'");
17386
+ }
17383
17387
  function runExtractStep(step, vars) {
17384
17388
  const saveTo = step.save_as ?? "extracted";
17385
17389
  if (step.pattern) {
@@ -17387,7 +17391,7 @@ function runExtractStep(step, vars) {
17387
17391
  const regex = new RegExp(step.pattern);
17388
17392
  const match = regex.exec(source);
17389
17393
  if (match) {
17390
- vars[saveTo] = match[1] ?? match[0];
17394
+ vars[saveTo] = decodeHtmlEntities(match[1] ?? match[0]);
17391
17395
  }
17392
17396
  }
17393
17397
  if (step.json_path) {
@@ -17402,56 +17406,30 @@ function runExtractStep(step, vars) {
17402
17406
  } catch {}
17403
17407
  }
17404
17408
  }
17405
- function createUsestableScript(email) {
17409
+ function createScriptFromJSON(jsonStr) {
17410
+ const parsed = JSON.parse(jsonStr);
17411
+ if (!parsed.name)
17412
+ throw new Error("Script must have a 'name' field");
17413
+ if (!parsed.domain)
17414
+ throw new Error("Script must have a 'domain' field");
17415
+ if (!parsed.steps || !Array.isArray(parsed.steps) || parsed.steps.length === 0) {
17416
+ throw new Error("Script must have a non-empty 'steps' array");
17417
+ }
17406
17418
  return {
17407
- name: "usestable",
17408
- domain: "dashboard.usestable.com",
17409
- description: "Login to Stable via magic link (email \u2192 Gmail \u2192 click link)",
17410
- variables: { email },
17411
- steps: [
17412
- { type: "browser", action: "navigate", url: "https://dashboard.usestable.com/login", description: "Go to login page" },
17413
- { type: "browser", action: "type", selector: "input", value: "{{email}}", description: "Enter email" },
17414
- { type: "browser", action: "click_text", text: "Continue", description: "Click Continue" },
17415
- { type: "wait", seconds: 1, description: "Wait for login options" },
17416
- { type: "browser", action: "click_text", text: "Send login link", description: "Request magic link" },
17417
- { type: "wait", seconds: 5, description: "Wait for email delivery" },
17418
- {
17419
- type: "connector",
17420
- connector: "gmail",
17421
- args: ["search", "from:authenticate.usestable.com newer_than:5m", "-n", "1"],
17422
- description: "Search Gmail for magic link email"
17423
- },
17424
- {
17425
- type: "extract",
17426
- pattern: "id:\\s*([a-f0-9]+)",
17427
- save_as: "email_id",
17428
- description: "Extract email ID from search results"
17429
- },
17430
- {
17431
- type: "connector",
17432
- connector: "gmail",
17433
- args: ["messages", "read", "{{email_id}}", "--body", "--html"],
17434
- save_as: "email_body",
17435
- description: "Read the magic link email"
17436
- },
17437
- {
17438
- type: "extract",
17439
- pattern: "href='(https://dashboard\\.usestable\\.com/login\\?[^']+)'",
17440
- check: "email_body",
17441
- save_as: "magic_link",
17442
- description: "Extract magic link URL from email HTML"
17443
- },
17444
- { type: "browser", action: "navigate", url: "{{magic_link}}", description: "Open magic link" },
17445
- { type: "wait", seconds: 2, description: "Wait for page to load" },
17446
- { type: "browser", action: "type", selector: "input", value: "{{email}}", description: "Re-enter email" },
17447
- { type: "browser", action: "click_text", text: "Login", description: "Click Login" },
17448
- { type: "browser", action: "wait_for_navigation", timeout: 15000, description: "Wait for redirect to dashboard" },
17449
- { type: "save_state", name: "usestable", description: "Save auth state" }
17450
- ],
17419
+ name: parsed.name,
17420
+ domain: parsed.domain,
17421
+ description: parsed.description ?? "",
17422
+ variables: parsed.variables ?? {},
17423
+ steps: parsed.steps,
17451
17424
  created_at: new Date().toISOString(),
17452
17425
  updated_at: new Date().toISOString()
17453
17426
  };
17454
17427
  }
17428
+ function createScriptFromFile(filePath) {
17429
+ if (!existsSync6(filePath))
17430
+ throw new Error(`File not found: ${filePath}`);
17431
+ return createScriptFromJSON(readFileSync4(filePath, "utf8"));
17432
+ }
17455
17433
  var activeJobs;
17456
17434
  var init_login_scripts = __esm(() => {
17457
17435
  init_schema();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/browser",
3
- "version": "0.2.2",
3
+ "version": "0.2.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",