@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.
- package/README.md +315 -0
- package/dist/adapters/angular.d.ts +56 -0
- package/dist/adapters/angular.js +207 -0
- package/dist/adapters/next.d.ts +36 -0
- package/dist/adapters/next.js +120 -0
- package/dist/adapters/nuxt.d.ts +36 -0
- package/dist/adapters/nuxt.js +190 -0
- package/dist/adapters/svelte.d.ts +39 -0
- package/dist/adapters/svelte.js +134 -0
- package/dist/core/auth.d.ts +3 -0
- package/dist/core/auth.js +84 -0
- package/dist/core/client.d.ts +5 -0
- package/dist/core/client.js +37 -0
- package/dist/core/socket.d.ts +2 -0
- package/dist/core/socket.js +62 -0
- package/dist/core/sync.d.ts +3 -0
- package/dist/core/sync.js +340 -0
- package/dist/core/types.d.ts +73 -0
- package/dist/core/types.js +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +14 -0
- package/examples/angular-app/dropbox-sync.service.ts +244 -0
- package/examples/next-app/api-routes.ts +109 -0
- package/examples/next-app/dropbox-client.ts +122 -0
- package/examples/nuxt-app/api-routes.ts +26 -0
- package/examples/nuxt-app/dropbox-plugin.ts +15 -0
- package/examples/nuxt-app/nuxt.config.ts +23 -0
- package/examples/svelte-app/dropbox-store.ts +174 -0
- package/examples/svelte-app/routes.server.ts +120 -0
- package/package.json +66 -0
- package/src/adapters/angular.ts +217 -0
- package/src/adapters/next.ts +155 -0
- package/src/adapters/nuxt.ts +270 -0
- package/src/adapters/svelte.ts +168 -0
- package/src/core/auth.ts +148 -0
- package/src/core/client.ts +52 -0
- package/src/core/socket.ts +73 -0
- package/src/core/sync.ts +476 -0
- package/src/core/types.ts +83 -0
- package/src/index.ts +32 -0
- 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
|
+
};
|