You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
JsRuntime::register_handler() in lib.rs L146-L149 uses a raw .contains("export") check to decide whether to auto-append export { handler };:
let handler_script = if !handler_script.contains("export"){format!("{}\nexport {{ handler }};", handler_script)}else{
handler_script
};
This is a plain substring match against the entire script source, including string literals, comments, and variable names. If the handler script contains the word "export" anywhere — even inside a string, a comment, or an identifier like exportData — the auto-export is skipped, and the subsequent module.get("handler") call on line 166 fails because the module has no handler export.
Reproduction
// This handler WORKS — no "export" anywhereconst script_ok = `
function handler(event){return{ result:"hello"};}
`;// This handler FAILS — "export" appears in a string literalconst script_broken = `
function handler(event){const xml = '<config mode="export">value</config>';return{ result: xml };}
`;// This handler FAILS — "export" appears in a commentconst script_comment = `
function handler(event){// TODO: export this data to CSVreturn{ result:42};}
`;// This handler FAILS — "export" appears in a variable nameconst script_ident = `
function handler(event){const exportPath = "/tmp/out.csv";return{ result: exportPath };}
`;
In all three broken cases, the runtime sees "export" in the source, assumes the developer has already written an ES export statement, skips auto-appending export { handler };, and the handler module has no exports → runtime error.
Impact
This silently breaks handler registration for any script whose content (not just its module structure) happens to contain the substring "export". The failure mode is confusing — the error comes from module.get("handler") failing, not from anything obviously related to exports.
For downstream consumers that generate handler scripts programmatically (e.g. wrapping LLM-generated code inside a function handler(event) { ... } body), this is especially problematic because the script content is arbitrary and frequently contains strings with "export" in them.
Suggested Fix
Since register_handler is specifically documented as taking "a JavaScript module that exports a function named handler", the safest fix is to always append the export and let QuickJS handle duplicates:
// Option A: Always append — QuickJS will ignore a duplicate export// of the same binding if one already exists in the source.let handler_script = format!("{}\nexport {{ handler }};", handler_script);
If QuickJS rejects duplicate exports, an alternative is to use a more precise heuristic:
// Option B: Regex that matches actual export syntax, not substringslet has_export = regex::Regex::new(r"\bexport\s+(default\s+|async\s+)?(function|class|const|let|var|\{|\*)").unwrap().is_match(&handler_script);let handler_script = if !has_export {format!("{}\nexport {{ handler }};", handler_script)}else{
handler_script
};
Activity
fix: use line-based heuristic for auto-export detection (hyperlight-d…
fix: use line-based heuristic for auto-export detection (hyperlight-d…
fix: use line-based heuristic for auto-export detection (hyperlight-d…
fix: use line-based heuristic for auto-export detection (#39) (#46)