barebrowse 0.19.1 → 0.19.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.19.2] - 2026-07-11
4
+
5
+ ### Fixed
6
+
7
+ - **Firefox `saveState()` now writes `sameSite` capitalized** (`Lax`/`Strict`/`None`,
8
+ was BiDi's lowercase `lax`/`strict`/`none`). The only loader for a state file is
9
+ `connect({ storageState })`, which is CDP-only (`Network.setCookies`) and rejects
10
+ a lowercase enum — so the whole batch threw and every cookie was silently dropped,
11
+ making a Firefox-saved state useless for auth restore. Found by `/code-review` and
12
+ confirmed against real Firefox.
13
+ - **Firefox CLI/daemon `eval` accepts statement-form expressions again**
14
+ (`var x = 2; x * 3`). A Phase-4 wrapper (`await (${expr})`, added to flatten
15
+ objects) turned every statement list into a `SyntaxError` — a regression versus
16
+ the CDP `Runtime.evaluate` path. Now evaluates the raw expression (BiDi
17
+ `script.evaluate` has eval-semantics) and deserializes the `{type,value}` remote
18
+ value back to the plain value CDP's `returnByValue` yields, so deep objects stay
19
+ clean *and* statements work.
20
+ - **Firefox daemon console capture no longer dumps nested serialization** for
21
+ object/array console arguments — it falls back to the type name, matching the CDP
22
+ capture's `RemoteObject.description` ("Object").
23
+
3
24
  ## [0.19.1] - 2026-07-11
4
25
 
5
26
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "barebrowse",
3
- "version": "0.19.1",
3
+ "version": "0.19.2",
4
4
  "description": "Authenticated web browsing for autonomous agents via CDP. URL in, pruned ARIA snapshot out.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/daemon.js CHANGED
@@ -67,6 +67,31 @@ export function buildDaemonArgs(opts, absDir, initialUrl, cliPath) {
67
67
  return args;
68
68
  }
69
69
 
70
+ /**
71
+ * Convert a BiDi remote value ({type,value} — see script.evaluate) into the
72
+ * plain JS value CDP's `Runtime.evaluate({returnByValue:true})` yields, so an
73
+ * `eval` returns the same shape on both engines. BiDi serializes objects/arrays
74
+ * as entry lists ([[k,v],…] / [v,…]) rather than plain values; walk them back.
75
+ * @param {object} r - BiDi remote value
76
+ * @returns {*}
77
+ */
78
+ export function deserializeBiDi(r) {
79
+ if (!r || typeof r !== 'object') return r;
80
+ switch (r.type) {
81
+ case 'undefined': return undefined;
82
+ case 'null': return null;
83
+ case 'string': case 'number': case 'boolean': case 'bigint': return r.value;
84
+ case 'array': case 'set': return (r.value || []).map(deserializeBiDi);
85
+ case 'object': case 'map':
86
+ return Object.fromEntries(
87
+ (r.value || []).map(([k, v]) => [typeof k === 'object' ? deserializeBiDi(k) : k, deserializeBiDi(v)]),
88
+ );
89
+ // date/regexp/node/function/etc. — no plain-value equivalent; use the raw
90
+ // value if BiDi provided one, else the type name (matches CDP's coarseness).
91
+ default: return r.value !== undefined ? r.value : r.type;
92
+ }
93
+ }
94
+
70
95
  /**
71
96
  * Wire Firefox/BiDi console + network capture onto the daemon's log arrays.
72
97
  * The BiDi analogue of the CDP `Runtime.consoleAPICalled` / `Network.*`
@@ -99,8 +124,12 @@ export async function attachBiDiCapture(bidi, { consoleLogs, networkLogs, pendin
99
124
  // engines — BiDi says 'warn', CDP says 'warning'.
100
125
  type: e.method === 'warn' ? 'warning' : (e.method || e.level),
101
126
  timestamp: new Date().toISOString(),
127
+ // Primitive args carry a usable `.value`; objects/arrays/functions carry a
128
+ // nested {type,value} serialization we must NOT splat into the log (it's
129
+ // deep junk) — fall back to the type name, mirroring the CDP capture which
130
+ // logs a RemoteObject's `.description` ("Object") for non-primitives.
102
131
  args: Array.isArray(e.args) && e.args.length
103
- ? e.args.map((a) => a.value ?? a.type)
132
+ ? e.args.map((a) => (a.value !== undefined && typeof a.value !== 'object' ? a.value : a.type))
104
133
  : [e.text],
105
134
  });
106
135
  });
@@ -416,13 +445,20 @@ export async function runDaemon(opts, outputDir, initialUrl) {
416
445
  // Firefox/BiDi has no page.cdp — evaluate over BiDi in the active context.
417
446
  if (!page.cdp) {
418
447
  try {
419
- // BiDi's raw result.value serializes objects into a {type,value}
420
- // entries structure, not a plain object (CDP's returnByValue does).
421
- // Stringify + parse in-page so an object/array eval matches the CDP
422
- // shape (same trick readable() uses). `undefined` JSON `null`.
423
- const wrapped = `(async () => { const v = await (${expression}); return JSON.stringify(v === undefined ? null : v); })()`;
424
- const raw = await page.bidi.evaluate(page.context, wrapped, true);
425
- return { ok: true, value: raw == null ? null : JSON.parse(raw) };
448
+ // Evaluate the RAW expression: script.evaluate has eval-semantics, so
449
+ // statement lists ("var x = 2; x * 3") work and yield the completion
450
+ // value matching the CDP Runtime.evaluate path. (An earlier
451
+ // `await (${expression})` wrapper flattened objects but broke every
452
+ // statement-form expression with a SyntaxError.) BiDi returns a
453
+ // {type,value} remote value; deserializeBiDi walks it back to the plain
454
+ // JS value CDP's returnByValue produces.
455
+ const res = await page.bidi.send('script.evaluate', {
456
+ expression, target: { context: page.context }, awaitPromise: true,
457
+ });
458
+ if (res.type === 'exception') {
459
+ return { ok: false, error: res.exceptionDetails?.text || 'eval error' };
460
+ }
461
+ return { ok: true, value: deserializeBiDi(res.result) };
426
462
  } catch (err) {
427
463
  return { ok: false, error: err.message || 'eval error' };
428
464
  }
@@ -575,7 +575,14 @@ export async function createFirefoxPage(bidi, opts = {}) {
575
575
  secure: !!c.secure,
576
576
  httpOnly: !!c.httpOnly,
577
577
  };
578
- if (c.sameSite && c.sameSite !== 'default') out.sameSite = c.sameSite;
578
+ // BiDi reports sameSite lowercase (strict|lax|none); the CDP saveState /
579
+ // Network.setCookies vocabulary is capitalized (Strict|Lax|None). The only
580
+ // loader for a state file is connect()'s storageState (CDP-only), which
581
+ // rejects a lowercase enum and silently drops every cookie — so capitalize
582
+ // here to keep the format truly symmetric and the round-trip working.
583
+ if (c.sameSite && c.sameSite !== 'default') {
584
+ out.sameSite = c.sameSite.charAt(0).toUpperCase() + c.sameSite.slice(1);
585
+ }
579
586
  if (c.expiry && c.expiry > 0) out.expires = c.expiry;
580
587
  return out;
581
588
  });
package/types/daemon.d.ts CHANGED
@@ -10,6 +10,15 @@
10
10
  * @returns {string[]}
11
11
  */
12
12
  export function buildDaemonArgs(opts: object, absDir: string, initialUrl: string | undefined, cliPath: string): string[];
13
+ /**
14
+ * Convert a BiDi remote value ({type,value} — see script.evaluate) into the
15
+ * plain JS value CDP's `Runtime.evaluate({returnByValue:true})` yields, so an
16
+ * `eval` returns the same shape on both engines. BiDi serializes objects/arrays
17
+ * as entry lists ([[k,v],…] / [v,…]) rather than plain values; walk them back.
18
+ * @param {object} r - BiDi remote value
19
+ * @returns {*}
20
+ */
21
+ export function deserializeBiDi(r: object): any;
13
22
  /**
14
23
  * Wire Firefox/BiDi console + network capture onto the daemon's log arrays.
15
24
  * The BiDi analogue of the CDP `Runtime.consoleAPICalled` / `Network.*`