@rsweeten/dropbox-sync
Version:
Reusable Dropbox synchronization module with framework adapters
169 lines (148 loc) • 5.67 kB
text/typescript
import { createDropboxSyncClient } from '../core/client'
import type { DropboxCredentials, DropboxSyncClient } from '../core/types'
import type { Cookies } from '@sveltejs/kit'
/**
* SvelteKit-specific helper for creating a Dropbox sync client
* Can be used in both client and server contexts
*/
export function useSvelteDropboxSync(
credentials: DropboxCredentials
): DropboxSyncClient {
return createDropboxSyncClient(credentials)
}
/**
* Helper to get credentials from SvelteKit cookies
*/
export function getCredentialsFromCookies(
cookies: Cookies
): DropboxCredentials {
return {
clientId: process.env.DROPBOX_APP_KEY || '',
clientSecret: process.env.DROPBOX_APP_SECRET,
accessToken: cookies.get('dropbox_access_token'),
refreshToken: cookies.get('dropbox_refresh_token'),
}
}
/**
* Create server-side handlers for SvelteKit
*/
export function createSvelteKitHandlers() {
return {
/**
* Handler for status check endpoint
*/
async status({ cookies }: { cookies: Cookies }) {
const isConnected = !!cookies.get('dropbox_access_token')
return new Response(JSON.stringify({ connected: isConnected }), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
})
},
/**
* Handler for OAuth start endpoint
*/
async oauthStart() {
const dropboxSync = createDropboxSyncClient({
clientId: process.env.DROPBOX_APP_KEY || '',
})
const redirectUri =
process.env.DROPBOX_REDIRECT_URI ||
`${
process.env.PUBLIC_APP_URL || 'http://localhost:5173'
}/api/dropbox/auth/callback`
const authUrl = await dropboxSync.auth.getAuthUrl(redirectUri)
return new Response(null, {
status: 302,
headers: {
Location: authUrl,
},
})
},
/**
* Handler for OAuth callback endpoint
*/
async oauthCallback({ url, cookies }: { url: URL; cookies: Cookies }) {
const code = url.searchParams.get('code')
if (!code) {
return new Response(null, {
status: 302,
headers: {
Location: '/auth/error',
},
})
}
const redirectUri =
process.env.DROPBOX_REDIRECT_URI ||
`${
process.env.PUBLIC_APP_URL || 'http://localhost:5173'
}/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
)
// Set cookies with the tokens
cookies.set('dropbox_access_token', tokens.accessToken, {
path: '/',
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',
})
if (tokens.refreshToken) {
cookies.set('dropbox_refresh_token', tokens.refreshToken, {
path: '/',
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 365 * 24 * 60 * 60, // 1 year
sameSite: 'lax',
})
}
cookies.set('dropbox_connected', 'true', {
path: '/',
secure: process.env.NODE_ENV === 'production',
maxAge: tokens.expiresAt
? Math.floor((tokens.expiresAt - Date.now()) / 1000)
: 14 * 24 * 60 * 60,
sameSite: 'lax',
})
return new Response(null, {
status: 302,
headers: {
Location: '/',
},
})
} catch (error) {
console.error('Error completing Dropbox OAuth flow:', error)
return new Response(null, {
status: 302,
headers: {
Location: '/auth/error',
},
})
}
},
/**
* Handler for logout endpoint
*/
async logout({ cookies }: { cookies: Cookies }) {
cookies.delete('dropbox_access_token', { path: '/' })
cookies.delete('dropbox_refresh_token', { path: '/' })
cookies.delete('dropbox_connected', { path: '/' })
return new Response(JSON.stringify({ success: true }), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
})
},
}
}