Merge branch 'develop' into out-ss
This commit is contained in:
@@ -133,9 +133,10 @@ BYOP (Bring Your Own Proxy) lets you connect external proxies to bypass anti-bot
|
||||
- ✨ Turn Websites to APIs
|
||||
- ✨ Turn Websites to Spreadsheets
|
||||
- ✨ Adapt To Website Layout Changes
|
||||
- ✨ Extract Behind Login,
|
||||
- ✨ Bypass Two-Factor Authentication For Extract Behind Login (coming soon)
|
||||
- ✨ Extract Behind Login
|
||||
- ✨ Integrations
|
||||
- ✨ MCP Server
|
||||
- ✨ Bypass 2FA & MFA For Extract Behind Login (coming soon)
|
||||
- +++ A lot of amazing things!
|
||||
|
||||
# Screenshots
|
||||
@@ -150,7 +151,7 @@ BYOP (Bring Your Own Proxy) lets you connect external proxies to bypass anti-bot
|
||||

|
||||
|
||||
# Note
|
||||
This project is in early stages of development. Your feedback is very important for us - we're actively working to improve the product. </a>
|
||||
This project is in early stages of development. Your feedback is very important for us - we're actively working on improvements. </a>
|
||||
|
||||
# License
|
||||
<p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ScrollSettings } from './scroll';
|
||||
import { ScreenshotSettings } from "./screenshot";
|
||||
import { ScrapeSettings } from "./scrape";
|
||||
import { ScrapeSchemaSettings } from "./scrapeSchema";
|
||||
import { ScrollSettings } from './Scroll';
|
||||
import { ScreenshotSettings } from "./Screenshot";
|
||||
import { ScrapeSettings } from "./Scrape";
|
||||
import { ScrapeSchemaSettings } from "./ScrapeSchema";
|
||||
|
||||
export {
|
||||
ScrollSettings,
|
||||
|
||||
@@ -130,7 +130,7 @@ export const BrowserContent = () => {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Fetching current url failed");
|
||||
console.log(`Fetching current url failed: ${error}`);
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import styled from 'styled-components';
|
||||
import ReplayIcon from '@mui/icons-material/Replay';
|
||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
|
||||
import { NavBarButton } from '../ui/buttons/buttons';
|
||||
import { NavBarButton } from '../ui/buttons/Buttons';
|
||||
import { UrlForm } from './UrlForm';
|
||||
import { useCallback, useEffect } from "react";
|
||||
import { useSocketStore } from "../../context/socket";
|
||||
@@ -63,7 +63,7 @@ const BrowserNavBar: FC<NavBarProps> = ({
|
||||
handleUrlChanged(response);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log("Fetching current url failed");
|
||||
console.log(`Fetching current url failed: ${error}`);
|
||||
})
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { useSocketStore } from '../../context/socket';
|
||||
import { Button } from '@mui/material';
|
||||
import Canvas from "../recorder/canvas";
|
||||
import Canvas from "../recorder/Canvas";
|
||||
import { Highlighter } from "../recorder/Highlighter";
|
||||
import { GenericModal } from '../ui/GenericModal';
|
||||
import { useActionContext } from '../../context/browserActions';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import type { SyntheticEvent } from 'react';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import { NavBarForm, NavBarInput } from "../ui/form";
|
||||
import { UrlFormButton } from "../ui/buttons/buttons";
|
||||
import { NavBarForm, NavBarInput } from "../ui/Form";
|
||||
import { UrlFormButton } from "../ui/buttons/Buttons";
|
||||
import { useSocketStore } from '../../context/socket';
|
||||
import { Socket } from "socket.io-client";
|
||||
|
||||
@@ -40,7 +40,7 @@ export const UrlForm = ({
|
||||
lastSubmittedRef.current = url; // Update the last submitted URL
|
||||
} catch (e) {
|
||||
//alert(`ERROR: ${url} is not a valid url!`);
|
||||
console.log(e)
|
||||
console.log(`Failed to submit form:`,e)
|
||||
}
|
||||
}, [setCurrentAddress]);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSocketStore } from '../../context/socket';
|
||||
import { Coordinates } from '../recorder/canvas';
|
||||
import { Coordinates } from '../recorder/Canvas';
|
||||
|
||||
interface DatePickerProps {
|
||||
coordinates: Coordinates;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSocketStore } from '../../context/socket';
|
||||
import { Coordinates } from '../recorder/canvas';
|
||||
import { Coordinates } from '../recorder/Canvas';
|
||||
|
||||
interface DateTimeLocalPickerProps {
|
||||
coordinates: Coordinates;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSocketStore } from '../../context/socket';
|
||||
import { Coordinates } from '../recorder/canvas';
|
||||
import { Coordinates } from '../recorder/Canvas';
|
||||
|
||||
interface DropdownProps {
|
||||
coordinates: Coordinates;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSocketStore } from '../../context/socket';
|
||||
import { Coordinates } from '../recorder/canvas';
|
||||
import { Coordinates } from '../recorder/Canvas';
|
||||
|
||||
interface TimePickerProps {
|
||||
coordinates: Coordinates;
|
||||
|
||||
@@ -307,4 +307,4 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => {
|
||||
};
|
||||
|
||||
|
||||
export default memo(Canvas);
|
||||
export default memo(Canvas);
|
||||
@@ -19,7 +19,7 @@ const fetchWorkflow = (id: string, callback: (response: WorkflowFile) => void) =
|
||||
throw new Error("No workflow found");
|
||||
}
|
||||
}
|
||||
).catch((error) => { console.log(error.message) })
|
||||
).catch((error) => { console.log(`Failed to fetch workflow:`,error.message) })
|
||||
};
|
||||
|
||||
interface LeftSidePanelProps {
|
||||
|
||||
@@ -32,7 +32,7 @@ const fetchWorkflow = (id: string, callback: (response: WorkflowFile) => void) =
|
||||
throw new Error("No workflow found");
|
||||
}
|
||||
}
|
||||
).catch((error) => { console.log(error.message) })
|
||||
).catch((error) => { console.log(`Failed to fetch workflow:`,error.message) })
|
||||
};
|
||||
|
||||
interface RightSidePanelProps {
|
||||
@@ -256,7 +256,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
||||
);
|
||||
|
||||
updateListStepData(currentListId, extractedData);
|
||||
console.log("✅ Client-side extraction completed:", extractedData);
|
||||
console.log("✅ UI extraction completed:");
|
||||
} catch (error) {
|
||||
console.error("Error in client-side data extraction:", error);
|
||||
notify("error", "Failed to extract data client-side");
|
||||
@@ -276,7 +276,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
||||
pagination: { type: "", selector: "" },
|
||||
});
|
||||
|
||||
console.log("📤 Sent extraction request to backend");
|
||||
console.log("📤 Sent extraction request to server");
|
||||
} catch (error) {
|
||||
console.error("Error in backend data extraction:", error);
|
||||
}
|
||||
|
||||
@@ -250,4 +250,4 @@ export const useBrowserSteps = () => {
|
||||
throw new Error('useBrowserSteps must be used within a BrowserStepsProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -464,8 +464,6 @@ class ClientListExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("📦 Found containers:", containers.length);
|
||||
|
||||
// Analyze fields for table vs non-table context
|
||||
const containerFields: ContainerFields[] = containers.map(() => ({
|
||||
tableFields: {},
|
||||
@@ -642,7 +640,6 @@ class ClientListExtractor {
|
||||
const value = this.extractValue(element, attribute);
|
||||
if (value !== null && value !== "") {
|
||||
record[label] = value;
|
||||
console.log(`✅ Extracted ${label}:`, value);
|
||||
} else {
|
||||
console.warn(
|
||||
`❌ No value for ${label} in row ${rowIndex + 1}`
|
||||
@@ -691,7 +688,6 @@ class ClientListExtractor {
|
||||
const value = this.extractValue(element, attribute);
|
||||
if (value !== null && value !== "") {
|
||||
record[label] = value;
|
||||
console.log(`✅ Extracted ${label}:`, value);
|
||||
} else {
|
||||
console.warn(
|
||||
`❌ No value for ${label} in container ${containerIndex + 1}`
|
||||
@@ -716,13 +712,6 @@ class ClientListExtractor {
|
||||
// Combine and limit results
|
||||
const extractedData = [...tableData, ...nonTableData].slice(0, limit);
|
||||
|
||||
console.log("🎉 Client extraction complete:", {
|
||||
totalRecords: extractedData.length,
|
||||
tableRecords: tableData.length,
|
||||
nonTableRecords: nonTableData.length,
|
||||
data: extractedData,
|
||||
});
|
||||
|
||||
return extractedData;
|
||||
} catch (error) {
|
||||
console.error("Error in client-side extractListData:", error);
|
||||
|
||||
@@ -1803,22 +1803,16 @@ class ClientSelectorGenerator {
|
||||
let elements = iframeDoc.elementsFromPoint(x, y) as HTMLElement[];
|
||||
if (!elements.length) return null;
|
||||
|
||||
console.log("ALL ELEMENTS", elements);
|
||||
|
||||
const dialogElement = elements.find(
|
||||
(el) => el.getAttribute("role") === "dialog"
|
||||
);
|
||||
|
||||
if (dialogElement) {
|
||||
console.log("FOUND DIALOG ELEMENT", dialogElement);
|
||||
|
||||
// Filter to keep only the dialog and its children
|
||||
const dialogElements = elements.filter(
|
||||
(el) => el === dialogElement || dialogElement.contains(el)
|
||||
);
|
||||
|
||||
console.log("FILTERED DIALOG ELEMENTS", dialogElements);
|
||||
|
||||
// Get deepest element within the dialog
|
||||
const findDeepestInDialog = (
|
||||
elements: HTMLElement[]
|
||||
@@ -1852,7 +1846,6 @@ class ClientSelectorGenerator {
|
||||
};
|
||||
|
||||
const deepestInDialog = findDeepestInDialog(dialogElements);
|
||||
console.log("DEEPEST IN DIALOG", deepestInDialog);
|
||||
return deepestInDialog;
|
||||
}
|
||||
|
||||
@@ -1874,13 +1867,11 @@ class ClientSelectorGenerator {
|
||||
(style.position === "fixed" || style.position === "absolute") &&
|
||||
zIndex > 50
|
||||
) {
|
||||
console.log("FOUND POSITIONED ELEMENT", element);
|
||||
return element;
|
||||
}
|
||||
|
||||
// For SVG elements (like close buttons), prefer them if they're in the top elements
|
||||
if (element.tagName === "SVG" && i < 2) {
|
||||
console.log("FOUND SVG ELEMENT", element);
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -1913,8 +1904,6 @@ class ClientSelectorGenerator {
|
||||
|
||||
let deepestElement = findDeepestElement(elements);
|
||||
|
||||
console.log("DEEPEST ELEMENT", deepestElement);
|
||||
|
||||
if (!deepestElement) return null;
|
||||
|
||||
const traverseShadowDOM = (element: HTMLElement): HTMLElement => {
|
||||
@@ -3133,13 +3122,6 @@ class ClientSelectorGenerator {
|
||||
childSelectors?: string[];
|
||||
} | null {
|
||||
try {
|
||||
console.log("🐛 DEBUG: generateDataForHighlighter called with:", {
|
||||
coordinates,
|
||||
getList: this.getList,
|
||||
listSelector: this.listSelector,
|
||||
isDOMMode,
|
||||
});
|
||||
|
||||
// Use instance variables instead of parameters
|
||||
const rect = this.getRect(
|
||||
iframeDocument,
|
||||
@@ -3161,11 +3143,6 @@ class ClientSelectorGenerator {
|
||||
);
|
||||
|
||||
if (!rect || !elementInfo || !displaySelector) {
|
||||
console.log("🐛 DEBUG: Missing basic data:", {
|
||||
rect: !!rect,
|
||||
elementInfo: !!elementInfo,
|
||||
selectors: !!displaySelector,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -3183,24 +3160,12 @@ class ClientSelectorGenerator {
|
||||
|
||||
if (this.getList === true) {
|
||||
if (this.listSelector !== "") {
|
||||
console.log(
|
||||
"🐛 DEBUG: Getting child selectors for:",
|
||||
this.listSelector
|
||||
);
|
||||
const childSelectors = this.getChildSelectors(
|
||||
iframeDocument,
|
||||
this.listSelector
|
||||
);
|
||||
console.log("🐛 DEBUG: Generated child selectors:", {
|
||||
count: childSelectors.length,
|
||||
selectors: childSelectors.slice(0, 10), // First 10
|
||||
listSelector: this.listSelector,
|
||||
});
|
||||
return { ...highlighterData, childSelectors };
|
||||
} else {
|
||||
console.log(
|
||||
"🐛 DEBUG: No listSelector set, returning without childSelectors"
|
||||
);
|
||||
return highlighterData;
|
||||
}
|
||||
} else {
|
||||
@@ -3234,8 +3199,6 @@ class ClientSelectorGenerator {
|
||||
)
|
||||
: this.getSelectors(iframeDocument, coordinates);
|
||||
|
||||
console.log("SELECTOR BASED ON CUSTOM ACTION", selectorBasedOnCustomAction);
|
||||
|
||||
if (this.paginationMode && selectorBasedOnCustomAction) {
|
||||
// Chain selectors in specific priority order
|
||||
const selectors = selectorBasedOnCustomAction;
|
||||
|
||||
@@ -42,7 +42,6 @@ const Register = () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const { data } = await axios.post(`${apiUrl}/auth/register`, { email, password });
|
||||
console.log(data);
|
||||
dispatch({ type: "LOGIN", payload: data });
|
||||
notify("success", t('register.welcome_notification'));
|
||||
window.localStorage.setItem("user", JSON.stringify(data));
|
||||
|
||||
Reference in New Issue
Block a user