mirror your GitHub repos to tangled.org automatically
1import { userIdentity } from '~~/server/db/schema'
2import { enqueue } from '~~/server/utils/queue'
3import { generateAndPublishKey } from '~~/server/utils/tangled-pubkey'
4
5export default defineEventHandler(async event => {
6 const url = getRequestURL(event)
7 const params = url.searchParams
8
9 const client = await useOAuthClient()
10 const { session, state } = await client.callback(params)
11
12 const installationId = state ? Number(state) : NaN
13 if (!Number.isFinite(installationId)) {
14 throw createError({ statusCode: 400, statusMessage: 'invalid state (missing installation id)' })
15 }
16
17 const db = useDb()
18 await db.insert(userIdentity).values({
19 did: session.did,
20 handle: null, // resolved separately; we don't have it from the session blob
21 installationId,
22 updatedAt: new Date(),
23 }).onConflictDoUpdate({
24 target: userIdentity.did,
25 set: { installationId, updatedAt: new Date() },
26 })
27
28 // Generate and publish the SSH key inline: it's one ed25519 keygen + one
29 // PDS write, well under the function timeout, and lets us land users on the
30 // dashboard already enrolled. Rotation is a separate dashboard action that
31 // goes via the queue.
32 await generateAndPublishKey({
33 oauthSession: session,
34 installationId,
35 })
36
37 // Backfill: enqueue a single job that walks the installation's repo list
38 // and fans out per-repo enrolment. Doing this in the worker (rather than
39 // inline here) keeps the OAuth callback fast regardless of repo count, and
40 // gives us proper retry semantics if pagination doesn't finish in one
41 // worker tick.
42 await enqueue('tangled.backfill-installation', { installationId, page: 1 })
43
44 await sendRedirect(event, '/dashboard', 302)
45})