hypha-debugger 0.2.9 → 0.3.1

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.
@@ -4202,7 +4202,7 @@
4202
4202
 
4203
4203
  const typedArrayToDtypeKeys = [];
4204
4204
  for (const arrType of Object.keys(typedArrayToDtypeMapping)) {
4205
- typedArrayToDtypeKeys.push(eval(arrType));
4205
+ typedArrayToDtypeKeys.push(globalThis[arrType]);
4206
4206
  }
4207
4207
 
4208
4208
  function typedArrayToDtype(obj) {
@@ -6964,7 +6964,7 @@
6964
6964
  /******/ }
6965
6965
  /******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
6966
6966
  /******/ // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
6967
- /******/ if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
6967
+ /******/ if(!scriptUrl)scriptUrl="";
6968
6968
  /******/ scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");
6969
6969
  /******/ __webpack_require__.p = scriptUrl;
6970
6970
  /******/ })();
@@ -10557,6 +10557,19 @@
10557
10557
  /**
10558
10558
  * Arbitrary JavaScript execution service.
10559
10559
  */
10560
+ /**
10561
+ * Detect the EvalError thrown when a page's Content Security Policy blocks the
10562
+ * Function constructor / eval (no 'unsafe-eval'). Chrome throws an EvalError
10563
+ * whose message mentions "unsafe-eval" / "Content Security Policy".
10564
+ */
10565
+ function isCspEvalError(e) {
10566
+ if (!e)
10567
+ return false;
10568
+ if (e instanceof EvalError)
10569
+ return true;
10570
+ const msg = String(e.message || e);
10571
+ return /unsafe-eval|Content Security Policy|call to .*Function/i.test(msg);
10572
+ }
10560
10573
  /**
10561
10574
  * Attempt to auto-return the last expression in a code block.
10562
10575
  * If the code doesn't contain an explicit `return`, we try to
@@ -10595,13 +10608,24 @@
10595
10608
  async function executeScript(code, timeout_ms) {
10596
10609
  const timeoutMs = timeout_ms ?? 10000;
10597
10610
  try {
10598
- // Try with auto-return first, fall back to original code if syntax error
10611
+ // Try with auto-return first, fall back to original code if syntax error.
10612
+ // NOTE: running arbitrary code fundamentally requires the Function
10613
+ // constructor, which strict CSP (no 'unsafe-eval') blocks. There is no
10614
+ // CSP-safe alternative for execute_script — detect that and report clearly.
10599
10615
  let execCode = autoReturn(code);
10600
10616
  let fn;
10601
10617
  try {
10602
10618
  fn = new Function("return (async () => {" + execCode + "})()");
10603
10619
  }
10604
- catch {
10620
+ catch (e) {
10621
+ if (isCspEvalError(e)) {
10622
+ return {
10623
+ error: "execute_script is unavailable on this page: its Content Security " +
10624
+ "Policy blocks dynamic code evaluation ('unsafe-eval' not allowed). " +
10625
+ "Use the DOM/interaction services (get_browser_state, click_element_by_index, " +
10626
+ "query_dom, etc.) instead — they do not need eval.",
10627
+ };
10628
+ }
10605
10629
  // Auto-return broke the syntax — use original code
10606
10630
  fn = new Function("return (async () => {" + code + "})()");
10607
10631
  }
@@ -11416,13 +11440,15 @@
11416
11440
  * Wrap a function with correct, unminified parameter names for hypha-rpc.
11417
11441
  *
11418
11442
  * In production builds, Babel/Terser minifies parameter names (e.g. 'code' → 'e').
11419
- * hypha-rpc's getParamNames() parses Function.toString() to map kwargs to
11443
+ * hypha-rpc's getFunctionInfo() parses Function.toString() to map kwargs to
11420
11444
  * positional args. With minified names, kwargs like {code: '...'} can't be
11421
11445
  * mapped and args are silently dropped.
11422
11446
  *
11423
- * This helper uses new Function() to create a wrapper whose parameter names
11424
- * are taken from the function's __schema__ property, so hypha-rpc always sees
11425
- * the real parameter names regardless of minification.
11447
+ * CSP NOTE: this used to build the wrapper with `new Function(...)`, but that is
11448
+ * blocked on pages whose Content Security Policy lacks `'unsafe-eval'` (the exact
11449
+ * pages the bookmarklet targets). Instead we use a normal closure and OVERRIDE its
11450
+ * `.toString()` so hypha-rpc still reads the real, unminified parameter names from
11451
+ * the schema — no eval / Function constructor involved.
11426
11452
  *
11427
11453
  * Additionally, it handles the case where hypha-rpc passes kwargs as a single
11428
11454
  * object argument (e.g. `fn({url: "..."})` instead of `fn("...")`). The
@@ -11436,33 +11462,51 @@
11436
11462
  if (paramNames.length === 0) {
11437
11463
  return fn;
11438
11464
  }
11439
- // Create a wrapper that:
11440
- // 1. Has correct, unminified parameter names (for hypha-rpc getParamNames)
11441
- // 2. Detects when kwargs are passed as a single object and destructures them
11442
- //
11443
- // hypha-rpc HTTP handler passes kwargs as a single plain object, e.g.:
11444
- // execute_script({code: "..."}) instead of execute_script("...")
11445
- // get_react_tree({}) instead of get_react_tree()
11446
- // We detect this and destructure, or discard empty objects.
11447
- const paramList = paramNames.join(", ");
11448
- const firstParam = paramNames[0];
11449
- const wrapper = new Function("fn", "paramNames", `return async function(${paramList}) {
11450
- // Detect kwargs-as-object: single argument that is a plain object
11451
- if (arguments.length === 1 && ${firstParam} != null && typeof ${firstParam} === "object" && !Array.isArray(${firstParam}) && !(${firstParam} instanceof Date) && ${firstParam}.constructor === Object) {
11452
- var _kw = ${firstParam};
11453
- var _keys = Object.keys(_kw);
11454
- // Empty object {} → call with no args (all defaults)
11455
- if (_keys.length === 0) {
11456
- return fn();
11457
- }
11458
- // Keys match schema params → destructure
11459
- if (paramNames.indexOf(_keys[0]) !== -1) {
11460
- var _args = paramNames.map(function(n) { return _kw[n]; });
11461
- return fn.apply(null, _args);
11462
- }
11463
- }
11464
- return fn(${paramList});
11465
- }`)(fn, paramNames);
11465
+ // A plain closure (no new Function). It:
11466
+ // 1. Detects kwargs passed as a single object and destructures them.
11467
+ // hypha-rpc's HTTP handler passes kwargs as one plain object, e.g.
11468
+ // execute_script({code: "..."}) instead of execute_script("..."),
11469
+ // get_react_tree({}) instead of get_react_tree().
11470
+ // 2. Otherwise forwards positional args unchanged.
11471
+ const wrapper = async function (...args) {
11472
+ if (args.length === 1 &&
11473
+ args[0] != null &&
11474
+ typeof args[0] === "object" &&
11475
+ !Array.isArray(args[0]) &&
11476
+ !(args[0] instanceof Date) &&
11477
+ args[0].constructor === Object) {
11478
+ const kw = args[0];
11479
+ const keys = Object.keys(kw);
11480
+ // Empty object {} → call with no args (all defaults)
11481
+ if (keys.length === 0) {
11482
+ return fn();
11483
+ }
11484
+ // Keys match schema params → destructure into positional args
11485
+ if (paramNames.indexOf(keys[0]) !== -1) {
11486
+ return fn.apply(null, paramNames.map((n) => kw[n]));
11487
+ }
11488
+ }
11489
+ return fn.apply(null, args);
11490
+ };
11491
+ // hypha-rpc's getFunctionInfo() does `func.toString()` and extracts the param
11492
+ // names from the first `(...)`. A real `...args` wrapper would hide them, so
11493
+ // expose the schema's names via a toString override (CSP-safe, unlike Function).
11494
+ const fakeSource = `function (${paramNames.join(", ")}) {}`;
11495
+ try {
11496
+ Object.defineProperty(wrapper, "toString", {
11497
+ value: () => fakeSource,
11498
+ writable: true,
11499
+ configurable: true,
11500
+ });
11501
+ // Some consumers read arity via Function.length — keep it consistent.
11502
+ Object.defineProperty(wrapper, "length", {
11503
+ value: paramNames.length,
11504
+ configurable: true,
11505
+ });
11506
+ }
11507
+ catch {
11508
+ wrapper.toString = () => fakeSource;
11509
+ }
11466
11510
  if (schema)
11467
11511
  wrapper.__schema__ = schema;
11468
11512
  return wrapper;