@rsweeten/dropbox-sync
Version:
Reusable Dropbox synchronization module with framework adapters
121 lines (120 loc) • 4.5 kB
JavaScript
import { createDropboxSyncClient } from '../core/client';
import { cookies } from 'next/headers';
import { 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) {
return createDropboxSyncClient(credentials);
}
/**
* Server-side helper to get credentials from Next.js cookies
*/
export async function getCredentialsFromCookies() {
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) {
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;
},
};
}