wb-browser-runtime 0.5.1 → 0.5.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/README.md +6 -3
- package/bin/wb-browser-runtime.js +51 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,9 +25,12 @@ specific run.
|
|
|
25
25
|
- `BROWSERBASE_API_KEY`
|
|
26
26
|
- `BROWSERBASE_PROJECT_ID`
|
|
27
27
|
|
|
28
|
-
Verb arguments support
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
Verb arguments support two substitutions at dispatch time:
|
|
29
|
+
|
|
30
|
+
- `{{ env.NAME }}` — reads `process.env.NAME`. Use for static secrets injected via Doppler / the agent's env.
|
|
31
|
+
- `{{ artifacts.NAME }}` — reads `$WB_ARTIFACTS_DIR/NAME.txt` (falling back to `$WB_ARTIFACTS_DIR/NAME`). Use for dynamic values produced by an earlier bash cell — OTPs, magic-link URLs, export IDs, anything polled from an external system mid-run. Each read happens per-verb with no caching, so writes land immediately.
|
|
32
|
+
|
|
33
|
+
Both forms are redacted in stdout summaries — only the verb name + selector make it into the log.
|
|
31
34
|
|
|
32
35
|
## Optional: anti-detection
|
|
33
36
|
|
|
@@ -14,9 +14,13 @@
|
|
|
14
14
|
// BROWSERBASE_API_KEY
|
|
15
15
|
// BROWSERBASE_PROJECT_ID
|
|
16
16
|
//
|
|
17
|
-
// Verb args support
|
|
18
|
-
//
|
|
19
|
-
//
|
|
17
|
+
// Verb args support two substitutions, expanded recursively at dispatch time:
|
|
18
|
+
// {{ env.NAME }} → process.env.NAME
|
|
19
|
+
// {{ artifacts.NAME }} → contents of $WB_ARTIFACTS_DIR/NAME.txt (or .../NAME)
|
|
20
|
+
// The artifacts form lets an earlier bash cell compute a value — OTP, magic
|
|
21
|
+
// link, export id — and feed it into a later browser verb without a sidecar
|
|
22
|
+
// round-trip. Credentials passed via either form never hit stdout — only the
|
|
23
|
+
// verb name + selector make it into the summary.
|
|
20
24
|
|
|
21
25
|
import readline from "node:readline";
|
|
22
26
|
import { chromium } from "playwright-core";
|
|
@@ -45,7 +49,7 @@ const SUPPORTS = [
|
|
|
45
49
|
];
|
|
46
50
|
|
|
47
51
|
const BB_BASE = "https://api.browserbase.com";
|
|
48
|
-
const VERSION = "0.5.
|
|
52
|
+
const VERSION = "0.5.3";
|
|
49
53
|
|
|
50
54
|
// --- Recording config -------------------------------------------------------
|
|
51
55
|
//
|
|
@@ -576,22 +580,44 @@ function sanitize(s) {
|
|
|
576
580
|
return String(s || "default").replace(/[^A-Za-z0-9_-]+/g, "_");
|
|
577
581
|
}
|
|
578
582
|
|
|
579
|
-
// --- {{ env.X }} substitution
|
|
583
|
+
// --- {{ env.X }} / {{ artifacts.X }} substitution --------------------------
|
|
580
584
|
|
|
581
585
|
const ENV_RE = /\{\{\s*env\.([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;
|
|
586
|
+
const ARTIFACT_RE = /\{\{\s*artifacts\.([A-Za-z_][A-Za-z0-9_.-]*)\s*\}\}/g;
|
|
587
|
+
|
|
588
|
+
function readArtifact(name) {
|
|
589
|
+
const dir = (process.env.WB_ARTIFACTS_DIR || "").trim();
|
|
590
|
+
if (!dir) {
|
|
591
|
+
log(`[warn] artifacts.${name} referenced but WB_ARTIFACTS_DIR is not set`);
|
|
592
|
+
return "";
|
|
593
|
+
}
|
|
594
|
+
// Per-verb read (no cache) so a bash cell that writes the artifact between
|
|
595
|
+
// slices is always picked up by the next browser verb.
|
|
596
|
+
for (const p of [path.join(dir, `${name}.txt`), path.join(dir, name)]) {
|
|
597
|
+
try {
|
|
598
|
+
return readFileSync(p, "utf8").trimEnd();
|
|
599
|
+
} catch {
|
|
600
|
+
// try next candidate
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
log(`[warn] artifact ${name} not found in ${dir}; leaving placeholder`);
|
|
604
|
+
return "";
|
|
605
|
+
}
|
|
582
606
|
|
|
583
607
|
function expand(value) {
|
|
584
608
|
if (typeof value === "string") {
|
|
585
|
-
return value
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
609
|
+
return value
|
|
610
|
+
.replace(ENV_RE, (_, name) => {
|
|
611
|
+
const v = process.env[name];
|
|
612
|
+
if (v === undefined) {
|
|
613
|
+
// Leave the placeholder visible so failures surface in stderr
|
|
614
|
+
// summaries instead of silently turning into empty strings.
|
|
615
|
+
log(`[warn] env var ${name} is not set; leaving placeholder`);
|
|
616
|
+
return "";
|
|
617
|
+
}
|
|
618
|
+
return v;
|
|
619
|
+
})
|
|
620
|
+
.replace(ARTIFACT_RE, (_, name) => readArtifact(name));
|
|
595
621
|
}
|
|
596
622
|
if (Array.isArray(value)) return value.map(expand);
|
|
597
623
|
if (value && typeof value === "object") {
|
|
@@ -656,9 +682,16 @@ async function runVerb(page, verb, index, ctx) {
|
|
|
656
682
|
return `${selector} (${state})`;
|
|
657
683
|
}
|
|
658
684
|
case "screenshot": {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
685
|
+
// Relative paths resolve into $WB_ARTIFACTS_DIR so wb's main-loop
|
|
686
|
+
// `artifacts.sync()` picks them up and uploads to R2. Absolute paths
|
|
687
|
+
// are respected as-is (escape hatch for one-off local dumps).
|
|
688
|
+
const requested = a.path ?? `screenshot-${Date.now()}.png`;
|
|
689
|
+
const artifactsDir = (process.env.WB_ARTIFACTS_DIR || "").trim();
|
|
690
|
+
const full = path.isAbsolute(requested)
|
|
691
|
+
? requested
|
|
692
|
+
: path.join(artifactsDir || ".", requested);
|
|
693
|
+
await page.screenshot({ path: full, fullPage: !!a.full_page });
|
|
694
|
+
return `→ ${requested}`;
|
|
662
695
|
}
|
|
663
696
|
case "extract": {
|
|
664
697
|
// Pull structured rows out of the page. Each `field` entry is either:
|
package/package.json
CHANGED