chore: lint

This commit is contained in:
amhsirak
2025-06-06 00:53:02 +05:30
parent 5d4412fb61
commit a23f2f7bcb

View File

@@ -23,7 +23,7 @@ chromium.use(stealthPlugin());
export const router = Router(); export const router = Router();
export const processWorkflowActions = async (workflow: any[], checkLimit: boolean = false): Promise<any[]> => { export const processWorkflowActions = async (workflow: any[], checkLimit: boolean = false): Promise<any[]> => {
const processedWorkflow = JSON.parse(JSON.stringify(workflow)); const processedWorkflow = JSON.parse(JSON.stringify(workflow));
processedWorkflow.forEach((pair: any) => { processedWorkflow.forEach((pair: any) => {
pair.what.forEach((action: any) => { pair.what.forEach((action: any) => {
@@ -108,52 +108,52 @@ router.get('/recordings/:id', requireSignIn, async (req, res) => {
router.get(('/recordings/:id/runs'), requireSignIn, async (req, res) => { router.get(('/recordings/:id/runs'), requireSignIn, async (req, res) => {
try { try {
const runs = await Run.findAll({ const runs = await Run.findAll({
where: { where: {
robotMetaId: req.params.id robotMetaId: req.params.id
}, },
raw: true raw: true
}); });
const formattedRuns = runs.map(formatRunResponse); const formattedRuns = runs.map(formatRunResponse);
const response = { const response = {
statusCode: 200, statusCode: 200,
messageCode: "success", messageCode: "success",
runs: { runs: {
totalCount: formattedRuns.length, totalCount: formattedRuns.length,
items: formattedRuns, items: formattedRuns,
}, },
}; };
res.status(200).json(response); res.status(200).json(response);
} catch (error) { } catch (error) {
console.error("Error fetching runs:", error); console.error("Error fetching runs:", error);
res.status(500).json({ res.status(500).json({
statusCode: 500, statusCode: 500,
messageCode: "error", messageCode: "error",
message: "Failed to retrieve runs", message: "Failed to retrieve runs",
}); });
} }
}) })
function formatRunResponse(run: any) { function formatRunResponse(run: any) {
const formattedRun = { const formattedRun = {
id: run.id, id: run.id,
status: run.status, status: run.status,
name: run.name, name: run.name,
robotId: run.robotMetaId, // Renaming robotMetaId to robotId robotId: run.robotMetaId, // Renaming robotMetaId to robotId
startedAt: run.startedAt, startedAt: run.startedAt,
finishedAt: run.finishedAt, finishedAt: run.finishedAt,
runId: run.runId, runId: run.runId,
runByUserId: run.runByUserId, runByUserId: run.runByUserId,
runByScheduleId: run.runByScheduleId, runByScheduleId: run.runByScheduleId,
runByAPI: run.runByAPI, runByAPI: run.runByAPI,
data: {}, data: {},
screenshot: null, screenshot: null,
}; };
if (run.serializableOutput && run.serializableOutput['item-0']) { if (run.serializableOutput && run.serializableOutput['item-0']) {
formattedRun.data = run.serializableOutput['item-0']; formattedRun.data = run.serializableOutput['item-0'];
} else if (run.binaryOutput && run.binaryOutput['item-0']) { } else if (run.binaryOutput && run.binaryOutput['item-0']) {
formattedRun.screenshot = run.binaryOutput['item-0']; formattedRun.screenshot = run.binaryOutput['item-0'];
} }
return formattedRun; return formattedRun;
@@ -170,81 +170,81 @@ interface Credentials {
function handleWorkflowActions(workflow: any[], credentials: Credentials) { function handleWorkflowActions(workflow: any[], credentials: Credentials) {
return workflow.map(step => { return workflow.map(step => {
if (!step.what) return step; if (!step.what) return step;
const newWhat: any[] = []; const newWhat: any[] = [];
const processedSelectors = new Set<string>(); const processedSelectors = new Set<string>();
for (let i = 0; i < step.what.length; i++) {
const action = step.what[i];
if (!action?.action || !action?.args?.[0]) {
newWhat.push(action);
continue;
}
const selector = action.args[0]; for (let i = 0; i < step.what.length; i++) {
const credential = credentials[selector]; const action = step.what[i];
if (!credential) { if (!action?.action || !action?.args?.[0]) {
newWhat.push(action); newWhat.push(action);
continue; continue;
}
if (action.action === 'click') {
newWhat.push(action);
if (!processedSelectors.has(selector) &&
i + 1 < step.what.length &&
(step.what[i + 1].action === 'type' || step.what[i + 1].action === 'press')) {
newWhat.push({
action: 'type',
args: [selector, encrypt(credential.value), credential.type]
});
newWhat.push({
action: 'waitForLoadState',
args: ['networkidle']
});
processedSelectors.add(selector);
while (i + 1 < step.what.length &&
(step.what[i + 1].action === 'type' ||
step.what[i + 1].action === 'press' ||
step.what[i + 1].action === 'waitForLoadState')) {
i++;
}
}
} else if ((action.action === 'type' || action.action === 'press') &&
!processedSelectors.has(selector)) {
newWhat.push({
action: 'type',
args: [selector, encrypt(credential.value), credential.type]
});
newWhat.push({
action: 'waitForLoadState',
args: ['networkidle']
});
processedSelectors.add(selector);
// Skip subsequent type/press/waitForLoadState actions for this selector
while (i + 1 < step.what.length &&
(step.what[i + 1].action === 'type' ||
step.what[i + 1].action === 'press' ||
step.what[i + 1].action === 'waitForLoadState')) {
i++;
}
}
} }
return { const selector = action.args[0];
...step, const credential = credentials[selector];
what: newWhat
}; if (!credential) {
newWhat.push(action);
continue;
}
if (action.action === 'click') {
newWhat.push(action);
if (!processedSelectors.has(selector) &&
i + 1 < step.what.length &&
(step.what[i + 1].action === 'type' || step.what[i + 1].action === 'press')) {
newWhat.push({
action: 'type',
args: [selector, encrypt(credential.value), credential.type]
});
newWhat.push({
action: 'waitForLoadState',
args: ['networkidle']
});
processedSelectors.add(selector);
while (i + 1 < step.what.length &&
(step.what[i + 1].action === 'type' ||
step.what[i + 1].action === 'press' ||
step.what[i + 1].action === 'waitForLoadState')) {
i++;
}
}
} else if ((action.action === 'type' || action.action === 'press') &&
!processedSelectors.has(selector)) {
newWhat.push({
action: 'type',
args: [selector, encrypt(credential.value), credential.type]
});
newWhat.push({
action: 'waitForLoadState',
args: ['networkidle']
});
processedSelectors.add(selector);
// Skip subsequent type/press/waitForLoadState actions for this selector
while (i + 1 < step.what.length &&
(step.what[i + 1].action === 'type' ||
step.what[i + 1].action === 'press' ||
step.what[i + 1].action === 'waitForLoadState')) {
i++;
}
}
}
return {
...step,
what: newWhat
};
}); });
} }
@@ -275,7 +275,7 @@ router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, r
if (targetUrl) { if (targetUrl) {
const updatedWorkflow = [...robot.recording.workflow]; const updatedWorkflow = [...robot.recording.workflow];
for (let i = updatedWorkflow.length - 1; i >= 0; i--) { for (let i = updatedWorkflow.length - 1; i >= 0; i--) {
const step = updatedWorkflow[i]; const step = updatedWorkflow[i];
for (let j = 0; j < step.what.length; j++) { for (let j = 0; j < step.what.length; j++) {
@@ -286,7 +286,7 @@ router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, r
if (step.where?.url && step.where.url !== "about:blank") { if (step.where?.url && step.where.url !== "about:blank") {
step.where.url = targetUrl; step.where.url = targetUrl;
} }
robot.set('recording', { ...robot.recording, workflow: updatedWorkflow }); robot.set('recording', { ...robot.recording, workflow: updatedWorkflow });
robot.changed('recording', true); robot.changed('recording', true);
i = -1; i = -1;
@@ -307,16 +307,16 @@ router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, r
if (limits && Array.isArray(limits) && limits.length > 0) { if (limits && Array.isArray(limits) && limits.length > 0) {
for (const limitInfo of limits) { for (const limitInfo of limits) {
const { pairIndex, actionIndex, argIndex, limit } = limitInfo; const { pairIndex, actionIndex, argIndex, limit } = limitInfo;
const pair = workflow[pairIndex]; const pair = workflow[pairIndex];
if (!pair || !pair.what) continue; if (!pair || !pair.what) continue;
const action = pair.what[actionIndex]; const action = pair.what[actionIndex];
if (!action || !action.args) continue; if (!action || !action.args) continue;
const arg = action.args[argIndex]; const arg = action.args[argIndex];
if (!arg || typeof arg !== 'object') continue; if (!arg || typeof arg !== 'object') continue;
(arg as { limit: number }).limit = limit; (arg as { limit: number }).limit = limit;
} }
} }
@@ -384,7 +384,7 @@ router.post('/recordings/:id/duplicate', requireSignIn, async (req: Authenticate
step.what.forEach((action) => { step.what.forEach((action) => {
if (action.action === "goto" && action.args?.length) { if (action.action === "goto" && action.args?.length) {
action.args[0] = targetUrl; action.args[0] = targetUrl;
} }
}); });
@@ -394,22 +394,22 @@ router.post('/recordings/:id/duplicate', requireSignIn, async (req: Authenticate
const currentTimestamp = new Date().toLocaleString(); const currentTimestamp = new Date().toLocaleString();
const newRobot = await Robot.create({ const newRobot = await Robot.create({
id: uuid(), id: uuid(),
userId: originalRobot.userId, userId: originalRobot.userId,
recording_meta: { recording_meta: {
...originalRobot.recording_meta, ...originalRobot.recording_meta,
id: uuid(), id: uuid(),
name: `${originalRobot.recording_meta.name} (${lastWord})`, name: `${originalRobot.recording_meta.name} (${lastWord})`,
createdAt: currentTimestamp, createdAt: currentTimestamp,
updatedAt: currentTimestamp, updatedAt: currentTimestamp,
}, },
recording: { ...originalRobot.recording, workflow }, recording: { ...originalRobot.recording, workflow },
google_sheet_email: null, google_sheet_email: null,
google_sheet_name: null, google_sheet_name: null,
google_sheet_id: null, google_sheet_id: null,
google_access_token: null, google_access_token: null,
google_refresh_token: null, google_refresh_token: null,
schedule: null, schedule: null,
}); });
logger.log('info', `Robot with ID ${id} duplicated successfully as ${newRobot.id}.`); logger.log('info', `Robot with ID ${id} duplicated successfully as ${newRobot.id}.`);
@@ -534,11 +534,11 @@ router.put('/runs/:id', requireSignIn, async (req: AuthenticatedRequest, res) =>
// Generate runId first // Generate runId first
const runId = uuid(); const runId = uuid();
// Check if user has reached browser limit // Check if user has reached browser limit
const userBrowserIds = browserPool.getAllBrowserIdsForUser(req.user.id); const userBrowserIds = browserPool.getAllBrowserIdsForUser(req.user.id);
const canCreateBrowser = userBrowserIds.length < 2; const canCreateBrowser = userBrowserIds.length < 2;
if (canCreateBrowser) { if (canCreateBrowser) {
// User has available browser slots, create it directly // User has available browser slots, create it directly
const id = createRemoteBrowserForRun(req.user.id); const id = createRemoteBrowserForRun(req.user.id);
@@ -572,7 +572,7 @@ router.put('/runs/:id', requireSignIn, async (req: AuthenticatedRequest, res) =>
if (browserId) { if (browserId) {
// User has reached the browser limit, queue the run // User has reached the browser limit, queue the run
try { try {
// Create the run record with 'queued' status // Create the run record with 'queued' status
await Run.create({ await Run.create({
status: 'queued', status: 'queued',
@@ -589,7 +589,7 @@ router.put('/runs/:id', requireSignIn, async (req: AuthenticatedRequest, res) =>
serializableOutput: {}, serializableOutput: {},
binaryOutput: {}, binaryOutput: {},
}); });
return res.send({ return res.send({
browserId: browserId, browserId: browserId,
runId: runId, runId: runId,
@@ -664,17 +664,17 @@ router.post('/runs/run/:id', requireSignIn, async (req: AuthenticatedRequest, re
// Queue the execution job // Queue the execution job
await pgBoss.createQueue(userQueueName); await pgBoss.createQueue(userQueueName);
const jobId = await pgBoss.send(userQueueName, { const jobId = await pgBoss.send(userQueueName, {
userId: req.user.id, userId: req.user.id,
runId: req.params.id, runId: req.params.id,
browserId: plainRun.browserId browserId: plainRun.browserId
}); });
logger.log('info', `Queued run execution job with ID: ${jobId} for run: ${req.params.id}`); logger.log('info', `Queued run execution job with ID: ${jobId} for run: ${req.params.id}`);
} catch (queueError: any) { } catch (queueError: any) {
logger.log('error', `Failed to queue run execution`); logger.log('error', `Failed to queue run execution`);
} }
} catch (e) { } catch (e) {
const { message } = e as Error; const { message } = e as Error;
@@ -889,15 +889,15 @@ router.delete('/schedule/:id', requireSignIn, async (req: AuthenticatedRequest,
*/ */
router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest, res) => { router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest, res) => {
try { try {
if (!req.user) { if (!req.user) {
return res.status(401).send({ error: 'Unauthorized' }); return res.status(401).send({ error: 'Unauthorized' });
} }
const run = await Run.findOne({ const run = await Run.findOne({
where: { where: {
runId: req.params.id, runId: req.params.id,
runByUserId: req.user.id, runByUserId: req.user.id,
} }
}); });
if (!run) { if (!run) {
@@ -905,8 +905,8 @@ router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest,
} }
if (!['running', 'queued'].includes(run.status)) { if (!['running', 'queued'].includes(run.status)) {
return res.status(400).send({ return res.status(400).send({
error: `Cannot abort run with status: ${run.status}` error: `Cannot abort run with status: ${run.status}`
}); });
} }
@@ -920,13 +920,13 @@ router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest,
finishedAt: new Date().toLocaleString(), finishedAt: new Date().toLocaleString(),
log: 'Run aborted while queued' log: 'Run aborted while queued'
}); });
return res.send({ success: true, message: 'Queued run aborted' }); return res.send({ success: true, message: 'Queued run aborted' });
} }
const userQueueName = `abort-run-user-${req.user.id}`; const userQueueName = `abort-run-user-${req.user.id}`;
await pgBoss.createQueue(userQueueName); await pgBoss.createQueue(userQueueName);
const jobId = await pgBoss.send(userQueueName, { const jobId = await pgBoss.send(userQueueName, {
userId: req.user.id, userId: req.user.id,
runId: req.params.id runId: req.params.id
@@ -934,10 +934,10 @@ router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest,
logger.log('info', `Abort signal sent for run ${req.params.id}, job ID: ${jobId}`); logger.log('info', `Abort signal sent for run ${req.params.id}, job ID: ${jobId}`);
return res.send({ return res.send({
success: true, success: true,
message: 'Abort signal sent', message: 'Abort signal sent',
jobId jobId
}); });
} catch (e) { } catch (e) {