Skip to content

Commit 5f02f64

Browse files
committed
refactor(connect): remove any usage in connect.ts, type GitHub token response
Collapses the 4 boilerplate preauth blocks (GET /status, GET /github, GET /github/autodiscover, DELETE /:platform) down to preHandler: [app.authenticate], matching the pattern already used in auth.ts's /me and DELETE /logout routes. The FastifyJWT augmentation in types/fastify.d.ts already types request.user as AuthenticatedUser, so the (request.user as any).id casts are no longer needed. Also types the GitHub token-exchange response in github/callback using GitHubTokenResponse/GitHubTokenErrorResponse and isGitHubTokenError from utils/error.util.ts, reusing the same types auth.ts already defines for the equivalent login-flow exchange instead of �s any.
1 parent 52e4df1 commit 5f02f64

1 file changed

Lines changed: 16 additions & 31 deletions

File tree

apps/backend/src/routes/connect.ts

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { randomBytes } from 'node:crypto';
22

33
import { decrypt, encrypt } from '../utils/encryption.js';
4-
import { getErrorMessage } from '../utils/error.util.js';
4+
import { getErrorMessage, isGitHubTokenError } from '../utils/error.util.js';
55

6+
import type { GitHubTokenErrorResponse, GitHubTokenResponse } from '../utils/error.util.js';
67
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
78

89
const GITHUB_AUTH_URL = 'https://github.com/login/oauth/authorize';
@@ -30,14 +31,10 @@ export async function connectRoutes(app: FastifyInstance): Promise<void> {
3031
// ─── Status ───
3132

3233
app.get('/status', {
33-
preHandler: [async (request, reply) => {
34-
const server = request.server as any;
35-
if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return }
36-
if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return }
37-
try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) }
38-
}],
34+
// eslint-disable-next-line @typescript-eslint/unbound-method
35+
preHandler: [app.authenticate],
3936
}, async (request: FastifyRequest, _reply: FastifyReply) => {
40-
const userId = (request.user as any).id;
37+
const userId = request.user.id;
4138

4239
const tokens = await app.prisma.oAuthToken.findMany({
4340
where: { userId },
@@ -50,14 +47,10 @@ export async function connectRoutes(app: FastifyInstance): Promise<void> {
5047
// ─── GitHub Connect ───
5148

5249
app.get('/github', {
53-
preHandler: [async (request, reply) => {
54-
const server = request.server as any;
55-
if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return }
56-
if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return }
57-
try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) }
58-
}],
50+
// eslint-disable-next-line @typescript-eslint/unbound-method
51+
preHandler: [app.authenticate],
5952
}, async (request: FastifyRequest, reply: FastifyReply) => {
60-
const userId = (request.user as any).id;
53+
const userId = request.user.id;
6154
const nonce = generateState();
6255

6356
// Store nonce in Redis with 10-minute TTL.
@@ -127,9 +120,9 @@ export async function connectRoutes(app: FastifyInstance): Promise<void> {
127120
}),
128121
});
129122

130-
const tokenData = (await tokenRes.json()) as any;
123+
const tokenData = (await tokenRes.json()) as GitHubTokenResponse | GitHubTokenErrorResponse;
131124

132-
if (tokenData.error) {
125+
if (isGitHubTokenError(tokenData)) {
133126
app.log.error('GitHub connect token error:', tokenData);
134127
return reply.redirect(`${process.env.PUBLIC_APP_URL}/settings?error=connect_failed`);
135128
}
@@ -174,14 +167,10 @@ export async function connectRoutes(app: FastifyInstance): Promise<void> {
174167
});
175168

176169
app.get('/github/autodiscover', {
177-
preHandler: [async (request, reply) => {
178-
const server = request.server as any;
179-
if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return }
180-
if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return }
181-
try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) }
182-
}],
170+
// eslint-disable-next-line @typescript-eslint/unbound-method
171+
preHandler: [app.authenticate],
183172
}, async (request: FastifyRequest, reply: FastifyReply) => {
184-
const userId = (request.user as any).id;
173+
const userId = request.user.id;
185174
const cacheKey = `github:autodiscover:${userId}`;
186175

187176
if (app.redis) {
@@ -263,14 +252,10 @@ export async function connectRoutes(app: FastifyInstance): Promise<void> {
263252
// ─── Disconnect ───
264253

265254
app.delete('/:platform', {
266-
preHandler: [async (request, reply) => {
267-
const server = request.server as any;
268-
if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return }
269-
if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return }
270-
try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) }
271-
}],
255+
// eslint-disable-next-line @typescript-eslint/unbound-method
256+
preHandler: [app.authenticate],
272257
}, async (request: FastifyRequest<{ Params: { platform: string } }>, reply: FastifyReply) => {
273-
const userId = (request.user as any).id;
258+
const userId = request.user.id;
274259
const { platform } = request.params;
275260

276261
const SUPPORTED_PLATFORMS = ['github', 'google', 'twitter', 'linkedin'];

0 commit comments

Comments
 (0)