📦 EqualifyEverything / equalify-hub

📄 app.tsx · 126 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126import { Hono } from 'hono';
import { handle } from 'hono/aws-lambda';
import type { LambdaEvent, LambdaContext } from 'hono/aws-lambda';
import { setCookie } from 'hono/cookie';

import { logView } from '#src/utils/db';
import { setEvent } from '#src/utils/event';

// Migrated pages (JSX components)
import { AboutPage } from '#src/pages/about';
import { userGuideHandler, userGuideDocHandler } from '#src/pages/user-guide';
import { technicalDocsHandler, technicalDocsDocHandler } from '#src/pages/technical-docs';
import { RoadmapPage } from '#src/pages/roadmap';
import { updatesHandler, updatesDocHandler } from '#src/pages/updates';
import { reportsHandler, reportsDocHandler } from '#src/pages/reports';
import { feedbackHandler, submitFeatureHandler, voteHandler, deleteFeatureHandler } from '#src/pages/feedback';
import { signupHandler, signupSubmitHandler } from '#src/pages/signup';
import { homeHandler } from '#src/pages/home';

// Route handlers (all native Hono now)
import { github, githubPro, callback, logout } from '#src/routes/public/auth';
import { robots, sitemap, security, humans } from '#src/routes/public/static';
import { repo } from '#src/routes/public/repo';
import { commits } from '#src/routes/public/commits';
import { issues, issuesList } from '#src/routes/public/issues';
import config from '#src/utils/config';

// Create app
const app = new Hono<{ Bindings: { event: LambdaEvent; context: LambdaContext } }>();

// Middleware to set legacy event (for auth utils) and log views
app.use('*', async (c, next) => {
    const rawEvent = c.env?.event || {} as LambdaEvent;
    setEvent(rawEvent); // Still needed for getCurrentUser/getGitHubToken which read cookies from event
    logView(rawEvent.headers || {}, c.req.path);
    await next();
});

// ============ THEME TOGGLE ============
app.post('/theme', async (c) => {
    const body = await c.req.parseBody();
    const theme = body.theme as string;
    if (theme === 'light' || theme === 'dark' || theme === 'system') {
        setCookie(c, 'theme', theme, {
            path: '/',
            maxAge: 60 * 60 * 24 * 365,
            sameSite: 'Lax',
        });
    }
    const referer = c.req.header('referer') || '/';
    return c.redirect(referer, 303);
});

// ============ STATIC FILES ============
app.get('/robots.txt', robots);
app.get('/sitemap.xml', sitemap);
app.get('/humans.txt', humans);
app.get('/.well-known/security.txt', security);

// ============ AUTH ROUTES ============
app.get('/github', github);
app.get('/github-pro', githubPro);
app.get('/callback', callback);
app.get('/auth/github/callback', callback);
app.get('/logout', logout);

// ============ MIGRATED ROUTES (Hono native JSX) ============
app.get('/', homeHandler);
app.get('/about', (c) => c.html(<AboutPage />));
app.get('/updates', updatesHandler);
app.get('/updates/:slug', updatesDocHandler);
app.get('/reports', reportsHandler);
app.get('/reports/:slug', reportsDocHandler);
app.get('/user-guide', userGuideHandler);
app.get('/user-guide/:slug', userGuideDocHandler);
app.get('/technical-docs', technicalDocsHandler);
app.get('/technical-docs/:slug', technicalDocsDocHandler);
app.get('/roadmap', (c) => c.html(<RoadmapPage />));
app.get('/signup', signupHandler);
app.post('/signup/submit', signupSubmitHandler);
app.get('/feedback', feedbackHandler);
app.post('/feedback/submit', submitFeatureHandler);
app.post('/feedback/vote', voteHandler);
app.post('/feedback/delete', deleteFeatureHandler);
app.get('/feature-request', feedbackHandler);
app.post('/feature-request/submit', submitFeatureHandler);
app.post('/feature-request/vote', voteHandler);
app.post('/feature-request/delete', deleteFeatureHandler);

// ============ DYNAMIC ROUTES ============
// Only allow repos/issues/commits for our own org
const ALLOWED_OWNER = config.githubOrg.toLowerCase();

app.use('/:owner{[^/]+}/*', async (c, next) => {
    const owner = c.req.param('owner')?.toLowerCase();
    if (owner && owner !== ALLOWED_OWNER) {
        return c.text('Not Found', 404);
    }
    await next();
});
app.use('/:owner', async (c, next) => {
    const owner = c.req.param('owner')?.toLowerCase();
    if (owner && owner !== ALLOWED_OWNER) {
        return c.text('Not Found', 404);
    }
    await next();
});

// Repo routes: /:owner, /:owner/:repo, /:owner/:repo/tree/:branch/...
app.get('/:owner', repo);
app.get('/:owner/:repo', repo);
app.get('/:owner/:repo/tree/:branch/*', repo);
app.get('/:owner/:repo/blob/:branch/*', repo);

// Issues routes
app.get('/:owner/:repo/issues', issuesList);
app.get('/:owner/:repo/issues/:number', issues);

// Commits routes: /:owner/:repo/commits, /:owner/:repo/commit/:sha
app.get('/:owner/:repo/commits', commits);
app.get('/:owner/:repo/commit/:sha', commits);

// Export handler for Lambda
export const handler = handle(app);