diff --git a/apps/sim/app/api/tools/drive/file/route.ts b/apps/sim/app/api/tools/drive/file/route.ts index edc1e77f1e..62eb9686c7 100644 --- a/apps/sim/app/api/tools/drive/file/route.ts +++ b/apps/sim/app/api/tools/drive/file/route.ts @@ -57,6 +57,35 @@ export async function GET(request: NextRequest) { } ) + if (!response.ok && response.status === 404) { + logger.info(`[${requestId}] File not found, checking if it's a shared drive`) + const driveResponse = await fetch( + `https://www.googleapis.com/drive/v3/drives/${fileId}?fields=id,name`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ) + + if (driveResponse.ok) { + const driveData = await driveResponse.json() + logger.info(`[${requestId}] Found shared drive: ${driveData.name}`) + return NextResponse.json( + { + file: { + id: driveData.id, + name: driveData.name, + mimeType: 'application/vnd.google-apps.folder', + iconLink: + 'https://ssl.gstatic.com/docs/doclist/images/icon_11_shared_collection_list_1.png', + }, + }, + { status: 200 } + ) + } + } + if (!response.ok) { const errorData = await response.json().catch(() => ({ error: { message: 'Unknown error' } })) logger.error(`[${requestId}] Google Drive API error`, { @@ -112,12 +141,12 @@ export async function GET(request: NextRequest) { if (!file.exportLinks) { file.downloadUrl = `https://www.googleapis.com/drive/v3/files/${file.id}/export?mimeType=${encodeURIComponent( format - )}` + )}&supportsAllDrives=true` } else { file.downloadUrl = file.exportLinks[format] } } else { - file.downloadUrl = `https://www.googleapis.com/drive/v3/files/${file.id}?alt=media` + file.downloadUrl = `https://www.googleapis.com/drive/v3/files/${file.id}?alt=media&supportsAllDrives=true` } return NextResponse.json({ file }, { status: 200 }) diff --git a/apps/sim/app/api/tools/drive/files/route.ts b/apps/sim/app/api/tools/drive/files/route.ts index a142821b14..33ecb6f105 100644 --- a/apps/sim/app/api/tools/drive/files/route.ts +++ b/apps/sim/app/api/tools/drive/files/route.ts @@ -12,6 +12,62 @@ function escapeForDriveQuery(value: string): string { return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'") } +interface SharedDrive { + id: string + name: string + kind: string +} + +interface DriveFile { + id: string + name: string + mimeType: string + iconLink?: string + webViewLink?: string + thumbnailLink?: string + createdTime?: string + modifiedTime?: string + size?: string + owners?: any[] + parents?: string[] +} + +/** + * Fetches shared drives the user has access to + */ +async function fetchSharedDrives(accessToken: string, requestId: string): Promise { + try { + const response = await fetch( + 'https://www.googleapis.com/drive/v3/drives?pageSize=100&fields=drives(id,name)', + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ) + + if (!response.ok) { + logger.warn(`[${requestId}] Failed to fetch shared drives`, { + status: response.status, + }) + return [] + } + + const data = await response.json() + const drives: SharedDrive[] = data.drives || [] + + return drives.map((drive) => ({ + id: drive.id, + name: drive.name, + mimeType: 'application/vnd.google-apps.folder', + iconLink: 'https://ssl.gstatic.com/docs/doclist/images/icon_11_shared_collection_list_1.png', + })) + } catch (error) { + logger.error(`[${requestId}] Error fetching shared drives`, error) + return [] + } +} + export async function GET(request: NextRequest) { const requestId = generateRequestId() logger.info(`[${requestId}] Google Drive files request received`) @@ -65,7 +121,7 @@ export async function GET(request: NextRequest) { const q = encodeURIComponent(qParts.join(' and ')) const response = await fetch( - `https://www.googleapis.com/drive/v3/files?q=${q}&supportsAllDrives=true&includeItemsFromAllDrives=true&spaces=drive&fields=files(id,name,mimeType,iconLink,webViewLink,thumbnailLink,createdTime,modifiedTime,size,owners,parents)`, + `https://www.googleapis.com/drive/v3/files?q=${q}&corpora=allDrives&supportsAllDrives=true&includeItemsFromAllDrives=true&fields=files(id,name,mimeType,iconLink,webViewLink,thumbnailLink,createdTime,modifiedTime,size,owners,parents)`, { headers: { Authorization: `Bearer ${accessToken}`, @@ -88,14 +144,26 @@ export async function GET(request: NextRequest) { } const data = await response.json() - let files = data.files || [] + let files: DriveFile[] = data.files || [] if (mimeType === 'application/vnd.google-apps.spreadsheet') { files = files.filter( - (file: any) => file.mimeType === 'application/vnd.google-apps.spreadsheet' + (file: DriveFile) => file.mimeType === 'application/vnd.google-apps.spreadsheet' ) } else if (mimeType === 'application/vnd.google-apps.document') { - files = files.filter((file: any) => file.mimeType === 'application/vnd.google-apps.document') + files = files.filter( + (file: DriveFile) => file.mimeType === 'application/vnd.google-apps.document' + ) + } + + const isRootFolderListing = + !folderId && mimeType === 'application/vnd.google-apps.folder' && !query + if (isRootFolderListing) { + const sharedDrives = await fetchSharedDrives(accessToken, requestId) + if (sharedDrives.length > 0) { + logger.info(`[${requestId}] Found ${sharedDrives.length} shared drives`) + files = [...sharedDrives, ...files] + } } return NextResponse.json({ files }, { status: 200 }) diff --git a/apps/sim/tools/google_docs/create.ts b/apps/sim/tools/google_docs/create.ts index 5339b36867..9191dd8b3f 100644 --- a/apps/sim/tools/google_docs/create.ts +++ b/apps/sim/tools/google_docs/create.ts @@ -50,7 +50,7 @@ export const createTool: ToolConfig { - return 'https://www.googleapis.com/drive/v3/files' + return 'https://www.googleapis.com/drive/v3/files?supportsAllDrives=true' }, method: 'POST', headers: (params) => { diff --git a/apps/sim/tools/google_drive/download.ts b/apps/sim/tools/google_drive/download.ts index 6e92e9474c..4aa0d58544 100644 --- a/apps/sim/tools/google_drive/download.ts +++ b/apps/sim/tools/google_drive/download.ts @@ -45,7 +45,7 @@ export const downloadTool: ToolConfig - `https://www.googleapis.com/drive/v3/files/${params.fileId}?fields=id,name,mimeType`, + `https://www.googleapis.com/drive/v3/files/${params.fileId}?fields=id,name,mimeType&supportsAllDrives=true`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, @@ -83,7 +83,7 @@ export const downloadTool: ToolConfig - `https://www.googleapis.com/drive/v3/files/${params.fileId}?fields=id,name,mimeType`, + `https://www.googleapis.com/drive/v3/files/${params.fileId}?fields=id,name,mimeType&supportsAllDrives=true`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, @@ -77,7 +77,7 @@ export const getContentTool: ToolConfig { - return 'https://www.googleapis.com/drive/v3/files' + return 'https://www.googleapis.com/drive/v3/files?supportsAllDrives=true' }, method: 'POST', headers: (params) => {