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.
- package/dist/bookmarklet.txt +1 -0
- package/dist/hypha-debugger.js +79 -35
- package/dist/hypha-debugger.min.js +4 -4
- package/dist/hypha-debugger.mjs +76 -32
- package/dist/hypha-debugger.mjs.map +1 -1
- package/dist/hypha-debugger.slim.min.js +1 -0
- package/dist/utils/wrap-fn.d.ts +6 -4
- package/package.json +3 -1
package/dist/hypha-debugger.mjs
CHANGED
|
@@ -2212,6 +2212,19 @@ takeScreenshot.__schema__ = {
|
|
|
2212
2212
|
/**
|
|
2213
2213
|
* Arbitrary JavaScript execution service.
|
|
2214
2214
|
*/
|
|
2215
|
+
/**
|
|
2216
|
+
* Detect the EvalError thrown when a page's Content Security Policy blocks the
|
|
2217
|
+
* Function constructor / eval (no 'unsafe-eval'). Chrome throws an EvalError
|
|
2218
|
+
* whose message mentions "unsafe-eval" / "Content Security Policy".
|
|
2219
|
+
*/
|
|
2220
|
+
function isCspEvalError(e) {
|
|
2221
|
+
if (!e)
|
|
2222
|
+
return false;
|
|
2223
|
+
if (e instanceof EvalError)
|
|
2224
|
+
return true;
|
|
2225
|
+
const msg = String(e.message || e);
|
|
2226
|
+
return /unsafe-eval|Content Security Policy|call to .*Function/i.test(msg);
|
|
2227
|
+
}
|
|
2215
2228
|
/**
|
|
2216
2229
|
* Attempt to auto-return the last expression in a code block.
|
|
2217
2230
|
* If the code doesn't contain an explicit `return`, we try to
|
|
@@ -2250,13 +2263,24 @@ function autoReturn(code) {
|
|
|
2250
2263
|
async function executeScript(code, timeout_ms) {
|
|
2251
2264
|
const timeoutMs = timeout_ms ?? 10000;
|
|
2252
2265
|
try {
|
|
2253
|
-
// Try with auto-return first, fall back to original code if syntax error
|
|
2266
|
+
// Try with auto-return first, fall back to original code if syntax error.
|
|
2267
|
+
// NOTE: running arbitrary code fundamentally requires the Function
|
|
2268
|
+
// constructor, which strict CSP (no 'unsafe-eval') blocks. There is no
|
|
2269
|
+
// CSP-safe alternative for execute_script — detect that and report clearly.
|
|
2254
2270
|
let execCode = autoReturn(code);
|
|
2255
2271
|
let fn;
|
|
2256
2272
|
try {
|
|
2257
2273
|
fn = new Function("return (async () => {" + execCode + "})()");
|
|
2258
2274
|
}
|
|
2259
|
-
catch {
|
|
2275
|
+
catch (e) {
|
|
2276
|
+
if (isCspEvalError(e)) {
|
|
2277
|
+
return {
|
|
2278
|
+
error: "execute_script is unavailable on this page: its Content Security " +
|
|
2279
|
+
"Policy blocks dynamic code evaluation ('unsafe-eval' not allowed). " +
|
|
2280
|
+
"Use the DOM/interaction services (get_browser_state, click_element_by_index, " +
|
|
2281
|
+
"query_dom, etc.) instead — they do not need eval.",
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
2260
2284
|
// Auto-return broke the syntax — use original code
|
|
2261
2285
|
fn = new Function("return (async () => {" + code + "})()");
|
|
2262
2286
|
}
|
|
@@ -3071,13 +3095,15 @@ function generateSkillMd(serviceFunctions, serviceUrl) {
|
|
|
3071
3095
|
* Wrap a function with correct, unminified parameter names for hypha-rpc.
|
|
3072
3096
|
*
|
|
3073
3097
|
* In production builds, Babel/Terser minifies parameter names (e.g. 'code' → 'e').
|
|
3074
|
-
* hypha-rpc's
|
|
3098
|
+
* hypha-rpc's getFunctionInfo() parses Function.toString() to map kwargs to
|
|
3075
3099
|
* positional args. With minified names, kwargs like {code: '...'} can't be
|
|
3076
3100
|
* mapped and args are silently dropped.
|
|
3077
3101
|
*
|
|
3078
|
-
*
|
|
3079
|
-
*
|
|
3080
|
-
* the
|
|
3102
|
+
* CSP NOTE: this used to build the wrapper with `new Function(...)`, but that is
|
|
3103
|
+
* blocked on pages whose Content Security Policy lacks `'unsafe-eval'` (the exact
|
|
3104
|
+
* pages the bookmarklet targets). Instead we use a normal closure and OVERRIDE its
|
|
3105
|
+
* `.toString()` so hypha-rpc still reads the real, unminified parameter names from
|
|
3106
|
+
* the schema — no eval / Function constructor involved.
|
|
3081
3107
|
*
|
|
3082
3108
|
* Additionally, it handles the case where hypha-rpc passes kwargs as a single
|
|
3083
3109
|
* object argument (e.g. `fn({url: "..."})` instead of `fn("...")`). The
|
|
@@ -3091,33 +3117,51 @@ function wrapFn(fn) {
|
|
|
3091
3117
|
if (paramNames.length === 0) {
|
|
3092
3118
|
return fn;
|
|
3093
3119
|
}
|
|
3094
|
-
//
|
|
3095
|
-
// 1.
|
|
3096
|
-
//
|
|
3097
|
-
//
|
|
3098
|
-
//
|
|
3099
|
-
//
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3120
|
+
// A plain closure (no new Function). It:
|
|
3121
|
+
// 1. Detects kwargs passed as a single object and destructures them.
|
|
3122
|
+
// hypha-rpc's HTTP handler passes kwargs as one plain object, e.g.
|
|
3123
|
+
// execute_script({code: "..."}) instead of execute_script("..."),
|
|
3124
|
+
// get_react_tree({}) instead of get_react_tree().
|
|
3125
|
+
// 2. Otherwise forwards positional args unchanged.
|
|
3126
|
+
const wrapper = async function (...args) {
|
|
3127
|
+
if (args.length === 1 &&
|
|
3128
|
+
args[0] != null &&
|
|
3129
|
+
typeof args[0] === "object" &&
|
|
3130
|
+
!Array.isArray(args[0]) &&
|
|
3131
|
+
!(args[0] instanceof Date) &&
|
|
3132
|
+
args[0].constructor === Object) {
|
|
3133
|
+
const kw = args[0];
|
|
3134
|
+
const keys = Object.keys(kw);
|
|
3135
|
+
// Empty object {} → call with no args (all defaults)
|
|
3136
|
+
if (keys.length === 0) {
|
|
3137
|
+
return fn();
|
|
3138
|
+
}
|
|
3139
|
+
// Keys match schema params → destructure into positional args
|
|
3140
|
+
if (paramNames.indexOf(keys[0]) !== -1) {
|
|
3141
|
+
return fn.apply(null, paramNames.map((n) => kw[n]));
|
|
3142
|
+
}
|
|
3117
3143
|
}
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3144
|
+
return fn.apply(null, args);
|
|
3145
|
+
};
|
|
3146
|
+
// hypha-rpc's getFunctionInfo() does `func.toString()` and extracts the param
|
|
3147
|
+
// names from the first `(...)`. A real `...args` wrapper would hide them, so
|
|
3148
|
+
// expose the schema's names via a toString override (CSP-safe, unlike Function).
|
|
3149
|
+
const fakeSource = `function (${paramNames.join(", ")}) {}`;
|
|
3150
|
+
try {
|
|
3151
|
+
Object.defineProperty(wrapper, "toString", {
|
|
3152
|
+
value: () => fakeSource,
|
|
3153
|
+
writable: true,
|
|
3154
|
+
configurable: true,
|
|
3155
|
+
});
|
|
3156
|
+
// Some consumers read arity via Function.length — keep it consistent.
|
|
3157
|
+
Object.defineProperty(wrapper, "length", {
|
|
3158
|
+
value: paramNames.length,
|
|
3159
|
+
configurable: true,
|
|
3160
|
+
});
|
|
3161
|
+
}
|
|
3162
|
+
catch {
|
|
3163
|
+
wrapper.toString = () => fakeSource;
|
|
3164
|
+
}
|
|
3121
3165
|
if (schema)
|
|
3122
3166
|
wrapper.__schema__ = schema;
|
|
3123
3167
|
return wrapper;
|