@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
package/README.md ADDED
@@ -0,0 +1,315 @@
1
+ # Dropbox Sync Module
2
+
3
+ A reusable TypeScript module for syncing files between your application and Dropbox. Features framework-specific adapters for Next.js, SvelteKit, Nuxt, and Angular.
4
+
5
+ > N.B. This NPM package is neither tested nor supported
6
+
7
+ ## Features
8
+
9
+ - **File Synchronization**: Upload local files to Dropbox and download Dropbox files to your local filesystem
10
+ - **Real-time Progress**: Integrated Socket.IO support for real-time sync progress updates
11
+ - **Path Normalization**: Robust path handling to ensure consistent comparison between local and remote paths
12
+ - **OAuth Authentication**: Built-in OAuth flow handling for Dropbox API authentication
13
+ - **Framework Adapters**: Ready-to-use integrations for Next.js, SvelteKit, and Angular
14
+ - **TypeScript Support**: Fully typed API for improved developer experience
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install dropbox-sync socket.io socket.io-client
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### Core Usage
25
+
26
+ ```typescript
27
+ import createDropboxSyncClient from 'dropbox-sync'
28
+
29
+ // Create a Dropbox sync client
30
+ const dropboxSync = createDropboxSyncClient({
31
+ clientId: 'YOUR_DROPBOX_APP_KEY',
32
+ clientSecret: 'YOUR_DROPBOX_APP_SECRET',
33
+ accessToken: 'OPTIONAL_EXISTING_TOKEN',
34
+ refreshToken: 'OPTIONAL_REFRESH_TOKEN',
35
+ })
36
+
37
+ // Start OAuth flow
38
+ const authUrl = await dropboxSync.auth.getAuthUrl(
39
+ 'http://localhost:3000/callback'
40
+ )
41
+ // Redirect the user to authUrl
42
+
43
+ // Exchange authorization code for tokens
44
+ const tokens = await dropboxSync.auth.exchangeCodeForToken(code, redirectUri)
45
+ // Save tokens.accessToken and tokens.refreshToken
46
+
47
+ // Sync files
48
+ const syncResult = await dropboxSync.sync.syncFiles({
49
+ localDir: './public/img',
50
+ dropboxDir: '/app-images',
51
+ })
52
+
53
+ console.log(`Uploaded ${syncResult.uploaded.length} files`)
54
+ console.log(`Downloaded ${syncResult.downloaded.length} files`)
55
+ ```
56
+
57
+ ## Framework-Specific Usage
58
+
59
+ ### Next.js
60
+
61
+ ```typescript
62
+ // In your component
63
+ import { useNextDropboxSync } from 'dropbox-sync'
64
+
65
+ export function DropboxComponent() {
66
+ // Initialize client
67
+ const dropboxSync = useNextDropboxSync({
68
+ clientId: process.env.NEXT_PUBLIC_DROPBOX_APP_KEY,
69
+ })
70
+
71
+ // Connect to socket for real-time updates
72
+ useEffect(() => {
73
+ dropboxSync.socket.connect()
74
+ dropboxSync.socket.on('sync:progress', handleProgress)
75
+
76
+ return () => {
77
+ dropboxSync.socket.disconnect()
78
+ }
79
+ }, [])
80
+
81
+ // Start sync
82
+ const handleSync = () => {
83
+ // This will trigger the server-side sync through Socket.IO
84
+ dropboxSync.socket.emit('dropbox:sync')
85
+ }
86
+
87
+ return <button onClick={handleSync}>Sync with Dropbox</button>
88
+ }
89
+
90
+ // In your API route
91
+ import { createNextDropboxApiHandlers } from 'dropbox-sync'
92
+
93
+ const handlers = createNextDropboxApiHandlers()
94
+
95
+ export async function GET(request) {
96
+ return handlers.status()
97
+ }
98
+ ```
99
+
100
+ ### Nuxt.js
101
+
102
+ The Nuxt adapter leverages Nuxt's runtime config system for app settings and uses H3 (Nitro's HTTP server) utilities for handling requests and cookies. It's designed to work seamlessly with Nuxt 3's composition API and server routes.
103
+
104
+ To use this adapter in a Nuxt project, developers would:
105
+
106
+ 1. Add runtime config in their nuxt.config.ts:
107
+
108
+ ```typescript
109
+ export default defineNuxtConfig({
110
+ runtimeConfig: {
111
+ // Private keys
112
+ dropboxAppSecret: process.env.DROPBOX_APP_SECRET,
113
+ dropboxRedirectUri: process.env.DROPBOX_REDIRECT_URI,
114
+
115
+ // Public keys
116
+ public: {
117
+ dropboxAppKey: process.env.DROPBOX_APP_KEY,
118
+ appUrl: process.env.APP_URL || 'http://localhost:3000',
119
+ },
120
+ },
121
+ })
122
+ ```
123
+
124
+ 2. Create a plugin using the example provided
125
+ 3. Set up API routes using the handlers from `createNuxtApiHandlers()`
126
+
127
+ ```typescript
128
+ // In your plugins/dropbox.ts
129
+ import { useNuxtDropboxSync } from 'dropbox-sync'
130
+ import { defineNuxtPlugin } from 'nuxt/app'
131
+
132
+ export default defineNuxtPlugin((nuxtApp) => {
133
+ // Create the Dropbox client
134
+ const dropboxSync = useNuxtDropboxSync()
135
+
136
+ // Provide the client to the app
137
+ return {
138
+ provide: {
139
+ dropbox: dropboxSync
140
+ }
141
+ }
142
+ })
143
+
144
+ // In your Vue component
145
+ <script setup>
146
+ import { ref, onMounted, onBeforeUnmount } from 'vue'
147
+
148
+ const { $dropbox } = useNuxtApp()
149
+ const syncProgress = ref(0)
150
+
151
+ // Handle progress updates
152
+ const handleProgress = (data) => {
153
+ syncProgress.value = data.progress
154
+ }
155
+
156
+ // Connect to socket
157
+ onMounted(() => {
158
+ $dropbox.socket.connect()
159
+ $dropbox.socket.on('sync:progress', handleProgress)
160
+ })
161
+
162
+ // Clean up on unmount
163
+ onBeforeUnmount(() => {
164
+ $dropbox.socket.disconnect()
165
+ })
166
+
167
+ // Start sync
168
+ const startSync = () => {
169
+ $dropbox.socket.emit('dropbox:sync')
170
+ }
171
+ </script>
172
+
173
+ <template>
174
+ <div>
175
+ <button @click="startSync">Sync with Dropbox</button>
176
+ <progress :value="syncProgress" max="100"></progress>
177
+ </div>
178
+ </template>
179
+
180
+ // In your server/api/dropbox/[...].ts
181
+ import { createNuxtApiHandlers } from 'dropbox-sync'
182
+ import { defineEventHandler } from 'h3'
183
+
184
+ // Create handlers
185
+ const handlers = createNuxtApiHandlers()
186
+
187
+ export default defineEventHandler(async (event) => {
188
+ // Handle different endpoints
189
+ const path = event.path || ''
190
+
191
+ if (path.endsWith('/status')) {
192
+ return await handlers.status(event)
193
+ }
194
+
195
+ if (path.endsWith('/auth')) {
196
+ return await handlers.oauthStart(event)
197
+ }
198
+
199
+ if (path.endsWith('/auth/callback')) {
200
+ return await handlers.oauthCallback(event)
201
+ }
202
+
203
+ if (path.endsWith('/logout')) {
204
+ return await handlers.logout(event)
205
+ }
206
+
207
+ return { error: 'Not found' }
208
+ })
209
+ ```
210
+
211
+ ### SvelteKit
212
+
213
+ ```typescript
214
+ // In your store
215
+ import { useSvelteDropboxSync } from 'dropbox-sync'
216
+ import { writable } from 'svelte/store'
217
+
218
+ // Create store
219
+ export function createDropboxStore() {
220
+ const dropboxSync = useSvelteDropboxSync({
221
+ clientId: import.meta.env.VITE_DROPBOX_APP_KEY,
222
+ })
223
+
224
+ const progress = writable(0)
225
+
226
+ // Set up socket listeners
227
+ dropboxSync.socket.connect()
228
+ dropboxSync.socket.on('sync:progress', (data) => {
229
+ progress.set(data.progress)
230
+ })
231
+
232
+ return {
233
+ progress: { subscribe: progress.subscribe },
234
+ startSync: () => {
235
+ dropboxSync.socket.emit('dropbox:sync')
236
+ },
237
+ }
238
+ }
239
+ ```
240
+
241
+ ### Angular
242
+
243
+ ```typescript
244
+ // In your service
245
+ import { DropboxSyncService, getCredentialsFromEnvironment } from 'dropbox-sync'
246
+ import { environment } from '../environments/environment'
247
+
248
+ @Injectable({ providedIn: 'root' })
249
+ export class DropboxService {
250
+ constructor(private dropboxSyncService: DropboxSyncService) {
251
+ // Initialize the service
252
+ this.dropboxSyncService.initialize(
253
+ getCredentialsFromEnvironment(environment)
254
+ )
255
+
256
+ // Listen for socket events
257
+ const socketEvents = this.dropboxSyncService.setupSocketListeners()
258
+ socketEvents.subscribe((event) => console.log(event))
259
+ }
260
+
261
+ startSync() {
262
+ return this.dropboxSyncService.startSync()
263
+ }
264
+ }
265
+ ```
266
+
267
+ ## API Reference
268
+
269
+ ### Core Client
270
+
271
+ - `createDropboxSyncClient(credentials)` - Creates a new client instance
272
+
273
+ ### Auth Methods
274
+
275
+ - `getAuthUrl(redirectUri, state?)` - Generate an OAuth authentication URL
276
+ - `exchangeCodeForToken(code, redirectUri)` - Exchange authorization code for access token
277
+ - `refreshAccessToken()` - Refresh an expired access token
278
+
279
+ ### Sync Methods
280
+
281
+ - `scanLocalFiles(dir?)` - Scan local directory for files
282
+ - `scanDropboxFiles(dir?)` - Scan Dropbox folder for files
283
+ - `createSyncQueue(options?)` - Create upload/download queues
284
+ - `syncFiles(options?)` - Synchronize files between local and Dropbox
285
+ - `cancelSync()` - Cancel an ongoing synchronization
286
+
287
+ ### Socket Methods
288
+
289
+ - `connect()` - Connect to Socket.IO
290
+ - `disconnect()` - Disconnect from Socket.IO
291
+ - `on(event, handler)` - Listen for an event
292
+ - `off(event)` - Remove event listener
293
+ - `emit(event, ...args)` - Emit an event
294
+
295
+ ## Socket Events
296
+
297
+ - `sync:progress` - Emitted during sync with progress information
298
+ - `sync:queue` - Emitted at the start of sync with queue information
299
+ - `sync:complete` - Emitted when sync is complete
300
+ - `sync:error` - Emitted when an error occurs during sync
301
+
302
+ ## Configuration Options
303
+
304
+ ```typescript
305
+ interface SyncOptions {
306
+ localDir: string // Local directory path
307
+ dropboxDir?: string // Dropbox folder path
308
+ fileTypes?: RegExp // File types to sync (default: images and JSON)
309
+ progressCallback?: (progress: SyncProgress) => void
310
+ }
311
+ ```
312
+
313
+ ## License
314
+
315
+ MIT
@@ -0,0 +1,56 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { Observable } from 'rxjs';
3
+ import type { DropboxCredentials, DropboxSyncClient, SyncOptions, SyncResult, TokenResponse } from '../core/types';
4
+ export declare class DropboxSyncService {
5
+ private http;
6
+ private client;
7
+ constructor(http: HttpClient);
8
+ /**
9
+ * Initialize the Dropbox sync client with credentials
10
+ */
11
+ initialize(credentials: DropboxCredentials): DropboxSyncClient;
12
+ /**
13
+ * Get the current Dropbox sync client instance, or initialize with credentials if not exists
14
+ */
15
+ getClient(credentials?: DropboxCredentials): DropboxSyncClient;
16
+ /**
17
+ * Check the connection status with Dropbox
18
+ */
19
+ checkConnection(): Observable<boolean>;
20
+ /**
21
+ * Start the OAuth flow to connect to Dropbox
22
+ */
23
+ connectDropbox(): void;
24
+ /**
25
+ * Disconnect from Dropbox
26
+ */
27
+ disconnectDropbox(): Observable<boolean>;
28
+ /**
29
+ * Start the sync process
30
+ */
31
+ startSync(options?: Partial<SyncOptions>): Observable<SyncResult>;
32
+ /**
33
+ * Cancel an ongoing sync process
34
+ */
35
+ cancelSync(): void;
36
+ /**
37
+ * Set up socket listeners for sync events
38
+ * Returns an RxJS Observable that emits sync progress events
39
+ */
40
+ setupSocketListeners(): Observable<any>;
41
+ /**
42
+ * Handle OAuth callback on the client side
43
+ */
44
+ handleOAuthCallback(code: string): Observable<TokenResponse>;
45
+ /**
46
+ * Create a sync queue to determine which files need to be uploaded/downloaded
47
+ */
48
+ createSyncQueue(options?: Partial<SyncOptions>): Observable<{
49
+ uploadQueue: string[];
50
+ downloadQueue: string[];
51
+ }>;
52
+ }
53
+ /**
54
+ * Function to extract credentials from Angular environment
55
+ */
56
+ export declare function getCredentialsFromEnvironment(environment: any): DropboxCredentials;
@@ -0,0 +1,207 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
36
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
37
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
38
+ };
39
+ import { Injectable } from '@angular/core';
40
+ import { Observable, from, of } from 'rxjs';
41
+ import { catchError, map, tap } from 'rxjs/operators';
42
+ import { createDropboxSyncClient } from '../core/client';
43
+ let DropboxSyncService = (() => {
44
+ let _classDecorators = [Injectable({
45
+ providedIn: 'root',
46
+ })];
47
+ let _classDescriptor;
48
+ let _classExtraInitializers = [];
49
+ let _classThis;
50
+ var DropboxSyncService = _classThis = class {
51
+ constructor(http) {
52
+ this.http = http;
53
+ this.client = null;
54
+ }
55
+ /**
56
+ * Initialize the Dropbox sync client with credentials
57
+ */
58
+ initialize(credentials) {
59
+ this.client = createDropboxSyncClient(credentials);
60
+ return this.client;
61
+ }
62
+ /**
63
+ * Get the current Dropbox sync client instance, or initialize with credentials if not exists
64
+ */
65
+ getClient(credentials) {
66
+ if (!this.client && credentials) {
67
+ return this.initialize(credentials);
68
+ }
69
+ if (!this.client) {
70
+ throw new Error('DropboxSyncService not initialized. Call initialize() first.');
71
+ }
72
+ return this.client;
73
+ }
74
+ /**
75
+ * Check the connection status with Dropbox
76
+ */
77
+ checkConnection() {
78
+ return this.http
79
+ .get('/api/dropbox/status')
80
+ .pipe(map((response) => response.connected), catchError(() => of(false)));
81
+ }
82
+ /**
83
+ * Start the OAuth flow to connect to Dropbox
84
+ */
85
+ connectDropbox() {
86
+ window.location.href = '/api/dropbox/auth/start';
87
+ }
88
+ /**
89
+ * Disconnect from Dropbox
90
+ */
91
+ disconnectDropbox() {
92
+ return this.http
93
+ .post('/api/dropbox/logout', {})
94
+ .pipe(map((response) => response.success), catchError(() => of(false)));
95
+ }
96
+ /**
97
+ * Start the sync process
98
+ */
99
+ startSync(options) {
100
+ if (!this.client) {
101
+ throw new Error('DropboxSyncService not initialized. Call initialize() first.');
102
+ }
103
+ // Connect to socket before starting sync
104
+ this.client.socket.connect();
105
+ // Setup socket listeners for sync events
106
+ this.setupSocketListeners();
107
+ return from(this.client.sync.syncFiles(options));
108
+ }
109
+ /**
110
+ * Cancel an ongoing sync process
111
+ */
112
+ cancelSync() {
113
+ if (!this.client) {
114
+ return;
115
+ }
116
+ this.client.sync.cancelSync();
117
+ }
118
+ /**
119
+ * Set up socket listeners for sync events
120
+ * Returns an RxJS Observable that emits sync progress events
121
+ */
122
+ setupSocketListeners() {
123
+ if (!this.client) {
124
+ throw new Error('DropboxSyncService not initialized. Call initialize() first.');
125
+ }
126
+ // Create observable for sync progress events
127
+ return new Observable((observer) => {
128
+ // Listen for progress updates
129
+ this.client.socket.on('sync:progress', (data) => {
130
+ observer.next({ type: 'progress', data });
131
+ });
132
+ // Listen for queue information
133
+ this.client.socket.on('sync:queue', (data) => {
134
+ observer.next({ type: 'queue', data });
135
+ });
136
+ // Listen for sync completion
137
+ this.client.socket.on('sync:complete', (data) => {
138
+ observer.next({ type: 'complete', data });
139
+ observer.complete();
140
+ });
141
+ // Listen for sync errors
142
+ this.client.socket.on('sync:error', (data) => {
143
+ if (!data.continue) {
144
+ observer.error(data.message);
145
+ }
146
+ else {
147
+ observer.next({ type: 'error', data });
148
+ }
149
+ });
150
+ // Cleanup function - remove event listeners when subscription is disposed
151
+ return () => {
152
+ this.client.socket.off('sync:progress');
153
+ this.client.socket.off('sync:queue');
154
+ this.client.socket.off('sync:complete');
155
+ this.client.socket.off('sync:error');
156
+ };
157
+ });
158
+ }
159
+ /**
160
+ * Handle OAuth callback on the client side
161
+ */
162
+ handleOAuthCallback(code) {
163
+ if (!this.client) {
164
+ throw new Error('DropboxSyncService not initialized. Call initialize() first.');
165
+ }
166
+ const redirectUri = window.location.origin + '/api/dropbox/auth/callback';
167
+ return from(this.client.auth.exchangeCodeForToken(code, redirectUri)).pipe(tap((tokens) => {
168
+ // Store tokens in local storage for client-side access
169
+ localStorage.setItem('dropbox_access_token', tokens.accessToken);
170
+ if (tokens.refreshToken) {
171
+ localStorage.setItem('dropbox_refresh_token', tokens.refreshToken);
172
+ }
173
+ localStorage.setItem('dropbox_connected', 'true');
174
+ }));
175
+ }
176
+ /**
177
+ * Create a sync queue to determine which files need to be uploaded/downloaded
178
+ */
179
+ createSyncQueue(options) {
180
+ if (!this.client) {
181
+ throw new Error('DropboxSyncService not initialized. Call initialize() first.');
182
+ }
183
+ return from(this.client.sync.createSyncQueue(options));
184
+ }
185
+ };
186
+ __setFunctionName(_classThis, "DropboxSyncService");
187
+ (() => {
188
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
189
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
190
+ DropboxSyncService = _classThis = _classDescriptor.value;
191
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
192
+ __runInitializers(_classThis, _classExtraInitializers);
193
+ })();
194
+ return DropboxSyncService = _classThis;
195
+ })();
196
+ export { DropboxSyncService };
197
+ /**
198
+ * Function to extract credentials from Angular environment
199
+ */
200
+ export function getCredentialsFromEnvironment(environment) {
201
+ return {
202
+ clientId: environment.dropboxAppKey || '',
203
+ clientSecret: environment.dropboxAppSecret,
204
+ accessToken: localStorage.getItem('dropbox_access_token') || undefined,
205
+ refreshToken: localStorage.getItem('dropbox_refresh_token') || undefined,
206
+ };
207
+ }
@@ -0,0 +1,36 @@
1
+ import type { DropboxCredentials, DropboxSyncClient } from '../core/types';
2
+ import { NextRequest, NextResponse } from 'next/server';
3
+ /**
4
+ * Next.js-specific helper to create a Dropbox sync client
5
+ * Can be used in both client and server components
6
+ */
7
+ export declare function useNextDropboxSync(credentials: DropboxCredentials): DropboxSyncClient;
8
+ /**
9
+ * Server-side helper to get credentials from Next.js cookies
10
+ */
11
+ export declare function getCredentialsFromCookies(): Promise<DropboxCredentials>;
12
+ /**
13
+ * Server action to handle Dropbox OAuth callback
14
+ */
15
+ export declare function handleOAuthCallback(request: NextRequest): Promise<NextResponse>;
16
+ /**
17
+ * Create API route handlers for a Next.js app
18
+ */
19
+ export declare function createNextDropboxApiHandlers(): {
20
+ /**
21
+ * Handler for status check route
22
+ */
23
+ status(): Promise<NextResponse<{
24
+ connected: boolean;
25
+ }>>;
26
+ /**
27
+ * Handler for OAuth start route
28
+ */
29
+ oauthStart(): Promise<NextResponse<unknown>>;
30
+ /**
31
+ * Handler for logout route
32
+ */
33
+ logout(): Promise<NextResponse<{
34
+ success: boolean;
35
+ }>>;
36
+ };