@rsweeten/dropbox-sync 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +315 -0
  2. package/dist/adapters/angular.d.ts +56 -0
  3. package/dist/adapters/angular.js +207 -0
  4. package/dist/adapters/next.d.ts +36 -0
  5. package/dist/adapters/next.js +120 -0
  6. package/dist/adapters/nuxt.d.ts +36 -0
  7. package/dist/adapters/nuxt.js +190 -0
  8. package/dist/adapters/svelte.d.ts +39 -0
  9. package/dist/adapters/svelte.js +134 -0
  10. package/dist/core/auth.d.ts +3 -0
  11. package/dist/core/auth.js +84 -0
  12. package/dist/core/client.d.ts +5 -0
  13. package/dist/core/client.js +37 -0
  14. package/dist/core/socket.d.ts +2 -0
  15. package/dist/core/socket.js +62 -0
  16. package/dist/core/sync.d.ts +3 -0
  17. package/dist/core/sync.js +340 -0
  18. package/dist/core/types.d.ts +73 -0
  19. package/dist/core/types.js +1 -0
  20. package/dist/index.d.ts +11 -0
  21. package/dist/index.js +14 -0
  22. package/examples/angular-app/dropbox-sync.service.ts +244 -0
  23. package/examples/next-app/api-routes.ts +109 -0
  24. package/examples/next-app/dropbox-client.ts +122 -0
  25. package/examples/nuxt-app/api-routes.ts +26 -0
  26. package/examples/nuxt-app/dropbox-plugin.ts +15 -0
  27. package/examples/nuxt-app/nuxt.config.ts +23 -0
  28. package/examples/svelte-app/dropbox-store.ts +174 -0
  29. package/examples/svelte-app/routes.server.ts +120 -0
  30. package/package.json +66 -0
  31. package/src/adapters/angular.ts +217 -0
  32. package/src/adapters/next.ts +155 -0
  33. package/src/adapters/nuxt.ts +270 -0
  34. package/src/adapters/svelte.ts +168 -0
  35. package/src/core/auth.ts +148 -0
  36. package/src/core/client.ts +52 -0
  37. package/src/core/socket.ts +73 -0
  38. package/src/core/sync.ts +476 -0
  39. package/src/core/types.ts +83 -0
  40. package/src/index.ts +32 -0
  41. package/tsconfig.json +16 -0
@@ -0,0 +1,120 @@
1
+ import { createDropboxSyncClient } from '../core/client';
2
+ import { cookies } from 'next/headers';
3
+ import { NextResponse } from 'next/server';
4
+ /**
5
+ * Next.js-specific helper to create a Dropbox sync client
6
+ * Can be used in both client and server components
7
+ */
8
+ export function useNextDropboxSync(credentials) {
9
+ return createDropboxSyncClient(credentials);
10
+ }
11
+ /**
12
+ * Server-side helper to get credentials from Next.js cookies
13
+ */
14
+ export async function getCredentialsFromCookies() {
15
+ const cookieStore = await cookies();
16
+ return {
17
+ clientId: process.env.DROPBOX_APP_KEY || '',
18
+ clientSecret: process.env.DROPBOX_APP_SECRET,
19
+ accessToken: cookieStore.get('dropbox_access_token')?.value,
20
+ refreshToken: cookieStore.get('dropbox_refresh_token')?.value,
21
+ };
22
+ }
23
+ /**
24
+ * Server action to handle Dropbox OAuth callback
25
+ */
26
+ export async function handleOAuthCallback(request) {
27
+ const url = new URL(request.url);
28
+ const code = url.searchParams.get('code');
29
+ if (!code) {
30
+ return NextResponse.redirect(new URL('/auth/error', request.url));
31
+ }
32
+ const redirectUri = process.env.DROPBOX_REDIRECT_URI ||
33
+ `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/api/dropbox/auth/callback`;
34
+ const dropboxSync = createDropboxSyncClient({
35
+ clientId: process.env.DROPBOX_APP_KEY || '',
36
+ clientSecret: process.env.DROPBOX_APP_SECRET,
37
+ });
38
+ try {
39
+ const tokens = await dropboxSync.auth.exchangeCodeForToken(code, redirectUri);
40
+ // Create response with redirect
41
+ const response = NextResponse.redirect(new URL('/', request.url));
42
+ // Set cookies with the tokens
43
+ response.cookies.set({
44
+ name: 'dropbox_access_token',
45
+ value: tokens.accessToken,
46
+ httpOnly: true,
47
+ secure: process.env.NODE_ENV === 'production',
48
+ maxAge: tokens.expiresAt
49
+ ? (tokens.expiresAt - Date.now()) / 1000
50
+ : 14 * 24 * 60 * 60, // 14 days default
51
+ sameSite: 'lax',
52
+ path: '/',
53
+ });
54
+ if (tokens.refreshToken) {
55
+ response.cookies.set({
56
+ name: 'dropbox_refresh_token',
57
+ value: tokens.refreshToken,
58
+ httpOnly: true,
59
+ secure: process.env.NODE_ENV === 'production',
60
+ maxAge: 365 * 24 * 60 * 60, // 1 year
61
+ sameSite: 'lax',
62
+ path: '/',
63
+ });
64
+ }
65
+ // Set a non-httpOnly cookie to indicate connection status to the client
66
+ response.cookies.set({
67
+ name: 'dropbox_connected',
68
+ value: 'true',
69
+ secure: process.env.NODE_ENV === 'production',
70
+ maxAge: tokens.expiresAt
71
+ ? (tokens.expiresAt - Date.now()) / 1000
72
+ : 14 * 24 * 60 * 60,
73
+ sameSite: 'lax',
74
+ path: '/',
75
+ });
76
+ return response;
77
+ }
78
+ catch (error) {
79
+ console.error('Error completing Dropbox OAuth flow:', error);
80
+ return NextResponse.redirect(new URL('/auth/error', request.url));
81
+ }
82
+ }
83
+ /**
84
+ * Create API route handlers for a Next.js app
85
+ */
86
+ export function createNextDropboxApiHandlers() {
87
+ return {
88
+ /**
89
+ * Handler for status check route
90
+ */
91
+ async status() {
92
+ const cookieStore = await cookies();
93
+ const isConnected = !!cookieStore.get('dropbox_access_token')?.value;
94
+ return NextResponse.json({ connected: isConnected });
95
+ },
96
+ /**
97
+ * Handler for OAuth start route
98
+ */
99
+ async oauthStart() {
100
+ const dropboxSync = createDropboxSyncClient({
101
+ clientId: process.env.DROPBOX_APP_KEY || '',
102
+ });
103
+ const redirectUri = process.env.DROPBOX_REDIRECT_URI ||
104
+ `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/api/dropbox/auth/callback`;
105
+ const authUrl = await dropboxSync.auth.getAuthUrl(redirectUri);
106
+ return NextResponse.redirect(authUrl);
107
+ },
108
+ /**
109
+ * Handler for logout route
110
+ */
111
+ async logout() {
112
+ const response = NextResponse.json({ success: true });
113
+ // Clear all Dropbox-related cookies
114
+ response.cookies.delete('dropbox_access_token');
115
+ response.cookies.delete('dropbox_refresh_token');
116
+ response.cookies.delete('dropbox_connected');
117
+ return response;
118
+ },
119
+ };
120
+ }
@@ -0,0 +1,36 @@
1
+ import type { DropboxCredentials, DropboxSyncClient } from '../core/types';
2
+ import type { H3Event } from 'h3';
3
+ /**
4
+ * Nuxt-specific helper for creating a Dropbox sync client
5
+ * Can be used in both client and server components
6
+ */
7
+ export declare function useNuxtDropboxSync(credentials?: Partial<DropboxCredentials>): DropboxSyncClient;
8
+ /**
9
+ * Server-side helper to get credentials from Nuxt server event
10
+ */
11
+ export declare function getCredentialsFromCookies(event: H3Event): DropboxCredentials;
12
+ /**
13
+ * Create API event handlers for a Nuxt app
14
+ */
15
+ export declare function createNuxtApiHandlers(): {
16
+ /**
17
+ * Handler for status check endpoint
18
+ */
19
+ status(event: H3Event): Promise<{
20
+ connected: boolean;
21
+ }>;
22
+ /**
23
+ * Handler for OAuth start endpoint
24
+ */
25
+ oauthStart(event: H3Event): Promise<any>;
26
+ /**
27
+ * Handler for OAuth callback endpoint
28
+ */
29
+ oauthCallback(event: H3Event): Promise<any>;
30
+ /**
31
+ * Handler for logout endpoint
32
+ */
33
+ logout(event: H3Event): Promise<{
34
+ success: boolean;
35
+ }>;
36
+ };
@@ -0,0 +1,190 @@
1
+ import { createDropboxSyncClient } from '../core/client';
2
+ import { useCookie, useRuntimeConfig } from 'nuxt/app';
3
+ /**
4
+ * Helper to safely access runtime config properties
5
+ */
6
+ function getConfigValue(obj, path, defaultValue) {
7
+ const parts = path.split('.');
8
+ let current = obj;
9
+ for (const part of parts) {
10
+ if (current === undefined || current === null) {
11
+ return defaultValue;
12
+ }
13
+ current = current[part];
14
+ }
15
+ return current || defaultValue;
16
+ }
17
+ /**
18
+ * Nuxt-specific helper for creating a Dropbox sync client
19
+ * Can be used in both client and server components
20
+ */
21
+ export function useNuxtDropboxSync(credentials) {
22
+ // Get Nuxt runtime config (for client ID and secret)
23
+ const config = useRuntimeConfig();
24
+ // Create base credentials with defaults from runtime config
25
+ const baseCredentials = {
26
+ clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
27
+ clientSecret: getConfigValue(config, 'dropboxAppSecret', ''),
28
+ ...credentials,
29
+ };
30
+ // On client-side, attempt to get tokens from cookies
31
+ if (process.client) {
32
+ const accessToken = useCookie('dropbox_access_token');
33
+ const refreshToken = useCookie('dropbox_refresh_token');
34
+ if (accessToken.value && !baseCredentials.accessToken) {
35
+ baseCredentials.accessToken = accessToken.value;
36
+ }
37
+ if (refreshToken.value && !baseCredentials.refreshToken) {
38
+ baseCredentials.refreshToken = refreshToken.value;
39
+ }
40
+ }
41
+ return createDropboxSyncClient(baseCredentials);
42
+ }
43
+ /**
44
+ * Server-side helper to get credentials from Nuxt server event
45
+ */
46
+ export function getCredentialsFromCookies(event) {
47
+ const config = useRuntimeConfig();
48
+ // Get cookies from Nuxt server event
49
+ const accessToken = getCookie(event, 'dropbox_access_token');
50
+ const refreshToken = getCookie(event, 'dropbox_refresh_token');
51
+ return {
52
+ clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
53
+ clientSecret: getConfigValue(config, 'dropboxAppSecret', ''),
54
+ accessToken,
55
+ refreshToken,
56
+ };
57
+ }
58
+ /**
59
+ * Create API event handlers for a Nuxt app
60
+ */
61
+ export function createNuxtApiHandlers() {
62
+ return {
63
+ /**
64
+ * Handler for status check endpoint
65
+ */
66
+ async status(event) {
67
+ const accessToken = getCookie(event, 'dropbox_access_token');
68
+ const isConnected = !!accessToken;
69
+ return { connected: isConnected };
70
+ },
71
+ /**
72
+ * Handler for OAuth start endpoint
73
+ */
74
+ async oauthStart(event) {
75
+ const config = useRuntimeConfig();
76
+ const dropboxSync = createDropboxSyncClient({
77
+ clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
78
+ });
79
+ const redirectUri = getConfigValue(config, 'dropboxRedirectUri', '') ||
80
+ `${getConfigValue(config, 'public.appUrl', 'http://localhost:3000')}/api/dropbox/auth/callback`;
81
+ const authUrl = await dropboxSync.auth.getAuthUrl(redirectUri);
82
+ return sendRedirect(event, authUrl);
83
+ },
84
+ /**
85
+ * Handler for OAuth callback endpoint
86
+ */
87
+ async oauthCallback(event) {
88
+ const config = useRuntimeConfig();
89
+ // Get the authorization code from query parameters
90
+ const query = getQuery(event);
91
+ const code = query.code;
92
+ if (!code) {
93
+ return sendRedirect(event, '/auth/error');
94
+ }
95
+ const redirectUri = getConfigValue(config, 'dropboxRedirectUri', '') ||
96
+ `${getConfigValue(config, 'public.appUrl', 'http://localhost:3000')}/api/dropbox/auth/callback`;
97
+ const dropboxSync = createDropboxSyncClient({
98
+ clientId: getConfigValue(config, 'public.dropboxAppKey', ''),
99
+ clientSecret: getConfigValue(config, 'dropboxAppSecret', ''),
100
+ });
101
+ try {
102
+ const tokens = await dropboxSync.auth.exchangeCodeForToken(code, redirectUri);
103
+ // Set cookies with the tokens
104
+ setCookie(event, 'dropbox_access_token', tokens.accessToken, {
105
+ httpOnly: true,
106
+ secure: process.env.NODE_ENV === 'production',
107
+ maxAge: tokens.expiresAt
108
+ ? Math.floor((tokens.expiresAt - Date.now()) / 1000)
109
+ : 14 * 24 * 60 * 60, // 14 days default
110
+ sameSite: 'lax',
111
+ path: '/',
112
+ });
113
+ if (tokens.refreshToken) {
114
+ setCookie(event, 'dropbox_refresh_token', tokens.refreshToken, {
115
+ httpOnly: true,
116
+ secure: process.env.NODE_ENV === 'production',
117
+ maxAge: 365 * 24 * 60 * 60, // 1 year
118
+ sameSite: 'lax',
119
+ path: '/',
120
+ });
121
+ }
122
+ // Set a non-httpOnly cookie to indicate connection status to the client
123
+ setCookie(event, 'dropbox_connected', 'true', {
124
+ secure: process.env.NODE_ENV === 'production',
125
+ maxAge: tokens.expiresAt
126
+ ? Math.floor((tokens.expiresAt - Date.now()) / 1000)
127
+ : 14 * 24 * 60 * 60,
128
+ sameSite: 'lax',
129
+ path: '/',
130
+ });
131
+ return sendRedirect(event, '/');
132
+ }
133
+ catch (error) {
134
+ console.error('Error completing Dropbox OAuth flow:', error);
135
+ return sendRedirect(event, '/auth/error');
136
+ }
137
+ },
138
+ /**
139
+ * Handler for logout endpoint
140
+ */
141
+ async logout(event) {
142
+ // Clear all Dropbox-related cookies
143
+ deleteCookie(event, 'dropbox_access_token');
144
+ deleteCookie(event, 'dropbox_refresh_token');
145
+ deleteCookie(event, 'dropbox_connected');
146
+ return { success: true };
147
+ },
148
+ };
149
+ }
150
+ /**
151
+ * Helper functions to work with Nuxt's H3Event
152
+ * These import statements need to be added to avoid reference errors
153
+ */
154
+ const { getCookie, setCookie, deleteCookie } = useNuxtCookies();
155
+ const { getQuery, sendRedirect } = useNuxtServer();
156
+ /**
157
+ * Helper to access h3 cookie methods
158
+ */
159
+ function useNuxtCookies() {
160
+ return {
161
+ getCookie: (event, name) => {
162
+ // Import inside function to avoid module loading issues
163
+ const { getCookie } = require('h3');
164
+ return getCookie(event, name);
165
+ },
166
+ setCookie: (event, name, value, options) => {
167
+ const { setCookie } = require('h3');
168
+ return setCookie(event, name, value, options);
169
+ },
170
+ deleteCookie: (event, name, options) => {
171
+ const { deleteCookie } = require('h3');
172
+ return deleteCookie(event, name, { ...options, path: '/' });
173
+ },
174
+ };
175
+ }
176
+ /**
177
+ * Helper to access h3 server methods
178
+ */
179
+ function useNuxtServer() {
180
+ return {
181
+ getQuery: (event) => {
182
+ const { getQuery } = require('h3');
183
+ return getQuery(event);
184
+ },
185
+ sendRedirect: (event, location) => {
186
+ const { sendRedirect } = require('h3');
187
+ return sendRedirect(event, location);
188
+ },
189
+ };
190
+ }
@@ -0,0 +1,39 @@
1
+ import type { DropboxCredentials, DropboxSyncClient } from '../core/types';
2
+ import type { Cookies } from '@sveltejs/kit';
3
+ /**
4
+ * SvelteKit-specific helper for creating a Dropbox sync client
5
+ * Can be used in both client and server contexts
6
+ */
7
+ export declare function useSvelteDropboxSync(credentials: DropboxCredentials): DropboxSyncClient;
8
+ /**
9
+ * Helper to get credentials from SvelteKit cookies
10
+ */
11
+ export declare function getCredentialsFromCookies(cookies: Cookies): DropboxCredentials;
12
+ /**
13
+ * Create server-side handlers for SvelteKit
14
+ */
15
+ export declare function createSvelteKitHandlers(): {
16
+ /**
17
+ * Handler for status check endpoint
18
+ */
19
+ status({ cookies }: {
20
+ cookies: Cookies;
21
+ }): Promise<Response>;
22
+ /**
23
+ * Handler for OAuth start endpoint
24
+ */
25
+ oauthStart(): Promise<Response>;
26
+ /**
27
+ * Handler for OAuth callback endpoint
28
+ */
29
+ oauthCallback({ url, cookies }: {
30
+ url: URL;
31
+ cookies: Cookies;
32
+ }): Promise<Response>;
33
+ /**
34
+ * Handler for logout endpoint
35
+ */
36
+ logout({ cookies }: {
37
+ cookies: Cookies;
38
+ }): Promise<Response>;
39
+ };
@@ -0,0 +1,134 @@
1
+ import { createDropboxSyncClient } from '../core/client';
2
+ /**
3
+ * SvelteKit-specific helper for creating a Dropbox sync client
4
+ * Can be used in both client and server contexts
5
+ */
6
+ export function useSvelteDropboxSync(credentials) {
7
+ return createDropboxSyncClient(credentials);
8
+ }
9
+ /**
10
+ * Helper to get credentials from SvelteKit cookies
11
+ */
12
+ export function getCredentialsFromCookies(cookies) {
13
+ return {
14
+ clientId: process.env.DROPBOX_APP_KEY || '',
15
+ clientSecret: process.env.DROPBOX_APP_SECRET,
16
+ accessToken: cookies.get('dropbox_access_token'),
17
+ refreshToken: cookies.get('dropbox_refresh_token'),
18
+ };
19
+ }
20
+ /**
21
+ * Create server-side handlers for SvelteKit
22
+ */
23
+ export function createSvelteKitHandlers() {
24
+ return {
25
+ /**
26
+ * Handler for status check endpoint
27
+ */
28
+ async status({ cookies }) {
29
+ const isConnected = !!cookies.get('dropbox_access_token');
30
+ return new Response(JSON.stringify({ connected: isConnected }), {
31
+ status: 200,
32
+ headers: {
33
+ 'Content-Type': 'application/json',
34
+ },
35
+ });
36
+ },
37
+ /**
38
+ * Handler for OAuth start endpoint
39
+ */
40
+ async oauthStart() {
41
+ const dropboxSync = createDropboxSyncClient({
42
+ clientId: process.env.DROPBOX_APP_KEY || '',
43
+ });
44
+ const redirectUri = process.env.DROPBOX_REDIRECT_URI ||
45
+ `${process.env.PUBLIC_APP_URL || 'http://localhost:5173'}/api/dropbox/auth/callback`;
46
+ const authUrl = await dropboxSync.auth.getAuthUrl(redirectUri);
47
+ return new Response(null, {
48
+ status: 302,
49
+ headers: {
50
+ Location: authUrl,
51
+ },
52
+ });
53
+ },
54
+ /**
55
+ * Handler for OAuth callback endpoint
56
+ */
57
+ async oauthCallback({ url, cookies }) {
58
+ const code = url.searchParams.get('code');
59
+ if (!code) {
60
+ return new Response(null, {
61
+ status: 302,
62
+ headers: {
63
+ Location: '/auth/error',
64
+ },
65
+ });
66
+ }
67
+ const redirectUri = process.env.DROPBOX_REDIRECT_URI ||
68
+ `${process.env.PUBLIC_APP_URL || 'http://localhost:5173'}/api/dropbox/auth/callback`;
69
+ const dropboxSync = createDropboxSyncClient({
70
+ clientId: process.env.DROPBOX_APP_KEY || '',
71
+ clientSecret: process.env.DROPBOX_APP_SECRET,
72
+ });
73
+ try {
74
+ const tokens = await dropboxSync.auth.exchangeCodeForToken(code, redirectUri);
75
+ // Set cookies with the tokens
76
+ cookies.set('dropbox_access_token', tokens.accessToken, {
77
+ path: '/',
78
+ httpOnly: true,
79
+ secure: process.env.NODE_ENV === 'production',
80
+ maxAge: tokens.expiresAt
81
+ ? Math.floor((tokens.expiresAt - Date.now()) / 1000)
82
+ : 14 * 24 * 60 * 60, // 14 days default
83
+ sameSite: 'lax',
84
+ });
85
+ if (tokens.refreshToken) {
86
+ cookies.set('dropbox_refresh_token', tokens.refreshToken, {
87
+ path: '/',
88
+ httpOnly: true,
89
+ secure: process.env.NODE_ENV === 'production',
90
+ maxAge: 365 * 24 * 60 * 60, // 1 year
91
+ sameSite: 'lax',
92
+ });
93
+ }
94
+ cookies.set('dropbox_connected', 'true', {
95
+ path: '/',
96
+ secure: process.env.NODE_ENV === 'production',
97
+ maxAge: tokens.expiresAt
98
+ ? Math.floor((tokens.expiresAt - Date.now()) / 1000)
99
+ : 14 * 24 * 60 * 60,
100
+ sameSite: 'lax',
101
+ });
102
+ return new Response(null, {
103
+ status: 302,
104
+ headers: {
105
+ Location: '/',
106
+ },
107
+ });
108
+ }
109
+ catch (error) {
110
+ console.error('Error completing Dropbox OAuth flow:', error);
111
+ return new Response(null, {
112
+ status: 302,
113
+ headers: {
114
+ Location: '/auth/error',
115
+ },
116
+ });
117
+ }
118
+ },
119
+ /**
120
+ * Handler for logout endpoint
121
+ */
122
+ async logout({ cookies }) {
123
+ cookies.delete('dropbox_access_token', { path: '/' });
124
+ cookies.delete('dropbox_refresh_token', { path: '/' });
125
+ cookies.delete('dropbox_connected', { path: '/' });
126
+ return new Response(JSON.stringify({ success: true }), {
127
+ status: 200,
128
+ headers: {
129
+ 'Content-Type': 'application/json',
130
+ },
131
+ });
132
+ },
133
+ };
134
+ }
@@ -0,0 +1,3 @@
1
+ import { Dropbox } from 'dropbox';
2
+ import type { AuthMethods, DropboxCredentials } from './types';
3
+ export declare function createAuthMethods(getClient: () => Dropbox, credentials: DropboxCredentials, setAccessToken: (token: string) => void): AuthMethods;
@@ -0,0 +1,84 @@
1
+ export function createAuthMethods(getClient, credentials, setAccessToken) {
2
+ return {
3
+ /**
4
+ * Generate an authentication URL for Dropbox OAuth flow
5
+ */
6
+ async getAuthUrl(redirectUri, state) {
7
+ const dropbox = getClient();
8
+ const randomState = state || Math.random().toString(36).substring(2, 15);
9
+ // Cast to extended auth type to access missing methods
10
+ const auth = dropbox.auth;
11
+ // Generate the authentication URL
12
+ const authUrl = auth.getAuthenticationUrl(redirectUri, randomState, 'code', // Use authorization code flow
13
+ 'offline', // Request a refresh token for long-lived access
14
+ undefined, // No scope specified, request full access
15
+ undefined, // No include_granted_scopes
16
+ true // Force reapproval to ensure we get fresh tokens
17
+ );
18
+ return authUrl;
19
+ },
20
+ /**
21
+ * Exchange authorization code for access token
22
+ */
23
+ async exchangeCodeForToken(code, redirectUri) {
24
+ const dropbox = getClient();
25
+ // Cast to extended auth type to access missing methods
26
+ const auth = dropbox.auth;
27
+ // Exchange the code for an access token
28
+ const response = await auth.getAccessTokenFromCode(redirectUri, code);
29
+ const tokenResponse = {
30
+ accessToken: response.result.access_token,
31
+ refreshToken: response.result.refresh_token,
32
+ expiresAt: response.result.expires_in
33
+ ? Date.now() + response.result.expires_in * 1000
34
+ : undefined,
35
+ };
36
+ // Update the client with the new token
37
+ setAccessToken(tokenResponse.accessToken);
38
+ return tokenResponse;
39
+ },
40
+ /**
41
+ * Refresh an expired access token using the refresh token
42
+ */
43
+ async refreshAccessToken() {
44
+ if (!credentials.refreshToken ||
45
+ !credentials.clientId ||
46
+ !credentials.clientSecret) {
47
+ throw new Error('Refresh token, client ID, and client secret are required to refresh access token');
48
+ }
49
+ // Dropbox API endpoint for token refresh
50
+ const tokenUrl = 'https://api.dropboxapi.com/oauth2/token';
51
+ // Prepare the form data for the token request
52
+ const formData = new URLSearchParams({
53
+ grant_type: 'refresh_token',
54
+ refresh_token: credentials.refreshToken,
55
+ client_id: credentials.clientId,
56
+ client_secret: credentials.clientSecret,
57
+ });
58
+ // Make the request to refresh the token
59
+ const response = await fetch(tokenUrl, {
60
+ method: 'POST',
61
+ headers: {
62
+ 'Content-Type': 'application/x-www-form-urlencoded',
63
+ },
64
+ body: formData.toString(),
65
+ });
66
+ if (!response.ok) {
67
+ await response.text(); // Consume the response body
68
+ throw new Error(`Failed to refresh token: ${response.status} ${response.statusText}`);
69
+ }
70
+ // Parse the response
71
+ const data = await response.json();
72
+ const tokenResponse = {
73
+ accessToken: data.access_token,
74
+ refreshToken: data.refresh_token || credentials.refreshToken,
75
+ expiresAt: data.expires_in
76
+ ? Date.now() + data.expires_in * 1000
77
+ : undefined,
78
+ };
79
+ // Update the client with the new token
80
+ setAccessToken(tokenResponse.accessToken);
81
+ return tokenResponse;
82
+ },
83
+ };
84
+ }
@@ -0,0 +1,5 @@
1
+ import type { DropboxCredentials, DropboxSyncClient } from './types';
2
+ /**
3
+ * Creates a Dropbox sync client with auth, sync, and socket methods
4
+ */
5
+ export declare function createDropboxSyncClient(credentials: DropboxCredentials): DropboxSyncClient;
@@ -0,0 +1,37 @@
1
+ import { Dropbox } from 'dropbox';
2
+ import { createAuthMethods } from './auth';
3
+ import { createSyncMethods } from './sync';
4
+ import { createSocketMethods } from './socket';
5
+ /**
6
+ * Creates a Dropbox sync client with auth, sync, and socket methods
7
+ */
8
+ export function createDropboxSyncClient(credentials) {
9
+ let dropboxClient = null;
10
+ function getClient() {
11
+ if (!dropboxClient) {
12
+ if (credentials.accessToken) {
13
+ dropboxClient = new Dropbox({
14
+ accessToken: credentials.accessToken,
15
+ });
16
+ }
17
+ else if (credentials.clientId) {
18
+ dropboxClient = new Dropbox({ clientId: credentials.clientId });
19
+ }
20
+ else {
21
+ throw new Error('Either clientId or accessToken must be provided');
22
+ }
23
+ }
24
+ return dropboxClient;
25
+ }
26
+ function setAccessToken(token) {
27
+ dropboxClient = new Dropbox({ accessToken: token });
28
+ }
29
+ const auth = createAuthMethods(getClient, credentials, setAccessToken);
30
+ const socket = createSocketMethods();
31
+ const sync = createSyncMethods(getClient, credentials, socket);
32
+ return {
33
+ auth,
34
+ sync,
35
+ socket,
36
+ };
37
+ }
@@ -0,0 +1,2 @@
1
+ import type { SocketMethods } from './types';
2
+ export declare function createSocketMethods(): SocketMethods;