import { requireAuth } from "@/lib/jwt"; import { sql } from "@/lib/db"; // Device registration for push notifications. // // POST — claim this device for the signed-in user. Upsert on the token, so // signing in as a different account on the same phone MOVES the // device rather than leaving the previous account subscribed to // notifications that are now someone else's. // DELETE — release the device, called on sign-out. // // Not driver-only: riders need it too (a driver accepting, arriving, or the // search timing out are all things worth waking a phone for), so it lives // under /push rather than /driver. const isExpoToken = (v: unknown): v is string => typeof v === "string" && v.length <= 256 && /^Expo(nent)?PushToken\[[^\]]+\]$/.test(v); export async function POST(req: Request) { const auth = requireAuth(req); if ("error" in auth) return auth.error; try { const body = await req.json(); const { token, platform } = body; if (!isExpoToken(token)) { return Response.json( { error: "A valid Expo push token is required." }, { status: 400 }, ); } const rows = await sql<{ token: string }>` INSERT INTO push_tokens (token, user_id, platform) VALUES (${token}, ${auth.userId}, ${platform ?? null}) ON CONFLICT (token) DO UPDATE SET user_id = EXCLUDED.user_id, platform = EXCLUDED.platform, updated_at = CURRENT_TIMESTAMP RETURNING token `; return Response.json({ data: { registered: Boolean(rows[0]) } }); } catch (error) { console.error("[PUSH_TOKEN_POST]: ", error); return Response.json({ error: "Internal Server Error" }, { status: 500 }); } } export async function DELETE(req: Request) { const auth = requireAuth(req); if ("error" in auth) return auth.error; try { const body = await req.json().catch(() => ({})); const { token } = body as { token?: unknown }; if (!isExpoToken(token)) { return Response.json( { error: "A valid Expo push token is required." }, { status: 400 }, ); } // Scoped to the caller: a token can only be released by the account that // currently holds it. await sql` DELETE FROM push_tokens WHERE token = ${token} AND user_id = ${auth.userId} `; return Response.json({ data: { released: true } }); } catch (error) { console.error("[PUSH_TOKEN_DELETE]: ", error); return Response.json({ error: "Internal Server Error" }, { status: 500 }); } }