import type { APIRoute } from 'astro' import { getOAuthClient } from '../../../lib/context' import { getSession } from '../../../lib/session' import { Agent, BlobRef } from '@atproto/api' import type { Main as ProfileRecord } from '../../../lexicon/types/org/atmosphereconf/profile' async function fileToBlob(agent: Agent, file: File): Promise { const arrayBuffer = await file.arrayBuffer() const uint8Array = new Uint8Array(arrayBuffer) const response = await agent.com.atproto.repo.uploadBlob(uint8Array, { encoding: file.type, }) return response.data.blob } export const POST: APIRoute = async ({ request, cookies, redirect }) => { try { const session = getSession(cookies) const oauthClient = getOAuthClient(cookies) if (!session.did) { return new Response('Unauthorized', { status: 401 }) } const oauthSession = await oauthClient.restore(session.did) if (!oauthSession) { return new Response('Session expired', { status: 401 }) } const agent = new Agent(oauthSession) const formData = await request.formData() // Extract form data const displayName = formData.get('displayName') const description = formData.get('description') const avatarFile = formData.get('avatar') const bannerFile = formData.get('banner') if (!displayName || typeof displayName !== 'string') { return new Response('Display name is required', { status: 400 }) } // Validate file sizes if (avatarFile instanceof File && avatarFile.size > 0 && avatarFile.size > 1000000) { return new Response('Avatar file size must be less than 1MB', { status: 400 }) } if (bannerFile instanceof File && bannerFile.size > 0 && bannerFile.size > 1000000) { return new Response('Banner file size must be less than 1MB', { status: 400 }) } // Build the profile record const record: Omit = { displayName: displayName.slice(0, 64), description: typeof description === 'string' ? description.slice(0, 256) : undefined, createdAt: new Date().toISOString(), } // Upload avatar if provided if (avatarFile instanceof File && avatarFile.size > 0) { try { record.avatar = await fileToBlob(agent, avatarFile) } catch (err) { console.error('Failed to upload avatar:', err) return new Response('Failed to upload avatar', { status: 500 }) } } // Upload banner if provided if (bannerFile instanceof File && bannerFile.size > 0) { try { record.banner = await fileToBlob(agent, bannerFile) } catch (err) { console.error('Failed to upload banner:', err) return new Response('Failed to upload banner', { status: 500 }) } } // Create or update the profile record try { await agent.com.atproto.repo.putRecord({ repo: agent.assertDid, collection: 'org.atmosphereconf.profile', rkey: 'self', record: { $type: 'org.atmosphereconf.profile', ...record, }, }) return redirect('/') } catch (err) { console.error('Failed to create profile:', err) const error = err instanceof Error ? err.message : 'unexpected error' return new Response(`Failed to create profile: ${error}`, { status: 500 }) } } catch (err) { console.error('Profile creation failed:', err) const error = err instanceof Error ? err.message : 'unexpected error' return new Response(`Profile creation failed: ${error}`, { status: 500 }) } }