@@ -14,7 +14,6 @@ import {
1414 FormulaEvaluationOptions ,
1515 FormulaError ,
1616 FormulaErrorType ,
17- FormulaFieldValue ,
1817 FormulaValue ,
1918 FormulaDataType ,
2019 FormulaMetadata ,
@@ -70,7 +69,6 @@ export class FormulaEngine {
7069 ) : FormulaEvaluationResult {
7170 const startTime = Date . now ( ) ;
7271 const timeout = options . timeout ?? this . config . max_execution_time ?? 1000 ;
73- const strict = options . strict ?? true ;
7472
7573 try {
7674 // Validate expression
@@ -177,6 +175,10 @@ export class FormulaEngine {
177175 options : FormulaEvaluationOptions
178176 ) : FormulaValue {
179177 // Check for blocked operations
178+ // NOTE: This is a basic check using string matching. It will have false positives
179+ // (e.g., a field named 'evaluation' contains 'eval') and can be bypassed
180+ // (e.g., using this['eval'] or globalThis['eval']).
181+ // For production security with untrusted formulas, use AST parsing or vm2.
180182 if ( this . config . sandbox ?. enabled ) {
181183 const blockedOps = this . config . sandbox . blocked_operations || [ ] ;
182184 for ( const op of blockedOps ) {
@@ -273,25 +275,29 @@ export class FormulaEngine {
273275 /**
274276 * Execute function with timeout protection
275277 *
276- * NOTE: This implements post-execution timeout validation, not pre-emptive interruption.
277- * The function will run to completion and then check if it exceeded the timeout.
278- * For true interruption, platform-specific mechanisms (Worker threads) would be needed.
278+ * NOTE: This synchronous implementation **cannot** pre-emptively interrupt execution.
279+ * The timeout check occurs AFTER the formula completes. Long-running formulas will
280+ * still block execution. This is a limitation of synchronous JavaScript.
281+ *
282+ * For true interruption, use platform-specific mechanisms like Worker threads or
283+ * migrate to an async/isolated runtime. Formulas should be written to be fast.
279284 */
280285 private executeWithTimeout (
281286 func : Function ,
282287 args : any [ ] ,
283288 timeout : number
284289 ) : unknown {
285- // Simple synchronous execution (timeout would require async or worker threads)
286- // For now, we execute directly. Advanced timeout requires platform-specific code.
290+ // Execute the formula synchronously
287291 const startTime = Date . now ( ) ;
288292 const result = func ( ...args ) ;
289293 const elapsed = Date . now ( ) - startTime ;
290294
295+ // Check timeout AFTER execution (cannot interrupt synchronous code)
291296 if ( elapsed > timeout ) {
292297 throw new FormulaError (
293298 FormulaErrorType . TIMEOUT ,
294- `Formula execution exceeded timeout of ${ timeout } ms` ,
299+ `Formula execution exceeded timeout of ${ timeout } ms (actual: ${ elapsed } ms). ` +
300+ `Note: Synchronous formulas cannot be interrupted. Write fast formulas or use async runtime.` ,
295301 '' ,
296302 { elapsed, timeout }
297303 ) ;
0 commit comments