@rsweeten/dropbox-sync
Version:
Reusable Dropbox synchronization module with framework adapters
191 lines (190 loc) • 7.38 kB
JavaScript
import { createDropboxSyncClient } from '../core/client';
import { useCookie, useRuntimeConfig } from 'nuxt/app';
/**
* Helper to safely access runtime config properties
*/
function getConfigValue(obj, path, defaultValue) {
const parts = path.split('.');
let current = obj;
for (const part of parts) {
if (current === undefined || current === null) {
return defaultValue;
}
current = current[part];
}
return current || defaultValue;
}
/**
* Nuxt-specific helper for creating a Dropbox sync client
* Can be used in both client and server components
*/
export function useNuxtDropboxSync(credentials) {
// Get Nuxt runtime config (for client ID and secret)
const config = useRuntimeConfig();
// Create base credentials with defaults from runtime config
const baseCredentials = {
clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
clientSecret: getConfigValue(config, 'dropboxAppSecret', ''),
...credentials,
};
// On client-side, attempt to get tokens from cookies
if (process.client) {
const accessToken = useCookie('dropbox_access_token');
const refreshToken = useCookie('dropbox_refresh_token');
if (accessToken.value && !baseCredentials.accessToken) {
baseCredentials.accessToken = accessToken.value;
}
if (refreshToken.value && !baseCredentials.refreshToken) {
baseCredentials.refreshToken = refreshToken.value;
}
}
return createDropboxSyncClient(baseCredentials);
}
/**
* Server-side helper to get credentials from Nuxt server event
*/
export function getCredentialsFromCookies(event) {
const config = useRuntimeConfig();
// Get cookies from Nuxt server event
const accessToken = getCookie(event, 'dropbox_access_token');
const refreshToken = getCookie(event, 'dropbox_refresh_token');
return {
clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
clientSecret: getConfigValue(config, 'dropboxAppSecret', ''),
accessToken,
refreshToken,
};
}
/**
* Create API event handlers for a Nuxt app
*/
export function createNuxtApiHandlers() {
return {
/**
* Handler for status check endpoint
*/
async status(event) {
const accessToken = getCookie(event, 'dropbox_access_token');
const isConnected = !!accessToken;
return { connected: isConnected };
},
/**
* Handler for OAuth start endpoint
*/
async oauthStart(event) {
const config = useRuntimeConfig();
const dropboxSync = createDropboxSyncClient({
clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
});
const redirectUri = getConfigValue(config, 'dropboxRedirectUri', '') ||
`${getConfigValue(config, 'public.appUrl', 'http://localhost:3000')}/api/dropbox/auth/callback`;
const authUrl = await dropboxSync.auth.getAuthUrl(redirectUri);
return sendRedirect(event, authUrl);
},
/**
* Handler for OAuth callback endpoint
*/
async oauthCallback(event) {
const config = useRuntimeConfig();
// Get the authorization code from query parameters
const query = getQuery(event);
const code = query.code;
if (!code) {
return sendRedirect(event, '/auth/error');
}
const redirectUri = getConfigValue(config, 'dropboxRedirectUri', '') ||
`${getConfigValue(config, 'public.appUrl', 'http://localhost:3000')}/api/dropbox/auth/callback`;
const dropboxSync = createDropboxSyncClient({
clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
clientSecret: getConfigValue(config, 'dropboxAppSecret', ''),
});
try {
const tokens = await dropboxSync.auth.exchangeCodeForToken(code, redirectUri);
// Set cookies with the tokens
setCookie(event, 'dropbox_access_token', tokens.accessToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: tokens.expiresAt
? Math.floor((tokens.expiresAt - Date.now()) / 1000)
: 14 * 24 * 60 * 60, // 14 days default
sameSite: 'lax',
path: '/',
});
if (tokens.refreshToken) {
setCookie(event, 'dropbox_refresh_token', 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
setCookie(event, 'dropbox_connected', 'true', {
secure: process.env.NODE_ENV === 'production',
maxAge: tokens.expiresAt
? Math.floor((tokens.expiresAt - Date.now()) / 1000)
: 14 * 24 * 60 * 60,
sameSite: 'lax',
path: '/',
});
return sendRedirect(event, '/');
}
catch (error) {
console.error('Error completing Dropbox OAuth flow:', error);
return sendRedirect(event, '/auth/error');
}
},
/**
* Handler for logout endpoint
*/
async logout(event) {
// Clear all Dropbox-related cookies
deleteCookie(event, 'dropbox_access_token');
deleteCookie(event, 'dropbox_refresh_token');
deleteCookie(event, 'dropbox_connected');
return { success: true };
},
};
}
/**
* Helper functions to work with Nuxt's H3Event
* These import statements need to be added to avoid reference errors
*/
const { getCookie, setCookie, deleteCookie } = useNuxtCookies();
const { getQuery, sendRedirect } = useNuxtServer();
/**
* Helper to access h3 cookie methods
*/
function useNuxtCookies() {
return {
getCookie: (event, name) => {
// Import inside function to avoid module loading issues
const { getCookie } = require('h3');
return getCookie(event, name);
},
setCookie: (event, name, value, options) => {
const { setCookie } = require('h3');
return setCookie(event, name, value, options);
},
deleteCookie: (event, name, options) => {
const { deleteCookie } = require('h3');
return deleteCookie(event, name, { ...options, path: '/' });
},
};
}
/**
* Helper to access h3 server methods
*/
function useNuxtServer() {
return {
getQuery: (event) => {
const { getQuery } = require('h3');
return getQuery(event);
},
sendRedirect: (event, location) => {
const { sendRedirect } = require('h3');
return sendRedirect(event, location);
},
};
}