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