@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/src/core/sync.ts
ADDED
@@ -0,0 +1,476 @@
|
|
1
|
+
import path from 'path'
|
2
|
+
import fs from 'fs'
|
3
|
+
import { Dropbox } from 'dropbox'
|
4
|
+
import type {
|
5
|
+
DropboxCredentials,
|
6
|
+
SyncMethods,
|
7
|
+
SyncOptions,
|
8
|
+
SyncResult,
|
9
|
+
SyncProgress,
|
10
|
+
ProgressCallback,
|
11
|
+
SocketMethods,
|
12
|
+
} from './types'
|
13
|
+
|
14
|
+
// Define interface for Dropbox file entries
|
15
|
+
interface DropboxFileEntry {
|
16
|
+
'.tag': string;
|
17
|
+
path_display?: string;
|
18
|
+
[key: string]: any;
|
19
|
+
}
|
20
|
+
|
21
|
+
// Define interface for Dropbox API responses
|
22
|
+
interface DropboxListFolderResponse {
|
23
|
+
result: {
|
24
|
+
entries: DropboxFileEntry[];
|
25
|
+
has_more: boolean;
|
26
|
+
cursor: string;
|
27
|
+
};
|
28
|
+
}
|
29
|
+
|
30
|
+
interface DropboxDownloadResponse {
|
31
|
+
result: {
|
32
|
+
fileBlob?: Blob;
|
33
|
+
fileBinary?: string;
|
34
|
+
[key: string]: any;
|
35
|
+
};
|
36
|
+
}
|
37
|
+
|
38
|
+
export function createSyncMethods(
|
39
|
+
getClient: () => Dropbox,
|
40
|
+
credentials: DropboxCredentials,
|
41
|
+
socket: SocketMethods
|
42
|
+
): SyncMethods {
|
43
|
+
let syncCancelled = false
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Normalize path for consistent comparison between local and Dropbox paths
|
47
|
+
*/
|
48
|
+
function normalizePath(filePath: string): string {
|
49
|
+
// Remove any leading slashes for consistency, then add a single leading slash
|
50
|
+
return '/' + filePath.replace(/^\/+/, '').toLowerCase()
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Convert blob/buffer types to Buffer
|
55
|
+
*/
|
56
|
+
async function blobToBuffer(data: any): Promise<Buffer> {
|
57
|
+
// If it's already a Buffer, return it directly
|
58
|
+
if (Buffer.isBuffer(data)) {
|
59
|
+
return data
|
60
|
+
}
|
61
|
+
|
62
|
+
// If it's a Blob, convert it to a Buffer
|
63
|
+
if (typeof Blob !== 'undefined' && data instanceof Blob) {
|
64
|
+
const arrayBuffer = await data.arrayBuffer()
|
65
|
+
return Buffer.from(arrayBuffer)
|
66
|
+
}
|
67
|
+
|
68
|
+
// If it's a plain ArrayBuffer
|
69
|
+
if (data instanceof ArrayBuffer) {
|
70
|
+
return Buffer.from(data)
|
71
|
+
}
|
72
|
+
|
73
|
+
// If it's a string
|
74
|
+
if (typeof data === 'string') {
|
75
|
+
return Buffer.from(data)
|
76
|
+
}
|
77
|
+
|
78
|
+
// If we don't know what it is, throw an error
|
79
|
+
throw new Error(`Unsupported data type: ${typeof data}`)
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Recursively scan local directory for files to sync
|
84
|
+
*/
|
85
|
+
async function scanLocalDirectory(
|
86
|
+
dir: string,
|
87
|
+
baseDir = ''
|
88
|
+
): Promise<string[]> {
|
89
|
+
const files: string[] = []
|
90
|
+
|
91
|
+
try {
|
92
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
93
|
+
|
94
|
+
for (const entry of entries) {
|
95
|
+
const fullPath = path.join(dir, entry.name)
|
96
|
+
const relativePath = path.join(baseDir, entry.name)
|
97
|
+
|
98
|
+
if (entry.isDirectory()) {
|
99
|
+
files.push(
|
100
|
+
...(await scanLocalDirectory(fullPath, relativePath))
|
101
|
+
)
|
102
|
+
} else if (
|
103
|
+
/\.(jpg|jpeg|png|gif|bmp|webp|svg|json)$/i.test(entry.name)
|
104
|
+
) {
|
105
|
+
// Only include image files by default
|
106
|
+
files.push('/' + relativePath.replace(/\\/g, '/'))
|
107
|
+
}
|
108
|
+
}
|
109
|
+
} catch (error) {
|
110
|
+
console.error(`Error scanning directory ${dir}:`, error)
|
111
|
+
}
|
112
|
+
|
113
|
+
return files
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Recursively scan Dropbox folder for files
|
118
|
+
*/
|
119
|
+
async function scanDropboxFolder(
|
120
|
+
dropboxPath: string = ''
|
121
|
+
): Promise<string[]> {
|
122
|
+
const dropbox = getClient()
|
123
|
+
const files: string[] = []
|
124
|
+
|
125
|
+
async function fetchFolderContents(path: string) {
|
126
|
+
try {
|
127
|
+
const response = await dropbox.filesListFolder({
|
128
|
+
path,
|
129
|
+
recursive: true,
|
130
|
+
}) as unknown as DropboxListFolderResponse
|
131
|
+
|
132
|
+
for (const entry of response.result.entries) {
|
133
|
+
if (
|
134
|
+
entry['.tag'] === 'file' &&
|
135
|
+
entry.path_display &&
|
136
|
+
/\.(jpg|jpeg|png|gif|bmp|webp|svg|json)$/i.test(
|
137
|
+
entry.path_display
|
138
|
+
)
|
139
|
+
) {
|
140
|
+
files.push(entry.path_display)
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
if (response.result.has_more) {
|
145
|
+
await continueListing(response.result.cursor)
|
146
|
+
}
|
147
|
+
} catch (error) {
|
148
|
+
console.error('Error fetching Dropbox folder contents:', error)
|
149
|
+
throw error
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
async function continueListing(cursor: string) {
|
154
|
+
const response = await dropbox.filesListFolderContinue({
|
155
|
+
cursor: cursor,
|
156
|
+
}) as unknown as DropboxListFolderResponse
|
157
|
+
|
158
|
+
for (const entry of response.result.entries) {
|
159
|
+
if (
|
160
|
+
entry['.tag'] === 'file' &&
|
161
|
+
entry.path_display &&
|
162
|
+
/\.(jpg|jpeg|png|gif|bmp|webp|svg|json)$/i.test(
|
163
|
+
entry.path_display
|
164
|
+
)
|
165
|
+
) {
|
166
|
+
files.push(entry.path_display)
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
if (response.result.has_more) {
|
171
|
+
await continueListing(response.result.cursor)
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
await fetchFolderContents(dropboxPath)
|
176
|
+
return files
|
177
|
+
}
|
178
|
+
|
179
|
+
return {
|
180
|
+
/**
|
181
|
+
* Scan local directory for files
|
182
|
+
*/
|
183
|
+
async scanLocalFiles(dir?: string): Promise<string[]> {
|
184
|
+
if (!dir && typeof window === 'undefined') {
|
185
|
+
throw new Error(
|
186
|
+
'Local directory must be provided in Node.js environment'
|
187
|
+
)
|
188
|
+
}
|
189
|
+
|
190
|
+
const localDir = dir || path.join(process.cwd(), 'public', 'img')
|
191
|
+
return scanLocalDirectory(localDir)
|
192
|
+
},
|
193
|
+
|
194
|
+
/**
|
195
|
+
* Scan Dropbox folder for files
|
196
|
+
*/
|
197
|
+
async scanDropboxFiles(dir?: string): Promise<string[]> {
|
198
|
+
const dropboxDir = dir || ''
|
199
|
+
return scanDropboxFolder(dropboxDir)
|
200
|
+
},
|
201
|
+
|
202
|
+
/**
|
203
|
+
* Compare local and Dropbox files and create a sync queue
|
204
|
+
*/
|
205
|
+
async createSyncQueue(
|
206
|
+
options?: Partial<SyncOptions>
|
207
|
+
): Promise<{ uploadQueue: string[]; downloadQueue: string[] }> {
|
208
|
+
const localDir =
|
209
|
+
options?.localDir || path.join(process.cwd(), 'public', 'img')
|
210
|
+
const dropboxDir = options?.dropboxDir || ''
|
211
|
+
|
212
|
+
const localFiles = await scanLocalDirectory(localDir)
|
213
|
+
const dropboxFiles = await scanDropboxFolder(dropboxDir)
|
214
|
+
|
215
|
+
// Normalize paths for comparison
|
216
|
+
const normalizedDropboxFiles = dropboxFiles.map(normalizePath)
|
217
|
+
const normalizedLocalFiles = localFiles.map(normalizePath)
|
218
|
+
|
219
|
+
// Files to upload (in local but not in Dropbox)
|
220
|
+
const uploadQueue = localFiles.filter((localFile) => {
|
221
|
+
const normalizedLocalFile = normalizePath(localFile)
|
222
|
+
return !normalizedDropboxFiles.includes(normalizedLocalFile)
|
223
|
+
})
|
224
|
+
|
225
|
+
// Files to download (in Dropbox but not in local)
|
226
|
+
const downloadQueue = dropboxFiles.filter((dropboxFile) => {
|
227
|
+
const normalizedDropboxFile = normalizePath(dropboxFile)
|
228
|
+
return !normalizedLocalFiles.includes(normalizedDropboxFile)
|
229
|
+
})
|
230
|
+
|
231
|
+
return { uploadQueue, downloadQueue }
|
232
|
+
},
|
233
|
+
|
234
|
+
/**
|
235
|
+
* Synchronize files between local filesystem and Dropbox
|
236
|
+
*/
|
237
|
+
async syncFiles(options?: Partial<SyncOptions>): Promise<SyncResult> {
|
238
|
+
const localDir =
|
239
|
+
options?.localDir || path.join(process.cwd(), 'public', 'img')
|
240
|
+
const dropboxDir = options?.dropboxDir || ''
|
241
|
+
const progressCallback = options?.progressCallback
|
242
|
+
|
243
|
+
syncCancelled = false
|
244
|
+
const result: SyncResult = {
|
245
|
+
uploaded: [],
|
246
|
+
downloaded: [],
|
247
|
+
errors: [],
|
248
|
+
}
|
249
|
+
|
250
|
+
// Report initial progress
|
251
|
+
const reportProgress = (progress: SyncProgress) => {
|
252
|
+
if (progressCallback) {
|
253
|
+
progressCallback(progress)
|
254
|
+
}
|
255
|
+
|
256
|
+
// Also emit via Socket.IO if available
|
257
|
+
if (progress.progress !== undefined && progress.message) {
|
258
|
+
socket.emit('sync:progress', {
|
259
|
+
type: progress.type || 'progress',
|
260
|
+
message: progress.message,
|
261
|
+
progress: progress.progress,
|
262
|
+
socketId: 'dropbox-sync-module',
|
263
|
+
})
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
reportProgress({
|
268
|
+
stage: 'init',
|
269
|
+
progress: 0,
|
270
|
+
message: 'Starting Dropbox synchronization',
|
271
|
+
})
|
272
|
+
|
273
|
+
try {
|
274
|
+
// Get the Dropbox client
|
275
|
+
const dropbox = getClient()
|
276
|
+
|
277
|
+
// Get files to sync
|
278
|
+
reportProgress({
|
279
|
+
stage: 'listing',
|
280
|
+
message: 'Analyzing files to sync...',
|
281
|
+
progress: 0,
|
282
|
+
})
|
283
|
+
|
284
|
+
const { uploadQueue, downloadQueue } =
|
285
|
+
await this.createSyncQueue({ localDir, dropboxDir })
|
286
|
+
const totalTasks = uploadQueue.length + downloadQueue.length
|
287
|
+
|
288
|
+
// Socket notification about queue
|
289
|
+
socket.emit('sync:queue', {
|
290
|
+
total: totalTasks,
|
291
|
+
totalUploads: uploadQueue.length,
|
292
|
+
totalDownloads: downloadQueue.length,
|
293
|
+
})
|
294
|
+
|
295
|
+
if (totalTasks === 0) {
|
296
|
+
reportProgress({
|
297
|
+
stage: 'complete',
|
298
|
+
progress: 100,
|
299
|
+
message: 'All files are already in sync',
|
300
|
+
})
|
301
|
+
|
302
|
+
socket.emit('sync:complete', {
|
303
|
+
message: 'All files are already in sync',
|
304
|
+
})
|
305
|
+
|
306
|
+
return result
|
307
|
+
}
|
308
|
+
|
309
|
+
let completedTasks = 0
|
310
|
+
|
311
|
+
// Upload files to Dropbox
|
312
|
+
for (const file of uploadQueue) {
|
313
|
+
if (syncCancelled) {
|
314
|
+
break
|
315
|
+
}
|
316
|
+
|
317
|
+
try {
|
318
|
+
reportProgress({
|
319
|
+
stage: 'processing',
|
320
|
+
type: 'upload',
|
321
|
+
current: completedTasks + 1,
|
322
|
+
total: totalTasks,
|
323
|
+
progress: Math.round(
|
324
|
+
(completedTasks / totalTasks) * 100
|
325
|
+
),
|
326
|
+
message: `Uploading: ${file}`,
|
327
|
+
item: file,
|
328
|
+
})
|
329
|
+
|
330
|
+
// Upload logic
|
331
|
+
const localFilePath = path.join(
|
332
|
+
localDir,
|
333
|
+
file.replace(/^\/+/, '')
|
334
|
+
)
|
335
|
+
const dropboxFilePath = '/' + file.replace(/^\/+/, '')
|
336
|
+
const fileContent = fs.readFileSync(localFilePath)
|
337
|
+
|
338
|
+
await dropbox.filesUpload({
|
339
|
+
path: dropboxFilePath,
|
340
|
+
contents: fileContent,
|
341
|
+
mode: { '.tag': 'overwrite' },
|
342
|
+
})
|
343
|
+
|
344
|
+
result.uploaded.push(file)
|
345
|
+
completedTasks++
|
346
|
+
} catch (error) {
|
347
|
+
result.errors.push({ file, error: error as Error })
|
348
|
+
console.error(`Error uploading file ${file}:`, error)
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
// Download files from Dropbox
|
353
|
+
for (const file of downloadQueue) {
|
354
|
+
if (syncCancelled) {
|
355
|
+
break
|
356
|
+
}
|
357
|
+
|
358
|
+
try {
|
359
|
+
reportProgress({
|
360
|
+
stage: 'processing',
|
361
|
+
type: 'download',
|
362
|
+
current: completedTasks + 1,
|
363
|
+
total: totalTasks,
|
364
|
+
progress: Math.round(
|
365
|
+
(completedTasks / totalTasks) * 100
|
366
|
+
),
|
367
|
+
message: `Downloading: ${file}`,
|
368
|
+
item: file,
|
369
|
+
})
|
370
|
+
|
371
|
+
// Download logic
|
372
|
+
const dropboxFilePath = file
|
373
|
+
const localRelativePath = file.replace(/^\/+/, '')
|
374
|
+
const localFilePath = path.join(
|
375
|
+
localDir,
|
376
|
+
localRelativePath
|
377
|
+
)
|
378
|
+
|
379
|
+
// Download the file from Dropbox with proper error handling
|
380
|
+
const response = await dropbox.filesDownload({
|
381
|
+
path: dropboxFilePath,
|
382
|
+
}) as unknown as DropboxDownloadResponse
|
383
|
+
|
384
|
+
// Get file content - handle different possible response formats
|
385
|
+
let fileContent: Buffer;
|
386
|
+
const responseResult = response.result;
|
387
|
+
|
388
|
+
if (responseResult.fileBlob) {
|
389
|
+
fileContent = await blobToBuffer(responseResult.fileBlob)
|
390
|
+
} else if (responseResult.fileBinary) {
|
391
|
+
fileContent = Buffer.from(
|
392
|
+
responseResult.fileBinary,
|
393
|
+
'binary'
|
394
|
+
)
|
395
|
+
} else {
|
396
|
+
// For Node.js environment, Dropbox might return content in different properties
|
397
|
+
const contentKey = Object.keys(responseResult).find(
|
398
|
+
(key) => ['content', 'fileContent', 'file', 'data'].includes(key)
|
399
|
+
)
|
400
|
+
|
401
|
+
if (contentKey) {
|
402
|
+
fileContent = Buffer.from(responseResult[contentKey])
|
403
|
+
} else {
|
404
|
+
throw new Error(
|
405
|
+
`Could not find file content in Dropbox response for ${dropboxFilePath}`
|
406
|
+
)
|
407
|
+
}
|
408
|
+
}
|
409
|
+
|
410
|
+
// Create directory if it doesn't exist
|
411
|
+
const dirPath = path.dirname(localFilePath)
|
412
|
+
if (!fs.existsSync(dirPath)) {
|
413
|
+
fs.mkdirSync(dirPath, { recursive: true })
|
414
|
+
}
|
415
|
+
|
416
|
+
// Write the file to disk
|
417
|
+
fs.writeFileSync(localFilePath, fileContent)
|
418
|
+
|
419
|
+
result.downloaded.push(file)
|
420
|
+
completedTasks++
|
421
|
+
} catch (error) {
|
422
|
+
result.errors.push({ file, error: error as Error })
|
423
|
+
console.error(`Error downloading file ${file}:`, error)
|
424
|
+
|
425
|
+
// Emit error but continue with the next file
|
426
|
+
socket.emit('sync:error', {
|
427
|
+
message: `Error downloading ${file}: ${
|
428
|
+
(error as Error).message
|
429
|
+
}`,
|
430
|
+
continue: true,
|
431
|
+
})
|
432
|
+
}
|
433
|
+
}
|
434
|
+
|
435
|
+
// Report completion
|
436
|
+
reportProgress({
|
437
|
+
stage: 'complete',
|
438
|
+
progress: 100,
|
439
|
+
message: 'Synchronization completed successfully',
|
440
|
+
})
|
441
|
+
|
442
|
+
// Sync complete notification
|
443
|
+
socket.emit('sync:complete', {
|
444
|
+
message: 'Synchronization completed successfully',
|
445
|
+
stats: {
|
446
|
+
uploaded: result.uploaded.length,
|
447
|
+
downloaded: result.downloaded.length,
|
448
|
+
},
|
449
|
+
})
|
450
|
+
} catch (error) {
|
451
|
+
reportProgress({
|
452
|
+
stage: 'error',
|
453
|
+
message: `Error: ${(error as Error).message}`,
|
454
|
+
})
|
455
|
+
|
456
|
+
// Emit error notification
|
457
|
+
socket.emit('sync:error', {
|
458
|
+
message: (error as Error).message,
|
459
|
+
})
|
460
|
+
|
461
|
+
// Re-throw the error for handling by the caller
|
462
|
+
throw error
|
463
|
+
}
|
464
|
+
|
465
|
+
return result
|
466
|
+
},
|
467
|
+
|
468
|
+
/**
|
469
|
+
* Cancel an ongoing synchronization
|
470
|
+
*/
|
471
|
+
cancelSync() {
|
472
|
+
syncCancelled = true
|
473
|
+
socket.emit('sync:cancel', {})
|
474
|
+
},
|
475
|
+
}
|
476
|
+
}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
export interface DropboxCredentials {
|
2
|
+
clientId: string
|
3
|
+
clientSecret?: string
|
4
|
+
accessToken?: string
|
5
|
+
refreshToken?: string
|
6
|
+
}
|
7
|
+
|
8
|
+
export interface SyncOptions {
|
9
|
+
localDir: string
|
10
|
+
dropboxDir?: string
|
11
|
+
fileTypes?: RegExp
|
12
|
+
progressCallback?: ProgressCallback
|
13
|
+
}
|
14
|
+
|
15
|
+
export interface SyncResult {
|
16
|
+
uploaded: string[]
|
17
|
+
downloaded: string[]
|
18
|
+
errors: { file: string; error: Error }[]
|
19
|
+
}
|
20
|
+
|
21
|
+
export interface SyncProgress {
|
22
|
+
stage: 'init' | 'listing' | 'processing' | 'complete' | 'error'
|
23
|
+
current?: number
|
24
|
+
total?: number
|
25
|
+
message?: string
|
26
|
+
item?: string
|
27
|
+
progress?: number
|
28
|
+
type?: 'upload' | 'download'
|
29
|
+
}
|
30
|
+
|
31
|
+
export type ProgressCallback = (progress: SyncProgress) => void
|
32
|
+
|
33
|
+
export interface SyncActivity {
|
34
|
+
type: 'upload' | 'download'
|
35
|
+
file: string
|
36
|
+
timestamp: number
|
37
|
+
}
|
38
|
+
|
39
|
+
export interface SyncStats {
|
40
|
+
total: number
|
41
|
+
uploads: number
|
42
|
+
downloads: number
|
43
|
+
completed: number
|
44
|
+
}
|
45
|
+
|
46
|
+
export interface TokenResponse {
|
47
|
+
accessToken: string
|
48
|
+
refreshToken?: string
|
49
|
+
expiresAt?: number
|
50
|
+
}
|
51
|
+
|
52
|
+
export interface AuthMethods {
|
53
|
+
getAuthUrl(redirectUri: string, state?: string): Promise<string>
|
54
|
+
exchangeCodeForToken(
|
55
|
+
code: string,
|
56
|
+
redirectUri: string
|
57
|
+
): Promise<TokenResponse>
|
58
|
+
refreshAccessToken(): Promise<TokenResponse>
|
59
|
+
}
|
60
|
+
|
61
|
+
export interface SyncMethods {
|
62
|
+
scanLocalFiles(dir?: string): Promise<string[]>
|
63
|
+
scanDropboxFiles(dir?: string): Promise<string[]>
|
64
|
+
createSyncQueue(
|
65
|
+
options?: Partial<SyncOptions>
|
66
|
+
): Promise<{ uploadQueue: string[]; downloadQueue: string[] }>
|
67
|
+
syncFiles(options?: Partial<SyncOptions>): Promise<SyncResult>
|
68
|
+
cancelSync(): void
|
69
|
+
}
|
70
|
+
|
71
|
+
export interface SocketMethods {
|
72
|
+
connect(): void
|
73
|
+
disconnect(): void
|
74
|
+
on(event: string, handler: (...args: any[]) => void): void
|
75
|
+
off(event: string): void
|
76
|
+
emit(event: string, ...args: any[]): void
|
77
|
+
}
|
78
|
+
|
79
|
+
export interface DropboxSyncClient {
|
80
|
+
auth: AuthMethods
|
81
|
+
sync: SyncMethods
|
82
|
+
socket: SocketMethods
|
83
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
// Export all core types and functionality
|
2
|
+
export * from './core/types'
|
3
|
+
export * from './core/auth'
|
4
|
+
export * from './core/client'
|
5
|
+
export * from './core/sync'
|
6
|
+
export * from './core/socket'
|
7
|
+
|
8
|
+
// Export framework-specific adapters with renamed exports to avoid conflicts
|
9
|
+
export {
|
10
|
+
useNextDropboxSync,
|
11
|
+
createNextDropboxApiHandlers,
|
12
|
+
handleOAuthCallback as handleNextOAuthCallback,
|
13
|
+
getCredentialsFromCookies as getNextCredentialsFromCookies,
|
14
|
+
} from './adapters/next'
|
15
|
+
|
16
|
+
export {
|
17
|
+
useSvelteDropboxSync,
|
18
|
+
createSvelteKitHandlers,
|
19
|
+
getCredentialsFromCookies as getSvelteCredentialsFromCookies,
|
20
|
+
} from './adapters/svelte'
|
21
|
+
|
22
|
+
export {
|
23
|
+
useNuxtDropboxSync,
|
24
|
+
createNuxtApiHandlers,
|
25
|
+
getCredentialsFromCookies as getNuxtCredentialsFromCookies,
|
26
|
+
} from './adapters/nuxt'
|
27
|
+
|
28
|
+
export * from './adapters/angular'
|
29
|
+
|
30
|
+
// Export default client creator function
|
31
|
+
import { createDropboxSyncClient } from './core/client'
|
32
|
+
export default createDropboxSyncClient
|
package/tsconfig.json
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "ES2020",
|
4
|
+
"module": "ESNext",
|
5
|
+
"moduleResolution": "node",
|
6
|
+
"esModuleInterop": true,
|
7
|
+
"strict": true,
|
8
|
+
"declaration": true,
|
9
|
+
"outDir": "./dist",
|
10
|
+
"rootDir": "./src",
|
11
|
+
"lib": ["DOM", "ESNext"],
|
12
|
+
"skipLibCheck": true
|
13
|
+
},
|
14
|
+
"include": ["src/**/*"],
|
15
|
+
"exclude": ["node_modules", "dist", "examples", "**/*.test.ts"]
|
16
|
+
}
|