Skip to content

Commit 86df298

Browse files
fixed github import modal and updated projects with animations
1 parent ba7b0bf commit 86df298

31 files changed

+4724
-1231
lines changed

IMPLEMENTATION_PLAN.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Implementation Plan: Fix GitHub Import Type Error
2+
3+
This document outlines the plan to resolve the TypeScript type error occurring during the build process in the `app/api/projects/[projectId]/github-import/route.ts` file.
4+
5+
## 1. Problem Analysis
6+
7+
The build fails with a type error related to the `RouteContext` of the `POST` handler in the GitHub import route. The error message:
8+
9+
```
10+
Type error: Type '{ __tag__: "POST"; __param_position__: "second"; __param_type__: GithubImportRouteContext; }' does not satisfy the constraint 'ParamCheck<RouteContext>'.
11+
The types of '__param_type__.params' are incompatible between these types.
12+
Type '{ projectId: string; }' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]
13+
```
14+
15+
This indicates that the TypeScript compiler is expecting the `params` object within the route's context to be a `Promise`, but it's being treated as a plain object `{ projectId: string; }`. This is a common issue with Next.js's type generation for dynamic routes, where the inferred types do not match the actual runtime structure.
16+
17+
## 2. Proposed Solution
18+
19+
The solution is to correct the type definition for the route's context to accurately reflect the structure of the `params` object. This will ensure that the TypeScript compiler understands the correct shape of the data and resolves the type mismatch.
20+
21+
## 3. Step-by-Step Implementation
22+
23+
1. **Modify `GithubImportRouteContext` Type:**
24+
In the file `app/api/projects/[projectId]/github-import/route.ts`, the existing `GithubImportRouteContext` interface will be updated. The current definition is correct in its structure, but it seems there's a conflict with a globally inferred `RouteContext`. To avoid this, we will rename it and ensure it's correctly applied.
25+
26+
The current interface is:
27+
```typescript
28+
interface GithubImportRouteContext {
29+
params: {
30+
projectId: string;
31+
};
32+
}
33+
```
34+
35+
We will ensure this type is explicitly used in the `POST` function signature. No changes to the interface itself are needed, but we need to make sure it's being used correctly. The investigation shows the interface is defined correctly, but the error persists. This suggests the issue might be in how Next.js is interpreting the types.
36+
37+
A common fix for this is to simplify the function signature and let Next.js infer the types, or to be more explicit in a way that doesn't conflict with Next.js's internal types.
38+
39+
2. **Update the POST Function Signature:**
40+
We will modify the `POST` function signature in `app/api/projects/[projectId]/github-import/route.ts` to resolve the ambiguity.
41+
42+
**Current Signature:**
43+
```typescript
44+
export async function POST(
45+
request: NextRequest,
46+
context: GithubImportRouteContext
47+
) {
48+
```
49+
50+
**Proposed Change:**
51+
We will adjust the signature to destructure the context parameter directly, which can help TypeScript resolve the types correctly.
52+
53+
```typescript
54+
export async function POST(
55+
request: NextRequest,
56+
{ params }: { params: { projectId: string } }
57+
) {
58+
```
59+
This change bypasses the intermediate `GithubImportRouteContext` interface and defines the expected shape of the context object directly in the function signature. This is a robust way to handle type inference issues with Next.js route handlers.
60+
61+
## 4. Verification
62+
63+
After applying the code change, the `npm run build` command will be executed again. The build should complete successfully without any TypeScript errors, confirming that the issue has been resolved.

app/api-docs/page.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"use client";
2+
3+
import dynamic from 'next/dynamic';
4+
import "swagger-ui-react/swagger-ui.css";
5+
6+
const SwaggerUI = dynamic(() => import("swagger-ui-react"), { ssr: false });
7+
8+
const ApiDocsPage = () => {
9+
return (
10+
<div style={{ paddingTop: '20px' }}>
11+
<SwaggerUI url="/api/openapi-spec" />
12+
</div>
13+
);
14+
};
15+
16+
export default ApiDocsPage;

app/api/github/callback/route.ts

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,87 @@ export async function GET(request: NextRequest) {
55
const code = url.searchParams.get('code')
66
const error = url.searchParams.get('error')
77
const errorDescription = url.searchParams.get('error_description')
8-
const state = url.searchParams.get('state')
8+
const state = url.searchParams.get('state')
9+
10+
const sanitize = (value: string | null): string => {
11+
if (!value) return ''
12+
return value
13+
.replace(/[<>"/&']/g, (char) => {
14+
const entities: Record<string, string> = {
15+
'<': '&lt;',
16+
'>': '&gt;',
17+
'"': '&quot;',
18+
'/': '&#x2F;',
19+
'&': '&amp;',
20+
"'": '&#x27;'
21+
}
22+
return entities[char] || char
23+
})
24+
}
25+
26+
const sanitizedError = sanitize(error)
27+
const sanitizedErrorDescription = sanitize(errorDescription)
28+
const sanitizedCode = sanitize(code)
29+
const sanitizedState = sanitize(state)
930

1031
const html = `
1132
<!DOCTYPE html>
1233
<html>
1334
<head>
1435
<title>GitHub Authentication</title>
36+
<meta charset="utf-8">
37+
<meta name="viewport" content="width=device-width, initial-scale=1">
38+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-inline';">
1539
</head>
1640
<body>
1741
<script>
18-
if (window.opener) {
19-
if (${error ? `true` : `false`}) {
20-
window.opener.postMessage({
21-
type: 'GITHUB_AUTH_ERROR',
22-
error: '${error}',
23-
errorDescription: '${errorDescription}'
24-
}, '*');
25-
} else if (${code ? `true` : `false`}) {
26-
27-
window.opener.postMessage({
28-
type: 'GITHUB_AUTH_CALLBACK',
29-
code: '${code}',
30-
state: '${state}'
31-
}, '*');
32-
} else {
42+
(function() {
43+
'use strict';
44+
45+
if (window.opener) {
46+
const hasError = ${error ? 'true' : 'false'};
47+
const hasCode = ${code ? 'true' : 'false'};
3348
34-
window.opener.postMessage({
35-
type: 'GITHUB_AUTH_ERROR',
36-
error: 'unknown_error',
37-
errorDescription: 'No authorization code or error returned from GitHub.'
38-
}, '*');
49+
if (hasError) {
50+
window.opener.postMessage({
51+
type: 'GITHUB_AUTH_ERROR',
52+
error: ${JSON.stringify(sanitizedError)},
53+
errorDescription: ${JSON.stringify(sanitizedErrorDescription)}
54+
}, window.location.origin);
55+
} else if (hasCode) {
56+
window.opener.postMessage({
57+
type: 'GITHUB_AUTH_CALLBACK',
58+
code: ${JSON.stringify(sanitizedCode)},
59+
state: ${JSON.stringify(sanitizedState)}
60+
}, window.location.origin);
61+
} else {
62+
window.opener.postMessage({
63+
type: 'GITHUB_AUTH_ERROR',
64+
error: 'unknown_error',
65+
errorDescription: 'No authorization code or error returned from GitHub.'
66+
}, window.location.origin);
67+
}
3968
}
40-
}
41-
42-
43-
setTimeout(() => { window.close(); }, 500);
69+
70+
setTimeout(function() {
71+
window.close();
72+
}, 1000);
73+
})();
4474
</script>
45-
<p>Processing GitHub authentication...</p>
46-
<p>You can close this window if it doesn't close automatically.</p>
75+
<div style="text-align: center; font-family: system-ui, sans-serif; padding: 2rem;">
76+
<h2>Processing GitHub authentication...</h2>
77+
<p>You can close this window if it doesn't close automatically.</p>
78+
</div>
4779
</body>
4880
</html>
4981
`
5082

5183
return new NextResponse(html, {
52-
headers: { 'Content-Type': 'text/html' },
84+
headers: {
85+
'Content-Type': 'text/html',
86+
'Cache-Control': 'no-store, no-cache, must-revalidate',
87+
'X-Content-Type-Options': 'nosniff',
88+
'X-Frame-Options': 'DENY'
89+
},
5390
})
5491
}

app/api/hello/route.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { NextResponse } from 'next/server';
2+
import type { paths } from '@/lib/openapi.types'; // Assuming openapi.types.ts is in lib
3+
4+
// This type would correspond to the response for GET /hello
5+
type HelloWorldResponse = paths['/hello']['get']['responses']['200']['content']['application/json'];
6+
7+
export async function GET() {
8+
const response: HelloWorldResponse = {
9+
message: 'Hello, world!',
10+
};
11+
return NextResponse.json(response);
12+
}

app/api/openapi-spec/route.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { NextResponse } from 'next/server';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import yaml from 'js-yaml';
5+
6+
export async function GET() {
7+
try {
8+
const filePath = path.join(process.cwd(), 'lib', 'openapi.yaml');
9+
const fileContents = fs.readFileSync(filePath, 'utf8');
10+
const spec = yaml.load(fileContents);
11+
return NextResponse.json(spec);
12+
} catch (error) {
13+
console.error('Error loading OpenAPI spec:', error);
14+
return NextResponse.json({ message: 'Error loading OpenAPI spec' }, { status: 500 });
15+
}
16+
}

0 commit comments

Comments
 (0)