export default defineEventHandler(async event => { const query = getQuery(event) const handleRaw = query.handle const installationIdRaw = query.installationId if (typeof handleRaw !== 'string' || !handleRaw.trim()) { throw createError({ statusCode: 400, statusMessage: 'handle is required' }) } // `installationId` is *optional*: // - First-time install → connect flow passes it (from the GitHub App // install settings) so we can bind the resulting `user_identity` row. // - Returning user sign-in (e.g. on a new device) omits it; the callback // looks up the existing `user_identity` row by DID. let installationId: string | undefined if (typeof installationIdRaw === 'string' && installationIdRaw !== '') { if (!/^\d+$/.test(installationIdRaw)) { throw createError({ statusCode: 400, statusMessage: 'installationId must be numeric' }) } installationId = installationIdRaw } const handle = handleRaw.trim() const client = await useOAuthClient() // Round-trip the installation id via OAuth `state` when we have one. The // library wraps and signs `state` itself (PKCE + state CSRF protection are // handled internally), so this is safe to use as an opaque link key. When // absent, the callback resolves the installation via the returned DID. const url = await client.authorize(handle, { ...(installationId ? { state: installationId } : {}), scope: SYNCHUB_OAUTH_SCOPE, }) await sendRedirect(event, url.toString(), 302) })