Skip to content

Commit dd4e18b

Browse files
committed
fix(dropbox): align integration with Dropbox API docs, add revision/sharing tools
- fix search root-path bug: Dropbox requires "" not "/" for root, same fix already applied to list_folder - fix create_shared_link to return the existing link's metadata (url) when Dropbox reports shared_link_already_exists with matching settings, instead of just erroring - fix upload route autorename default (was true, Dropbox's documented default is false) - trim() all path/fromPath/toPath/rev params to guard against copy-pasted whitespace - mark nullable output fields (id, size, path_display, etc.) optional: true so folder/deleted items don't imply always-present file fields - widen path_display/path_lower types to optional, matching the real API - add dropbox_list_shared_links, dropbox_list_revisions, dropbox_restore tools + block wiring, filling gaps flagged during the audit (revision history/version recovery, and a companion to create_shared_link for looking up existing links)
1 parent 3ddf254 commit dd4e18b

18 files changed

Lines changed: 518 additions & 44 deletions

File tree

apps/sim/app/api/tools/dropbox/upload/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
8989
const dropboxApiArg = {
9090
path: finalPath,
9191
mode: validatedData.mode || 'add',
92-
autorename: validatedData.autorename ?? true,
92+
autorename: validatedData.autorename ?? false,
9393
mute: validatedData.mute ?? false,
9494
}
9595

apps/sim/blocks/blocks/dropbox.ts

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ export const DropboxBlock: BlockConfig<DropboxResponse> = {
3333
{ label: 'Move File/Folder', id: 'dropbox_move' },
3434
{ label: 'Get Metadata', id: 'dropbox_get_metadata' },
3535
{ label: 'Create Shared Link', id: 'dropbox_create_shared_link' },
36+
{ label: 'List Shared Links', id: 'dropbox_list_shared_links' },
3637
{ label: 'Search Files', id: 'dropbox_search' },
38+
{ label: 'List Revisions', id: 'dropbox_list_revisions' },
39+
{ label: 'Restore File', id: 'dropbox_restore' },
3740
],
3841
value: () => 'dropbox_upload',
3942
},
@@ -299,6 +302,55 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
299302
placeholder: '100',
300303
condition: { field: 'operation', value: 'dropbox_search' },
301304
},
305+
// List shared links operation inputs
306+
{
307+
id: 'path',
308+
title: 'Path',
309+
type: 'short-input',
310+
placeholder: '/ (all links) or /folder',
311+
condition: { field: 'operation', value: 'dropbox_list_shared_links' },
312+
},
313+
{
314+
id: 'directOnly',
315+
title: 'Direct Links Only',
316+
type: 'switch',
317+
condition: { field: 'operation', value: 'dropbox_list_shared_links' },
318+
mode: 'advanced',
319+
},
320+
// List revisions operation inputs
321+
{
322+
id: 'path',
323+
title: 'File Path',
324+
type: 'short-input',
325+
placeholder: '/folder/document.pdf',
326+
condition: { field: 'operation', value: 'dropbox_list_revisions' },
327+
required: true,
328+
},
329+
{
330+
id: 'limit',
331+
title: 'Maximum Revisions',
332+
type: 'short-input',
333+
placeholder: '10',
334+
condition: { field: 'operation', value: 'dropbox_list_revisions' },
335+
mode: 'advanced',
336+
},
337+
// Restore operation inputs
338+
{
339+
id: 'path',
340+
title: 'File Path',
341+
type: 'short-input',
342+
placeholder: '/folder/document.pdf',
343+
condition: { field: 'operation', value: 'dropbox_restore' },
344+
required: true,
345+
},
346+
{
347+
id: 'rev',
348+
title: 'Revision',
349+
type: 'short-input',
350+
placeholder: 'a1c10ce0dd78',
351+
condition: { field: 'operation', value: 'dropbox_restore' },
352+
required: true,
353+
},
302354
],
303355
tools: {
304356
access: [
@@ -311,7 +363,10 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
311363
'dropbox_move',
312364
'dropbox_get_metadata',
313365
'dropbox_create_shared_link',
366+
'dropbox_list_shared_links',
314367
'dropbox_search',
368+
'dropbox_list_revisions',
369+
'dropbox_restore',
315370
],
316371
config: {
317372
tool: (params) => {
@@ -334,8 +389,14 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
334389
return 'dropbox_get_metadata'
335390
case 'dropbox_create_shared_link':
336391
return 'dropbox_create_shared_link'
392+
case 'dropbox_list_shared_links':
393+
return 'dropbox_list_shared_links'
337394
case 'dropbox_search':
338395
return 'dropbox_search'
396+
case 'dropbox_list_revisions':
397+
return 'dropbox_list_revisions'
398+
case 'dropbox_restore':
399+
return 'dropbox_restore'
339400
default:
340401
return 'dropbox_upload'
341402
}
@@ -379,14 +440,21 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
379440
query: { type: 'string', description: 'Search query' },
380441
fileExtensions: { type: 'string', description: 'File extensions filter' },
381442
maxResults: { type: 'number', description: 'Maximum search results' },
443+
// List shared links inputs
444+
directOnly: { type: 'boolean', description: 'Only return direct links, not parent folders' },
445+
// Restore input
446+
rev: { type: 'string', description: 'Revision identifier to restore' },
382447
},
383448
outputs: {
384449
// Upload/Download outputs
385450
file: { type: 'file', description: 'Downloaded file stored in execution files' },
386451
content: { type: 'string', description: 'File content (base64)' },
387452
temporaryLink: { type: 'string', description: 'Temporary download link' },
388-
// List folder outputs
389-
entries: { type: 'json', description: 'List of files and folders' },
453+
// List folder / List revisions outputs
454+
entries: {
455+
type: 'json',
456+
description: 'List of files and folders (List Folder), or file revisions (List Revisions)',
457+
},
390458
cursor: { type: 'string', description: 'Pagination cursor' },
391459
hasMore: { type: 'boolean', description: 'Whether more results exist' },
392460
// Create folder output
@@ -399,6 +467,10 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
399467
sharedLink: { type: 'json', description: 'Shared link details' },
400468
// Search outputs
401469
matches: { type: 'json', description: 'Search results' },
470+
// List shared links outputs
471+
links: { type: 'json', description: 'List of shared links (url, name, path_lower, expires)' },
472+
// List revisions output
473+
isDeleted: { type: 'boolean', description: 'Whether the latest revision is deleted or moved' },
402474
},
403475
}
404476

@@ -501,5 +573,12 @@ export const DropboxBlockMeta = {
501573
content:
502574
'# Share Dropbox Link\n\nGenerate a shareable link for an existing Dropbox item with the right access controls.\n\n## Steps\n1. Confirm the exact path of the file or folder. Use Get Metadata to verify it exists.\n2. Call Create Shared Link with the path and the requested visibility — public for anyone, team-only for internal sharing, or password-protected with a supplied password.\n3. Set an expiration date if the link should not be permanent.\n\n## Output\nReturn the shared link URL, its visibility setting, and the expiration date if one was applied.',
503575
},
576+
{
577+
name: 'recover-dropbox-file-version',
578+
description:
579+
'Recover an earlier version of a Dropbox file after an unwanted overwrite or edit.',
580+
content:
581+
'# Recover Dropbox File Version\n\nRoll a file back to an earlier saved revision.\n\n## Steps\n1. Call List Revisions on the file path to see prior versions, each with a revision identifier and modification time.\n2. Identify the revision to recover based on its timestamp or size.\n3. Call Restore File with the file path and the chosen revision identifier. This saves that revision as the new current version — it does not delete history.\n\n## Output\nReturn the restored file metadata, including its path and the revision that was restored.',
582+
},
504583
],
505584
} as const satisfies BlockMeta

apps/sim/tools/dropbox/copy.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ export const dropboxCopyTool: ToolConfig<DropboxCopyParams, DropboxCopyResponse>
4646
}
4747
},
4848
body: (params) => ({
49-
from_path: params.fromPath,
50-
to_path: params.toPath,
49+
from_path: params.fromPath.trim(),
50+
to_path: params.toPath.trim(),
5151
autorename: params.autorename ?? false,
5252
}),
5353
},
@@ -77,10 +77,10 @@ export const dropboxCopyTool: ToolConfig<DropboxCopyParams, DropboxCopyResponse>
7777
description: 'Metadata of the copied item',
7878
properties: {
7979
'.tag': { type: 'string', description: 'Type: file or folder' },
80-
id: { type: 'string', description: 'Unique identifier' },
80+
id: { type: 'string', description: 'Unique identifier', optional: true },
8181
name: { type: 'string', description: 'Name of the copied item' },
82-
path_display: { type: 'string', description: 'Display path' },
83-
size: { type: 'number', description: 'Size in bytes (files only)' },
82+
path_display: { type: 'string', description: 'Display path', optional: true },
83+
size: { type: 'number', description: 'Size in bytes (files only)', optional: true },
8484
},
8585
},
8686
},

apps/sim/tools/dropbox/create_folder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const dropboxCreateFolderTool: ToolConfig<
4343
}
4444
},
4545
body: (params) => ({
46-
path: params.path,
46+
path: params.path.trim(),
4747
autorename: params.autorename ?? false,
4848
}),
4949
},

apps/sim/tools/dropbox/create_shared_link.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export const dropboxCreateSharedLinkTool: ToolConfig<
5959
},
6060
body: (params) => {
6161
const body: Record<string, any> = {
62-
path: params.path,
62+
path: params.path.trim(),
6363
}
6464

6565
const settings: Record<string, any> = {}
@@ -88,12 +88,22 @@ export const dropboxCreateSharedLinkTool: ToolConfig<
8888
const data = await response.json()
8989

9090
if (!response.ok) {
91-
// Check if a shared link already exists
91+
// A link may already exist for this path - Dropbox includes its metadata in the error
92+
// when the requested settings match the existing link, so surface it as a success.
93+
const existingLink = data.error?.shared_link_already_exists?.metadata
94+
if (existingLink) {
95+
return {
96+
success: true,
97+
output: {
98+
sharedLink: existingLink,
99+
},
100+
}
101+
}
92102
if (data.error_summary?.includes('shared_link_already_exists')) {
93103
return {
94104
success: false,
95105
error:
96-
'A shared link already exists for this path. Use list_shared_links to get the existing link.',
106+
'A shared link already exists for this path with different settings. Use Dropbox List Shared Links to retrieve it.',
97107
output: {},
98108
}
99109
}
@@ -119,8 +129,12 @@ export const dropboxCreateSharedLinkTool: ToolConfig<
119129
properties: {
120130
url: { type: 'string', description: 'The shared link URL' },
121131
name: { type: 'string', description: 'Name of the shared item' },
122-
path_lower: { type: 'string', description: 'Lowercase path of the shared item' },
123-
expires: { type: 'string', description: 'Expiration date if set' },
132+
path_lower: {
133+
type: 'string',
134+
description: 'Lowercase path of the shared item',
135+
optional: true,
136+
},
137+
expires: { type: 'string', description: 'Expiration date if set', optional: true },
124138
link_permissions: {
125139
type: 'object',
126140
description: 'Permissions for the shared link',

apps/sim/tools/dropbox/delete.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const dropboxDeleteTool: ToolConfig<DropboxDeleteParams, DropboxDeleteRes
3434
}
3535
},
3636
body: (params) => ({
37-
path: params.path,
37+
path: params.path.trim(),
3838
}),
3939
},
4040

@@ -65,7 +65,7 @@ export const dropboxDeleteTool: ToolConfig<DropboxDeleteParams, DropboxDeleteRes
6565
properties: {
6666
'.tag': { type: 'string', description: 'Type: file, folder, or deleted' },
6767
name: { type: 'string', description: 'Name of the deleted item' },
68-
path_display: { type: 'string', description: 'Display path' },
68+
path_display: { type: 'string', description: 'Display path', optional: true },
6969
},
7070
},
7171
deleted: {

apps/sim/tools/dropbox/download.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const dropboxDownloadTool: ToolConfig<DropboxDownloadParams, DropboxDownl
3232
return {
3333
Authorization: `Bearer ${params.accessToken}`,
3434
'Content-Type': 'application/octet-stream',
35-
'Dropbox-API-Arg': httpHeaderSafeJson({ path: params.path }),
35+
'Dropbox-API-Arg': httpHeaderSafeJson({ path: params.path.trim() }),
3636
}
3737
},
3838
},
@@ -64,7 +64,7 @@ export const dropboxDownloadTool: ToolConfig<DropboxDownloadParams, DropboxDownl
6464
Authorization: `Bearer ${params.accessToken}`,
6565
'Content-Type': 'application/json',
6666
},
67-
body: JSON.stringify({ path: params.path }),
67+
body: JSON.stringify({ path: params.path.trim() }),
6868
})
6969
if (linkResponse.ok) {
7070
const linkData = await linkResponse.json()

apps/sim/tools/dropbox/get_metadata.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const dropboxGetMetadataTool: ToolConfig<
4949
}
5050
},
5151
body: (params) => ({
52-
path: params.path,
52+
path: params.path.trim(),
5353
include_media_info: params.includeMediaInfo ?? false,
5454
include_deleted: params.includeDeleted ?? false,
5555
}),
@@ -80,15 +80,27 @@ export const dropboxGetMetadataTool: ToolConfig<
8080
description: 'Metadata for the file or folder',
8181
properties: {
8282
'.tag': { type: 'string', description: 'Type: file, folder, or deleted' },
83-
id: { type: 'string', description: 'Unique identifier' },
83+
id: { type: 'string', description: 'Unique identifier', optional: true },
8484
name: { type: 'string', description: 'Name of the item' },
85-
path_display: { type: 'string', description: 'Display path' },
86-
path_lower: { type: 'string', description: 'Lowercase path' },
87-
size: { type: 'number', description: 'Size in bytes (files only)' },
88-
client_modified: { type: 'string', description: 'Client modification time' },
89-
server_modified: { type: 'string', description: 'Server modification time' },
90-
rev: { type: 'string', description: 'Revision identifier' },
91-
content_hash: { type: 'string', description: 'Content hash' },
85+
path_display: { type: 'string', description: 'Display path', optional: true },
86+
path_lower: { type: 'string', description: 'Lowercase path', optional: true },
87+
size: { type: 'number', description: 'Size in bytes (files only)', optional: true },
88+
client_modified: {
89+
type: 'string',
90+
description: 'Client modification time (files only)',
91+
optional: true,
92+
},
93+
server_modified: {
94+
type: 'string',
95+
description: 'Server modification time (files only)',
96+
optional: true,
97+
},
98+
rev: { type: 'string', description: 'Revision identifier (files only)', optional: true },
99+
content_hash: {
100+
type: 'string',
101+
description: 'Content hash (files only)',
102+
optional: true,
103+
},
92104
},
93105
},
94106
},

apps/sim/tools/dropbox/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import { dropboxDeleteTool } from '@/tools/dropbox/delete'
55
import { dropboxDownloadTool } from '@/tools/dropbox/download'
66
import { dropboxGetMetadataTool } from '@/tools/dropbox/get_metadata'
77
import { dropboxListFolderTool } from '@/tools/dropbox/list_folder'
8+
import { dropboxListRevisionsTool } from '@/tools/dropbox/list_revisions'
9+
import { dropboxListSharedLinksTool } from '@/tools/dropbox/list_shared_links'
810
import { dropboxMoveTool } from '@/tools/dropbox/move'
11+
import { dropboxRestoreTool } from '@/tools/dropbox/restore'
912
import { dropboxSearchTool } from '@/tools/dropbox/search'
1013
import { dropboxUploadTool } from '@/tools/dropbox/upload'
1114

@@ -17,7 +20,10 @@ export {
1720
dropboxDownloadTool,
1821
dropboxGetMetadataTool,
1922
dropboxListFolderTool,
23+
dropboxListRevisionsTool,
24+
dropboxListSharedLinksTool,
2025
dropboxMoveTool,
26+
dropboxRestoreTool,
2127
dropboxSearchTool,
2228
dropboxUploadTool,
2329
}

apps/sim/tools/dropbox/list_folder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export const dropboxListFolderTool: ToolConfig<DropboxListFolderParams, DropboxL
5959
}
6060
},
6161
body: (params) => ({
62-
path: params.path === '/' ? '' : params.path,
62+
path: params.path.trim() === '/' ? '' : params.path.trim(),
6363
recursive: params.recursive ?? false,
6464
include_deleted: params.includeDeleted ?? false,
6565
include_media_info: params.includeMediaInfo ?? false,
@@ -96,10 +96,10 @@ export const dropboxListFolderTool: ToolConfig<DropboxListFolderParams, DropboxL
9696
type: 'object',
9797
properties: {
9898
'.tag': { type: 'string', description: 'Type: file, folder, or deleted' },
99-
id: { type: 'string', description: 'Unique identifier' },
99+
id: { type: 'string', description: 'Unique identifier', optional: true },
100100
name: { type: 'string', description: 'Name of the file/folder' },
101101
path_display: { type: 'string', description: 'Display path' },
102-
size: { type: 'number', description: 'Size in bytes (files only)' },
102+
size: { type: 'number', description: 'Size in bytes (files only)', optional: true },
103103
},
104104
},
105105
},

0 commit comments

Comments
 (0)