UNPKG

@rsweeten/dropbox-sync

Version:

Reusable Dropbox synchronization module with framework adapters

156 lines (133 loc) 4.96 kB
import { createDropboxSyncClient } from '../core/client' import type { DropboxCredentials, DropboxSyncClient } from '../core/types' import { cookies } from 'next/headers' import { NextRequest, NextResponse } from 'next/server' /** * Next.js-specific helper to create a Dropbox sync client * Can be used in both client and server components */ export function useNextDropboxSync( credentials: DropboxCredentials ): DropboxSyncClient { return createDropboxSyncClient(credentials) } /** * Server-side helper to get credentials from Next.js cookies */ export async function getCredentialsFromCookies(): Promise<DropboxCredentials> { const cookieStore = await cookies() return { clientId: process.env.DROPBOX_APP_KEY || '', clientSecret: process.env.DROPBOX_APP_SECRET, accessToken: cookieStore.get('dropbox_access_token')?.value, refreshToken: cookieStore.get('dropbox_refresh_token')?.value, } } /** * Server action to handle Dropbox OAuth callback */ export async function handleOAuthCallback( request: NextRequest ): Promise<NextResponse> { const url = new URL(request.url) const code = url.searchParams.get('code') if (!code) { return NextResponse.redirect(new URL('/auth/error', request.url)) } const redirectUri = process.env.DROPBOX_REDIRECT_URI || `${ process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' }/api/dropbox/auth/callback` const dropboxSync = createDropboxSyncClient({ clientId: process.env.DROPBOX_APP_KEY || '', clientSecret: process.env.DROPBOX_APP_SECRET, }) try { const tokens = await dropboxSync.auth.exchangeCodeForToken( code, redirectUri ) // Create response with redirect const response = NextResponse.redirect(new URL('/', request.url)) // Set cookies with the tokens response.cookies.set({ name: 'dropbox_access_token', value: tokens.accessToken, httpOnly: true, secure: process.env.NODE_ENV === 'production', maxAge: tokens.expiresAt ? (tokens.expiresAt - Date.now()) / 1000 : 14 * 24 * 60 * 60, // 14 days default sameSite: 'lax', path: '/', }) if (tokens.refreshToken) { response.cookies.set({ name: 'dropbox_refresh_token', value: tokens.refreshToken, httpOnly: true, secure: process.env.NODE_ENV === 'production', maxAge: 365 * 24 * 60 * 60, // 1 year sameSite: 'lax', path: '/', }) } // Set a non-httpOnly cookie to indicate connection status to the client response.cookies.set({ name: 'dropbox_connected', value: 'true', secure: process.env.NODE_ENV === 'production', maxAge: tokens.expiresAt ? (tokens.expiresAt - Date.now()) / 1000 : 14 * 24 * 60 * 60, sameSite: 'lax', path: '/', }) return response } catch (error) { console.error('Error completing Dropbox OAuth flow:', error) return NextResponse.redirect(new URL('/auth/error', request.url)) } } /** * Create API route handlers for a Next.js app */ export function createNextDropboxApiHandlers() { return { /** * Handler for status check route */ async status() { const cookieStore = await cookies() const isConnected = !!cookieStore.get('dropbox_access_token')?.value return NextResponse.json({ connected: isConnected }) }, /** * Handler for OAuth start route */ async oauthStart() { const dropboxSync = createDropboxSyncClient({ clientId: process.env.DROPBOX_APP_KEY || '', }) const redirectUri = process.env.DROPBOX_REDIRECT_URI || `${ process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' }/api/dropbox/auth/callback` const authUrl = await dropboxSync.auth.getAuthUrl(redirectUri) return NextResponse.redirect(authUrl) }, /** * Handler for logout route */ async logout() { const response = NextResponse.json({ success: true }) // Clear all Dropbox-related cookies response.cookies.delete('dropbox_access_token') response.cookies.delete('dropbox_refresh_token') response.cookies.delete('dropbox_connected') return response }, } }