mirror your GitHub repos to tangled.org automatically
1export default defineEventHandler(async event => {
2 const query = getQuery(event)
3 const handleRaw = query.handle
4 const installationIdRaw = query.installationId
5
6 if (typeof handleRaw !== 'string' || !handleRaw.trim()) {
7 throw createError({ statusCode: 400, statusMessage: 'handle is required' })
8 }
9
10 // `installationId` is *optional*:
11 // - First-time install → connect flow passes it (from the GitHub App
12 // install settings) so we can bind the resulting `user_identity` row.
13 // - Returning user sign-in (e.g. on a new device) omits it; the callback
14 // looks up the existing `user_identity` row by DID.
15 let installationId: string | undefined
16 if (typeof installationIdRaw === 'string' && installationIdRaw !== '') {
17 if (!/^\d+$/.test(installationIdRaw)) {
18 throw createError({ statusCode: 400, statusMessage: 'installationId must be numeric' })
19 }
20 installationId = installationIdRaw
21 }
22
23 const handle = handleRaw.trim()
24 const client = await useOAuthClient()
25
26 // Round-trip the installation id via OAuth `state` when we have one. The
27 // library wraps and signs `state` itself (PKCE + state CSRF protection are
28 // handled internally), so this is safe to use as an opaque link key. When
29 // absent, the callback resolves the installation via the returned DID.
30 const url = await client.authorize(handle, {
31 ...(installationId ? { state: installationId } : {}),
32 scope: SYNCHUB_OAUTH_SCOPE,
33 })
34
35 await sendRedirect(event, url.toString(), 302)
36})