@rsweeten/dropbox-sync 0.1.1 → 0.1.3

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 (32) hide show
  1. package/.github/workflows/test-pr.yml +30 -0
  2. package/README.md +521 -315
  3. package/__mocks__/nuxt/app.js +20 -0
  4. package/dist/adapters/__tests__/angular.spec.d.ts +1 -0
  5. package/dist/adapters/__tests__/angular.spec.js +237 -0
  6. package/dist/adapters/__tests__/next.spec.d.ts +1 -0
  7. package/dist/adapters/__tests__/next.spec.js +179 -0
  8. package/dist/adapters/__tests__/nuxt.spec.d.ts +1 -0
  9. package/dist/adapters/__tests__/nuxt.spec.js +145 -0
  10. package/dist/adapters/__tests__/svelte.spec.d.ts +1 -0
  11. package/dist/adapters/__tests__/svelte.spec.js +149 -0
  12. package/dist/core/__tests__/auth.spec.d.ts +1 -0
  13. package/dist/core/__tests__/auth.spec.js +83 -0
  14. package/dist/core/__tests__/client.spec.d.ts +1 -0
  15. package/dist/core/__tests__/client.spec.js +102 -0
  16. package/dist/core/__tests__/socket.spec.d.ts +1 -0
  17. package/dist/core/__tests__/socket.spec.js +122 -0
  18. package/dist/core/__tests__/sync.spec.d.ts +1 -0
  19. package/dist/core/__tests__/sync.spec.js +375 -0
  20. package/dist/core/sync.js +30 -11
  21. package/jest.config.js +24 -0
  22. package/jest.setup.js +38 -0
  23. package/package.json +77 -74
  24. package/src/adapters/__tests__/angular.spec.ts +338 -0
  25. package/src/adapters/__tests__/next.spec.ts +240 -0
  26. package/src/adapters/__tests__/nuxt.spec.ts +185 -0
  27. package/src/adapters/__tests__/svelte.spec.ts +194 -0
  28. package/src/core/__tests__/auth.spec.ts +142 -0
  29. package/src/core/__tests__/client.spec.ts +128 -0
  30. package/src/core/__tests__/socket.spec.ts +153 -0
  31. package/src/core/__tests__/sync.spec.ts +508 -0
  32. package/src/core/sync.ts +503 -476
package/README.md CHANGED
@@ -1,315 +1,521 @@
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
1
+ # Dropbox Sync Module
2
+
3
+ [![Test Pull Request](https://github.com/sweetenr/dropbox-sync-service/actions/workflows/test-pr.yml/badge.svg)](https://github.com/sweetenr/dropbox-sync-service/actions/workflows/test-pr.yml)
4
+
5
+ A reusable TypeScript module for syncing files between your application and Dropbox. Features framework-specific adapters for Next.js, SvelteKit, Nuxt, and Angular.
6
+
7
+ > N.B. This NPM package is neither tested nor supported
8
+
9
+ ## Table of Contents
10
+
11
+ - [Features](#features)
12
+ - [Installation](#installation)
13
+ - [Quick Start](#quick-start)
14
+ - [Core Usage](#core-usage)
15
+ - [Development Setup](#development-setup)
16
+ - [Architecture](#architecture)
17
+ - [Data Flow](#data-flow)
18
+ - [Testing](#testing)
19
+ - [Test Structure](#test-structure)
20
+ - [Running Tests](#running-tests)
21
+ - [Testing Approach](#testing-approach)
22
+ - [Mock Strategy](#mock-strategy)
23
+ - [Test Coverage](#test-coverage)
24
+ - [Framework-Specific Usage](#framework-specific-usage)
25
+ - [Next.js](#nextjs)
26
+ - [Nuxt.js](#nuxtjs)
27
+ - [SvelteKit](#sveltekit)
28
+ - [Angular](#angular)
29
+ - [API Reference](#api-reference)
30
+ - [Core Client](#core-client)
31
+ - [Auth Methods](#auth-methods)
32
+ - [Sync Methods](#sync-methods)
33
+ - [Socket Methods](#socket-methods)
34
+ - [Socket Events](#socket-events)
35
+ - [Configuration Options](#configuration-options)
36
+ - [License](#license)
37
+
38
+ ## Features
39
+
40
+ - **File Synchronization**: Upload local files to Dropbox and download Dropbox files to your local filesystem
41
+ - **Real-time Progress**: Integrated Socket.IO support for real-time sync progress updates
42
+ - **Path Normalization**: Robust path handling to ensure consistent comparison between local and remote paths
43
+ - **OAuth Authentication**: Built-in OAuth flow handling for Dropbox API authentication
44
+ - **Framework Adapters**: Ready-to-use integrations for Next.js, SvelteKit, and Angular
45
+ - **TypeScript Support**: Fully typed API for improved developer experience
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ # Install the package in your project
51
+ npm install dropbox-sync
52
+ # or
53
+ yarn add dropbox-sync
54
+ ```
55
+
56
+ You may also need to install peer dependencies:
57
+
58
+ ```bash
59
+ npm install socket.io socket.io-client
60
+ # or
61
+ yarn add socket.io socket.io-client
62
+ ```
63
+
64
+ ## Quick Start
65
+
66
+ ### Core Usage
67
+
68
+ ```typescript
69
+ import createDropboxSyncClient from 'dropbox-sync'
70
+
71
+ // Create a Dropbox sync client
72
+ const dropboxSync = createDropboxSyncClient({
73
+ clientId: 'YOUR_DROPBOX_APP_KEY',
74
+ clientSecret: 'YOUR_DROPBOX_APP_SECRET',
75
+ accessToken: 'OPTIONAL_EXISTING_TOKEN',
76
+ refreshToken: 'OPTIONAL_REFRESH_TOKEN',
77
+ })
78
+
79
+ // Start OAuth flow
80
+ const authUrl = await dropboxSync.auth.getAuthUrl(
81
+ 'http://localhost:3000/callback'
82
+ )
83
+ // Redirect the user to authUrl
84
+
85
+ // Exchange authorization code for tokens
86
+ const tokens = await dropboxSync.auth.exchangeCodeForToken(code, redirectUri)
87
+ // Save tokens.accessToken and tokens.refreshToken
88
+
89
+ // Sync files
90
+ const syncResult = await dropboxSync.sync.syncFiles({
91
+ localDir: './public/img',
92
+ dropboxDir: '/app-images',
93
+ })
94
+
95
+ console.log(`Uploaded ${syncResult.uploaded.length} files`)
96
+ console.log(`Downloaded ${syncResult.downloaded.length} files`)
97
+ ```
98
+
99
+ ## Development Setup
100
+
101
+ To set up this project for local development:
102
+
103
+ ```bash
104
+ # Clone the repository
105
+ git clone https://github.com/yourusername/dropbox-sync-service.git
106
+ cd dropbox-sync-service
107
+
108
+ # Install dependencies
109
+ npm install
110
+
111
+ # Run tests
112
+ npm test
113
+
114
+ # Build the package
115
+ npm run build
116
+ ```
117
+
118
+ ## Architecture
119
+
120
+ The Dropbox Sync Module architecture is designed with modularity, extensibility, and framework-agnosticism in mind.
121
+
122
+ ```mermaid
123
+ graph TD
124
+ A[Application] --> B[Framework Adapter]
125
+ B --> C[Core Client]
126
+ C --> D[Auth Module]
127
+ C --> E[Sync Module]
128
+ C --> F[Socket Module]
129
+ D --> G[Dropbox API]
130
+ E --> G
131
+ F --> H[Socket.IO]
132
+ H --> E
133
+ H --> A
134
+
135
+ %% File Flow
136
+ I[Local Files] --> E
137
+ E --> I
138
+ G --> E
139
+ E --> G
140
+ ```
141
+
142
+ ### Data Flow
143
+
144
+ 1. **Authentication Flow:**
145
+
146
+ ```mermaid
147
+ sequenceDiagram
148
+ participant User
149
+ participant App
150
+ participant DropboxSync
151
+ participant Dropbox
152
+
153
+ User->>App: Initiate auth
154
+ App->>DropboxSync: getAuthUrl()
155
+ DropboxSync->>Dropbox: Request auth URL
156
+ Dropbox-->>DropboxSync: Auth URL
157
+ DropboxSync-->>App: Auth URL
158
+ App-->>User: Redirect to auth URL
159
+ User->>Dropbox: Authorize app
160
+ Dropbox-->>App: Auth code (via redirect)
161
+ App->>DropboxSync: exchangeCodeForToken(code)
162
+ DropboxSync->>Dropbox: Exchange code for token
163
+ Dropbox-->>DropboxSync: Access & refresh tokens
164
+ DropboxSync-->>App: Tokens
165
+ ```
166
+
167
+ 2. **Sync Flow:**
168
+
169
+ ```mermaid
170
+ sequenceDiagram
171
+ participant App
172
+ participant DropboxSync
173
+ participant Socket
174
+ participant Dropbox
175
+ participant LocalFS
176
+
177
+ App->>DropboxSync: syncFiles(options)
178
+ DropboxSync->>LocalFS: Scan local files
179
+ LocalFS-->>DropboxSync: Local file list
180
+ DropboxSync->>Dropbox: List files
181
+ Dropbox-->>DropboxSync: Dropbox file list
182
+ DropboxSync->>DropboxSync: Create sync queue
183
+
184
+ loop For each file to upload
185
+ DropboxSync->>Dropbox: Upload file
186
+ DropboxSync->>Socket: Emit progress
187
+ Socket-->>App: Progress update
188
+ end
189
+
190
+ loop For each file to download
191
+ DropboxSync->>Dropbox: Download file
192
+ DropboxSync->>LocalFS: Write file
193
+ DropboxSync->>Socket: Emit progress
194
+ Socket-->>App: Progress update
195
+ end
196
+
197
+ DropboxSync-->>App: Sync results
198
+ ```
199
+
200
+ ## Testing
201
+
202
+ The Dropbox Sync Module uses Jest for unit testing. Tests are organized to match the structure of the source code.
203
+
204
+ ### Test Structure
205
+
206
+ ```
207
+ __tests__/ # Test utilities and mocks
208
+ src/
209
+ core/
210
+ __tests__/ # Core module tests
211
+ auth.spec.ts # Authentication tests
212
+ client.spec.ts # Client tests
213
+ socket.spec.ts # Socket tests
214
+ sync.spec.ts # Sync tests
215
+ adapters/
216
+ __tests__/ # Framework adapter tests
217
+ angular.spec.ts # Angular adapter tests
218
+ next.spec.ts # Next.js adapter tests
219
+ nuxt.spec.ts # Nuxt adapter tests
220
+ svelte.spec.ts # SvelteKit adapter tests
221
+ ```
222
+
223
+ ### Running Tests
224
+
225
+ ```bash
226
+ # Run all tests
227
+ npm test
228
+
229
+ # Run tests with coverage
230
+ npm test -- --coverage
231
+
232
+ # Run specific test file
233
+ npm test -- src/core/__tests__/auth.spec.ts
234
+
235
+ # Run tests in watch mode during development
236
+ npm test -- --watch
237
+ ```
238
+
239
+ ### Testing Approach
240
+
241
+ 1. **Unit Tests**: Each module is tested in isolation with mocked dependencies
242
+ 2. **Integration Tests**: Tests for interactions between modules
243
+ 3. **Adapter Tests**: Tests for framework-specific adapters
244
+
245
+ ### Mock Strategy
246
+
247
+ - Dropbox API calls are mocked using Jest mock functions
248
+ - File system operations are mocked to avoid touching real files
249
+ - Socket.IO is mocked to test event emission and handling
250
+
251
+ ### Test Coverage
252
+
253
+ We aim for high test coverage, especially for the core functionality:
254
+
255
+ | Module | Coverage |
256
+ | -------- | -------- |
257
+ | Core | >90% |
258
+ | Auth | >95% |
259
+ | Sync | >90% |
260
+ | Socket | >90% |
261
+ | Adapters | >85% |
262
+
263
+ ## Framework-Specific Usage
264
+
265
+ ### Next.js
266
+
267
+ ```typescript
268
+ // In your component
269
+ import { useNextDropboxSync } from 'dropbox-sync'
270
+
271
+ export function DropboxComponent() {
272
+ // Initialize client
273
+ const dropboxSync = useNextDropboxSync({
274
+ clientId: process.env.NEXT_PUBLIC_DROPBOX_APP_KEY,
275
+ })
276
+
277
+ // Connect to socket for real-time updates
278
+ useEffect(() => {
279
+ dropboxSync.socket.connect()
280
+ dropboxSync.socket.on('sync:progress', handleProgress)
281
+
282
+ return () => {
283
+ dropboxSync.socket.disconnect()
284
+ }
285
+ }, [])
286
+
287
+ // Start sync
288
+ const handleSync = () => {
289
+ // This will trigger the server-side sync through Socket.IO
290
+ dropboxSync.socket.emit('dropbox:sync')
291
+ }
292
+
293
+ return <button onClick={handleSync}>Sync with Dropbox</button>
294
+ }
295
+
296
+ // In your API route
297
+ import { createNextDropboxApiHandlers } from 'dropbox-sync'
298
+
299
+ const handlers = createNextDropboxApiHandlers()
300
+
301
+ export async function GET(request) {
302
+ return handlers.status()
303
+ }
304
+ ```
305
+
306
+ ### Nuxt.js
307
+
308
+ 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.
309
+
310
+ To use this adapter in a Nuxt project, developers would:
311
+
312
+ 1. Add runtime config in their nuxt.config.ts:
313
+
314
+ ```typescript
315
+ export default defineNuxtConfig({
316
+ runtimeConfig: {
317
+ // Private keys
318
+ dropboxAppSecret: process.env.DROPBOX_APP_SECRET,
319
+ dropboxRedirectUri: process.env.DROPBOX_REDIRECT_URI,
320
+
321
+ // Public keys
322
+ public: {
323
+ dropboxAppKey: process.env.DROPBOX_APP_KEY,
324
+ appUrl: process.env.APP_URL || 'http://localhost:3000',
325
+ },
326
+ },
327
+ })
328
+ ```
329
+
330
+ 2. Create a plugin using the example provided
331
+ 3. Set up API routes using the handlers from `createNuxtApiHandlers()`
332
+
333
+ ```typescript
334
+ // In your plugins/dropbox.ts
335
+ import { useNuxtDropboxSync } from 'dropbox-sync'
336
+ import { defineNuxtPlugin } from 'nuxt/app'
337
+
338
+ export default defineNuxtPlugin((nuxtApp) => {
339
+ // Create the Dropbox client
340
+ const dropboxSync = useNuxtDropboxSync()
341
+
342
+ // Provide the client to the app
343
+ return {
344
+ provide: {
345
+ dropbox: dropboxSync
346
+ }
347
+ }
348
+ })
349
+
350
+ // In your Vue component
351
+ <script setup>
352
+ import { ref, onMounted, onBeforeUnmount } from 'vue'
353
+
354
+ const { $dropbox } = useNuxtApp()
355
+ const syncProgress = ref(0)
356
+
357
+ // Handle progress updates
358
+ const handleProgress = (data) => {
359
+ syncProgress.value = data.progress
360
+ }
361
+
362
+ // Connect to socket
363
+ onMounted(() => {
364
+ $dropbox.socket.connect()
365
+ $dropbox.socket.on('sync:progress', handleProgress)
366
+ })
367
+
368
+ // Clean up on unmount
369
+ onBeforeUnmount(() => {
370
+ $dropbox.socket.disconnect()
371
+ })
372
+
373
+ // Start sync
374
+ const startSync = () => {
375
+ $dropbox.socket.emit('dropbox:sync')
376
+ }
377
+ </script>
378
+
379
+ <template>
380
+ <div>
381
+ <button @click="startSync">Sync with Dropbox</button>
382
+ <progress :value="syncProgress" max="100"></progress>
383
+ </div>
384
+ </template>
385
+
386
+ // In your server/api/dropbox/[...].ts
387
+ import { createNuxtApiHandlers } from 'dropbox-sync'
388
+ import { defineEventHandler } from 'h3'
389
+
390
+ // Create handlers
391
+ const handlers = createNuxtApiHandlers()
392
+
393
+ export default defineEventHandler(async (event) => {
394
+ // Handle different endpoints
395
+ const path = event.path || ''
396
+
397
+ if (path.endsWith('/status')) {
398
+ return await handlers.status(event)
399
+ }
400
+
401
+ if (path.endsWith('/auth')) {
402
+ return await handlers.oauthStart(event)
403
+ }
404
+
405
+ if (path.endsWith('/auth/callback')) {
406
+ return await handlers.oauthCallback(event)
407
+ }
408
+
409
+ if (path.endsWith('/logout')) {
410
+ return await handlers.logout(event)
411
+ }
412
+
413
+ return { error: 'Not found' }
414
+ })
415
+ ```
416
+
417
+ ### SvelteKit
418
+
419
+ ```typescript
420
+ // In your store
421
+ import { useSvelteDropboxSync } from 'dropbox-sync'
422
+ import { writable } from 'svelte/store'
423
+
424
+ // Create store
425
+ export function createDropboxStore() {
426
+ const dropboxSync = useSvelteDropboxSync({
427
+ clientId: import.meta.env.VITE_DROPBOX_APP_KEY,
428
+ })
429
+
430
+ const progress = writable(0)
431
+
432
+ // Set up socket listeners
433
+ dropboxSync.socket.connect()
434
+ dropboxSync.socket.on('sync:progress', (data) => {
435
+ progress.set(data.progress)
436
+ })
437
+
438
+ return {
439
+ progress: { subscribe: progress.subscribe },
440
+ startSync: () => {
441
+ dropboxSync.socket.emit('dropbox:sync')
442
+ },
443
+ }
444
+ }
445
+ ```
446
+
447
+ ### Angular
448
+
449
+ ```typescript
450
+ // In your service
451
+ import { DropboxSyncService, getCredentialsFromEnvironment } from 'dropbox-sync'
452
+ import { environment } from '../environments/environment'
453
+
454
+ @Injectable({ providedIn: 'root' })
455
+ export class DropboxService {
456
+ constructor(private dropboxSyncService: DropboxSyncService) {
457
+ // Initialize the service
458
+ this.dropboxSyncService.initialize(
459
+ getCredentialsFromEnvironment(environment)
460
+ )
461
+
462
+ // Listen for socket events
463
+ const socketEvents = this.dropboxSyncService.setupSocketListeners()
464
+ socketEvents.subscribe((event) => console.log(event))
465
+ }
466
+
467
+ startSync() {
468
+ return this.dropboxSyncService.startSync()
469
+ }
470
+ }
471
+ ```
472
+
473
+ ## API Reference
474
+
475
+ ### Core Client
476
+
477
+ - `createDropboxSyncClient(credentials)` - Creates a new client instance
478
+
479
+ ### Auth Methods
480
+
481
+ - `getAuthUrl(redirectUri, state?)` - Generate an OAuth authentication URL
482
+ - `exchangeCodeForToken(code, redirectUri)` - Exchange authorization code for access token
483
+ - `refreshAccessToken()` - Refresh an expired access token
484
+
485
+ ### Sync Methods
486
+
487
+ - `scanLocalFiles(dir?)` - Scan local directory for files
488
+ - `scanDropboxFiles(dir?)` - Scan Dropbox folder for files
489
+ - `createSyncQueue(options?)` - Create upload/download queues
490
+ - `syncFiles(options?)` - Synchronize files between local and Dropbox
491
+ - `cancelSync()` - Cancel an ongoing synchronization
492
+
493
+ ### Socket Methods
494
+
495
+ - `connect()` - Connect to Socket.IO
496
+ - `disconnect()` - Disconnect from Socket.IO
497
+ - `on(event, handler)` - Listen for an event
498
+ - `off(event)` - Remove event listener
499
+ - `emit(event, ...args)` - Emit an event
500
+
501
+ ## Socket Events
502
+
503
+ - `sync:progress` - Emitted during sync with progress information
504
+ - `sync:queue` - Emitted at the start of sync with queue information
505
+ - `sync:complete` - Emitted when sync is complete
506
+ - `sync:error` - Emitted when an error occurs during sync
507
+
508
+ ## Configuration Options
509
+
510
+ ```typescript
511
+ interface SyncOptions {
512
+ localDir: string // Local directory path
513
+ dropboxDir?: string // Dropbox folder path
514
+ fileTypes?: RegExp // File types to sync (default: images and JSON)
515
+ progressCallback?: (progress: SyncProgress) => void
516
+ }
517
+ ```
518
+
519
+ ## License
520
+
521
+ MIT