package browser import ( "encoding/json" "fmt" ) // CdpEvalInFrame ejecuta una expresion JavaScript en el contexto aislado de un iframe // especifico usando Page.createIsolatedWorld + Runtime.evaluate con el contextId del frame. // Retorna el resultado serializado como string. func CdpEvalInFrame(c *CDPConn, frameID, expression string) (string, error) { if c == nil { return "", fmt.Errorf("cdp eval in frame: conexion nula") } if frameID == "" { return "", fmt.Errorf("cdp eval in frame: frameID vacio") } // Page.enable es idempotente; necesario antes de crear mundos aislados if _, err := c.sendCDP("Page.enable", nil); err != nil { return "", fmt.Errorf("cdp eval in frame: Page.enable: %w", err) } // Crear un mundo aislado en el frame indicado para no contaminar su contexto JS ctxRes, err := c.sendCDP("Page.createIsolatedWorld", map[string]any{ "frameId": frameID, "worldName": "fn_registry_isolated", "grantUniveralAccess": false, }) if err != nil { return "", fmt.Errorf("cdp eval in frame: createIsolatedWorld: %w", err) } ctxIDRaw, ok := ctxRes["executionContextId"] if !ok { return "", fmt.Errorf("cdp eval in frame: executionContextId no encontrado en respuesta") } ctxID, ok := ctxIDRaw.(float64) if !ok { return "", fmt.Errorf("cdp eval in frame: executionContextId tipo inesperado: %T", ctxIDRaw) } // Evaluar la expresion en el contexto aislado del frame evRes, err := c.sendCDP("Runtime.evaluate", map[string]any{ "expression": expression, "contextId": int(ctxID), "returnByValue": true, "awaitPromise": true, }) if err != nil { return "", fmt.Errorf("cdp eval in frame: Runtime.evaluate: %w", err) } // Verificar excepcion JS if exc, ok := evRes["exceptionDetails"]; ok && exc != nil { excMap, _ := exc.(map[string]any) text, _ := excMap["text"].(string) return "", fmt.Errorf("cdp eval in frame: excepcion JS en frame %q: %s", frameID, text) } // Extraer valor del resultado (mismo patron que CdpEvaluate) resVal, ok := evRes["result"].(map[string]any) if !ok { return "", fmt.Errorf("cdp eval in frame: resultado inesperado: %v", evRes) } value, ok := resVal["value"] if !ok { // undefined u otro tipo no serializable typ, _ := resVal["type"].(string) return typ, nil } // Strings tal cual; objetos/arrays JS a JSON real (no la repr de Go de "%v"). if s, ok := value.(string); ok { return s, nil } b, err := json.Marshal(value) if err != nil { return fmt.Sprintf("%v", value), nil } return string(b), nil }