dev3000 0.0.121 → 0.0.124

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/cli.js +19 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/dev-environment.d.ts.map +1 -1
  4. package/dist/dev-environment.js +11 -0
  5. package/dist/dev-environment.js.map +1 -1
  6. package/dist/utils/log-filename.d.ts.map +1 -1
  7. package/dist/utils/log-filename.js +8 -3
  8. package/dist/utils/log-filename.js.map +1 -1
  9. package/mcp-server/app/mcp/route.ts +81 -7
  10. package/mcp-server/app/mcp/tools.ts +33 -3
  11. package/mcp-server/next-env.d.ts +1 -1
  12. package/mcp-server/package.json +0 -12
  13. package/package.json +6 -7
  14. package/mcp-server/.next/build/chunks/[root-of-the-server]__25374c4f._.js +0 -500
  15. package/mcp-server/.next/build/chunks/[root-of-the-server]__25374c4f._.js.map +0 -11
  16. package/mcp-server/.next/build/chunks/[root-of-the-server]__6e020478._.js +0 -441
  17. package/mcp-server/.next/build/chunks/[root-of-the-server]__6e020478._.js.map +0 -7
  18. package/mcp-server/.next/build/chunks/[root-of-the-server]__c438ef56._.js +0 -205
  19. package/mcp-server/.next/build/chunks/[root-of-the-server]__c438ef56._.js.map +0 -8
  20. package/mcp-server/.next/build/chunks/[root-of-the-server]__c7ae8543._.js +0 -500
  21. package/mcp-server/.next/build/chunks/[root-of-the-server]__c7ae8543._.js.map +0 -11
  22. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_80bff36f._.js +0 -13
  23. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_80bff36f._.js.map +0 -5
  24. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_webpack-loaders_ts_c84aa21a._.js +0 -12
  25. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_webpack-loaders_ts_c84aa21a._.js.map +0 -5
  26. package/mcp-server/.next/build/chunks/[turbopack]_runtime.js +0 -770
  27. package/mcp-server/.next/build/chunks/[turbopack]_runtime.js.map +0 -10
  28. package/mcp-server/.next/build/chunks/node_modules__pnpm_806d01c0._.js +0 -6758
  29. package/mcp-server/.next/build/chunks/node_modules__pnpm_806d01c0._.js.map +0 -47
  30. package/mcp-server/.next/build/package.json +0 -1
  31. package/mcp-server/.next/build/postcss.js +0 -6
  32. package/mcp-server/.next/build/postcss.js.map +0 -5
  33. package/mcp-server/.next/build/webpack-loaders.js +0 -6
  34. package/mcp-server/.next/build/webpack-loaders.js.map +0 -5
  35. package/mcp-server/.next/package.json +0 -1
  36. package/mcp-server/app/api/auth/authorize/route.ts +0 -52
  37. package/mcp-server/app/api/auth/callback/route.ts +0 -128
  38. package/mcp-server/app/api/auth/signout/route.ts +0 -34
  39. package/mcp-server/app/api/auth/token/route.ts +0 -16
  40. package/mcp-server/app/api/cloud/check-pr/route.ts +0 -53
  41. package/mcp-server/app/api/cloud/check-pr/steps.ts +0 -458
  42. package/mcp-server/app/api/cloud/check-pr/workflow.ts +0 -109
  43. package/mcp-server/app/api/cloud/fix-workflow/health/route.ts +0 -10
  44. package/mcp-server/app/api/cloud/fix-workflow/route.ts +0 -50
  45. package/mcp-server/app/api/cloud/fix-workflow/steps.ts +0 -2091
  46. package/mcp-server/app/api/cloud/fix-workflow/workflow.ts +0 -296
  47. package/mcp-server/app/api/cloud/start-fix/route.ts +0 -192
  48. package/mcp-server/app/api/integration/webhook/route.ts +0 -290
  49. package/mcp-server/app/api/projects/[projectId]/bypass-token/route.ts +0 -48
  50. package/mcp-server/app/api/projects/branches/route.ts +0 -115
  51. package/mcp-server/app/api/projects/check-protection/route.ts +0 -33
  52. package/mcp-server/app/api/projects/route.ts +0 -97
  53. package/mcp-server/app/api/workflows/route.ts +0 -105
  54. package/mcp-server/app/auth/error/page.tsx +0 -47
  55. package/mcp-server/app/signin/page.tsx +0 -37
  56. package/mcp-server/app/workflows/[id]/report/agent-analysis.tsx +0 -7
  57. package/mcp-server/app/workflows/[id]/report/page.tsx +0 -199
  58. package/mcp-server/app/workflows/new/new-workflow-client.tsx +0 -32
  59. package/mcp-server/app/workflows/new/page.tsx +0 -13
  60. package/mcp-server/app/workflows/new-workflow-modal.tsx +0 -973
  61. package/mcp-server/app/workflows/page.tsx +0 -16
  62. package/mcp-server/app/workflows/workflows-client.tsx +0 -290
@@ -1,290 +0,0 @@
1
- /**
2
- * Vercel Integration Webhook Handler
3
- *
4
- * This endpoint receives webhooks from Vercel when deployments are ready.
5
- * It automatically triggers PR checks for preview deployments.
6
- *
7
- * Note: This uses Vercel's deployment metadata which includes GitHub info
8
- * automatically - no GitHub token setup required!
9
- */
10
-
11
- export async function POST(request: Request) {
12
- try {
13
- const payload = await request.json()
14
-
15
- console.log("[Webhook] Received deployment event")
16
- console.log(`[Webhook] Type: ${payload.type}`)
17
- console.log(`[Webhook] Deployment: ${payload.deployment?.url}`)
18
-
19
- // Only process deployment.created events for preview deployments
20
- if (payload.type !== "deployment.created") {
21
- return Response.json({ message: "Ignoring non-deployment event" })
22
- }
23
-
24
- const deployment = payload.deployment
25
-
26
- // Only process preview deployments (not production)
27
- if (deployment.target === "production") {
28
- console.log("[Webhook] Skipping production deployment")
29
- return Response.json({ message: "Skipping production deployment" })
30
- }
31
-
32
- // Check if this is a PR deployment
33
- if (!deployment.meta?.githubCommitRef || !deployment.meta?.githubOrg || !deployment.meta?.githubRepo) {
34
- console.log("[Webhook] Not a GitHub PR deployment")
35
- return Response.json({ message: "Not a GitHub PR deployment" })
36
- }
37
-
38
- const branch = deployment.meta.githubCommitRef
39
- const owner = deployment.meta.githubOrg
40
- const repo = deployment.meta.githubRepo
41
- const previewUrl = `https://${deployment.url}`
42
-
43
- console.log(`[Webhook] Processing PR deployment for ${owner}/${repo}#${branch}`)
44
-
45
- // Find the PR number for this branch
46
- const prNumber = await findPRNumber(owner, repo, branch)
47
-
48
- if (!prNumber) {
49
- console.log(`[Webhook] No PR found for branch: ${branch}`)
50
- return Response.json({ message: "No PR found for this branch" })
51
- }
52
-
53
- console.log(`[Webhook] Found PR #${prNumber}`)
54
-
55
- // Fetch PR details
56
- const prDetails = await fetchPRDetails(owner, repo, prNumber)
57
-
58
- if (!prDetails) {
59
- console.log(`[Webhook] Failed to fetch PR details`)
60
- return Response.json({ error: "Failed to fetch PR details" }, { status: 500 })
61
- }
62
-
63
- // Get changed files
64
- const changedFiles = await getChangedFiles(owner, repo, prNumber)
65
-
66
- // Trigger the check-pr workflow
67
- console.log(`[Webhook] Triggering PR check workflow`)
68
-
69
- const workflowUrl = "https://dev3000-mcp.vercel.sh/api/cloud/check-pr"
70
-
71
- const workflowResponse = await fetch(workflowUrl, {
72
- method: "POST",
73
- headers: {
74
- "Content-Type": "application/json"
75
- },
76
- body: JSON.stringify({
77
- previewUrl,
78
- prTitle: prDetails.title,
79
- prBody: prDetails.body,
80
- changedFiles,
81
- repoOwner: owner,
82
- repoName: repo,
83
- prNumber
84
- })
85
- })
86
-
87
- if (!workflowResponse.ok) {
88
- console.error(`[Webhook] Workflow failed: ${workflowResponse.status}`)
89
- return Response.json({ error: "Workflow failed" }, { status: 500 })
90
- }
91
-
92
- const result = await workflowResponse.json()
93
-
94
- console.log(`[Webhook] Workflow completed: ${result.success ? "success" : "failed"}`)
95
- console.log(`[Webhook] Report URL: ${result.reportUrl}`)
96
-
97
- // Optional: Post comment on PR if GITHUB_TOKEN is set
98
- if (process.env.GITHUB_TOKEN) {
99
- await postPRComment(owner, repo, prNumber, result)
100
- await setGitHubCheck(owner, repo, deployment.meta.githubCommitSha, result)
101
- console.log(`[Webhook] Posted results to PR`)
102
- } else {
103
- console.log(`[Webhook] Skipping GitHub comment (no GITHUB_TOKEN set)`)
104
- console.log(`[Webhook] View report at: ${result.reportUrl}`)
105
- }
106
-
107
- return Response.json({
108
- success: true,
109
- prNumber,
110
- reportUrl: result.reportUrl,
111
- checksPassed: result.success,
112
- githubCommentPosted: !!process.env.GITHUB_TOKEN
113
- })
114
- } catch (error) {
115
- console.error("[Webhook] Error:", error)
116
- return Response.json({ error: error instanceof Error ? error.message : "Unknown error" }, { status: 500 })
117
- }
118
- }
119
-
120
- /**
121
- * Find PR number for a given branch
122
- */
123
- async function findPRNumber(owner: string, repo: string, branch: string): Promise<string | null> {
124
- try {
125
- const headers: Record<string, string> = {
126
- Accept: "application/vnd.github.v3+json"
127
- }
128
-
129
- // Only add Authorization header if token is available
130
- if (process.env.GITHUB_TOKEN) {
131
- headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`
132
- }
133
-
134
- const response = await fetch(
135
- `https://api.github.com/repos/${owner}/${repo}/pulls?head=${owner}:${branch}&state=open`,
136
- { headers }
137
- )
138
-
139
- if (!response.ok) {
140
- console.error(`Failed to find PR: ${response.status}`)
141
- return null
142
- }
143
-
144
- const prs = await response.json()
145
- return prs.length > 0 ? String(prs[0].number) : null
146
- } catch (error) {
147
- console.error("Error finding PR:", error)
148
- return null
149
- }
150
- }
151
-
152
- /**
153
- * Fetch PR details from GitHub
154
- */
155
- async function fetchPRDetails(owner: string, repo: string, prNumber: string) {
156
- try {
157
- const headers: Record<string, string> = {
158
- Accept: "application/vnd.github.v3+json"
159
- }
160
-
161
- // Only add Authorization header if token is available
162
- if (process.env.GITHUB_TOKEN) {
163
- headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`
164
- }
165
-
166
- const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}`, {
167
- headers
168
- })
169
-
170
- if (!response.ok) {
171
- return null
172
- }
173
-
174
- const pr = await response.json()
175
- return {
176
- title: pr.title,
177
- body: pr.body || "",
178
- number: pr.number
179
- }
180
- } catch (error) {
181
- console.error("Error fetching PR details:", error)
182
- return null
183
- }
184
- }
185
-
186
- /**
187
- * Get changed files in PR
188
- */
189
- async function getChangedFiles(owner: string, repo: string, prNumber: string): Promise<string[]> {
190
- try {
191
- const headers: Record<string, string> = {
192
- Accept: "application/vnd.github.v3+json"
193
- }
194
-
195
- // Only add Authorization header if token is available
196
- if (process.env.GITHUB_TOKEN) {
197
- headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`
198
- }
199
-
200
- const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/files`, {
201
- headers
202
- })
203
-
204
- if (!response.ok) {
205
- return []
206
- }
207
-
208
- const files = await response.json()
209
- // biome-ignore lint/suspicious/noExplicitAny: GitHub API file objects have dynamic structure
210
- return files.map((file: any) => file.filename)
211
- } catch (error) {
212
- console.error("Error getting changed files:", error)
213
- return []
214
- }
215
- }
216
-
217
- /**
218
- * Post comment on PR with results
219
- */
220
- // biome-ignore lint/suspicious/noExplicitAny: Workflow result object has dynamic structure
221
- async function postPRComment(owner: string, repo: string, prNumber: string, result: any) {
222
- try {
223
- const statusEmoji = result.success ? "✅" : "❌"
224
- const comment = `## ${statusEmoji} dev3000 PR Check Results
225
-
226
- **Status**: ${result.success ? "All checks passed" : "Some checks failed"}
227
-
228
- ### Summary
229
- ${result.verification?.summary || "Check completed"}
230
-
231
- ${result.performance?.slowPagesCount > 0 ? `\n⚠️ **Performance**: ${result.performance.slowPagesCount} slow page(s) detected` : ""}
232
-
233
- **Full Report**: [View Details](${result.reportUrl})
234
-
235
- ---
236
- *Powered by [dev3000](https://github.com/vercel-labs/dev3000)*`
237
-
238
- const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/comments`, {
239
- method: "POST",
240
- headers: {
241
- Accept: "application/vnd.github.v3+json",
242
- Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
243
- "Content-Type": "application/json"
244
- },
245
- body: JSON.stringify({ body: comment })
246
- })
247
-
248
- if (!response.ok) {
249
- console.error(`Failed to post comment: ${response.status}`)
250
- } else {
251
- console.log(`[Webhook] Posted comment on PR #${prNumber}`)
252
- }
253
- } catch (error) {
254
- console.error("Error posting PR comment:", error)
255
- }
256
- }
257
-
258
- /**
259
- * Set GitHub Check status
260
- */
261
- // biome-ignore lint/suspicious/noExplicitAny: Workflow result object has dynamic structure
262
- async function setGitHubCheck(owner: string, repo: string, sha: string, result: any) {
263
- try {
264
- const status = result.success ? "success" : "failure"
265
- const description = result.success ? "All PR checks passed" : "Some PR checks failed"
266
-
267
- const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/statuses/${sha}`, {
268
- method: "POST",
269
- headers: {
270
- Accept: "application/vnd.github.v3+json",
271
- Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
272
- "Content-Type": "application/json"
273
- },
274
- body: JSON.stringify({
275
- state: status,
276
- target_url: result.reportUrl,
277
- description,
278
- context: "dev3000/pr-check"
279
- })
280
- })
281
-
282
- if (!response.ok) {
283
- console.error(`Failed to set GitHub check: ${response.status}`)
284
- } else {
285
- console.log(`[Webhook] Set GitHub check status: ${status}`)
286
- }
287
- } catch (error) {
288
- console.error("Error setting GitHub check:", error)
289
- }
290
- }
@@ -1,48 +0,0 @@
1
- import { cookies } from "next/headers"
2
-
3
- export async function POST(request: Request, { params }: { params: Promise<{ projectId: string }> }) {
4
- try {
5
- const { projectId } = await params
6
- const url = new URL(request.url)
7
- const teamId = url.searchParams.get("teamId")
8
-
9
- // Get access token from cookies
10
- const cookieStore = await cookies()
11
- const accessToken = cookieStore.get("access_token")?.value
12
-
13
- if (!accessToken) {
14
- return Response.json({ error: "Unauthorized" }, { status: 401 })
15
- }
16
-
17
- // Generate/update deployment protection bypass token for the project
18
- const response = await fetch(
19
- `https://api.vercel.com/v1/projects/${projectId}/protection-bypass${teamId ? `?teamId=${teamId}` : ""}`,
20
- {
21
- method: "PATCH",
22
- headers: {
23
- Authorization: `Bearer ${accessToken}`,
24
- "Content-Type": "application/json"
25
- },
26
- body: JSON.stringify({
27
- generate: true
28
- })
29
- }
30
- )
31
-
32
- if (!response.ok) {
33
- const error = await response.text()
34
- console.error("Failed to generate bypass token:", response.status, error)
35
- return Response.json({ error: "Failed to generate bypass token", details: error }, { status: response.status })
36
- }
37
-
38
- const data = await response.json()
39
-
40
- return Response.json({
41
- success: true,
42
- token: data.secret
43
- })
44
- } catch (error) {
45
- console.error("Error generating bypass token:", error)
46
- return Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: 500 })
47
- }
48
- }
@@ -1,115 +0,0 @@
1
- import { getValidAccessToken } from "@/lib/auth"
2
-
3
- /**
4
- * API Route to fetch branches with recent deployments for a project
5
- *
6
- * Query params:
7
- * - projectId: Vercel project ID (required)
8
- * - teamId: Team ID or username (optional)
9
- * - limit: Number of deployments to check (default: 20)
10
- */
11
- export async function GET(request: Request) {
12
- try {
13
- const accessToken = await getValidAccessToken()
14
-
15
- if (!accessToken) {
16
- return Response.json({ error: "Not authenticated" }, { status: 401 })
17
- }
18
-
19
- const url = new URL(request.url)
20
- const projectId = url.searchParams.get("projectId")
21
- const teamId = url.searchParams.get("teamId")
22
- const limit = url.searchParams.get("limit") || "20"
23
-
24
- if (!projectId) {
25
- return Response.json({ error: "projectId is required" }, { status: 400 })
26
- }
27
-
28
- // Build the API URL to fetch recent deployments
29
- const apiUrl = new URL(`https://api.vercel.com/v6/deployments`)
30
- apiUrl.searchParams.set("projectId", projectId)
31
- apiUrl.searchParams.set("limit", limit)
32
- if (teamId) {
33
- apiUrl.searchParams.set("teamId", teamId)
34
- }
35
-
36
- console.log("Fetching deployments from Vercel API:", apiUrl.toString())
37
- const response = await fetch(apiUrl.toString(), {
38
- headers: {
39
- Authorization: `Bearer ${accessToken}`
40
- }
41
- })
42
-
43
- if (!response.ok) {
44
- const errorText = await response.text()
45
- console.error("Failed to fetch deployments:", response.status, errorText)
46
- return Response.json(
47
- { error: `Failed to fetch deployments: ${response.status} ${errorText}` },
48
- { status: response.status }
49
- )
50
- }
51
-
52
- const data = await response.json()
53
- console.log(`Fetched ${data.deployments?.length || 0} deployments`)
54
-
55
- // Extract unique branches with their latest deployment info
56
- const branchesMap = new Map<
57
- string,
58
- {
59
- name: string
60
- lastDeployment: {
61
- url: string
62
- createdAt: number
63
- state: string
64
- readyState: string
65
- }
66
- }
67
- >()
68
-
69
- for (const deployment of data.deployments || []) {
70
- const branch = deployment.meta?.githubCommitRef || deployment.gitSource?.ref || "main"
71
-
72
- // Only include deployments that are ready
73
- if (deployment.readyState !== "READY") {
74
- continue
75
- }
76
-
77
- // Only include the latest deployment per branch
78
- if (!branchesMap.has(branch)) {
79
- branchesMap.set(branch, {
80
- name: branch,
81
- lastDeployment: {
82
- url: deployment.url,
83
- createdAt: deployment.createdAt,
84
- state: deployment.state,
85
- readyState: deployment.readyState
86
- }
87
- })
88
- }
89
- }
90
-
91
- // Convert to array and sort by most recent deployment
92
- const branches = Array.from(branchesMap.values()).sort(
93
- (a, b) => b.lastDeployment.createdAt - a.lastDeployment.createdAt
94
- )
95
-
96
- console.log(
97
- `Found ${branches.length} unique branches with ready deployments:`,
98
- branches.map((b) => b.name)
99
- )
100
-
101
- return Response.json({
102
- success: true,
103
- branches
104
- })
105
- } catch (error) {
106
- console.error("Error fetching branches:", error)
107
- return Response.json(
108
- {
109
- success: false,
110
- error: error instanceof Error ? error.message : String(error)
111
- },
112
- { status: 500 }
113
- )
114
- }
115
- }
@@ -1,33 +0,0 @@
1
- export async function POST(request: Request) {
2
- try {
3
- const { url } = await request.json()
4
-
5
- if (!url) {
6
- return Response.json({ error: "URL is required" }, { status: 400 })
7
- }
8
-
9
- // Make HEAD request to check if deployment is protected
10
- const response = await fetch(url, {
11
- method: "HEAD",
12
- // Don't follow redirects
13
- redirect: "manual"
14
- })
15
-
16
- // If we get 401, deployment is protected
17
- const isProtected = response.status === 401
18
-
19
- return Response.json({
20
- isProtected,
21
- status: response.status
22
- })
23
- } catch (error) {
24
- console.error("Error checking deployment protection:", error)
25
- return Response.json(
26
- {
27
- error: error instanceof Error ? error.message : String(error),
28
- isProtected: false
29
- },
30
- { status: 500 }
31
- )
32
- }
33
- }
@@ -1,97 +0,0 @@
1
- import { cookies } from "next/headers"
2
-
3
- /**
4
- * API Route to fetch Vercel projects for a team/account
5
- *
6
- * Query params:
7
- * - teamId: Team ID or username (optional - if omitted, fetches personal projects)
8
- */
9
- export async function GET(request: Request) {
10
- try {
11
- const cookieStore = await cookies()
12
- const accessToken = cookieStore.get("access_token")?.value
13
-
14
- if (!accessToken) {
15
- return Response.json({ error: "Not authenticated" }, { status: 401 })
16
- }
17
-
18
- const url = new URL(request.url)
19
- const teamId = url.searchParams.get("teamId")
20
-
21
- // Build the API URL with optional teamId parameter
22
- const apiUrl = new URL("https://api.vercel.com/v9/projects")
23
- if (teamId) {
24
- apiUrl.searchParams.set("teamId", teamId)
25
- }
26
-
27
- // Fetch projects from Vercel API
28
- console.log("Fetching projects from Vercel API:", apiUrl.toString())
29
- const response = await fetch(apiUrl.toString(), {
30
- headers: {
31
- Authorization: `Bearer ${accessToken}`
32
- }
33
- })
34
-
35
- if (!response.ok) {
36
- const errorText = await response.text()
37
- console.error("Failed to fetch projects:", response.status, errorText)
38
- return Response.json(
39
- { error: `Failed to fetch projects: ${response.status} ${errorText}` },
40
- { status: response.status }
41
- )
42
- }
43
-
44
- const data = await response.json()
45
- console.log("Projects API response:", JSON.stringify(data, null, 2))
46
- console.log(`Fetched ${data.projects?.length || 0} projects from Vercel API`)
47
-
48
- // Handle case where no projects exist
49
- if (!data.projects || data.projects.length === 0) {
50
- return Response.json({
51
- success: true,
52
- projects: []
53
- })
54
- }
55
-
56
- // Format projects data
57
- // biome-ignore lint/suspicious/noExplicitAny: Vercel API response shape is external
58
- const projects = data.projects.map((project: any) => ({
59
- id: project.id,
60
- name: project.name,
61
- framework: project.framework,
62
- link: project.link,
63
- latestDeployments:
64
- // biome-ignore lint/suspicious/noExplicitAny: Vercel API response shape is external
65
- project.latestDeployments?.map((deployment: any) => ({
66
- id: deployment.id,
67
- url: deployment.url,
68
- state: deployment.state,
69
- readyState: deployment.readyState,
70
- createdAt: deployment.createdAt,
71
- gitSource: deployment.gitSource
72
- ? {
73
- type: deployment.gitSource.type,
74
- repoId: deployment.gitSource.repoId,
75
- ref: deployment.gitSource.ref,
76
- sha: deployment.gitSource.sha,
77
- message: deployment.gitSource.message
78
- }
79
- : null
80
- })) || []
81
- }))
82
-
83
- return Response.json({
84
- success: true,
85
- projects
86
- })
87
- } catch (error) {
88
- console.error("Error fetching projects:", error)
89
- return Response.json(
90
- {
91
- success: false,
92
- error: error instanceof Error ? error.message : String(error)
93
- },
94
- { status: 500 }
95
- )
96
- }
97
- }
@@ -1,105 +0,0 @@
1
- import { deleteWorkflowRuns, listWorkflowRuns } from "@/lib/workflow-storage"
2
-
3
- // CORS headers - allowing credentials from localhost
4
- const corsHeaders = {
5
- "Access-Control-Allow-Origin": "http://localhost:3000",
6
- "Access-Control-Allow-Methods": "GET, DELETE, OPTIONS",
7
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
8
- "Access-Control-Allow-Credentials": "true"
9
- }
10
-
11
- // Handle OPTIONS preflight request
12
- export async function OPTIONS() {
13
- return new Response(null, {
14
- status: 204,
15
- headers: corsHeaders
16
- })
17
- }
18
-
19
- /**
20
- * GET /api/workflows
21
- * Fetches all workflow runs for a user
22
- *
23
- * Query params:
24
- * - userId: Required. The user ID to fetch runs for
25
- */
26
- export async function GET(request: Request) {
27
- try {
28
- const { searchParams } = new URL(request.url)
29
- const userId = searchParams.get("userId")
30
-
31
- if (!userId) {
32
- return Response.json({ error: "userId is required" }, { status: 400, headers: corsHeaders })
33
- }
34
-
35
- console.log(`[Workflows API] Fetching runs for user: ${userId}`)
36
-
37
- const runs = await listWorkflowRuns(userId)
38
-
39
- console.log(`[Workflows API] Found ${runs.length} runs`)
40
-
41
- return Response.json(
42
- {
43
- success: true,
44
- runs
45
- },
46
- { headers: corsHeaders }
47
- )
48
- } catch (error) {
49
- console.error("[Workflows API] Error fetching workflow runs:", error)
50
- return Response.json(
51
- {
52
- success: false,
53
- error: error instanceof Error ? error.message : String(error)
54
- },
55
- { status: 500, headers: corsHeaders }
56
- )
57
- }
58
- }
59
-
60
- /**
61
- * DELETE /api/workflows
62
- * Deletes workflow runs and their associated blobs
63
- *
64
- * Body:
65
- * - userId: Required. The user ID
66
- * - runIds: Required. Array of run IDs to delete
67
- */
68
- export async function DELETE(request: Request) {
69
- try {
70
- const body = await request.json()
71
- const { userId, runIds } = body
72
-
73
- if (!userId) {
74
- return Response.json({ error: "userId is required" }, { status: 400, headers: corsHeaders })
75
- }
76
-
77
- if (!runIds || !Array.isArray(runIds) || runIds.length === 0) {
78
- return Response.json({ error: "runIds array is required" }, { status: 400, headers: corsHeaders })
79
- }
80
-
81
- console.log(`[Workflows API] Deleting ${runIds.length} runs for user: ${userId}`)
82
-
83
- const result = await deleteWorkflowRuns(userId, runIds)
84
-
85
- console.log(`[Workflows API] Deleted ${result.deleted} runs, ${result.errors.length} errors`)
86
-
87
- return Response.json(
88
- {
89
- success: true,
90
- deleted: result.deleted,
91
- errors: result.errors
92
- },
93
- { headers: corsHeaders }
94
- )
95
- } catch (error) {
96
- console.error("[Workflows API] Error deleting workflow runs:", error)
97
- return Response.json(
98
- {
99
- success: false,
100
- error: error instanceof Error ? error.message : String(error)
101
- },
102
- { status: 500, headers: corsHeaders }
103
- )
104
- }
105
- }