drbh
commited on
Commit
·
6f5b644
1
Parent(s):
1b70735
feat: boilderplate app
Browse files- app/lib/github-app.server.ts +151 -0
- app/lib/session.server.ts +39 -0
- app/routes/_index.tsx +165 -124
- app/routes/auth.github.callback.tsx +46 -0
- app/routes/auth.github.tsx +13 -0
- app/routes/auth.logout.tsx +17 -0
- app/routes/dashboard.tsx +143 -0
- app/routes/install.tsx +119 -0
- app/routes/status.tsx +243 -0
- app/routes/webhook.github.tsx +165 -0
- package-lock.json +609 -9
- package.json +8 -1
app/lib/github-app.server.ts
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { App } from "@octokit/app";
|
2 |
+
import { createAppAuth } from "@octokit/auth-app";
|
3 |
+
import jwt from "jsonwebtoken";
|
4 |
+
|
5 |
+
// GitHub App configuration - these should be environment variables in production
|
6 |
+
const GITHUB_APP_ID = process.env.GITHUB_APP_ID || "1356087";
|
7 |
+
const GITHUB_APP_PRIVATE_KEY = process.env.GITHUB_APP_PRIVATE_KEY || "your-private-key";
|
8 |
+
const GITHUB_APP_CLIENT_ID = process.env.GITHUB_APP_CLIENT_ID || "Iv23liFxEtiiREnjOeB2";
|
9 |
+
const GITHUB_APP_CLIENT_SECRET = process.env.GITHUB_APP_CLIENT_SECRET || "your-client-secret";
|
10 |
+
|
11 |
+
// For now, we'll hardcode a simple in-memory store
|
12 |
+
// In production, you'd use a database
|
13 |
+
const userAuthStore = new Map<string, any>();
|
14 |
+
|
15 |
+
export class GitHubAppAuth {
|
16 |
+
private app: App;
|
17 |
+
|
18 |
+
constructor() {
|
19 |
+
this.app = new App({
|
20 |
+
appId: GITHUB_APP_ID,
|
21 |
+
privateKey: GITHUB_APP_PRIVATE_KEY,
|
22 |
+
oauth: {
|
23 |
+
clientId: GITHUB_APP_CLIENT_ID,
|
24 |
+
clientSecret: GITHUB_APP_CLIENT_SECRET,
|
25 |
+
},
|
26 |
+
});
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Generate the installation URL for users to authorize the app
|
31 |
+
*/
|
32 |
+
getInstallationUrl(state?: string): string {
|
33 |
+
const baseUrl = `https://github.com/apps/${process.env.GITHUB_APP_NAME || 'hugex-gh'}/installations/new`;
|
34 |
+
const params = new URLSearchParams();
|
35 |
+
|
36 |
+
if (state) {
|
37 |
+
params.append('state', state);
|
38 |
+
}
|
39 |
+
|
40 |
+
return `${baseUrl}?${params.toString()}`;
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Get OAuth authorization URL for user identity
|
45 |
+
*/
|
46 |
+
getOAuthUrl(state?: string): string {
|
47 |
+
const params = new URLSearchParams({
|
48 |
+
client_id: GITHUB_APP_CLIENT_ID,
|
49 |
+
redirect_uri: process.env.GITHUB_CALLBACK_URL || 'http://localhost:3000/auth/github/callback',
|
50 |
+
scope: 'user:email',
|
51 |
+
state: state || '',
|
52 |
+
});
|
53 |
+
|
54 |
+
return `https://github.com/login/oauth/authorize?${params.toString()}`;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Exchange code for access token and get user info
|
59 |
+
*/
|
60 |
+
async handleCallback(code: string, state?: string) {
|
61 |
+
try {
|
62 |
+
const { data } = await this.app.oauth.createToken({
|
63 |
+
code,
|
64 |
+
});
|
65 |
+
|
66 |
+
const { token } = data;
|
67 |
+
|
68 |
+
// Get user information
|
69 |
+
const userOctokit = await this.app.oauth.getUserOctokit({
|
70 |
+
token,
|
71 |
+
});
|
72 |
+
|
73 |
+
const { data: user } = await userOctokit.rest.users.getAuthenticated();
|
74 |
+
|
75 |
+
// Store user auth info (in production, save to database)
|
76 |
+
const userAuth = {
|
77 |
+
id: user.id,
|
78 |
+
login: user.login,
|
79 |
+
name: user.name,
|
80 |
+
email: user.email,
|
81 |
+
avatar_url: user.avatar_url,
|
82 |
+
token,
|
83 |
+
authenticated_at: new Date().toISOString(),
|
84 |
+
state,
|
85 |
+
};
|
86 |
+
|
87 |
+
userAuthStore.set(user.login, userAuth);
|
88 |
+
|
89 |
+
return userAuth;
|
90 |
+
} catch (error) {
|
91 |
+
console.error('GitHub callback error:', error);
|
92 |
+
throw new Error('Failed to authenticate with GitHub');
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Get stored user authentication info
|
98 |
+
*/
|
99 |
+
getUserAuth(login: string) {
|
100 |
+
return userAuthStore.get(login);
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Get all stored user auths (for debugging)
|
105 |
+
*/
|
106 |
+
getAllUserAuths() {
|
107 |
+
return Array.from(userAuthStore.values());
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Create an authenticated Octokit instance for a user
|
112 |
+
*/
|
113 |
+
async getUserOctokit(login: string) {
|
114 |
+
const userAuth = this.getUserAuth(login);
|
115 |
+
if (!userAuth) {
|
116 |
+
throw new Error(`No authentication found for user: ${login}`);
|
117 |
+
}
|
118 |
+
|
119 |
+
return await this.app.oauth.getUserOctokit({
|
120 |
+
token: userAuth.token,
|
121 |
+
});
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Get app installation for a repository
|
126 |
+
*/
|
127 |
+
async getInstallationOctokit(installationId: number) {
|
128 |
+
return await this.app.getInstallationOctokit(installationId);
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Verify webhook signature
|
133 |
+
*/
|
134 |
+
verifyWebhookSignature(payload: string, signature: string): boolean {
|
135 |
+
const webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;
|
136 |
+
if (!webhookSecret) {
|
137 |
+
console.warn('GITHUB_WEBHOOK_SECRET not set, skipping signature verification');
|
138 |
+
return true;
|
139 |
+
}
|
140 |
+
|
141 |
+
const expectedSignature = `sha256=${require('crypto')
|
142 |
+
.createHmac('sha256', webhookSecret)
|
143 |
+
.update(payload, 'utf8')
|
144 |
+
.digest('hex')}`;
|
145 |
+
|
146 |
+
return signature === expectedSignature;
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
// Singleton instance
|
151 |
+
export const githubApp = new GitHubAppAuth();
|
app/lib/session.server.ts
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { createCookieSessionStorage } from "@remix-run/node";
|
2 |
+
|
3 |
+
const { getSession, commitSession, destroySession } = createCookieSessionStorage({
|
4 |
+
cookie: {
|
5 |
+
name: "__session",
|
6 |
+
httpOnly: true,
|
7 |
+
maxAge: 60 * 60 * 24 * 30, // 30 days
|
8 |
+
path: "/",
|
9 |
+
sameSite: "lax",
|
10 |
+
secrets: [process.env.SESSION_SECRET || "your-secret-key"],
|
11 |
+
secure: process.env.NODE_ENV === "production",
|
12 |
+
},
|
13 |
+
});
|
14 |
+
|
15 |
+
export { getSession, commitSession, destroySession };
|
16 |
+
|
17 |
+
export interface UserSession {
|
18 |
+
userId: string;
|
19 |
+
login: string;
|
20 |
+
name?: string;
|
21 |
+
email?: string;
|
22 |
+
avatar_url?: string;
|
23 |
+
}
|
24 |
+
|
25 |
+
export async function requireUserSession(request: Request): Promise<UserSession> {
|
26 |
+
const session = await getSession(request.headers.get("Cookie"));
|
27 |
+
const userSession = session.get("user");
|
28 |
+
|
29 |
+
if (!userSession) {
|
30 |
+
throw new Response("Unauthorized", { status: 401 });
|
31 |
+
}
|
32 |
+
|
33 |
+
return userSession;
|
34 |
+
}
|
35 |
+
|
36 |
+
export async function getUserSession(request: Request): Promise<UserSession | null> {
|
37 |
+
const session = await getSession(request.headers.get("Cookie"));
|
38 |
+
return session.get("user") || null;
|
39 |
+
}
|
app/routes/_index.tsx
CHANGED
@@ -1,138 +1,179 @@
|
|
1 |
-
import type { MetaFunction } from "@remix-run/node";
|
|
|
|
|
|
|
2 |
|
3 |
export const meta: MetaFunction = () => {
|
4 |
return [
|
5 |
-
{ title: "
|
6 |
-
{ name: "description", content: "
|
7 |
];
|
8 |
};
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
export default function Index() {
|
|
|
|
|
|
|
11 |
return (
|
12 |
-
<div className="
|
13 |
-
<div className="flex
|
14 |
-
<
|
15 |
-
<
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
>
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
</div>
|
52 |
</div>
|
53 |
);
|
54 |
}
|
55 |
|
56 |
-
|
57 |
-
{
|
58 |
-
href: "https://remix.run/start/quickstart",
|
59 |
-
text: "Quick Start (5 min)",
|
60 |
-
icon: (
|
61 |
-
<svg
|
62 |
-
xmlns="http://www.w3.org/2000/svg"
|
63 |
-
width="24"
|
64 |
-
height="20"
|
65 |
-
viewBox="0 0 20 20"
|
66 |
-
fill="none"
|
67 |
-
className="stroke-gray-600 group-hover:stroke-current dark:stroke-gray-300"
|
68 |
-
>
|
69 |
-
<path
|
70 |
-
d="M8.51851 12.0741L7.92592 18L15.6296 9.7037L11.4815 7.33333L12.0741 2L4.37036 10.2963L8.51851 12.0741Z"
|
71 |
-
strokeWidth="1.5"
|
72 |
-
strokeLinecap="round"
|
73 |
-
strokeLinejoin="round"
|
74 |
-
/>
|
75 |
-
</svg>
|
76 |
-
),
|
77 |
-
},
|
78 |
-
{
|
79 |
-
href: "https://remix.run/start/tutorial",
|
80 |
-
text: "Tutorial (30 min)",
|
81 |
-
icon: (
|
82 |
-
<svg
|
83 |
-
xmlns="http://www.w3.org/2000/svg"
|
84 |
-
width="24"
|
85 |
-
height="20"
|
86 |
-
viewBox="0 0 20 20"
|
87 |
-
fill="none"
|
88 |
-
className="stroke-gray-600 group-hover:stroke-current dark:stroke-gray-300"
|
89 |
-
>
|
90 |
-
<path
|
91 |
-
d="M4.561 12.749L3.15503 14.1549M3.00811 8.99944H1.01978M3.15503 3.84489L4.561 5.2508M8.3107 1.70923L8.3107 3.69749M13.4655 3.84489L12.0595 5.2508M18.1868 17.0974L16.635 18.6491C16.4636 18.8205 16.1858 18.8205 16.0144 18.6491L13.568 16.2028C13.383 16.0178 13.0784 16.0347 12.915 16.239L11.2697 18.2956C11.047 18.5739 10.6029 18.4847 10.505 18.142L7.85215 8.85711C7.75756 8.52603 8.06365 8.21994 8.39472 8.31453L17.6796 10.9673C18.0223 11.0653 18.1115 11.5094 17.8332 11.7321L15.7766 13.3773C15.5723 13.5408 15.5554 13.8454 15.7404 14.0304L18.1868 16.4767C18.3582 16.6481 18.3582 16.926 18.1868 17.0974Z"
|
92 |
-
strokeWidth="1.5"
|
93 |
-
strokeLinecap="round"
|
94 |
-
strokeLinejoin="round"
|
95 |
-
/>
|
96 |
-
</svg>
|
97 |
-
),
|
98 |
-
},
|
99 |
-
{
|
100 |
-
href: "https://remix.run/docs",
|
101 |
-
text: "Remix Docs",
|
102 |
-
icon: (
|
103 |
-
<svg
|
104 |
-
xmlns="http://www.w3.org/2000/svg"
|
105 |
-
width="24"
|
106 |
-
height="20"
|
107 |
-
viewBox="0 0 20 20"
|
108 |
-
fill="none"
|
109 |
-
className="stroke-gray-600 group-hover:stroke-current dark:stroke-gray-300"
|
110 |
-
>
|
111 |
-
<path
|
112 |
-
d="M9.99981 10.0751V9.99992M17.4688 17.4688C15.889 19.0485 11.2645 16.9853 7.13958 12.8604C3.01467 8.73546 0.951405 4.11091 2.53116 2.53116C4.11091 0.951405 8.73546 3.01467 12.8604 7.13958C16.9853 11.2645 19.0485 15.889 17.4688 17.4688ZM2.53132 17.4688C0.951566 15.8891 3.01483 11.2645 7.13974 7.13963C11.2647 3.01471 15.8892 0.951453 17.469 2.53121C19.0487 4.11096 16.9854 8.73551 12.8605 12.8604C8.73562 16.9853 4.11107 19.0486 2.53132 17.4688Z"
|
113 |
-
strokeWidth="1.5"
|
114 |
-
strokeLinecap="round"
|
115 |
-
/>
|
116 |
-
</svg>
|
117 |
-
),
|
118 |
-
},
|
119 |
-
{
|
120 |
-
href: "https://rmx.as/discord",
|
121 |
-
text: "Join Discord",
|
122 |
-
icon: (
|
123 |
-
<svg
|
124 |
-
xmlns="http://www.w3.org/2000/svg"
|
125 |
-
width="24"
|
126 |
-
height="20"
|
127 |
-
viewBox="0 0 24 20"
|
128 |
-
fill="none"
|
129 |
-
className="stroke-gray-600 group-hover:stroke-current dark:stroke-gray-300"
|
130 |
-
>
|
131 |
-
<path
|
132 |
-
d="M15.0686 1.25995L14.5477 1.17423L14.2913 1.63578C14.1754 1.84439 14.0545 2.08275 13.9422 2.31963C12.6461 2.16488 11.3406 2.16505 10.0445 2.32014C9.92822 2.08178 9.80478 1.84975 9.67412 1.62413L9.41449 1.17584L8.90333 1.25995C7.33547 1.51794 5.80717 1.99419 4.37748 2.66939L4.19 2.75793L4.07461 2.93019C1.23864 7.16437 0.46302 11.3053 0.838165 15.3924L0.868838 15.7266L1.13844 15.9264C2.81818 17.1714 4.68053 18.1233 6.68582 18.719L7.18892 18.8684L7.50166 18.4469C7.96179 17.8268 8.36504 17.1824 8.709 16.4944L8.71099 16.4904C10.8645 17.0471 13.128 17.0485 15.2821 16.4947C15.6261 17.1826 16.0293 17.8269 16.4892 18.4469L16.805 18.8725L17.3116 18.717C19.3056 18.105 21.1876 17.1751 22.8559 15.9238L23.1224 15.724L23.1528 15.3923C23.5873 10.6524 22.3579 6.53306 19.8947 2.90714L19.7759 2.73227L19.5833 2.64518C18.1437 1.99439 16.6386 1.51826 15.0686 1.25995ZM16.6074 10.7755L16.6074 10.7756C16.5934 11.6409 16.0212 12.1444 15.4783 12.1444C14.9297 12.1444 14.3493 11.6173 14.3493 10.7877C14.3493 9.94885 14.9378 9.41192 15.4783 9.41192C16.0471 9.41192 16.6209 9.93851 16.6074 10.7755ZM8.49373 12.1444C7.94513 12.1444 7.36471 11.6173 7.36471 10.7877C7.36471 9.94885 7.95323 9.41192 8.49373 9.41192C9.06038 9.41192 9.63892 9.93712 9.6417 10.7815C9.62517 11.6239 9.05462 12.1444 8.49373 12.1444Z"
|
133 |
-
strokeWidth="1.5"
|
134 |
-
/>
|
135 |
-
</svg>
|
136 |
-
),
|
137 |
-
},
|
138 |
-
];
|
|
|
1 |
+
import type { MetaFunction, LoaderFunctionArgs } from "@remix-run/node";
|
2 |
+
import { json } from "@remix-run/node";
|
3 |
+
import { useLoaderData, Link, useSearchParams } from "@remix-run/react";
|
4 |
+
import { getUserSession } from "~/lib/session.server";
|
5 |
|
6 |
export const meta: MetaFunction = () => {
|
7 |
return [
|
8 |
+
{ title: "HugeX GitHub App" },
|
9 |
+
{ name: "description", content: "GitHub App with user authentication" },
|
10 |
];
|
11 |
};
|
12 |
|
13 |
+
export async function loader({ request }: LoaderFunctionArgs) {
|
14 |
+
const user = await getUserSession(request);
|
15 |
+
const url = new URL(request.url);
|
16 |
+
const error = url.searchParams.get("error");
|
17 |
+
|
18 |
+
return json({ user, error });
|
19 |
+
}
|
20 |
+
|
21 |
export default function Index() {
|
22 |
+
const { user, error } = useLoaderData<typeof loader>();
|
23 |
+
const [searchParams] = useSearchParams();
|
24 |
+
|
25 |
return (
|
26 |
+
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
27 |
+
<div className="flex h-screen items-center justify-center">
|
28 |
+
<div className="flex flex-col items-center gap-8 max-w-2xl mx-auto px-4">
|
29 |
+
<header className="flex flex-col items-center gap-6">
|
30 |
+
<div className="bg-white rounded-full p-4 shadow-lg">
|
31 |
+
<svg
|
32 |
+
className="w-16 h-16 text-blue-600"
|
33 |
+
fill="currentColor"
|
34 |
+
viewBox="0 0 24 24"
|
35 |
+
>
|
36 |
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
37 |
+
</svg>
|
38 |
+
</div>
|
39 |
+
<h1 className="text-4xl font-bold text-gray-900">
|
40 |
+
HugeX GitHub App
|
41 |
+
</h1>
|
42 |
+
<p className="text-lg text-gray-600 text-center">
|
43 |
+
GitHub App with user authentication and webhook support
|
44 |
+
</p>
|
45 |
+
</header>
|
46 |
+
|
47 |
+
{/* Error Messages */}
|
48 |
+
{error && (
|
49 |
+
<div className="bg-red-50 border border-red-200 rounded-lg p-4 w-full">
|
50 |
+
<div className="flex">
|
51 |
+
<div className="flex-shrink-0">
|
52 |
+
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
|
53 |
+
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
|
54 |
+
</svg>
|
55 |
+
</div>
|
56 |
+
<div className="ml-3">
|
57 |
+
<h3 className="text-sm font-medium text-red-800">
|
58 |
+
Authentication Error
|
59 |
+
</h3>
|
60 |
+
<div className="mt-2 text-sm text-red-700">
|
61 |
+
{error === "oauth_failed" && "OAuth authentication failed. Please try again."}
|
62 |
+
{error === "no_code" && "No authorization code received from GitHub."}
|
63 |
+
{error === "callback_failed" && "Failed to complete authentication. Please try again."}
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
</div>
|
67 |
+
</div>
|
68 |
+
)}
|
69 |
+
|
70 |
+
{/* Main Content */}
|
71 |
+
{user ? (
|
72 |
+
<div className="bg-white rounded-lg shadow-lg p-8 w-full">
|
73 |
+
<div className="text-center">
|
74 |
+
<div className="flex items-center justify-center mb-4">
|
75 |
+
{user.avatar_url && (
|
76 |
+
<img
|
77 |
+
src={user.avatar_url}
|
78 |
+
alt={user.login}
|
79 |
+
className="w-16 h-16 rounded-full mr-4"
|
80 |
+
/>
|
81 |
+
)}
|
82 |
+
<div>
|
83 |
+
<h2 className="text-2xl font-bold text-gray-900">
|
84 |
+
Welcome back, {user.name || user.login}!
|
85 |
+
</h2>
|
86 |
+
<p className="text-gray-600">@{user.login}</p>
|
87 |
+
</div>
|
88 |
+
</div>
|
89 |
+
<div className="mt-6 flex gap-4 justify-center">
|
90 |
+
<Link
|
91 |
+
to="/dashboard"
|
92 |
+
className="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
93 |
+
>
|
94 |
+
Go to Dashboard
|
95 |
+
</Link>
|
96 |
+
<Link
|
97 |
+
to="/status"
|
98 |
+
className="inline-flex items-center px-6 py-3 border border-gray-300 text-base font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
99 |
+
>
|
100 |
+
Check Status
|
101 |
+
</Link>
|
102 |
+
</div>
|
103 |
+
</div>
|
104 |
+
</div>
|
105 |
+
) : (
|
106 |
+
<div className="bg-white rounded-lg shadow-lg p-8 w-full">
|
107 |
+
<div className="text-center">
|
108 |
+
<h2 className="text-2xl font-bold text-gray-900 mb-4">
|
109 |
+
Get Started
|
110 |
+
</h2>
|
111 |
+
<p className="text-gray-600 mb-6">
|
112 |
+
Authenticate with GitHub to enable user-specific actions when webhooks are triggered.
|
113 |
+
</p>
|
114 |
+
<Link
|
115 |
+
to="/auth/github"
|
116 |
+
className="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-gray-900 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
|
117 |
>
|
118 |
+
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
|
119 |
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
120 |
+
</svg>
|
121 |
+
Sign in with GitHub
|
122 |
+
</Link>
|
123 |
+
<div className="mt-4">
|
124 |
+
<Link
|
125 |
+
to="/status"
|
126 |
+
className="text-sm text-blue-600 hover:text-blue-700 font-medium"
|
127 |
+
>
|
128 |
+
Check Environment Status
|
129 |
+
</Link>
|
130 |
+
</div>
|
131 |
+
</div>
|
132 |
+
</div>
|
133 |
+
)}
|
134 |
+
|
135 |
+
{/* Features */}
|
136 |
+
<div className="grid md:grid-cols-3 gap-6 w-full mt-8">
|
137 |
+
<div className="bg-white rounded-lg shadow p-6">
|
138 |
+
<div className="text-blue-600 mb-3">
|
139 |
+
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
140 |
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
141 |
+
</svg>
|
142 |
+
</div>
|
143 |
+
<h3 className="text-lg font-semibold text-gray-900 mb-2">User Authentication</h3>
|
144 |
+
<p className="text-gray-600 text-sm">
|
145 |
+
Authenticate users with GitHub OAuth to perform actions on their behalf.
|
146 |
+
</p>
|
147 |
+
</div>
|
148 |
+
|
149 |
+
<div className="bg-white rounded-lg shadow p-6">
|
150 |
+
<div className="text-green-600 mb-3">
|
151 |
+
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
152 |
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
153 |
+
</svg>
|
154 |
+
</div>
|
155 |
+
<h3 className="text-lg font-semibold text-gray-900 mb-2">Webhook Support</h3>
|
156 |
+
<p className="text-gray-600 text-sm">
|
157 |
+
Handle GitHub webhooks and associate them with authenticated users.
|
158 |
+
</p>
|
159 |
+
</div>
|
160 |
+
|
161 |
+
<div className="bg-white rounded-lg shadow p-6">
|
162 |
+
<div className="text-purple-600 mb-3">
|
163 |
+
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
164 |
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
165 |
+
</svg>
|
166 |
+
</div>
|
167 |
+
<h3 className="text-lg font-semibold text-gray-900 mb-2">API Integration</h3>
|
168 |
+
<p className="text-gray-600 text-sm">
|
169 |
+
Use authenticated user sessions to make GitHub API calls.
|
170 |
+
</p>
|
171 |
+
</div>
|
172 |
+
</div>
|
173 |
+
</div>
|
174 |
</div>
|
175 |
</div>
|
176 |
);
|
177 |
}
|
178 |
|
179 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/routes/auth.github.callback.tsx
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { redirect } from "@remix-run/node";
|
2 |
+
import type { LoaderFunctionArgs } from "@remix-run/node";
|
3 |
+
import { githubApp } from "~/lib/github-app.server";
|
4 |
+
import { getSession, commitSession } from "~/lib/session.server";
|
5 |
+
|
6 |
+
export async function loader({ request }: LoaderFunctionArgs) {
|
7 |
+
const url = new URL(request.url);
|
8 |
+
const code = url.searchParams.get("code");
|
9 |
+
const state = url.searchParams.get("state");
|
10 |
+
const error = url.searchParams.get("error");
|
11 |
+
|
12 |
+
// Handle OAuth errors
|
13 |
+
if (error) {
|
14 |
+
console.error("GitHub OAuth error:", error);
|
15 |
+
return redirect("/?error=oauth_failed");
|
16 |
+
}
|
17 |
+
|
18 |
+
if (!code) {
|
19 |
+
console.error("No authorization code received");
|
20 |
+
return redirect("/?error=no_code");
|
21 |
+
}
|
22 |
+
|
23 |
+
try {
|
24 |
+
// Exchange code for access token and get user info
|
25 |
+
const userAuth = await githubApp.handleCallback(code, state || undefined);
|
26 |
+
|
27 |
+
// Create user session
|
28 |
+
const session = await getSession(request.headers.get("Cookie"));
|
29 |
+
session.set("user", {
|
30 |
+
userId: userAuth.id.toString(),
|
31 |
+
login: userAuth.login,
|
32 |
+
name: userAuth.name,
|
33 |
+
email: userAuth.email,
|
34 |
+
avatar_url: userAuth.avatar_url,
|
35 |
+
});
|
36 |
+
|
37 |
+
return redirect("/dashboard", {
|
38 |
+
headers: {
|
39 |
+
"Set-Cookie": await commitSession(session),
|
40 |
+
},
|
41 |
+
});
|
42 |
+
} catch (error) {
|
43 |
+
console.error("GitHub callback error:", error);
|
44 |
+
return redirect("/?error=callback_failed");
|
45 |
+
}
|
46 |
+
}
|
app/routes/auth.github.tsx
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { redirect } from "@remix-run/node";
|
2 |
+
import type { LoaderFunctionArgs } from "@remix-run/node";
|
3 |
+
import { githubApp } from "~/lib/github-app.server";
|
4 |
+
|
5 |
+
export async function loader({ request }: LoaderFunctionArgs) {
|
6 |
+
const url = new URL(request.url);
|
7 |
+
const state = url.searchParams.get("state") || crypto.randomUUID();
|
8 |
+
|
9 |
+
// Generate OAuth URL for user identity authorization
|
10 |
+
const oauthUrl = githubApp.getOAuthUrl(state);
|
11 |
+
|
12 |
+
return redirect(oauthUrl);
|
13 |
+
}
|
app/routes/auth.logout.tsx
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { redirect } from "@remix-run/node";
|
2 |
+
import type { ActionFunctionArgs } from "@remix-run/node";
|
3 |
+
import { getSession, destroySession } from "~/lib/session.server";
|
4 |
+
|
5 |
+
export async function action({ request }: ActionFunctionArgs) {
|
6 |
+
const session = await getSession(request.headers.get("Cookie"));
|
7 |
+
|
8 |
+
return redirect("/", {
|
9 |
+
headers: {
|
10 |
+
"Set-Cookie": await destroySession(session),
|
11 |
+
},
|
12 |
+
});
|
13 |
+
}
|
14 |
+
|
15 |
+
export async function loader() {
|
16 |
+
return redirect("/");
|
17 |
+
}
|
app/routes/dashboard.tsx
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { json } from "@remix-run/node";
|
2 |
+
import type { LoaderFunctionArgs } from "@remix-run/node";
|
3 |
+
import { useLoaderData, Form } from "@remix-run/react";
|
4 |
+
import { requireUserSession } from "~/lib/session.server";
|
5 |
+
import { githubApp } from "~/lib/github-app.server";
|
6 |
+
|
7 |
+
export async function loader({ request }: LoaderFunctionArgs) {
|
8 |
+
const userSession = await requireUserSession(request);
|
9 |
+
|
10 |
+
// Get additional user auth info from our store
|
11 |
+
const userAuth = githubApp.getUserAuth(userSession.login);
|
12 |
+
|
13 |
+
return json({
|
14 |
+
user: userSession,
|
15 |
+
userAuth,
|
16 |
+
allAuths: githubApp.getAllUserAuths(), // For debugging
|
17 |
+
});
|
18 |
+
}
|
19 |
+
|
20 |
+
export default function Dashboard() {
|
21 |
+
const { user, userAuth, allAuths } = useLoaderData<typeof loader>();
|
22 |
+
|
23 |
+
return (
|
24 |
+
<div className="min-h-screen bg-gray-50 py-8">
|
25 |
+
<div className="max-w-4xl mx-auto px-4">
|
26 |
+
<div className="bg-white rounded-lg shadow-md p-6">
|
27 |
+
<div className="flex items-center justify-between mb-6">
|
28 |
+
<h1 className="text-2xl font-bold text-gray-900">
|
29 |
+
GitHub App Dashboard
|
30 |
+
</h1>
|
31 |
+
<Form method="post" action="/auth/logout">
|
32 |
+
<button
|
33 |
+
type="submit"
|
34 |
+
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-md text-sm font-medium"
|
35 |
+
>
|
36 |
+
Logout
|
37 |
+
</button>
|
38 |
+
</Form>
|
39 |
+
</div>
|
40 |
+
|
41 |
+
<div className="grid md:grid-cols-2 gap-6">
|
42 |
+
{/* User Info */}
|
43 |
+
<div className="bg-gray-50 rounded-lg p-4">
|
44 |
+
<h2 className="text-lg font-semibold text-gray-900 mb-4">
|
45 |
+
User Information
|
46 |
+
</h2>
|
47 |
+
<div className="flex items-center mb-4">
|
48 |
+
{user.avatar_url && (
|
49 |
+
<img
|
50 |
+
src={user.avatar_url}
|
51 |
+
alt={user.login}
|
52 |
+
className="w-12 h-12 rounded-full mr-4"
|
53 |
+
/>
|
54 |
+
)}
|
55 |
+
<div>
|
56 |
+
<p className="font-medium text-gray-900">{user.name || user.login}</p>
|
57 |
+
<p className="text-gray-600">@{user.login}</p>
|
58 |
+
{user.email && (
|
59 |
+
<p className="text-gray-600 text-sm">{user.email}</p>
|
60 |
+
)}
|
61 |
+
</div>
|
62 |
+
</div>
|
63 |
+
</div>
|
64 |
+
|
65 |
+
{/* Auth Info */}
|
66 |
+
<div className="bg-gray-50 rounded-lg p-4">
|
67 |
+
<h2 className="text-lg font-semibold text-gray-900 mb-4">
|
68 |
+
Authentication Status
|
69 |
+
</h2>
|
70 |
+
<div className="space-y-2">
|
71 |
+
<p className="text-sm">
|
72 |
+
<span className="font-medium">Status:</span>{' '}
|
73 |
+
<span className="text-green-600">✅ Authenticated</span>
|
74 |
+
</p>
|
75 |
+
<p className="text-sm">
|
76 |
+
<span className="font-medium">User ID:</span> {user.userId}
|
77 |
+
</p>
|
78 |
+
{userAuth && (
|
79 |
+
<>
|
80 |
+
<p className="text-sm">
|
81 |
+
<span className="font-medium">Authenticated At:</span>{' '}
|
82 |
+
{new Date(userAuth.authenticated_at).toLocaleString()}
|
83 |
+
</p>
|
84 |
+
{userAuth.state && (
|
85 |
+
<p className="text-sm">
|
86 |
+
<span className="font-medium">State:</span> {userAuth.state}
|
87 |
+
</p>
|
88 |
+
)}
|
89 |
+
</>
|
90 |
+
)}
|
91 |
+
</div>
|
92 |
+
</div>
|
93 |
+
</div>
|
94 |
+
|
95 |
+
{/* Debug Info */}
|
96 |
+
<div className="mt-8 bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
97 |
+
<h3 className="text-lg font-semibold text-yellow-800 mb-2">
|
98 |
+
Debug Information
|
99 |
+
</h3>
|
100 |
+
<p className="text-sm text-yellow-700 mb-2">
|
101 |
+
All authenticated users ({allAuths.length}):
|
102 |
+
</p>
|
103 |
+
<div className="bg-white rounded border p-3 max-h-48 overflow-y-auto">
|
104 |
+
<pre className="text-xs text-gray-600">
|
105 |
+
{JSON.stringify(allAuths, null, 2)}
|
106 |
+
</pre>
|
107 |
+
</div>
|
108 |
+
</div>
|
109 |
+
|
110 |
+
{/* Usage Instructions */}
|
111 |
+
<div className="mt-8 bg-blue-50 border border-blue-200 rounded-lg p-4">
|
112 |
+
<h3 className="text-lg font-semibold text-blue-800 mb-2">
|
113 |
+
Next Steps
|
114 |
+
</h3>
|
115 |
+
<div className="text-sm text-blue-700 space-y-2">
|
116 |
+
<p>✅ User authentication is working!</p>
|
117 |
+
<p>
|
118 |
+
🔧 Now you can use the authenticated user identity when GitHub
|
119 |
+
triggers your app webhooks
|
120 |
+
</p>
|
121 |
+
<p>
|
122 |
+
📝 The user's authentication info is stored and can be retrieved
|
123 |
+
using: <code className="bg-blue-100 px-1 rounded">githubApp.getUserAuth('{user.login}')</code>
|
124 |
+
</p>
|
125 |
+
<p>
|
126 |
+
🔗 You can create an authenticated Octokit instance using:{' '}
|
127 |
+
<code className="bg-blue-100 px-1 rounded">githubApp.getUserOctokit('{user.login}')</code>
|
128 |
+
</p>
|
129 |
+
<div className="mt-4">
|
130 |
+
<Link
|
131 |
+
to="/install"
|
132 |
+
className="inline-flex items-center px-4 py-2 border border-blue-300 text-sm font-medium rounded-md text-blue-700 bg-white hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
133 |
+
>
|
134 |
+
📦 Install GitHub App on Repositories
|
135 |
+
</Link>
|
136 |
+
</div>
|
137 |
+
</div>
|
138 |
+
</div>
|
139 |
+
</div>
|
140 |
+
</div>
|
141 |
+
</div>
|
142 |
+
);
|
143 |
+
}
|
app/routes/install.tsx
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { json } from "@remix-run/node";
|
2 |
+
import type { LoaderFunctionArgs } from "@remix-run/node";
|
3 |
+
import { useLoaderData, Link } from "@remix-run/react";
|
4 |
+
import { requireUserSession } from "~/lib/session.server";
|
5 |
+
import { githubApp } from "~/lib/github-app.server";
|
6 |
+
|
7 |
+
export async function loader({ request }: LoaderFunctionArgs) {
|
8 |
+
const userSession = await requireUserSession(request);
|
9 |
+
|
10 |
+
// Generate installation URL
|
11 |
+
const installationUrl = githubApp.getInstallationUrl(
|
12 |
+
`user:${userSession.login}`
|
13 |
+
);
|
14 |
+
|
15 |
+
return json({
|
16 |
+
user: userSession,
|
17 |
+
installationUrl,
|
18 |
+
});
|
19 |
+
}
|
20 |
+
|
21 |
+
export default function InstallApp() {
|
22 |
+
const { user, installationUrl } = useLoaderData<typeof loader>();
|
23 |
+
|
24 |
+
return (
|
25 |
+
<div className="min-h-screen bg-gray-50 py-8">
|
26 |
+
<div className="max-w-2xl mx-auto px-4">
|
27 |
+
<div className="bg-white rounded-lg shadow-md p-6">
|
28 |
+
<div className="flex items-center justify-between mb-6">
|
29 |
+
<h1 className="text-2xl font-bold text-gray-900">
|
30 |
+
Install GitHub App
|
31 |
+
</h1>
|
32 |
+
<Link
|
33 |
+
to="/dashboard"
|
34 |
+
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
35 |
+
>
|
36 |
+
← Back to Dashboard
|
37 |
+
</Link>
|
38 |
+
</div>
|
39 |
+
|
40 |
+
<div className="space-y-6">
|
41 |
+
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
42 |
+
<div className="flex">
|
43 |
+
<div className="flex-shrink-0">
|
44 |
+
<svg className="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor">
|
45 |
+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
|
46 |
+
</svg>
|
47 |
+
</div>
|
48 |
+
<div className="ml-3">
|
49 |
+
<h3 className="text-sm font-medium text-blue-800">
|
50 |
+
Install Required
|
51 |
+
</h3>
|
52 |
+
<div className="mt-2 text-sm text-blue-700">
|
53 |
+
<p>
|
54 |
+
To receive webhooks and interact with repositories, you need to install
|
55 |
+
the HugeX GitHub App on your repositories or organization.
|
56 |
+
</p>
|
57 |
+
</div>
|
58 |
+
</div>
|
59 |
+
</div>
|
60 |
+
</div>
|
61 |
+
|
62 |
+
<div className="bg-gray-50 rounded-lg p-4">
|
63 |
+
<h2 className="text-lg font-semibold text-gray-900 mb-4">
|
64 |
+
What happens when you install?
|
65 |
+
</h2>
|
66 |
+
<ul className="space-y-2 text-gray-600">
|
67 |
+
<li className="flex items-start">
|
68 |
+
<svg className="w-5 h-5 text-green-500 mr-2 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
69 |
+
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
70 |
+
</svg>
|
71 |
+
The app will be able to receive webhook events from your selected repositories
|
72 |
+
</li>
|
73 |
+
<li className="flex items-start">
|
74 |
+
<svg className="w-5 h-5 text-green-500 mr-2 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
75 |
+
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
76 |
+
</svg>
|
77 |
+
Events will be associated with your authenticated user account
|
78 |
+
</li>
|
79 |
+
<li className="flex items-start">
|
80 |
+
<svg className="w-5 h-5 text-green-500 mr-2 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
81 |
+
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
82 |
+
</svg>
|
83 |
+
The app can perform actions on your behalf using your user token
|
84 |
+
</li>
|
85 |
+
<li className="flex items-start">
|
86 |
+
<svg className="w-5 h-5 text-green-500 mr-2 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
87 |
+
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
88 |
+
</svg>
|
89 |
+
You can uninstall the app at any time from your GitHub settings
|
90 |
+
</li>
|
91 |
+
</ul>
|
92 |
+
</div>
|
93 |
+
|
94 |
+
<div className="text-center">
|
95 |
+
<a
|
96 |
+
href={installationUrl}
|
97 |
+
target="_blank"
|
98 |
+
rel="noopener noreferrer"
|
99 |
+
className="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-gray-900 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
|
100 |
+
>
|
101 |
+
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
|
102 |
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
103 |
+
</svg>
|
104 |
+
Install HugeX GitHub App
|
105 |
+
</a>
|
106 |
+
</div>
|
107 |
+
|
108 |
+
<div className="text-center text-sm text-gray-500">
|
109 |
+
<p>
|
110 |
+
This will open GitHub in a new tab where you can choose which repositories
|
111 |
+
to install the app on. You can install it on specific repositories or your entire organization.
|
112 |
+
</p>
|
113 |
+
</div>
|
114 |
+
</div>
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
</div>
|
118 |
+
);
|
119 |
+
}
|
app/routes/status.tsx
ADDED
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { json } from "@remix-run/node";
|
2 |
+
import type { LoaderFunctionArgs } from "@remix-run/node";
|
3 |
+
import { useLoaderData, Link } from "@remix-run/react";
|
4 |
+
|
5 |
+
export async function loader({ request }: LoaderFunctionArgs) {
|
6 |
+
// Check environment variables
|
7 |
+
const envCheck = {
|
8 |
+
GITHUB_APP_ID: {
|
9 |
+
value: process.env.GITHUB_APP_ID || null,
|
10 |
+
required: true,
|
11 |
+
example: "1356087",
|
12 |
+
},
|
13 |
+
GITHUB_APP_NAME: {
|
14 |
+
value: process.env.GITHUB_APP_NAME || null,
|
15 |
+
required: true,
|
16 |
+
example: "hugex-gh",
|
17 |
+
},
|
18 |
+
GITHUB_APP_PRIVATE_KEY: {
|
19 |
+
value: process.env.GITHUB_APP_PRIVATE_KEY ? "✓ Set" : null,
|
20 |
+
required: true,
|
21 |
+
example: "-----BEGIN RSA PRIVATE KEY-----...",
|
22 |
+
},
|
23 |
+
GITHUB_APP_CLIENT_ID: {
|
24 |
+
value: process.env.GITHUB_APP_CLIENT_ID || null,
|
25 |
+
required: true,
|
26 |
+
example: "Iv23liFxEtiiREnjOeB2",
|
27 |
+
},
|
28 |
+
GITHUB_APP_CLIENT_SECRET: {
|
29 |
+
value: process.env.GITHUB_APP_CLIENT_SECRET ? "✓ Set" : null,
|
30 |
+
required: true,
|
31 |
+
example: "your-client-secret",
|
32 |
+
},
|
33 |
+
GITHUB_WEBHOOK_SECRET: {
|
34 |
+
value: process.env.GITHUB_WEBHOOK_SECRET ? "✓ Set" : null,
|
35 |
+
required: false,
|
36 |
+
example: "your-webhook-secret",
|
37 |
+
},
|
38 |
+
GITHUB_CALLBACK_URL: {
|
39 |
+
value: process.env.GITHUB_CALLBACK_URL || null,
|
40 |
+
required: true,
|
41 |
+
example: "http://localhost:3000/auth/github/callback",
|
42 |
+
},
|
43 |
+
SESSION_SECRET: {
|
44 |
+
value: process.env.SESSION_SECRET ? "✓ Set" : null,
|
45 |
+
required: true,
|
46 |
+
example: "your-session-secret",
|
47 |
+
},
|
48 |
+
};
|
49 |
+
|
50 |
+
const missing = Object.entries(envCheck).filter(
|
51 |
+
([key, config]) => config.required && !config.value
|
52 |
+
);
|
53 |
+
|
54 |
+
const isReady = missing.length === 0;
|
55 |
+
|
56 |
+
return json({
|
57 |
+
envCheck,
|
58 |
+
missing,
|
59 |
+
isReady,
|
60 |
+
nodeEnv: process.env.NODE_ENV || "development",
|
61 |
+
});
|
62 |
+
}
|
63 |
+
|
64 |
+
export default function Status() {
|
65 |
+
const { envCheck, missing, isReady, nodeEnv } = useLoaderData<typeof loader>();
|
66 |
+
|
67 |
+
return (
|
68 |
+
<div className="min-h-screen bg-gray-50 py-8">
|
69 |
+
<div className="max-w-4xl mx-auto px-4">
|
70 |
+
<div className="bg-white rounded-lg shadow-md p-6">
|
71 |
+
<div className="flex items-center justify-between mb-6">
|
72 |
+
<h1 className="text-2xl font-bold text-gray-900">
|
73 |
+
Environment Status
|
74 |
+
</h1>
|
75 |
+
<Link
|
76 |
+
to="/"
|
77 |
+
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
78 |
+
>
|
79 |
+
← Back to Home
|
80 |
+
</Link>
|
81 |
+
</div>
|
82 |
+
|
83 |
+
{/* Status Overview */}
|
84 |
+
<div className="mb-8">
|
85 |
+
<div className={`p-4 rounded-lg border ${
|
86 |
+
isReady
|
87 |
+
? 'bg-green-50 border-green-200'
|
88 |
+
: 'bg-red-50 border-red-200'
|
89 |
+
}`}>
|
90 |
+
<div className="flex items-center">
|
91 |
+
<div className="flex-shrink-0">
|
92 |
+
{isReady ? (
|
93 |
+
<svg className="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
|
94 |
+
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
95 |
+
</svg>
|
96 |
+
) : (
|
97 |
+
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
|
98 |
+
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
|
99 |
+
</svg>
|
100 |
+
)}
|
101 |
+
</div>
|
102 |
+
<div className="ml-3">
|
103 |
+
<h3 className={`text-sm font-medium ${
|
104 |
+
isReady ? 'text-green-800' : 'text-red-800'
|
105 |
+
}`}>
|
106 |
+
{isReady ? '✅ Ready to go!' : '⚠️ Configuration needed'}
|
107 |
+
</h3>
|
108 |
+
<div className={`mt-2 text-sm ${
|
109 |
+
isReady ? 'text-green-700' : 'text-red-700'
|
110 |
+
}`}>
|
111 |
+
{isReady ? (
|
112 |
+
<p>All required environment variables are configured.</p>
|
113 |
+
) : (
|
114 |
+
<p>
|
115 |
+
{missing.length} required environment variable{missing.length > 1 ? 's' : ''} missing.
|
116 |
+
</p>
|
117 |
+
)}
|
118 |
+
</div>
|
119 |
+
</div>
|
120 |
+
</div>
|
121 |
+
</div>
|
122 |
+
</div>
|
123 |
+
|
124 |
+
{/* Environment Variables Table */}
|
125 |
+
<div className="mb-8">
|
126 |
+
<h2 className="text-lg font-semibold text-gray-900 mb-4">
|
127 |
+
Environment Variables
|
128 |
+
</h2>
|
129 |
+
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
|
130 |
+
<table className="min-w-full divide-y divide-gray-300">
|
131 |
+
<thead className="bg-gray-50">
|
132 |
+
<tr>
|
133 |
+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
134 |
+
Variable
|
135 |
+
</th>
|
136 |
+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
137 |
+
Status
|
138 |
+
</th>
|
139 |
+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
140 |
+
Required
|
141 |
+
</th>
|
142 |
+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
143 |
+
Example
|
144 |
+
</th>
|
145 |
+
</tr>
|
146 |
+
</thead>
|
147 |
+
<tbody className="bg-white divide-y divide-gray-200">
|
148 |
+
{Object.entries(envCheck).map(([key, config]) => (
|
149 |
+
<tr key={key}>
|
150 |
+
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
151 |
+
{key}
|
152 |
+
</td>
|
153 |
+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
154 |
+
{config.value ? (
|
155 |
+
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
156 |
+
{config.value}
|
157 |
+
</span>
|
158 |
+
) : (
|
159 |
+
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
|
160 |
+
Not set
|
161 |
+
</span>
|
162 |
+
)}
|
163 |
+
</td>
|
164 |
+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
165 |
+
{config.required ? '✅ Yes' : '⚪ Optional'}
|
166 |
+
</td>
|
167 |
+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 font-mono">
|
168 |
+
{config.example}
|
169 |
+
</td>
|
170 |
+
</tr>
|
171 |
+
))}
|
172 |
+
</tbody>
|
173 |
+
</table>
|
174 |
+
</div>
|
175 |
+
</div>
|
176 |
+
|
177 |
+
{/* Missing Variables */}
|
178 |
+
{missing.length > 0 && (
|
179 |
+
<div className="mb-8">
|
180 |
+
<h2 className="text-lg font-semibold text-gray-900 mb-4">
|
181 |
+
Missing Configuration
|
182 |
+
</h2>
|
183 |
+
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
184 |
+
<div className="flex">
|
185 |
+
<div className="flex-shrink-0">
|
186 |
+
<svg className="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
187 |
+
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
188 |
+
</svg>
|
189 |
+
</div>
|
190 |
+
<div className="ml-3">
|
191 |
+
<h3 className="text-sm font-medium text-yellow-800">
|
192 |
+
Add these to your .env file:
|
193 |
+
</h3>
|
194 |
+
<div className="mt-2 text-sm text-yellow-700">
|
195 |
+
<div className="bg-gray-900 text-green-400 p-3 rounded font-mono text-xs overflow-x-auto">
|
196 |
+
{missing.map(([key, config]) => (
|
197 |
+
<div key={key}>
|
198 |
+
{key}={config.example}
|
199 |
+
</div>
|
200 |
+
))}
|
201 |
+
</div>
|
202 |
+
</div>
|
203 |
+
</div>
|
204 |
+
</div>
|
205 |
+
</div>
|
206 |
+
</div>
|
207 |
+
)}
|
208 |
+
|
209 |
+
{/* Quick Actions */}
|
210 |
+
<div className="bg-gray-50 rounded-lg p-4">
|
211 |
+
<h3 className="text-lg font-semibold text-gray-900 mb-4">
|
212 |
+
Quick Actions
|
213 |
+
</h3>
|
214 |
+
<div className="grid md:grid-cols-2 gap-4">
|
215 |
+
<div>
|
216 |
+
<h4 className="font-medium text-gray-900 mb-2">Generate Secrets</h4>
|
217 |
+
<p className="text-sm text-gray-600 mb-3">
|
218 |
+
Generate random secrets for SESSION_SECRET and GITHUB_WEBHOOK_SECRET:
|
219 |
+
</p>
|
220 |
+
<code className="text-xs bg-gray-800 text-green-400 p-2 rounded block">
|
221 |
+
npm run secrets
|
222 |
+
</code>
|
223 |
+
</div>
|
224 |
+
<div>
|
225 |
+
<h4 className="font-medium text-gray-900 mb-2">Environment</h4>
|
226 |
+
<p className="text-sm text-gray-600 mb-2">
|
227 |
+
Current environment: <span className="font-mono">{nodeEnv}</span>
|
228 |
+
</p>
|
229 |
+
<p className="text-sm text-gray-600">
|
230 |
+
{nodeEnv === 'development' ? (
|
231 |
+
<>✅ Development mode - using .env file</>
|
232 |
+
) : (
|
233 |
+
<>🚀 Production mode - using system environment</>
|
234 |
+
)}
|
235 |
+
</p>
|
236 |
+
</div>
|
237 |
+
</div>
|
238 |
+
</div>
|
239 |
+
</div>
|
240 |
+
</div>
|
241 |
+
</div>
|
242 |
+
);
|
243 |
+
}
|
app/routes/webhook.github.tsx
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { json } from "@remix-run/node";
|
2 |
+
import type { ActionFunctionArgs } from "@remix-run/node";
|
3 |
+
import { githubApp } from "~/lib/github-app.server";
|
4 |
+
|
5 |
+
export async function action({ request }: ActionFunctionArgs) {
|
6 |
+
if (request.method !== "POST") {
|
7 |
+
return json({ error: "Method not allowed" }, { status: 405 });
|
8 |
+
}
|
9 |
+
|
10 |
+
try {
|
11 |
+
const payload = await request.text();
|
12 |
+
const signature = request.headers.get("x-hub-signature-256") || "";
|
13 |
+
const event = request.headers.get("x-github-event") || "";
|
14 |
+
const delivery = request.headers.get("x-github-delivery") || "";
|
15 |
+
|
16 |
+
// Verify webhook signature
|
17 |
+
if (!githubApp.verifyWebhookSignature(payload, signature)) {
|
18 |
+
console.error("Invalid webhook signature");
|
19 |
+
return json({ error: "Invalid signature" }, { status: 401 });
|
20 |
+
}
|
21 |
+
|
22 |
+
const eventData = JSON.parse(payload);
|
23 |
+
|
24 |
+
console.log(`📥 Received GitHub webhook: ${event} (${delivery})`);
|
25 |
+
console.log("Event data:", JSON.stringify(eventData, null, 2));
|
26 |
+
|
27 |
+
// Handle different webhook events
|
28 |
+
switch (event) {
|
29 |
+
case "installation":
|
30 |
+
await handleInstallationEvent(eventData);
|
31 |
+
break;
|
32 |
+
|
33 |
+
case "installation_repositories":
|
34 |
+
await handleInstallationRepositoriesEvent(eventData);
|
35 |
+
break;
|
36 |
+
|
37 |
+
case "push":
|
38 |
+
await handlePushEvent(eventData);
|
39 |
+
break;
|
40 |
+
|
41 |
+
case "pull_request":
|
42 |
+
await handlePullRequestEvent(eventData);
|
43 |
+
break;
|
44 |
+
|
45 |
+
case "issues":
|
46 |
+
await handleIssuesEvent(eventData);
|
47 |
+
break;
|
48 |
+
|
49 |
+
default:
|
50 |
+
console.log(`Unhandled event type: ${event}`);
|
51 |
+
}
|
52 |
+
|
53 |
+
return json({ success: true, event, delivery });
|
54 |
+
} catch (error) {
|
55 |
+
console.error("Webhook error:", error);
|
56 |
+
return json({ error: "Internal server error" }, { status: 500 });
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
async function handleInstallationEvent(data: any) {
|
61 |
+
const { action, installation, repositories } = data;
|
62 |
+
|
63 |
+
console.log(`🔧 Installation ${action}:`, {
|
64 |
+
installationId: installation.id,
|
65 |
+
account: installation.account.login,
|
66 |
+
repositoryCount: repositories?.length || 0,
|
67 |
+
});
|
68 |
+
|
69 |
+
if (action === "created") {
|
70 |
+
// App was installed - you can store installation info here
|
71 |
+
console.log(`✅ App installed by ${installation.account.login}`);
|
72 |
+
} else if (action === "deleted") {
|
73 |
+
// App was uninstalled
|
74 |
+
console.log(`❌ App uninstalled by ${installation.account.login}`);
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
async function handleInstallationRepositoriesEvent(data: any) {
|
79 |
+
const { action, installation, repositories_added, repositories_removed } = data;
|
80 |
+
|
81 |
+
console.log(`📁 Installation repositories ${action}:`, {
|
82 |
+
installationId: installation.id,
|
83 |
+
added: repositories_added?.length || 0,
|
84 |
+
removed: repositories_removed?.length || 0,
|
85 |
+
});
|
86 |
+
}
|
87 |
+
|
88 |
+
async function handlePushEvent(data: any) {
|
89 |
+
const { repository, pusher, commits } = data;
|
90 |
+
|
91 |
+
console.log(`🚀 Push to ${repository.full_name}:`, {
|
92 |
+
pusher: pusher.name,
|
93 |
+
commits: commits.length,
|
94 |
+
branch: data.ref.replace('refs/heads/', ''),
|
95 |
+
});
|
96 |
+
|
97 |
+
// Example: Use the pusher's authenticated session
|
98 |
+
try {
|
99 |
+
const userAuth = githubApp.getUserAuth(pusher.name);
|
100 |
+
if (userAuth) {
|
101 |
+
console.log(`🔑 Found authenticated user: ${pusher.name}`);
|
102 |
+
// You can now use the user's authentication to perform actions on their behalf
|
103 |
+
// const userOctokit = await githubApp.getUserOctokit(pusher.name);
|
104 |
+
// Use userOctokit to make API calls as the authenticated user
|
105 |
+
} else {
|
106 |
+
console.log(`⚠️ No authentication found for user: ${pusher.name}`);
|
107 |
+
}
|
108 |
+
} catch (error) {
|
109 |
+
console.error("Error handling push event:", error);
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
async function handlePullRequestEvent(data: any) {
|
114 |
+
const { action, pull_request, repository } = data;
|
115 |
+
|
116 |
+
console.log(`🔀 Pull request ${action} in ${repository.full_name}:`, {
|
117 |
+
number: pull_request.number,
|
118 |
+
title: pull_request.title,
|
119 |
+
author: pull_request.user.login,
|
120 |
+
});
|
121 |
+
|
122 |
+
// Example: Use the PR author's authenticated session
|
123 |
+
try {
|
124 |
+
const userAuth = githubApp.getUserAuth(pull_request.user.login);
|
125 |
+
if (userAuth) {
|
126 |
+
console.log(`🔑 Found authenticated user: ${pull_request.user.login}`);
|
127 |
+
// You can now use the user's authentication to perform actions
|
128 |
+
} else {
|
129 |
+
console.log(`⚠️ No authentication found for user: ${pull_request.user.login}`);
|
130 |
+
}
|
131 |
+
} catch (error) {
|
132 |
+
console.error("Error handling pull request event:", error);
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
async function handleIssuesEvent(data: any) {
|
137 |
+
const { action, issue, repository } = data;
|
138 |
+
|
139 |
+
console.log(`🐛 Issue ${action} in ${repository.full_name}:`, {
|
140 |
+
number: issue.number,
|
141 |
+
title: issue.title,
|
142 |
+
author: issue.user.login,
|
143 |
+
});
|
144 |
+
|
145 |
+
// Example: Use the issue author's authenticated session
|
146 |
+
try {
|
147 |
+
const userAuth = githubApp.getUserAuth(issue.user.login);
|
148 |
+
if (userAuth) {
|
149 |
+
console.log(`🔑 Found authenticated user: ${issue.user.login}`);
|
150 |
+
// You can now use the user's authentication to perform actions
|
151 |
+
} else {
|
152 |
+
console.log(`⚠️ No authentication found for user: ${issue.user.login}`);
|
153 |
+
}
|
154 |
+
} catch (error) {
|
155 |
+
console.error("Error handling issues event:", error);
|
156 |
+
}
|
157 |
+
}
|
158 |
+
|
159 |
+
// Prevent GET requests
|
160 |
+
export async function loader() {
|
161 |
+
return json(
|
162 |
+
{ error: "This endpoint only accepts POST requests from GitHub webhooks" },
|
163 |
+
{ status: 405 }
|
164 |
+
);
|
165 |
+
}
|
package-lock.json
CHANGED
@@ -6,15 +6,20 @@
|
|
6 |
"": {
|
7 |
"name": "hugex-gh",
|
8 |
"dependencies": {
|
|
|
|
|
|
|
9 |
"@remix-run/node": "^2.16.8",
|
10 |
"@remix-run/react": "^2.16.8",
|
11 |
"@remix-run/serve": "^2.16.8",
|
12 |
"isbot": "^4.1.0",
|
|
|
13 |
"react": "^18.2.0",
|
14 |
"react-dom": "^18.2.0"
|
15 |
},
|
16 |
"devDependencies": {
|
17 |
"@remix-run/dev": "^2.16.8",
|
|
|
18 |
"@types/react": "^18.2.20",
|
19 |
"@types/react-dom": "^18.2.7",
|
20 |
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
@@ -1446,6 +1451,454 @@
|
|
1446 |
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
1447 |
}
|
1448 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1449 |
"node_modules/@pkgjs/parseargs": {
|
1450 |
"version": "0.11.0",
|
1451 |
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
@@ -2043,6 +2496,18 @@
|
|
2043 |
"@types/estree": "*"
|
2044 |
}
|
2045 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2046 |
"node_modules/@types/cookie": {
|
2047 |
"version": "0.6.0",
|
2048 |
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
@@ -2100,6 +2565,16 @@
|
|
2100 |
"dev": true,
|
2101 |
"license": "MIT"
|
2102 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2103 |
"node_modules/@types/mdast": {
|
2104 |
"version": "3.0.15",
|
2105 |
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz",
|
@@ -2121,14 +2596,12 @@
|
|
2121 |
"version": "2.1.0",
|
2122 |
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
2123 |
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
2124 |
-
"dev": true,
|
2125 |
"license": "MIT"
|
2126 |
},
|
2127 |
"node_modules/@types/node": {
|
2128 |
"version": "22.15.29",
|
2129 |
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz",
|
2130 |
"integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==",
|
2131 |
-
"dev": true,
|
2132 |
"license": "MIT",
|
2133 |
"dependencies": {
|
2134 |
"undici-types": "~6.21.0"
|
@@ -3292,7 +3765,6 @@
|
|
3292 |
"version": "3.1.0",
|
3293 |
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
|
3294 |
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
|
3295 |
-
"dev": true,
|
3296 |
"license": "MIT",
|
3297 |
"dependencies": {
|
3298 |
"clean-stack": "^2.0.0",
|
@@ -3722,6 +4194,12 @@
|
|
3722 |
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
3723 |
"license": "MIT"
|
3724 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
3725 |
"node_modules/binary-extensions": {
|
3726 |
"version": "2.3.0",
|
3727 |
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
@@ -3850,6 +4328,12 @@
|
|
3850 |
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
3851 |
}
|
3852 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
3853 |
"node_modules/buffer": {
|
3854 |
"version": "5.7.1",
|
3855 |
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
@@ -3875,6 +4359,12 @@
|
|
3875 |
"ieee754": "^1.1.13"
|
3876 |
}
|
3877 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
3878 |
"node_modules/buffer-from": {
|
3879 |
"version": "1.1.2",
|
3880 |
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
@@ -4132,7 +4622,6 @@
|
|
4132 |
"version": "2.2.0",
|
4133 |
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
4134 |
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
|
4135 |
-
"dev": true,
|
4136 |
"license": "MIT",
|
4137 |
"engines": {
|
4138 |
"node": ">=6"
|
@@ -4589,6 +5078,12 @@
|
|
4589 |
"node": ">= 0.8"
|
4590 |
}
|
4591 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
4592 |
"node_modules/dequal": {
|
4593 |
"version": "2.0.3",
|
4594 |
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
@@ -4746,6 +5241,15 @@
|
|
4746 |
"dev": true,
|
4747 |
"license": "MIT"
|
4748 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4749 |
"node_modules/ee-first": {
|
4750 |
"version": "1.1.1",
|
4751 |
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
@@ -6733,7 +7237,6 @@
|
|
6733 |
"version": "4.0.0",
|
6734 |
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
|
6735 |
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
|
6736 |
-
"dev": true,
|
6737 |
"license": "MIT",
|
6738 |
"engines": {
|
6739 |
"node": ">=8"
|
@@ -7541,6 +8044,28 @@
|
|
7541 |
"graceful-fs": "^4.1.6"
|
7542 |
}
|
7543 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7544 |
"node_modules/jsx-ast-utils": {
|
7545 |
"version": "3.3.5",
|
7546 |
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
@@ -7557,6 +8082,27 @@
|
|
7557 |
"node": ">=4.0"
|
7558 |
}
|
7559 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7560 |
"node_modules/keyv": {
|
7561 |
"version": "4.5.4",
|
7562 |
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
@@ -7696,6 +8242,42 @@
|
|
7696 |
"dev": true,
|
7697 |
"license": "MIT"
|
7698 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7699 |
"node_modules/lodash.merge": {
|
7700 |
"version": "4.6.2",
|
7701 |
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
@@ -7703,6 +8285,12 @@
|
|
7703 |
"dev": true,
|
7704 |
"license": "MIT"
|
7705 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
7706 |
"node_modules/log-symbols": {
|
7707 |
"version": "4.1.0",
|
7708 |
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
@@ -9373,7 +9961,6 @@
|
|
9373 |
"version": "1.4.0",
|
9374 |
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
9375 |
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
9376 |
-
"dev": true,
|
9377 |
"license": "ISC",
|
9378 |
"dependencies": {
|
9379 |
"wrappy": "1"
|
@@ -10825,7 +11412,6 @@
|
|
10825 |
"version": "7.7.2",
|
10826 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
10827 |
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
10828 |
-
"dev": true,
|
10829 |
"license": "ISC",
|
10830 |
"bin": {
|
10831 |
"semver": "bin/semver.js"
|
@@ -12134,7 +12720,6 @@
|
|
12134 |
"version": "6.21.0",
|
12135 |
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
12136 |
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
12137 |
-
"dev": true,
|
12138 |
"license": "MIT"
|
12139 |
},
|
12140 |
"node_modules/unified": {
|
@@ -12309,6 +12894,22 @@
|
|
12309 |
"url": "https://opencollective.com/unified"
|
12310 |
}
|
12311 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12312 |
"node_modules/universalify": {
|
12313 |
"version": "2.0.1",
|
12314 |
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
@@ -13345,7 +13946,6 @@
|
|
13345 |
"version": "1.0.2",
|
13346 |
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
13347 |
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
13348 |
-
"dev": true,
|
13349 |
"license": "ISC"
|
13350 |
},
|
13351 |
"node_modules/ws": {
|
|
|
6 |
"": {
|
7 |
"name": "hugex-gh",
|
8 |
"dependencies": {
|
9 |
+
"@octokit/app": "^14.0.2",
|
10 |
+
"@octokit/auth-app": "^6.0.1",
|
11 |
+
"@octokit/webhooks": "^12.0.4",
|
12 |
"@remix-run/node": "^2.16.8",
|
13 |
"@remix-run/react": "^2.16.8",
|
14 |
"@remix-run/serve": "^2.16.8",
|
15 |
"isbot": "^4.1.0",
|
16 |
+
"jsonwebtoken": "^9.0.2",
|
17 |
"react": "^18.2.0",
|
18 |
"react-dom": "^18.2.0"
|
19 |
},
|
20 |
"devDependencies": {
|
21 |
"@remix-run/dev": "^2.16.8",
|
22 |
+
"@types/jsonwebtoken": "^9.0.5",
|
23 |
"@types/react": "^18.2.20",
|
24 |
"@types/react-dom": "^18.2.7",
|
25 |
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
|
|
1451 |
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
1452 |
}
|
1453 |
},
|
1454 |
+
"node_modules/@octokit/app": {
|
1455 |
+
"version": "14.1.0",
|
1456 |
+
"resolved": "https://registry.npmjs.org/@octokit/app/-/app-14.1.0.tgz",
|
1457 |
+
"integrity": "sha512-g3uEsGOQCBl1+W1rgfwoRFUIR6PtvB2T1E4RpygeUU5LrLvlOqcxrt5lfykIeRpUPpupreGJUYl70fqMDXdTpw==",
|
1458 |
+
"license": "MIT",
|
1459 |
+
"dependencies": {
|
1460 |
+
"@octokit/auth-app": "^6.0.0",
|
1461 |
+
"@octokit/auth-unauthenticated": "^5.0.0",
|
1462 |
+
"@octokit/core": "^5.0.0",
|
1463 |
+
"@octokit/oauth-app": "^6.0.0",
|
1464 |
+
"@octokit/plugin-paginate-rest": "^9.0.0",
|
1465 |
+
"@octokit/types": "^12.0.0",
|
1466 |
+
"@octokit/webhooks": "^12.0.4"
|
1467 |
+
},
|
1468 |
+
"engines": {
|
1469 |
+
"node": ">= 18"
|
1470 |
+
}
|
1471 |
+
},
|
1472 |
+
"node_modules/@octokit/auth-app": {
|
1473 |
+
"version": "6.1.3",
|
1474 |
+
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-6.1.3.tgz",
|
1475 |
+
"integrity": "sha512-dcaiteA6Y/beAlDLZOPNReN3FGHu+pARD6OHfh3T9f3EO09++ec+5wt3KtGGSSs2Mp5tI8fQwdMOEnrzBLfgUA==",
|
1476 |
+
"license": "MIT",
|
1477 |
+
"dependencies": {
|
1478 |
+
"@octokit/auth-oauth-app": "^7.1.0",
|
1479 |
+
"@octokit/auth-oauth-user": "^4.1.0",
|
1480 |
+
"@octokit/request": "^8.3.1",
|
1481 |
+
"@octokit/request-error": "^5.1.0",
|
1482 |
+
"@octokit/types": "^13.1.0",
|
1483 |
+
"deprecation": "^2.3.1",
|
1484 |
+
"lru-cache": "npm:@wolfy1339/lru-cache@^11.0.2-patch.1",
|
1485 |
+
"universal-github-app-jwt": "^1.1.2",
|
1486 |
+
"universal-user-agent": "^6.0.0"
|
1487 |
+
},
|
1488 |
+
"engines": {
|
1489 |
+
"node": ">= 18"
|
1490 |
+
}
|
1491 |
+
},
|
1492 |
+
"node_modules/@octokit/auth-app/node_modules/@octokit/openapi-types": {
|
1493 |
+
"version": "24.2.0",
|
1494 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1495 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1496 |
+
"license": "MIT"
|
1497 |
+
},
|
1498 |
+
"node_modules/@octokit/auth-app/node_modules/@octokit/types": {
|
1499 |
+
"version": "13.10.0",
|
1500 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1501 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1502 |
+
"license": "MIT",
|
1503 |
+
"dependencies": {
|
1504 |
+
"@octokit/openapi-types": "^24.2.0"
|
1505 |
+
}
|
1506 |
+
},
|
1507 |
+
"node_modules/@octokit/auth-app/node_modules/lru-cache": {
|
1508 |
+
"name": "@wolfy1339/lru-cache",
|
1509 |
+
"version": "11.0.2-patch.1",
|
1510 |
+
"resolved": "https://registry.npmjs.org/@wolfy1339/lru-cache/-/lru-cache-11.0.2-patch.1.tgz",
|
1511 |
+
"integrity": "sha512-BgYZfL2ADCXKOw2wJtkM3slhHotawWkgIRRxq4wEybnZQPjvAp71SPX35xepMykTw8gXlzWcWPTY31hlbnRsDA==",
|
1512 |
+
"license": "ISC",
|
1513 |
+
"engines": {
|
1514 |
+
"node": "18 >=18.20 || 20 || >=22"
|
1515 |
+
}
|
1516 |
+
},
|
1517 |
+
"node_modules/@octokit/auth-oauth-app": {
|
1518 |
+
"version": "7.1.0",
|
1519 |
+
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-7.1.0.tgz",
|
1520 |
+
"integrity": "sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA==",
|
1521 |
+
"license": "MIT",
|
1522 |
+
"dependencies": {
|
1523 |
+
"@octokit/auth-oauth-device": "^6.1.0",
|
1524 |
+
"@octokit/auth-oauth-user": "^4.1.0",
|
1525 |
+
"@octokit/request": "^8.3.1",
|
1526 |
+
"@octokit/types": "^13.0.0",
|
1527 |
+
"@types/btoa-lite": "^1.0.0",
|
1528 |
+
"btoa-lite": "^1.0.0",
|
1529 |
+
"universal-user-agent": "^6.0.0"
|
1530 |
+
},
|
1531 |
+
"engines": {
|
1532 |
+
"node": ">= 18"
|
1533 |
+
}
|
1534 |
+
},
|
1535 |
+
"node_modules/@octokit/auth-oauth-app/node_modules/@octokit/openapi-types": {
|
1536 |
+
"version": "24.2.0",
|
1537 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1538 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1539 |
+
"license": "MIT"
|
1540 |
+
},
|
1541 |
+
"node_modules/@octokit/auth-oauth-app/node_modules/@octokit/types": {
|
1542 |
+
"version": "13.10.0",
|
1543 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1544 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1545 |
+
"license": "MIT",
|
1546 |
+
"dependencies": {
|
1547 |
+
"@octokit/openapi-types": "^24.2.0"
|
1548 |
+
}
|
1549 |
+
},
|
1550 |
+
"node_modules/@octokit/auth-oauth-device": {
|
1551 |
+
"version": "6.1.0",
|
1552 |
+
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz",
|
1553 |
+
"integrity": "sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw==",
|
1554 |
+
"license": "MIT",
|
1555 |
+
"dependencies": {
|
1556 |
+
"@octokit/oauth-methods": "^4.1.0",
|
1557 |
+
"@octokit/request": "^8.3.1",
|
1558 |
+
"@octokit/types": "^13.0.0",
|
1559 |
+
"universal-user-agent": "^6.0.0"
|
1560 |
+
},
|
1561 |
+
"engines": {
|
1562 |
+
"node": ">= 18"
|
1563 |
+
}
|
1564 |
+
},
|
1565 |
+
"node_modules/@octokit/auth-oauth-device/node_modules/@octokit/openapi-types": {
|
1566 |
+
"version": "24.2.0",
|
1567 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1568 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1569 |
+
"license": "MIT"
|
1570 |
+
},
|
1571 |
+
"node_modules/@octokit/auth-oauth-device/node_modules/@octokit/types": {
|
1572 |
+
"version": "13.10.0",
|
1573 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1574 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1575 |
+
"license": "MIT",
|
1576 |
+
"dependencies": {
|
1577 |
+
"@octokit/openapi-types": "^24.2.0"
|
1578 |
+
}
|
1579 |
+
},
|
1580 |
+
"node_modules/@octokit/auth-oauth-user": {
|
1581 |
+
"version": "4.1.0",
|
1582 |
+
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-4.1.0.tgz",
|
1583 |
+
"integrity": "sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ==",
|
1584 |
+
"license": "MIT",
|
1585 |
+
"dependencies": {
|
1586 |
+
"@octokit/auth-oauth-device": "^6.1.0",
|
1587 |
+
"@octokit/oauth-methods": "^4.1.0",
|
1588 |
+
"@octokit/request": "^8.3.1",
|
1589 |
+
"@octokit/types": "^13.0.0",
|
1590 |
+
"btoa-lite": "^1.0.0",
|
1591 |
+
"universal-user-agent": "^6.0.0"
|
1592 |
+
},
|
1593 |
+
"engines": {
|
1594 |
+
"node": ">= 18"
|
1595 |
+
}
|
1596 |
+
},
|
1597 |
+
"node_modules/@octokit/auth-oauth-user/node_modules/@octokit/openapi-types": {
|
1598 |
+
"version": "24.2.0",
|
1599 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1600 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1601 |
+
"license": "MIT"
|
1602 |
+
},
|
1603 |
+
"node_modules/@octokit/auth-oauth-user/node_modules/@octokit/types": {
|
1604 |
+
"version": "13.10.0",
|
1605 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1606 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1607 |
+
"license": "MIT",
|
1608 |
+
"dependencies": {
|
1609 |
+
"@octokit/openapi-types": "^24.2.0"
|
1610 |
+
}
|
1611 |
+
},
|
1612 |
+
"node_modules/@octokit/auth-token": {
|
1613 |
+
"version": "4.0.0",
|
1614 |
+
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
|
1615 |
+
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
|
1616 |
+
"license": "MIT",
|
1617 |
+
"engines": {
|
1618 |
+
"node": ">= 18"
|
1619 |
+
}
|
1620 |
+
},
|
1621 |
+
"node_modules/@octokit/auth-unauthenticated": {
|
1622 |
+
"version": "5.0.1",
|
1623 |
+
"resolved": "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-5.0.1.tgz",
|
1624 |
+
"integrity": "sha512-oxeWzmBFxWd+XolxKTc4zr+h3mt+yofn4r7OfoIkR/Cj/o70eEGmPsFbueyJE2iBAGpjgTnEOKM3pnuEGVmiqg==",
|
1625 |
+
"license": "MIT",
|
1626 |
+
"dependencies": {
|
1627 |
+
"@octokit/request-error": "^5.0.0",
|
1628 |
+
"@octokit/types": "^12.0.0"
|
1629 |
+
},
|
1630 |
+
"engines": {
|
1631 |
+
"node": ">= 18"
|
1632 |
+
}
|
1633 |
+
},
|
1634 |
+
"node_modules/@octokit/core": {
|
1635 |
+
"version": "5.2.1",
|
1636 |
+
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.1.tgz",
|
1637 |
+
"integrity": "sha512-dKYCMuPO1bmrpuogcjQ8z7ICCH3FP6WmxpwC03yjzGfZhj9fTJg6+bS1+UAplekbN2C+M61UNllGOOoAfGCrdQ==",
|
1638 |
+
"license": "MIT",
|
1639 |
+
"dependencies": {
|
1640 |
+
"@octokit/auth-token": "^4.0.0",
|
1641 |
+
"@octokit/graphql": "^7.1.0",
|
1642 |
+
"@octokit/request": "^8.4.1",
|
1643 |
+
"@octokit/request-error": "^5.1.1",
|
1644 |
+
"@octokit/types": "^13.0.0",
|
1645 |
+
"before-after-hook": "^2.2.0",
|
1646 |
+
"universal-user-agent": "^6.0.0"
|
1647 |
+
},
|
1648 |
+
"engines": {
|
1649 |
+
"node": ">= 18"
|
1650 |
+
}
|
1651 |
+
},
|
1652 |
+
"node_modules/@octokit/core/node_modules/@octokit/openapi-types": {
|
1653 |
+
"version": "24.2.0",
|
1654 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1655 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1656 |
+
"license": "MIT"
|
1657 |
+
},
|
1658 |
+
"node_modules/@octokit/core/node_modules/@octokit/types": {
|
1659 |
+
"version": "13.10.0",
|
1660 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1661 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1662 |
+
"license": "MIT",
|
1663 |
+
"dependencies": {
|
1664 |
+
"@octokit/openapi-types": "^24.2.0"
|
1665 |
+
}
|
1666 |
+
},
|
1667 |
+
"node_modules/@octokit/endpoint": {
|
1668 |
+
"version": "9.0.6",
|
1669 |
+
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
|
1670 |
+
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
|
1671 |
+
"license": "MIT",
|
1672 |
+
"dependencies": {
|
1673 |
+
"@octokit/types": "^13.1.0",
|
1674 |
+
"universal-user-agent": "^6.0.0"
|
1675 |
+
},
|
1676 |
+
"engines": {
|
1677 |
+
"node": ">= 18"
|
1678 |
+
}
|
1679 |
+
},
|
1680 |
+
"node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": {
|
1681 |
+
"version": "24.2.0",
|
1682 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1683 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1684 |
+
"license": "MIT"
|
1685 |
+
},
|
1686 |
+
"node_modules/@octokit/endpoint/node_modules/@octokit/types": {
|
1687 |
+
"version": "13.10.0",
|
1688 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1689 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1690 |
+
"license": "MIT",
|
1691 |
+
"dependencies": {
|
1692 |
+
"@octokit/openapi-types": "^24.2.0"
|
1693 |
+
}
|
1694 |
+
},
|
1695 |
+
"node_modules/@octokit/graphql": {
|
1696 |
+
"version": "7.1.1",
|
1697 |
+
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz",
|
1698 |
+
"integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==",
|
1699 |
+
"license": "MIT",
|
1700 |
+
"dependencies": {
|
1701 |
+
"@octokit/request": "^8.4.1",
|
1702 |
+
"@octokit/types": "^13.0.0",
|
1703 |
+
"universal-user-agent": "^6.0.0"
|
1704 |
+
},
|
1705 |
+
"engines": {
|
1706 |
+
"node": ">= 18"
|
1707 |
+
}
|
1708 |
+
},
|
1709 |
+
"node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": {
|
1710 |
+
"version": "24.2.0",
|
1711 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1712 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1713 |
+
"license": "MIT"
|
1714 |
+
},
|
1715 |
+
"node_modules/@octokit/graphql/node_modules/@octokit/types": {
|
1716 |
+
"version": "13.10.0",
|
1717 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1718 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1719 |
+
"license": "MIT",
|
1720 |
+
"dependencies": {
|
1721 |
+
"@octokit/openapi-types": "^24.2.0"
|
1722 |
+
}
|
1723 |
+
},
|
1724 |
+
"node_modules/@octokit/oauth-app": {
|
1725 |
+
"version": "6.1.0",
|
1726 |
+
"resolved": "https://registry.npmjs.org/@octokit/oauth-app/-/oauth-app-6.1.0.tgz",
|
1727 |
+
"integrity": "sha512-nIn/8eUJ/BKUVzxUXd5vpzl1rwaVxMyYbQkNZjHrF7Vk/yu98/YDF/N2KeWO7uZ0g3b5EyiFXFkZI8rJ+DH1/g==",
|
1728 |
+
"license": "MIT",
|
1729 |
+
"dependencies": {
|
1730 |
+
"@octokit/auth-oauth-app": "^7.0.0",
|
1731 |
+
"@octokit/auth-oauth-user": "^4.0.0",
|
1732 |
+
"@octokit/auth-unauthenticated": "^5.0.0",
|
1733 |
+
"@octokit/core": "^5.0.0",
|
1734 |
+
"@octokit/oauth-authorization-url": "^6.0.2",
|
1735 |
+
"@octokit/oauth-methods": "^4.0.0",
|
1736 |
+
"@types/aws-lambda": "^8.10.83",
|
1737 |
+
"universal-user-agent": "^6.0.0"
|
1738 |
+
},
|
1739 |
+
"engines": {
|
1740 |
+
"node": ">= 18"
|
1741 |
+
}
|
1742 |
+
},
|
1743 |
+
"node_modules/@octokit/oauth-authorization-url": {
|
1744 |
+
"version": "6.0.2",
|
1745 |
+
"resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz",
|
1746 |
+
"integrity": "sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA==",
|
1747 |
+
"license": "MIT",
|
1748 |
+
"engines": {
|
1749 |
+
"node": ">= 18"
|
1750 |
+
}
|
1751 |
+
},
|
1752 |
+
"node_modules/@octokit/oauth-methods": {
|
1753 |
+
"version": "4.1.0",
|
1754 |
+
"resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz",
|
1755 |
+
"integrity": "sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw==",
|
1756 |
+
"license": "MIT",
|
1757 |
+
"dependencies": {
|
1758 |
+
"@octokit/oauth-authorization-url": "^6.0.2",
|
1759 |
+
"@octokit/request": "^8.3.1",
|
1760 |
+
"@octokit/request-error": "^5.1.0",
|
1761 |
+
"@octokit/types": "^13.0.0",
|
1762 |
+
"btoa-lite": "^1.0.0"
|
1763 |
+
},
|
1764 |
+
"engines": {
|
1765 |
+
"node": ">= 18"
|
1766 |
+
}
|
1767 |
+
},
|
1768 |
+
"node_modules/@octokit/oauth-methods/node_modules/@octokit/openapi-types": {
|
1769 |
+
"version": "24.2.0",
|
1770 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1771 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1772 |
+
"license": "MIT"
|
1773 |
+
},
|
1774 |
+
"node_modules/@octokit/oauth-methods/node_modules/@octokit/types": {
|
1775 |
+
"version": "13.10.0",
|
1776 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1777 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1778 |
+
"license": "MIT",
|
1779 |
+
"dependencies": {
|
1780 |
+
"@octokit/openapi-types": "^24.2.0"
|
1781 |
+
}
|
1782 |
+
},
|
1783 |
+
"node_modules/@octokit/openapi-types": {
|
1784 |
+
"version": "20.0.0",
|
1785 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
1786 |
+
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
1787 |
+
"license": "MIT"
|
1788 |
+
},
|
1789 |
+
"node_modules/@octokit/plugin-paginate-rest": {
|
1790 |
+
"version": "9.2.2",
|
1791 |
+
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz",
|
1792 |
+
"integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==",
|
1793 |
+
"license": "MIT",
|
1794 |
+
"dependencies": {
|
1795 |
+
"@octokit/types": "^12.6.0"
|
1796 |
+
},
|
1797 |
+
"engines": {
|
1798 |
+
"node": ">= 18"
|
1799 |
+
},
|
1800 |
+
"peerDependencies": {
|
1801 |
+
"@octokit/core": "5"
|
1802 |
+
}
|
1803 |
+
},
|
1804 |
+
"node_modules/@octokit/request": {
|
1805 |
+
"version": "8.4.1",
|
1806 |
+
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz",
|
1807 |
+
"integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==",
|
1808 |
+
"license": "MIT",
|
1809 |
+
"dependencies": {
|
1810 |
+
"@octokit/endpoint": "^9.0.6",
|
1811 |
+
"@octokit/request-error": "^5.1.1",
|
1812 |
+
"@octokit/types": "^13.1.0",
|
1813 |
+
"universal-user-agent": "^6.0.0"
|
1814 |
+
},
|
1815 |
+
"engines": {
|
1816 |
+
"node": ">= 18"
|
1817 |
+
}
|
1818 |
+
},
|
1819 |
+
"node_modules/@octokit/request-error": {
|
1820 |
+
"version": "5.1.1",
|
1821 |
+
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz",
|
1822 |
+
"integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==",
|
1823 |
+
"license": "MIT",
|
1824 |
+
"dependencies": {
|
1825 |
+
"@octokit/types": "^13.1.0",
|
1826 |
+
"deprecation": "^2.0.0",
|
1827 |
+
"once": "^1.4.0"
|
1828 |
+
},
|
1829 |
+
"engines": {
|
1830 |
+
"node": ">= 18"
|
1831 |
+
}
|
1832 |
+
},
|
1833 |
+
"node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": {
|
1834 |
+
"version": "24.2.0",
|
1835 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1836 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1837 |
+
"license": "MIT"
|
1838 |
+
},
|
1839 |
+
"node_modules/@octokit/request-error/node_modules/@octokit/types": {
|
1840 |
+
"version": "13.10.0",
|
1841 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1842 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1843 |
+
"license": "MIT",
|
1844 |
+
"dependencies": {
|
1845 |
+
"@octokit/openapi-types": "^24.2.0"
|
1846 |
+
}
|
1847 |
+
},
|
1848 |
+
"node_modules/@octokit/request/node_modules/@octokit/openapi-types": {
|
1849 |
+
"version": "24.2.0",
|
1850 |
+
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
1851 |
+
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
1852 |
+
"license": "MIT"
|
1853 |
+
},
|
1854 |
+
"node_modules/@octokit/request/node_modules/@octokit/types": {
|
1855 |
+
"version": "13.10.0",
|
1856 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
1857 |
+
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
1858 |
+
"license": "MIT",
|
1859 |
+
"dependencies": {
|
1860 |
+
"@octokit/openapi-types": "^24.2.0"
|
1861 |
+
}
|
1862 |
+
},
|
1863 |
+
"node_modules/@octokit/types": {
|
1864 |
+
"version": "12.6.0",
|
1865 |
+
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
1866 |
+
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
1867 |
+
"license": "MIT",
|
1868 |
+
"dependencies": {
|
1869 |
+
"@octokit/openapi-types": "^20.0.0"
|
1870 |
+
}
|
1871 |
+
},
|
1872 |
+
"node_modules/@octokit/webhooks": {
|
1873 |
+
"version": "12.3.1",
|
1874 |
+
"resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-12.3.1.tgz",
|
1875 |
+
"integrity": "sha512-BVwtWE3rRXB9IugmQTfKspqjNa8q+ab73ddkV9k1Zok3XbuOxJUi4lTYk5zBZDhfWb/Y2H+RO9Iggm25gsqeow==",
|
1876 |
+
"license": "MIT",
|
1877 |
+
"dependencies": {
|
1878 |
+
"@octokit/request-error": "^5.0.0",
|
1879 |
+
"@octokit/webhooks-methods": "^4.1.0",
|
1880 |
+
"@octokit/webhooks-types": "7.6.1",
|
1881 |
+
"aggregate-error": "^3.1.0"
|
1882 |
+
},
|
1883 |
+
"engines": {
|
1884 |
+
"node": ">= 18"
|
1885 |
+
}
|
1886 |
+
},
|
1887 |
+
"node_modules/@octokit/webhooks-methods": {
|
1888 |
+
"version": "4.1.0",
|
1889 |
+
"resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-4.1.0.tgz",
|
1890 |
+
"integrity": "sha512-zoQyKw8h9STNPqtm28UGOYFE7O6D4Il8VJwhAtMHFt2C4L0VQT1qGKLeefUOqHNs1mNRYSadVv7x0z8U2yyeWQ==",
|
1891 |
+
"license": "MIT",
|
1892 |
+
"engines": {
|
1893 |
+
"node": ">= 18"
|
1894 |
+
}
|
1895 |
+
},
|
1896 |
+
"node_modules/@octokit/webhooks-types": {
|
1897 |
+
"version": "7.6.1",
|
1898 |
+
"resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-7.6.1.tgz",
|
1899 |
+
"integrity": "sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw==",
|
1900 |
+
"license": "MIT"
|
1901 |
+
},
|
1902 |
"node_modules/@pkgjs/parseargs": {
|
1903 |
"version": "0.11.0",
|
1904 |
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
|
|
2496 |
"@types/estree": "*"
|
2497 |
}
|
2498 |
},
|
2499 |
+
"node_modules/@types/aws-lambda": {
|
2500 |
+
"version": "8.10.149",
|
2501 |
+
"resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.149.tgz",
|
2502 |
+
"integrity": "sha512-NXSZIhfJjnXqJgtS7IwutqIF/SOy1Wz5Px4gUY1RWITp3AYTyuJS4xaXr/bIJY1v15XMzrJ5soGnPM+7uigZjA==",
|
2503 |
+
"license": "MIT"
|
2504 |
+
},
|
2505 |
+
"node_modules/@types/btoa-lite": {
|
2506 |
+
"version": "1.0.2",
|
2507 |
+
"resolved": "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.2.tgz",
|
2508 |
+
"integrity": "sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg==",
|
2509 |
+
"license": "MIT"
|
2510 |
+
},
|
2511 |
"node_modules/@types/cookie": {
|
2512 |
"version": "0.6.0",
|
2513 |
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
|
|
2565 |
"dev": true,
|
2566 |
"license": "MIT"
|
2567 |
},
|
2568 |
+
"node_modules/@types/jsonwebtoken": {
|
2569 |
+
"version": "9.0.9",
|
2570 |
+
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz",
|
2571 |
+
"integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==",
|
2572 |
+
"license": "MIT",
|
2573 |
+
"dependencies": {
|
2574 |
+
"@types/ms": "*",
|
2575 |
+
"@types/node": "*"
|
2576 |
+
}
|
2577 |
+
},
|
2578 |
"node_modules/@types/mdast": {
|
2579 |
"version": "3.0.15",
|
2580 |
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz",
|
|
|
2596 |
"version": "2.1.0",
|
2597 |
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
2598 |
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
|
|
2599 |
"license": "MIT"
|
2600 |
},
|
2601 |
"node_modules/@types/node": {
|
2602 |
"version": "22.15.29",
|
2603 |
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz",
|
2604 |
"integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==",
|
|
|
2605 |
"license": "MIT",
|
2606 |
"dependencies": {
|
2607 |
"undici-types": "~6.21.0"
|
|
|
3765 |
"version": "3.1.0",
|
3766 |
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
|
3767 |
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
|
|
|
3768 |
"license": "MIT",
|
3769 |
"dependencies": {
|
3770 |
"clean-stack": "^2.0.0",
|
|
|
4194 |
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
4195 |
"license": "MIT"
|
4196 |
},
|
4197 |
+
"node_modules/before-after-hook": {
|
4198 |
+
"version": "2.2.3",
|
4199 |
+
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
4200 |
+
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
|
4201 |
+
"license": "Apache-2.0"
|
4202 |
+
},
|
4203 |
"node_modules/binary-extensions": {
|
4204 |
"version": "2.3.0",
|
4205 |
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
|
|
4328 |
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
4329 |
}
|
4330 |
},
|
4331 |
+
"node_modules/btoa-lite": {
|
4332 |
+
"version": "1.0.0",
|
4333 |
+
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
|
4334 |
+
"integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==",
|
4335 |
+
"license": "MIT"
|
4336 |
+
},
|
4337 |
"node_modules/buffer": {
|
4338 |
"version": "5.7.1",
|
4339 |
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
|
|
4359 |
"ieee754": "^1.1.13"
|
4360 |
}
|
4361 |
},
|
4362 |
+
"node_modules/buffer-equal-constant-time": {
|
4363 |
+
"version": "1.0.1",
|
4364 |
+
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
4365 |
+
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
4366 |
+
"license": "BSD-3-Clause"
|
4367 |
+
},
|
4368 |
"node_modules/buffer-from": {
|
4369 |
"version": "1.1.2",
|
4370 |
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
|
|
4622 |
"version": "2.2.0",
|
4623 |
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
4624 |
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
|
|
|
4625 |
"license": "MIT",
|
4626 |
"engines": {
|
4627 |
"node": ">=6"
|
|
|
5078 |
"node": ">= 0.8"
|
5079 |
}
|
5080 |
},
|
5081 |
+
"node_modules/deprecation": {
|
5082 |
+
"version": "2.3.1",
|
5083 |
+
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
5084 |
+
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
|
5085 |
+
"license": "ISC"
|
5086 |
+
},
|
5087 |
"node_modules/dequal": {
|
5088 |
"version": "2.0.3",
|
5089 |
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
|
|
5241 |
"dev": true,
|
5242 |
"license": "MIT"
|
5243 |
},
|
5244 |
+
"node_modules/ecdsa-sig-formatter": {
|
5245 |
+
"version": "1.0.11",
|
5246 |
+
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
5247 |
+
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
5248 |
+
"license": "Apache-2.0",
|
5249 |
+
"dependencies": {
|
5250 |
+
"safe-buffer": "^5.0.1"
|
5251 |
+
}
|
5252 |
+
},
|
5253 |
"node_modules/ee-first": {
|
5254 |
"version": "1.1.1",
|
5255 |
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
|
|
7237 |
"version": "4.0.0",
|
7238 |
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
|
7239 |
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
|
|
|
7240 |
"license": "MIT",
|
7241 |
"engines": {
|
7242 |
"node": ">=8"
|
|
|
8044 |
"graceful-fs": "^4.1.6"
|
8045 |
}
|
8046 |
},
|
8047 |
+
"node_modules/jsonwebtoken": {
|
8048 |
+
"version": "9.0.2",
|
8049 |
+
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
8050 |
+
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
8051 |
+
"license": "MIT",
|
8052 |
+
"dependencies": {
|
8053 |
+
"jws": "^3.2.2",
|
8054 |
+
"lodash.includes": "^4.3.0",
|
8055 |
+
"lodash.isboolean": "^3.0.3",
|
8056 |
+
"lodash.isinteger": "^4.0.4",
|
8057 |
+
"lodash.isnumber": "^3.0.3",
|
8058 |
+
"lodash.isplainobject": "^4.0.6",
|
8059 |
+
"lodash.isstring": "^4.0.1",
|
8060 |
+
"lodash.once": "^4.0.0",
|
8061 |
+
"ms": "^2.1.1",
|
8062 |
+
"semver": "^7.5.4"
|
8063 |
+
},
|
8064 |
+
"engines": {
|
8065 |
+
"node": ">=12",
|
8066 |
+
"npm": ">=6"
|
8067 |
+
}
|
8068 |
+
},
|
8069 |
"node_modules/jsx-ast-utils": {
|
8070 |
"version": "3.3.5",
|
8071 |
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
|
|
8082 |
"node": ">=4.0"
|
8083 |
}
|
8084 |
},
|
8085 |
+
"node_modules/jwa": {
|
8086 |
+
"version": "1.4.2",
|
8087 |
+
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
|
8088 |
+
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
|
8089 |
+
"license": "MIT",
|
8090 |
+
"dependencies": {
|
8091 |
+
"buffer-equal-constant-time": "^1.0.1",
|
8092 |
+
"ecdsa-sig-formatter": "1.0.11",
|
8093 |
+
"safe-buffer": "^5.0.1"
|
8094 |
+
}
|
8095 |
+
},
|
8096 |
+
"node_modules/jws": {
|
8097 |
+
"version": "3.2.2",
|
8098 |
+
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
8099 |
+
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
8100 |
+
"license": "MIT",
|
8101 |
+
"dependencies": {
|
8102 |
+
"jwa": "^1.4.1",
|
8103 |
+
"safe-buffer": "^5.0.1"
|
8104 |
+
}
|
8105 |
+
},
|
8106 |
"node_modules/keyv": {
|
8107 |
"version": "4.5.4",
|
8108 |
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
|
|
8242 |
"dev": true,
|
8243 |
"license": "MIT"
|
8244 |
},
|
8245 |
+
"node_modules/lodash.includes": {
|
8246 |
+
"version": "4.3.0",
|
8247 |
+
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
8248 |
+
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
8249 |
+
"license": "MIT"
|
8250 |
+
},
|
8251 |
+
"node_modules/lodash.isboolean": {
|
8252 |
+
"version": "3.0.3",
|
8253 |
+
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
8254 |
+
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
8255 |
+
"license": "MIT"
|
8256 |
+
},
|
8257 |
+
"node_modules/lodash.isinteger": {
|
8258 |
+
"version": "4.0.4",
|
8259 |
+
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
8260 |
+
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
8261 |
+
"license": "MIT"
|
8262 |
+
},
|
8263 |
+
"node_modules/lodash.isnumber": {
|
8264 |
+
"version": "3.0.3",
|
8265 |
+
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
8266 |
+
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
8267 |
+
"license": "MIT"
|
8268 |
+
},
|
8269 |
+
"node_modules/lodash.isplainobject": {
|
8270 |
+
"version": "4.0.6",
|
8271 |
+
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
8272 |
+
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
8273 |
+
"license": "MIT"
|
8274 |
+
},
|
8275 |
+
"node_modules/lodash.isstring": {
|
8276 |
+
"version": "4.0.1",
|
8277 |
+
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
8278 |
+
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
8279 |
+
"license": "MIT"
|
8280 |
+
},
|
8281 |
"node_modules/lodash.merge": {
|
8282 |
"version": "4.6.2",
|
8283 |
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
|
|
8285 |
"dev": true,
|
8286 |
"license": "MIT"
|
8287 |
},
|
8288 |
+
"node_modules/lodash.once": {
|
8289 |
+
"version": "4.1.1",
|
8290 |
+
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
8291 |
+
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
8292 |
+
"license": "MIT"
|
8293 |
+
},
|
8294 |
"node_modules/log-symbols": {
|
8295 |
"version": "4.1.0",
|
8296 |
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
|
|
9961 |
"version": "1.4.0",
|
9962 |
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
9963 |
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
|
|
9964 |
"license": "ISC",
|
9965 |
"dependencies": {
|
9966 |
"wrappy": "1"
|
|
|
11412 |
"version": "7.7.2",
|
11413 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
11414 |
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
|
|
11415 |
"license": "ISC",
|
11416 |
"bin": {
|
11417 |
"semver": "bin/semver.js"
|
|
|
12720 |
"version": "6.21.0",
|
12721 |
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
12722 |
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
|
|
12723 |
"license": "MIT"
|
12724 |
},
|
12725 |
"node_modules/unified": {
|
|
|
12894 |
"url": "https://opencollective.com/unified"
|
12895 |
}
|
12896 |
},
|
12897 |
+
"node_modules/universal-github-app-jwt": {
|
12898 |
+
"version": "1.2.0",
|
12899 |
+
"resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.2.0.tgz",
|
12900 |
+
"integrity": "sha512-dncpMpnsKBk0eetwfN8D8OUHGfiDhhJ+mtsbMl+7PfW7mYjiH8LIcqRmYMtzYLgSh47HjfdBtrBwIQ/gizKR3g==",
|
12901 |
+
"license": "MIT",
|
12902 |
+
"dependencies": {
|
12903 |
+
"@types/jsonwebtoken": "^9.0.0",
|
12904 |
+
"jsonwebtoken": "^9.0.2"
|
12905 |
+
}
|
12906 |
+
},
|
12907 |
+
"node_modules/universal-user-agent": {
|
12908 |
+
"version": "6.0.1",
|
12909 |
+
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
|
12910 |
+
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
|
12911 |
+
"license": "ISC"
|
12912 |
+
},
|
12913 |
"node_modules/universalify": {
|
12914 |
"version": "2.0.1",
|
12915 |
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
|
|
13946 |
"version": "1.0.2",
|
13947 |
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
13948 |
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
|
|
13949 |
"license": "ISC"
|
13950 |
},
|
13951 |
"node_modules/ws": {
|
package.json
CHANGED
@@ -8,12 +8,18 @@
|
|
8 |
"dev": "remix vite:dev",
|
9 |
"lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
|
10 |
"start": "remix-serve ./build/server/index.js",
|
11 |
-
"typecheck": "tsc"
|
|
|
|
|
12 |
},
|
13 |
"dependencies": {
|
14 |
"@remix-run/node": "^2.16.8",
|
15 |
"@remix-run/react": "^2.16.8",
|
16 |
"@remix-run/serve": "^2.16.8",
|
|
|
|
|
|
|
|
|
17 |
"isbot": "^4.1.0",
|
18 |
"react": "^18.2.0",
|
19 |
"react-dom": "^18.2.0"
|
@@ -22,6 +28,7 @@
|
|
22 |
"@remix-run/dev": "^2.16.8",
|
23 |
"@types/react": "^18.2.20",
|
24 |
"@types/react-dom": "^18.2.7",
|
|
|
25 |
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
26 |
"@typescript-eslint/parser": "^6.7.4",
|
27 |
"autoprefixer": "^10.4.19",
|
|
|
8 |
"dev": "remix vite:dev",
|
9 |
"lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
|
10 |
"start": "remix-serve ./build/server/index.js",
|
11 |
+
"typecheck": "tsc",
|
12 |
+
"setup": "node generate-secrets.mjs",
|
13 |
+
"secrets": "node generate-secrets.mjs"
|
14 |
},
|
15 |
"dependencies": {
|
16 |
"@remix-run/node": "^2.16.8",
|
17 |
"@remix-run/react": "^2.16.8",
|
18 |
"@remix-run/serve": "^2.16.8",
|
19 |
+
"@octokit/app": "^14.0.2",
|
20 |
+
"@octokit/auth-app": "^6.0.1",
|
21 |
+
"@octokit/webhooks": "^12.0.4",
|
22 |
+
"jsonwebtoken": "^9.0.2",
|
23 |
"isbot": "^4.1.0",
|
24 |
"react": "^18.2.0",
|
25 |
"react-dom": "^18.2.0"
|
|
|
28 |
"@remix-run/dev": "^2.16.8",
|
29 |
"@types/react": "^18.2.20",
|
30 |
"@types/react-dom": "^18.2.7",
|
31 |
+
"@types/jsonwebtoken": "^9.0.5",
|
32 |
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
33 |
"@typescript-eslint/parser": "^6.7.4",
|
34 |
"autoprefixer": "^10.4.19",
|