arudradey commited on
Commit
23aa653
·
verified ·
1 Parent(s): 2e6fbe5

Update src/app/api/action/route.ts

Browse files
Files changed (1) hide show
  1. src/app/api/action/route.ts +73 -22
src/app/api/action/route.ts CHANGED
@@ -1,76 +1,127 @@
1
  import { NextRequest, NextResponse } from "next/server";
2
  import { getPage, navigateTo } from "@/lib/browser";
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  export async function POST(req: NextRequest) {
5
  try {
6
- const action = await req.json();
7
  const page = getPage();
8
 
9
  if (!page) {
10
  return NextResponse.json(
11
- { error: "No active browser session. Click Launch first." },
12
  { status: 400 }
13
  );
14
  }
15
 
16
  switch (action.type) {
17
  case "click": {
 
 
 
 
18
  await page.mouse.click(action.x, action.y);
19
- await page
20
- .waitForLoadState("domcontentloaded", { timeout: 8_000 })
21
- .catch(() => {});
22
  break;
23
  }
24
 
25
  case "type": {
26
- if (action.x !== undefined && action.y !== undefined) {
27
  await page.mouse.click(action.x, action.y);
28
- await new Promise((r) => setTimeout(r, 150));
29
  }
 
30
  await page.keyboard.type(action.text || "", { delay: 25 });
 
31
  break;
32
  }
33
 
34
  case "keypress": {
35
  await page.keyboard.press(action.key || "Enter");
36
- await page
37
- .waitForLoadState("domcontentloaded", { timeout: 8_000 })
38
- .catch(() => {});
39
  break;
40
  }
41
 
42
  case "scroll": {
43
  await page.mouse.wheel(action.scrollX || 0, action.scrollY || 300);
44
- await new Promise((r) => setTimeout(r, 300));
45
  break;
46
  }
47
 
48
  case "navigate": {
49
- // Use the layered navigateTo helper instead of bare page.goto
50
- await navigateTo(action.url);
51
  break;
52
  }
53
 
54
  case "hover": {
55
- await page.mouse.move(action.x || 0, action.y || 0);
 
 
 
 
 
56
  break;
57
  }
58
 
59
  case "wait": {
60
- await new Promise((r) =>
61
- setTimeout(r, Math.min(action.ms || 1000, 5000))
62
- );
63
  break;
64
  }
65
 
66
- default:
 
67
  break;
 
 
 
 
 
 
 
68
  }
69
 
70
- return NextResponse.json({ success: true });
 
 
 
71
  } catch (e: unknown) {
72
- const msg = e instanceof Error ? e.message : "Unknown error";
73
- console.error("[/api/action]", msg);
74
- return NextResponse.json({ error: msg }, { status: 500 });
 
75
  }
76
  }
 
1
  import { NextRequest, NextResponse } from "next/server";
2
  import { getPage, navigateTo } from "@/lib/browser";
3
 
4
+ export const runtime = "nodejs";
5
+ export const dynamic = "force-dynamic";
6
+
7
+ type ActionPayload = {
8
+ type?:
9
+ | "click"
10
+ | "type"
11
+ | "scroll"
12
+ | "navigate"
13
+ | "keypress"
14
+ | "hover"
15
+ | "answer"
16
+ | "wait";
17
+ description?: string;
18
+ x?: number;
19
+ y?: number;
20
+ text?: string;
21
+ key?: string;
22
+ url?: string;
23
+ scrollX?: number;
24
+ scrollY?: number;
25
+ ms?: number;
26
+ };
27
+
28
+ function normalizeUrl(input: string): string {
29
+ const value = (input || "").trim();
30
+ if (!value) throw new Error("URL is required");
31
+ if (/^https?:\/\//i.test(value)) return value;
32
+ return `https://${value}`;
33
+ }
34
+
35
  export async function POST(req: NextRequest) {
36
  try {
37
+ const action = (await req.json()) as ActionPayload;
38
  const page = getPage();
39
 
40
  if (!page) {
41
  return NextResponse.json(
42
+ { error: "No active browser session. Launch the browser first." },
43
  { status: 400 }
44
  );
45
  }
46
 
47
  switch (action.type) {
48
  case "click": {
49
+ if (typeof action.x !== "number" || typeof action.y !== "number") {
50
+ throw new Error("Click action requires numeric x and y");
51
+ }
52
+
53
  await page.mouse.click(action.x, action.y);
54
+ await page.waitForLoadState("domcontentloaded", { timeout: 5000 }).catch(() => {});
55
+ await page.waitForTimeout(500);
 
56
  break;
57
  }
58
 
59
  case "type": {
60
+ if (typeof action.x === "number" && typeof action.y === "number") {
61
  await page.mouse.click(action.x, action.y);
62
+ await page.waitForTimeout(150);
63
  }
64
+
65
  await page.keyboard.type(action.text || "", { delay: 25 });
66
+ await page.waitForTimeout(300);
67
  break;
68
  }
69
 
70
  case "keypress": {
71
  await page.keyboard.press(action.key || "Enter");
72
+ await page.waitForLoadState("domcontentloaded", { timeout: 5000 }).catch(() => {});
73
+ await page.waitForTimeout(400);
 
74
  break;
75
  }
76
 
77
  case "scroll": {
78
  await page.mouse.wheel(action.scrollX || 0, action.scrollY || 300);
79
+ await page.waitForTimeout(400);
80
  break;
81
  }
82
 
83
  case "navigate": {
84
+ const targetUrl = normalizeUrl(action.url || "");
85
+ await navigateTo(targetUrl);
86
  break;
87
  }
88
 
89
  case "hover": {
90
+ if (typeof action.x !== "number" || typeof action.y !== "number") {
91
+ throw new Error("Hover action requires numeric x and y");
92
+ }
93
+
94
+ await page.mouse.move(action.x, action.y);
95
+ await page.waitForTimeout(250);
96
  break;
97
  }
98
 
99
  case "wait": {
100
+ const ms = Math.min(Math.max(action.ms || 1000, 100), 10000);
101
+ await page.waitForTimeout(ms);
 
102
  break;
103
  }
104
 
105
+ case "answer": {
106
+ // No browser action needed; handled client-side
107
  break;
108
+ }
109
+
110
+ default:
111
+ return NextResponse.json(
112
+ { error: "Unsupported action type" },
113
+ { status: 400 }
114
+ );
115
  }
116
 
117
+ return NextResponse.json({
118
+ success: true,
119
+ action: action.type,
120
+ });
121
  } catch (e: unknown) {
122
+ const message = e instanceof Error ? e.message : "Unknown error";
123
+ console.error("[/api/action]", message);
124
+
125
+ return NextResponse.json({ error: message }, { status: 500 });
126
  }
127
  }