@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
@@ -0,0 +1,174 @@
|
|
1
|
+
// SvelteKit store for Dropbox sync
|
2
|
+
import { writable, derived } from 'svelte/store'
|
3
|
+
// For a private module, you would import from your private registry or local path
|
4
|
+
// import { useSvelteDropboxSync } from '@yourcompany/dropbox-sync';
|
5
|
+
import { useSvelteDropboxSync } from 'dropbox-sync'
|
6
|
+
import { browser } from '$app/environment'
|
7
|
+
import { goto } from '$app/navigation'
|
8
|
+
|
9
|
+
// Create a persistent store
|
10
|
+
export function createDropboxStore() {
|
11
|
+
const credentials = {
|
12
|
+
clientId: browser
|
13
|
+
? import.meta.env.VITE_DROPBOX_APP_KEY
|
14
|
+
: process.env.DROPBOX_APP_KEY,
|
15
|
+
// The access token will be added from cookies on the server side
|
16
|
+
}
|
17
|
+
|
18
|
+
// Initialize the Dropbox client
|
19
|
+
const dropboxSync = useSvelteDropboxSync(credentials)
|
20
|
+
|
21
|
+
// Create stores for state management
|
22
|
+
const connected = writable(false)
|
23
|
+
const syncing = writable(false)
|
24
|
+
const progress = writable(0)
|
25
|
+
const message = writable('')
|
26
|
+
const error = writable<string | null>(null)
|
27
|
+
const syncStats = writable({
|
28
|
+
total: 0,
|
29
|
+
uploads: 0,
|
30
|
+
downloads: 0,
|
31
|
+
completed: 0,
|
32
|
+
})
|
33
|
+
|
34
|
+
// Check connection status on initialization
|
35
|
+
async function checkConnection() {
|
36
|
+
if (!browser) return
|
37
|
+
|
38
|
+
try {
|
39
|
+
const response = await fetch('/api/dropbox/status')
|
40
|
+
const data = await response.json()
|
41
|
+
connected.set(data.connected)
|
42
|
+
} catch (err) {
|
43
|
+
console.error('Error checking Dropbox connection:', err)
|
44
|
+
connected.set(false)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
if (browser) {
|
49
|
+
checkConnection()
|
50
|
+
|
51
|
+
// Set up socket connection for real-time updates
|
52
|
+
dropboxSync.socket.connect()
|
53
|
+
|
54
|
+
// Listen for progress updates
|
55
|
+
dropboxSync.socket.on('sync:progress', (data) => {
|
56
|
+
progress.set(data.progress)
|
57
|
+
message.set(data.message)
|
58
|
+
})
|
59
|
+
|
60
|
+
// Listen for queue information
|
61
|
+
dropboxSync.socket.on('sync:queue', (data) => {
|
62
|
+
syncStats.set({
|
63
|
+
total: data.total,
|
64
|
+
uploads: data.totalUploads,
|
65
|
+
downloads: data.totalDownloads,
|
66
|
+
completed: 0,
|
67
|
+
})
|
68
|
+
})
|
69
|
+
|
70
|
+
// Listen for completion
|
71
|
+
dropboxSync.socket.on('sync:complete', (data) => {
|
72
|
+
progress.set(100)
|
73
|
+
message.set(data.message)
|
74
|
+
syncing.set(false)
|
75
|
+
|
76
|
+
if (data.stats) {
|
77
|
+
syncStats.update((stats) => ({
|
78
|
+
...stats,
|
79
|
+
completed: stats.total,
|
80
|
+
}))
|
81
|
+
}
|
82
|
+
})
|
83
|
+
|
84
|
+
// Listen for errors
|
85
|
+
dropboxSync.socket.on('sync:error', (data) => {
|
86
|
+
error.set(data.message)
|
87
|
+
syncing.set(false)
|
88
|
+
})
|
89
|
+
}
|
90
|
+
|
91
|
+
return {
|
92
|
+
connected: { subscribe: connected.subscribe },
|
93
|
+
syncing: { subscribe: syncing.subscribe },
|
94
|
+
progress: { subscribe: progress.subscribe },
|
95
|
+
message: { subscribe: message.subscribe },
|
96
|
+
error: { subscribe: error.subscribe },
|
97
|
+
syncStats: { subscribe: syncStats.subscribe },
|
98
|
+
|
99
|
+
// Connect to Dropbox
|
100
|
+
connect() {
|
101
|
+
if (!browser) return
|
102
|
+
goto('/api/dropbox/auth/start')
|
103
|
+
},
|
104
|
+
|
105
|
+
// Disconnect from Dropbox
|
106
|
+
async disconnect() {
|
107
|
+
if (!browser) return
|
108
|
+
|
109
|
+
try {
|
110
|
+
await fetch('/api/dropbox/logout', { method: 'POST' })
|
111
|
+
connected.set(false)
|
112
|
+
} catch (err) {
|
113
|
+
console.error('Error disconnecting from Dropbox:', err)
|
114
|
+
}
|
115
|
+
},
|
116
|
+
|
117
|
+
// Start synchronization
|
118
|
+
async startSync() {
|
119
|
+
if (!browser) return
|
120
|
+
|
121
|
+
try {
|
122
|
+
syncing.set(true)
|
123
|
+
progress.set(0)
|
124
|
+
message.set('Initializing Dropbox sync...')
|
125
|
+
error.set(null)
|
126
|
+
|
127
|
+
// Trigger sync via socket
|
128
|
+
dropboxSync.socket.emit('dropbox:sync')
|
129
|
+
} catch (err: any) {
|
130
|
+
console.error('Error starting Dropbox sync:', err)
|
131
|
+
error.set(
|
132
|
+
err.message || 'An error occurred while starting sync'
|
133
|
+
)
|
134
|
+
syncing.set(false)
|
135
|
+
}
|
136
|
+
},
|
137
|
+
|
138
|
+
// Cancel synchronization
|
139
|
+
cancelSync() {
|
140
|
+
if (!browser) return
|
141
|
+
|
142
|
+
dropboxSync.sync.cancelSync()
|
143
|
+
syncing.set(false)
|
144
|
+
message.set('Sync cancelled')
|
145
|
+
},
|
146
|
+
|
147
|
+
// Check files that need syncing without starting the sync
|
148
|
+
async checkSyncNeeded(options?: {
|
149
|
+
localDir?: string
|
150
|
+
dropboxDir?: string
|
151
|
+
}) {
|
152
|
+
if (!browser) return { upload: 0, download: 0 }
|
153
|
+
|
154
|
+
try {
|
155
|
+
const { uploadQueue, downloadQueue } =
|
156
|
+
await dropboxSync.sync.createSyncQueue({
|
157
|
+
localDir: options?.localDir,
|
158
|
+
dropboxDir: options?.dropboxDir,
|
159
|
+
})
|
160
|
+
|
161
|
+
return {
|
162
|
+
upload: uploadQueue.length,
|
163
|
+
download: downloadQueue.length,
|
164
|
+
}
|
165
|
+
} catch (err) {
|
166
|
+
console.error('Error checking sync status:', err)
|
167
|
+
return { upload: 0, download: 0 }
|
168
|
+
}
|
169
|
+
},
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
// Export singleton instance
|
174
|
+
export const dropbox = createDropboxStore()
|
@@ -0,0 +1,120 @@
|
|
1
|
+
// SvelteKit server routes for Dropbox integration
|
2
|
+
// For a private module, you would import from your private registry or local path
|
3
|
+
// import { createSvelteKitHandlers } from '@yourcompany/dropbox-sync';
|
4
|
+
import { createSvelteKitHandlers } from 'dropbox-sync'
|
5
|
+
import { Server } from 'socket.io'
|
6
|
+
import type { RequestEvent } from '@sveltejs/kit'
|
7
|
+
|
8
|
+
// Create all the route handlers
|
9
|
+
export const handlers = createSvelteKitHandlers()
|
10
|
+
|
11
|
+
// Status endpoint handler
|
12
|
+
export async function handleStatus(event: RequestEvent) {
|
13
|
+
return handlers.status({ cookies: event.cookies })
|
14
|
+
}
|
15
|
+
|
16
|
+
// OAuth start endpoint handler
|
17
|
+
export async function handleOAuthStart() {
|
18
|
+
return handlers.oauthStart()
|
19
|
+
}
|
20
|
+
|
21
|
+
// OAuth callback endpoint handler
|
22
|
+
export async function handleOAuthCallback(event: RequestEvent) {
|
23
|
+
return handlers.oauthCallback({
|
24
|
+
url: new URL(event.request.url),
|
25
|
+
cookies: event.cookies,
|
26
|
+
})
|
27
|
+
}
|
28
|
+
|
29
|
+
// Logout endpoint handler
|
30
|
+
export async function handleLogout(event: RequestEvent) {
|
31
|
+
return handlers.logout({ cookies: event.cookies })
|
32
|
+
}
|
33
|
+
|
34
|
+
// Setup Socket.IO for SvelteKit
|
35
|
+
let io: Server
|
36
|
+
|
37
|
+
export function getSocketIO(server: any) {
|
38
|
+
if (!io) {
|
39
|
+
io = new Server(server)
|
40
|
+
|
41
|
+
io.on('connection', (socket) => {
|
42
|
+
console.log('Client connected:', socket.id)
|
43
|
+
|
44
|
+
// Handle sync start request
|
45
|
+
socket.on('dropbox:sync', async () => {
|
46
|
+
try {
|
47
|
+
// In a real implementation, this would use the server-side Dropbox client
|
48
|
+
// to perform the actual sync
|
49
|
+
|
50
|
+
// Emit queue information
|
51
|
+
socket.emit('sync:queue', {
|
52
|
+
total: 8,
|
53
|
+
totalUploads: 3,
|
54
|
+
totalDownloads: 5,
|
55
|
+
})
|
56
|
+
|
57
|
+
// Simulate sync process with progress updates
|
58
|
+
let progress = 0
|
59
|
+
const interval = setInterval(() => {
|
60
|
+
progress += 12.5 // 8 total files, so each is 12.5%
|
61
|
+
|
62
|
+
if (progress <= 100) {
|
63
|
+
socket.emit('sync:progress', {
|
64
|
+
progress,
|
65
|
+
message: `Processing files... ${Math.round(
|
66
|
+
progress
|
67
|
+
)}%`,
|
68
|
+
type: progress < 50 ? 'upload' : 'download',
|
69
|
+
})
|
70
|
+
}
|
71
|
+
|
72
|
+
if (progress >= 100) {
|
73
|
+
clearInterval(interval)
|
74
|
+
socket.emit('sync:complete', {
|
75
|
+
message: 'Sync completed successfully',
|
76
|
+
stats: {
|
77
|
+
uploaded: 3,
|
78
|
+
downloaded: 5,
|
79
|
+
},
|
80
|
+
})
|
81
|
+
}
|
82
|
+
}, 600)
|
83
|
+
|
84
|
+
// Store the interval for cancellation
|
85
|
+
socket.data.syncInterval = interval
|
86
|
+
} catch (error: any) {
|
87
|
+
console.error('Error syncing with Dropbox:', error)
|
88
|
+
socket.emit('sync:error', {
|
89
|
+
message:
|
90
|
+
error.message || 'An error occurred during sync',
|
91
|
+
})
|
92
|
+
}
|
93
|
+
})
|
94
|
+
|
95
|
+
// Handle sync cancel request
|
96
|
+
socket.on('sync:cancel', () => {
|
97
|
+
if (socket.data.syncInterval) {
|
98
|
+
clearInterval(socket.data.syncInterval)
|
99
|
+
delete socket.data.syncInterval
|
100
|
+
}
|
101
|
+
|
102
|
+
socket.emit('sync:complete', {
|
103
|
+
message: 'Sync cancelled by user',
|
104
|
+
})
|
105
|
+
})
|
106
|
+
|
107
|
+
// Handle disconnect
|
108
|
+
socket.on('disconnect', () => {
|
109
|
+
console.log('Client disconnected:', socket.id)
|
110
|
+
|
111
|
+
// Clean up any ongoing operations
|
112
|
+
if (socket.data.syncInterval) {
|
113
|
+
clearInterval(socket.data.syncInterval)
|
114
|
+
}
|
115
|
+
})
|
116
|
+
})
|
117
|
+
}
|
118
|
+
|
119
|
+
return io
|
120
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
{
|
2
|
+
"name": "@rsweeten/dropbox-sync",
|
3
|
+
"version": "0.1.0",
|
4
|
+
"description": "Reusable Dropbox synchronization module with framework adapters",
|
5
|
+
"private": false,
|
6
|
+
"publishConfig": {
|
7
|
+
"access": "public"
|
8
|
+
},
|
9
|
+
"main": "dist/index.js",
|
10
|
+
"types": "dist/index.d.ts",
|
11
|
+
"scripts": {
|
12
|
+
"build": "tsc",
|
13
|
+
"test": "jest",
|
14
|
+
"prepublishOnly": "npm run build"
|
15
|
+
},
|
16
|
+
"keywords": [
|
17
|
+
"dropbox",
|
18
|
+
"sync",
|
19
|
+
"upload",
|
20
|
+
"download",
|
21
|
+
"file-sync"
|
22
|
+
],
|
23
|
+
"author": "",
|
24
|
+
"license": "MIT",
|
25
|
+
"dependencies": {
|
26
|
+
"dropbox": "^10.34.0",
|
27
|
+
"socket.io": "^4.7.2",
|
28
|
+
"socket.io-client": "^4.7.2"
|
29
|
+
},
|
30
|
+
"devDependencies": {
|
31
|
+
"@angular/common": "^19.2.11",
|
32
|
+
"@angular/core": "^19.2.11",
|
33
|
+
"@sveltejs/kit": "^2.21.1",
|
34
|
+
"@types/angular": "^1.8.9",
|
35
|
+
"@types/jest": "^29.5.1",
|
36
|
+
"@types/node": "^20.1.0",
|
37
|
+
"h3": "^1.11.1",
|
38
|
+
"jest": "^29.5.0",
|
39
|
+
"next": "^15.3.2",
|
40
|
+
"nuxt": "^3.10.3",
|
41
|
+
"rxjs": "^7.8.2",
|
42
|
+
"svelte": "^5.31.1",
|
43
|
+
"ts-jest": "^29.1.0",
|
44
|
+
"typescript": "^5.0.4"
|
45
|
+
},
|
46
|
+
"peerDependencies": {
|
47
|
+
"@angular/core": ">=14.0.0",
|
48
|
+
"next": ">=13.0.0",
|
49
|
+
"nuxt": ">=3.0.0",
|
50
|
+
"svelte": ">=3.0.0"
|
51
|
+
},
|
52
|
+
"peerDependenciesMeta": {
|
53
|
+
"next": {
|
54
|
+
"optional": true
|
55
|
+
},
|
56
|
+
"svelte": {
|
57
|
+
"optional": true
|
58
|
+
},
|
59
|
+
"@angular/core": {
|
60
|
+
"optional": true
|
61
|
+
},
|
62
|
+
"nuxt": {
|
63
|
+
"optional": true
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
@@ -0,0 +1,217 @@
|
|
1
|
+
import { Injectable } from '@angular/core'
|
2
|
+
import { HttpClient, HttpHeaders } from '@angular/common/http'
|
3
|
+
import { Observable, from, of } from 'rxjs'
|
4
|
+
import { catchError, map, switchMap, tap } from 'rxjs/operators'
|
5
|
+
import { createDropboxSyncClient } from '../core/client'
|
6
|
+
import type {
|
7
|
+
DropboxCredentials,
|
8
|
+
DropboxSyncClient,
|
9
|
+
SyncOptions,
|
10
|
+
SyncResult,
|
11
|
+
TokenResponse,
|
12
|
+
} from '../core/types'
|
13
|
+
|
14
|
+
@Injectable({
|
15
|
+
providedIn: 'root',
|
16
|
+
})
|
17
|
+
export class DropboxSyncService {
|
18
|
+
private client: DropboxSyncClient | null = null
|
19
|
+
|
20
|
+
constructor(private http: HttpClient) {}
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Initialize the Dropbox sync client with credentials
|
24
|
+
*/
|
25
|
+
initialize(credentials: DropboxCredentials): DropboxSyncClient {
|
26
|
+
this.client = createDropboxSyncClient(credentials)
|
27
|
+
return this.client
|
28
|
+
}
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Get the current Dropbox sync client instance, or initialize with credentials if not exists
|
32
|
+
*/
|
33
|
+
getClient(credentials?: DropboxCredentials): DropboxSyncClient {
|
34
|
+
if (!this.client && credentials) {
|
35
|
+
return this.initialize(credentials)
|
36
|
+
}
|
37
|
+
|
38
|
+
if (!this.client) {
|
39
|
+
throw new Error(
|
40
|
+
'DropboxSyncService not initialized. Call initialize() first.'
|
41
|
+
)
|
42
|
+
}
|
43
|
+
|
44
|
+
return this.client
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Check the connection status with Dropbox
|
49
|
+
*/
|
50
|
+
checkConnection(): Observable<boolean> {
|
51
|
+
return this.http
|
52
|
+
.get<{ connected: boolean }>('/api/dropbox/status')
|
53
|
+
.pipe(
|
54
|
+
map((response: any) => response.connected),
|
55
|
+
catchError(() => of(false))
|
56
|
+
)
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Start the OAuth flow to connect to Dropbox
|
61
|
+
*/
|
62
|
+
connectDropbox(): void {
|
63
|
+
window.location.href = '/api/dropbox/auth/start'
|
64
|
+
}
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Disconnect from Dropbox
|
68
|
+
*/
|
69
|
+
disconnectDropbox(): Observable<boolean> {
|
70
|
+
return this.http
|
71
|
+
.post<{ success: boolean }>('/api/dropbox/logout', {})
|
72
|
+
.pipe(
|
73
|
+
map((response: any) => response.success),
|
74
|
+
catchError(() => of(false))
|
75
|
+
)
|
76
|
+
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Start the sync process
|
80
|
+
*/
|
81
|
+
startSync(options?: Partial<SyncOptions>): Observable<SyncResult> {
|
82
|
+
if (!this.client) {
|
83
|
+
throw new Error(
|
84
|
+
'DropboxSyncService not initialized. Call initialize() first.'
|
85
|
+
)
|
86
|
+
}
|
87
|
+
|
88
|
+
// Connect to socket before starting sync
|
89
|
+
this.client.socket.connect()
|
90
|
+
|
91
|
+
// Setup socket listeners for sync events
|
92
|
+
this.setupSocketListeners()
|
93
|
+
|
94
|
+
return from(this.client.sync.syncFiles(options))
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Cancel an ongoing sync process
|
99
|
+
*/
|
100
|
+
cancelSync(): void {
|
101
|
+
if (!this.client) {
|
102
|
+
return
|
103
|
+
}
|
104
|
+
|
105
|
+
this.client.sync.cancelSync()
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Set up socket listeners for sync events
|
110
|
+
* Returns an RxJS Observable that emits sync progress events
|
111
|
+
*/
|
112
|
+
setupSocketListeners(): Observable<any> {
|
113
|
+
if (!this.client) {
|
114
|
+
throw new Error(
|
115
|
+
'DropboxSyncService not initialized. Call initialize() first.'
|
116
|
+
)
|
117
|
+
}
|
118
|
+
|
119
|
+
// Create observable for sync progress events
|
120
|
+
return new Observable((observer: any) => {
|
121
|
+
// Listen for progress updates
|
122
|
+
this.client!.socket.on('sync:progress', (data: any) => {
|
123
|
+
observer.next({ type: 'progress', data })
|
124
|
+
})
|
125
|
+
|
126
|
+
// Listen for queue information
|
127
|
+
this.client!.socket.on('sync:queue', (data: any) => {
|
128
|
+
observer.next({ type: 'queue', data })
|
129
|
+
})
|
130
|
+
|
131
|
+
// Listen for sync completion
|
132
|
+
this.client!.socket.on('sync:complete', (data: any) => {
|
133
|
+
observer.next({ type: 'complete', data })
|
134
|
+
observer.complete()
|
135
|
+
})
|
136
|
+
|
137
|
+
// Listen for sync errors
|
138
|
+
this.client!.socket.on('sync:error', (data: any) => {
|
139
|
+
if (!data.continue) {
|
140
|
+
observer.error(data.message)
|
141
|
+
} else {
|
142
|
+
observer.next({ type: 'error', data })
|
143
|
+
}
|
144
|
+
})
|
145
|
+
|
146
|
+
// Cleanup function - remove event listeners when subscription is disposed
|
147
|
+
return () => {
|
148
|
+
this.client!.socket.off('sync:progress')
|
149
|
+
this.client!.socket.off('sync:queue')
|
150
|
+
this.client!.socket.off('sync:complete')
|
151
|
+
this.client!.socket.off('sync:error')
|
152
|
+
}
|
153
|
+
})
|
154
|
+
}
|
155
|
+
|
156
|
+
/**
|
157
|
+
* Handle OAuth callback on the client side
|
158
|
+
*/
|
159
|
+
handleOAuthCallback(code: string): Observable<TokenResponse> {
|
160
|
+
if (!this.client) {
|
161
|
+
throw new Error(
|
162
|
+
'DropboxSyncService not initialized. Call initialize() first.'
|
163
|
+
)
|
164
|
+
}
|
165
|
+
|
166
|
+
const redirectUri =
|
167
|
+
window.location.origin + '/api/dropbox/auth/callback'
|
168
|
+
|
169
|
+
return from(
|
170
|
+
this.client.auth.exchangeCodeForToken(code, redirectUri)
|
171
|
+
).pipe(
|
172
|
+
tap((tokens: any) => {
|
173
|
+
// Store tokens in local storage for client-side access
|
174
|
+
localStorage.setItem('dropbox_access_token', tokens.accessToken)
|
175
|
+
|
176
|
+
if (tokens.refreshToken) {
|
177
|
+
localStorage.setItem(
|
178
|
+
'dropbox_refresh_token',
|
179
|
+
tokens.refreshToken
|
180
|
+
)
|
181
|
+
}
|
182
|
+
|
183
|
+
localStorage.setItem('dropbox_connected', 'true')
|
184
|
+
})
|
185
|
+
)
|
186
|
+
}
|
187
|
+
|
188
|
+
/**
|
189
|
+
* Create a sync queue to determine which files need to be uploaded/downloaded
|
190
|
+
*/
|
191
|
+
createSyncQueue(
|
192
|
+
options?: Partial<SyncOptions>
|
193
|
+
): Observable<{ uploadQueue: string[]; downloadQueue: string[] }> {
|
194
|
+
if (!this.client) {
|
195
|
+
throw new Error(
|
196
|
+
'DropboxSyncService not initialized. Call initialize() first.'
|
197
|
+
)
|
198
|
+
}
|
199
|
+
|
200
|
+
return from(this.client.sync.createSyncQueue(options))
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
/**
|
205
|
+
* Function to extract credentials from Angular environment
|
206
|
+
*/
|
207
|
+
export function getCredentialsFromEnvironment(
|
208
|
+
environment: any
|
209
|
+
): DropboxCredentials {
|
210
|
+
return {
|
211
|
+
clientId: environment.dropboxAppKey || '',
|
212
|
+
clientSecret: environment.dropboxAppSecret,
|
213
|
+
accessToken: localStorage.getItem('dropbox_access_token') || undefined,
|
214
|
+
refreshToken:
|
215
|
+
localStorage.getItem('dropbox_refresh_token') || undefined,
|
216
|
+
}
|
217
|
+
}
|