Skip to content

google drive integration #1606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

AshishViradiya153
Copy link
Contributor

@AshishViradiya153 AshishViradiya153 commented Apr 24, 2025

Summary by CodeRabbit

  • New Features

    • Added Google Drive integration, allowing users to connect their account, browse, and import files or folders directly into the application.
    • Introduced a multi-step Google Drive import flow with a dedicated picker, folder/file tree view, and bulk upload confirmation.
    • Added a comprehensive upload progress panel and minimized upload progress UI for tracking multiple file uploads.
    • Created an "Integrations" settings page for managing connected services.
  • Improvements

    • Expanded the document upload modal to support Google Drive alongside existing upload and Notion options.
    • Enhanced status notifications and error handling during file uploads and integration flows.
  • Bug Fixes

    • Improved error handling and user notifications for Google Drive authentication and upload errors.
  • Database & Schema

    • Added new fields and tables to support Google Drive integration and file/folder associations.
  • Documentation

    • Updated navigation and UI to reflect new integration capabilities.

Copy link

vercel bot commented Apr 24, 2025

@AshishViradiya153 is attempting to deploy a commit to the mftsio Team on Vercel.

A member of the Team first needs to authorize it.

@mfts
Copy link
Owner

mfts commented May 11, 2025

@coderabbitai full review

Copy link
Contributor

coderabbitai bot commented May 11, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

coderabbitai bot commented May 11, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update introduces comprehensive Google Drive integration into the application. It adds OAuth-based connection management, file/folder selection via Google Picker, recursive folder/file import and upload, and batch upload progress tracking. The backend supports Google Drive file/folder metadata, upload sessions, folder structure creation, and document association. UI components and database schema are extended to accommodate these new features, including integration management in settings.

Changes

File(s) / Area Change Summary
components/documents/add-document-modal.tsx Enhanced AddDocumentModal to support Google Drive import: new tabs, Google Drive picker integration, recursive folder/file processing, confirmation dialog, error handling, and extended state management. Added new interfaces for file/folder metadata.
components/documents/upload-notification-drawer.tsx,
components/minimized-upload-progress.tsx,
components/google-drive-upload-progress.tsx
Added new components for upload progress: UploadNotificationDrawer manages drawer state and displays upload progress; MinimizedUploadProgress provides a compact view; GoogleDriveUploadProgress offers detailed, filterable upload status for Google Drive uploads.
components/integrations/google-drive/google-drive-picker.tsx New GoogleDrivePicker component for selecting files/folders from Google Drive using the Picker API, with dynamic script loading, OAuth token handling, error management, and UI feedback.
components/integrations/google-drive/google-drive.tsx New GoogleDriveIntegration component and hooks for managing connection status, OAuth flow, and disconnection. Handles state, user feedback, and triggers OAuth requests.
components/settings/settings-header.tsx Added "Integrations" navigation item to the settings menu.
components/shared/icons/google-drive.tsx Added GoogleDrive SVG icon component.
components/ui/badge.tsx Added "success" badge variant with green styling.
components/ui/confirmation-dialog.tsx New ConfirmationDialog component for modal confirmation with customizable messages and counts.
lib/api/documents/process-document.ts
lib/documents/create-document.ts
Added optional googleDriveFileId to document creation parameters and database record, supporting association of documents with Google Drive files.
lib/auth/gdrive-upload-session.ts New module for managing Google Drive upload sessions in Redis, with Zod schema validation and session lifecycle functions.
lib/context/upload-context.tsx Introduced UploadContext and provider for managing upload state and operations across the app.
lib/files/file-utils.ts New utility functions for creating and finding folder records in the database, supporting both standard and dataroom folders, with Google Drive folder ID support.
lib/files/process-and-upload.ts New module for recursively creating folder structures and processing Google Drive file uploads, including folder uniqueness, path construction, and PDF page counting.
lib/files/tus-upload.ts Extended resumableUpload to support Buffer or File input, explicit fileName/fileType, and Google Drive file ID metadata. Updated upload result accordingly.
lib/google-drive.ts New GoogleDriveClient class for managing OAuth2, token refresh, recursive file/folder listing, file download, token revocation, and disconnect. Singleton pattern, shortcut resolution, and error constants included.
lib/hooks/use-google-drive-token.ts New hook for managing and refreshing Google Drive access tokens, with error handling and UI feedback.
lib/hooks/use-google-drive-upload.ts New hook for managing Google Drive upload lifecycle: progress, error, document creation, session management, and UI state. Integrates with real-time updates and SWR.
lib/swr/use-google-drive-integration.ts New SWR hook for fetching and managing Google Drive integration status.
lib/trigger/batch-file-upload.ts New Trigger.dev task for batch file upload: manages chunked uploads, folder creation, progress/error tracking, document creation, dataroom association, and final status reporting.
lib/utils/node-pdf-page-counter.ts New utility for estimating PDF page count from a Buffer using multiple heuristics.
package.json Added googleapis dependency for Google Drive API integration.
pages/_app.tsx Wrapped app in UploadProvider, added UploadNotificationDrawer, and inserted viewport meta tag for responsiveness.
pages/api/file/browser-upload.ts Added a single comment for file identification.
pages/api/integrations/google-drive/batch-upload.ts New POST API handler for batch uploading Google Drive files; validates input, triggers batch upload job, and manages upload session cookie.
pages/api/integrations/google-drive/callback.ts New API handler for OAuth2 callback: validates state, exchanges code for tokens, fetches profile, stores integration, and redirects with status.
pages/api/integrations/google-drive/disconnect.ts New POST API handler for disconnecting Google Drive integration, revoking tokens, and removing integration record.
pages/api/integrations/google-drive/generate-state.ts New GET API handler for generating secure OAuth2 state parameter with checksum.
pages/api/integrations/google-drive/index.tsx New GET API handler for fetching and refreshing Google Drive integration status and tokens.
pages/api/integrations/google-drive/list-files.ts New POST API handler for recursively listing files/folders from Google Drive, building folder tree, and returning metadata.
pages/api/integrations/google-drive/upload-session.ts New API handler for managing upload session lifecycle: fetch, validate, delete, and clear session cookies.
pages/api/teams/[teamId]/datarooms/[id]/documents/index.ts Extended POST handler to support API token authentication, accept googleDriveFileId, and allow configurable notification delay.
pages/api/teams/[teamId]/documents/index.ts POST handler now accepts optional googleDriveFileId for associating documents with Google Drive files.
pages/settings/integrations.tsx New Integrations settings page with GoogleDriveIntegration component and layout.
prisma/migrations/20250424171651_google_drive/migration.sql Database migration: added GoogleDriveIntegration table, new columns for Google Drive IDs in Document, Folder, DataroomDocument, and DataroomFolder tables, with indexes and constraints.
prisma/schema/dataroom.prisma Schema: added googleDriveFileId and googleDriveFolderId fields to DataroomDocument and DataroomFolder models.
prisma/schema/schema.prisma Schema: added GoogleDriveIntegration model, new fields for Google Drive IDs in User, Document, and Folder models, and relations/indexes.

Sequence Diagram(s)

Google Drive File Import and Upload Flow

sequenceDiagram
    participant User
    participant AddDocumentModal
    participant GoogleDrivePicker
    participant BackendAPI
    participant UploadContext
    participant UploadNotificationDrawer

    User->>AddDocumentModal: Opens modal
    AddDocumentModal->>User: Shows tabs (Document, Google Drive, Notion)
    User->>AddDocumentModal: Selects "Google Drive" tab
    AddDocumentModal->>GoogleDrivePicker: Initiates file/folder picker
    GoogleDrivePicker->>User: User selects files/folders
    GoogleDrivePicker->>AddDocumentModal: Returns selected items
    AddDocumentModal->>BackendAPI: POST /api/integrations/google-drive/list-files
    BackendAPI->>AddDocumentModal: Returns folder tree & file metadata
    AddDocumentModal->>User: Shows confirmation dialog (file/folder count)
    User->>AddDocumentModal: Confirms upload
    AddDocumentModal->>UploadContext: startUpload(treeFiles, filesList, etc.)
    UploadContext->>BackendAPI: Triggers batch upload (Trigger.dev)
    UploadContext->>UploadNotificationDrawer: Updates upload progress
    UploadNotificationDrawer->>User: Displays upload status
    UploadContext->>User: Notifies on completion/errors
Loading

Google Drive Integration Management Flow

sequenceDiagram
    participant User
    participant GoogleDriveIntegration
    participant BackendAPI

    User->>GoogleDriveIntegration: Clicks "Connect"
    GoogleDriveIntegration->>BackendAPI: GET /api/integrations/google-drive/generate-state
    GoogleDriveIntegration->>User: Redirects to Google OAuth
    User->>BackendAPI: Google OAuth callback (/api/integrations/google-drive/callback)
    BackendAPI->>GoogleDriveIntegration: Stores tokens, updates status
    User->>GoogleDriveIntegration: Sees connected status
    User->>GoogleDriveIntegration: Clicks "Disconnect"
    GoogleDriveIntegration->>BackendAPI: POST /api/integrations/google-drive/disconnect
    BackendAPI->>GoogleDriveIntegration: Revokes tokens, removes integration
    GoogleDriveIntegration->>User: Updates to disconnected status
Loading

Poem

🐰✨
In the warren of code, new tunnels appear,
Google Drive now hops in—let’s all give a cheer!
With folders and files, and uploads in flight,
Progress bars twinkle, integrations feel right.
From OAuth to icons, the changes are wide—
Now Papermark’s ready for a Drive-powered ride!
🚀📄🌱


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 29

🧹 Nitpick comments (26)
lib/utils/node-pdf-page-counter.ts (2)

1-39: Strong implementation with multiple fallback methods for PDF page counting.

The function employs a multi-method approach to determine PDF page count, gracefully falling back to alternative methods when preferred ones fail. This is robust for handling different PDF structures.

Two minor improvements using optional chaining:

- if (countMatch && countMatch[1]) {
+ if (countMatch?.[1]) {
- if (nMatch && nMatch[1]) {
+ if (nMatch?.[1]) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 9-9: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 26-26: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


35-38: Consider more specific error handling.

The current implementation catches all errors and defaults to returning 1 page. Consider adding more specific error types or logging additional details to help with debugging in production.

  } catch (error) {
-     console.error('Error counting PDF pages:', error);
+     console.error('Error counting PDF pages:', 
+         error instanceof Error ? `${error.name}: ${error.message}` : String(error)
+     );
      return 1;
  }
lib/documents/create-document.ts (1)

21-22: Potential duplication in Google Drive file ID handling.

The function accepts a separate googleDriveFileId parameter despite documentData already containing this property. This could lead to confusion if the values differ.

Consider one of these approaches:

  1. Remove the separate parameter and use only documentData.googleDriveFileId
  2. Document which parameter takes precedence if both are provided
export const createDocument = async ({
  documentData,
  teamId,
  numPages,
  folderPathName,
  createLink = false,
  token,
-  googleDriveFileId
}: {
  documentData: DocumentData;
  teamId: string;
  numPages?: number;
  folderPathName?: string;
  createLink?: boolean;
  token?: string;
-  googleDriveFileId?: string;
}) => {
  // ...
      body: JSON.stringify({
        // ...
-       googleDriveFileId: googleDriveFileId,
+       googleDriveFileId: documentData.googleDriveFileId,
      }),
  // ...
};

Also applies to: 29-30

prisma/schema/schema.prisma (2)

190-203: Index (or unique) googleDriveFileId for fast look-ups & deduping

googleDriveFileId will be queried frequently during upload → document sync and must be unique within a workspace. Consider:

@@ model Document
   googleDriveFileId String?
+
+  @@index([googleDriveFileId])
+  // or @@unique([teamId, googleDriveFileId]) if duplicates must be prevented

Without an index each sync iteration results in full-table scans on Document, hampering large tenants.


414-417: Add an index for googleDriveFolderId similar to documents

Folder synchronisation will need quick mapping driveFolderId → Folder. Add an index / uniqueness constraint analogous to the document suggestion to avoid O(n) scans.

components/minimized-upload-progress.tsx (3)

41-45: latestActiveUpload picks the first active upload, not the latest

Array.find stops at the first match. If older uploads remain “active”, the newest one won’t show. Sort by timestamp (or iterate in reverse) to display the most recent:

-const latestActiveUpload = uploads.find((u) =>
+const latestActiveUpload = [...uploads]
+  .filter((u) => ["uploading", "pending", "initializing", "processing"].includes(u.status))
+  .sort((a, b) => b.timestamp - a.timestamp)[0];

47-52: Average progress should weight by file size

A 1 GB file at 10 % and a 1 KB file at 100 % currently report 55 % average, misleading users. If bytesTotal is available, compute a weighted mean:

-const averageProgress = uploads.length > 0
-  ? uploads.reduce((sum, upload) => sum + upload.progress, 0) / uploads.length
-  : 0;
+const totalBytes = uploads.reduce((s, u) => s + (u.bytesTotal ?? 0), 0);
+const averageProgress =
+  totalBytes > 0
+    ? uploads.reduce((s, u) => s + (u.progress * (u.bytesTotal ?? 0)), 0) /
+      totalBytes
+    : 0;

78-116: DRY: wrap both icon buttons in a single TooltipProvider

Two nested TooltipProviders are unnecessary; place one higher to avoid duplicate context providers:

-          <div className="flex items-center space-x-1">
-            <TooltipProvider>
+          <TooltipProvider>
+            <div className="flex items-center space-x-1">
               ...
-            </TooltipProvider>
-            <TooltipProvider>
               ...
-            </TooltipProvider>
-          </div>
+            </div>
+          </TooltipProvider>
pages/api/integrations/google-drive/callback.ts (1)

67-69: Avoid cross-layer imports (scope from a React component)

callback.ts pulls scope from components/integrations/google-drive/google-drive, coupling API code to a frontend file. This risks cyclic imports and bloats the server bundle. Export the scope list from a shared util (e.g., lib/google-drive/constants.ts) and import it in both places.

lib/context/upload-context.tsx (2)

37-47: Remove debug code before production deployment.

The console debug statements and TODO comment should be removed before pushing to production. These logs expose internal state information that should not be present in production code.

-  // TODO : REMOVE THIS
-  if (uploads.length > 0) {
-    console.debug("Upload state updated:", {
-      count: uploads.length,
-      statuses: uploads.map((u) => ({
-        id: u.fileId,
-        status: u.status,
-        progress: u.progress,
-      })),
-    });
-  }

30-31: Consider documenting the purpose of local upload state.

The component maintains a separate uploadState instead of directly using uploads from the hook. Adding a comment explaining why this local state is necessary would improve code maintainability.

-  // Force re-render when uploads change
+  // Maintain local state copy to ensure component re-renders when upload progress updates
+  // This is needed because the uploads array reference from the hook might not change
+  // even when the contents (progress values) change
   const [uploadState, setUploadState] = useState<UploadProgress[]>([]);
pages/api/integrations/google-drive/batch-upload.ts (2)

63-63: Use optional chaining for cleaner conditional checks.

The static analysis tool correctly suggests using optional chaining here for better code readability.

-        if (handle && handle.id && handle.publicAccessToken) {
+        if (handle?.id && handle?.publicAccessToken) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 63-63: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


36-36: Remove unnecessary empty line.

For code consistency, remove this empty line.

     const { treeFiles, filesList, path, dataroomId, teamId } = req.body as { treeFiles: ProcessedFile, filesList: Files[], path: string, dataroomId: string, teamId: string };

-
     if (filesList.length === 0) {
pages/api/integrations/google-drive/list-files.ts (4)

46-48: Remove console.log statements before production.

Debug logging should be removed before deploying to production environments.

-        console.log("----------------folderPathName ----------------");
-        console.log('folderPathName', folderPathName);
-        console.log("----------------folderPathName ----------------");

69-71: Remove console.log statements before production.

Debug logging should be removed before deploying to production environments.

-        console.log("----------------files----------------");
-        console.log('files', { files, fileArray });
-        console.log("----------------files----------------");

75-77: Remove console.log statements before production.

Debug logging should be removed before deploying to production environments.

-        console.log("----------------tree----------------");
-        console.log('tree', tree);
-        console.log("----------------tree----------------");

57-66: Consider collecting errors instead of failing on the first error.

The current implementation returns an error response if any single folder fails to list files. Consider collecting errors and continuing with successfully processed folders.

+        const errors: Record<string, string> = {};
         for (const folderId of folderIds) {
             try {
                 const file = await googleDrive.listFiles(driveClient, folderId);
                 files.push(...file);
             } catch (error) {
                 console.error(`Error listing files for folder ${folderId}:`, error);
-                return res.status(500).json({
-                    error: 'Failed to list files',
-                    message: error instanceof Error ? error.message : 'Unknown error'
-                });
+                errors[folderId] = error instanceof Error ? error.message : 'Unknown error';
             }
         }
+        
+        // If all folders failed, return an error
+        if (Object.keys(errors).length === folderIds.length) {
+            return res.status(500).json({
+                error: 'Failed to list files from all folders',
+                errors
+            });
+        }
prisma/migrations/20250424171651_google_drive/migration.sql (1)

2-12: Missing indexes on the new googleDriveFileId / googleDriveFolderId columns

These IDs will be used in look-ups during document/folder sync. Add non-unique B-tree indexes to avoid full-table scans:

CREATE INDEX "Document_googleDriveFileId_idx" ON "Document"("googleDriveFileId");
CREATE INDEX "DataroomDocument_googleDriveFileId_idx" ON "DataroomDocument"("googleDriveFileId");
CREATE INDEX "Folder_googleDriveFolderId_idx" ON "Folder"("googleDriveFolderId");
CREATE INDEX "DataroomFolder_googleDriveFolderId_idx" ON "DataroomFolder"("googleDriveFolderId");
lib/files/tus-upload.ts (1)

56-63: Metadata values must be ASCII strings

tus spec limits metadata values to ASCII. googleDriveFileId can contain non-ASCII characters if users create folders with Unicode; encode with encodeURIComponent to stay spec-compliant.

- googleDriveFileId: googleDriveFileId || "",
+ googleDriveFileId: googleDriveFileId ? encodeURIComponent(googleDriveFileId) : "",
components/integrations/google-drive/google-drive-picker.tsx (2)

129-137: MULTISELECT_ENABLED should depend on the multiple prop

The picker is always created with multiselect enabled, even when multiple === false, which is confusing from a UX standpoint and can break downstream logic.

-        .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
+        {multiple && builder.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)}

(or conditionally call enableFeature before .build()).


152-170: Treating a plain cancel as an error

Inside the Picker callback, Action.CANCEL is routed through handleError, showing a toast for what is actually a normal user action.
Only invoke handleError if data[google.picker.Response.ERROR] exists; otherwise just silently reset the state.

lib/hooks/use-google-drive-upload.ts (1)

11-20: Duplicate / unused status values

UploadStatus already contains "failed" and "error", yet mapStatusFromServer never returns "failed" – the server’s "failed" string is mapped to "error". This makes "failed" impossible at runtime and complicates consumers that have to handle both.

Consider unifying:

 export type UploadStatus =
   | "pending"
   | "initializing"
   | "uploading"
   | "processing"
   | "completed"
-  | "failed"
-  | "error"
+  | "failed"        // single failure state
   | "unknown";
…
 case "failed":  return "failed";

That simplification propagates through reducers & UI components.

Also applies to: 33-41

components/documents/add-document-modal.tsx (2)

94-100: selectedGoogleDriveFile is never read – remove dead state to keep component lean

The local state selectedGoogleDriveFile is created but never used anywhere in the component.
Keeping unused state hurts readability and triggers unnecessary re-renders when it’s updated.

-  const [selectedGoogleDriveFile, setSelectedGoogleDriveFile] = useState<{
-    id: string;
-    name: string;
-    mimeType: string;
-    size: number;
-  } | null>(null);

If you plan to leverage it later, please add the corresponding logic; otherwise, delete it together with the setSelectedGoogleDriveFile call in clearModelStates.


744-748: UI message can mislead when Drive is disconnected but finished loading

isConnected || !isLoading will display “Select a file…” even if the user is not connected (isConnected === false) but the fetch finished (isLoading === false). This is the typical state right after a failed/expired connection.

- {isConnected || !isLoading
+ {isConnected

or explicitly

{isConnected ? "Select a file ..." : "Sync your Google Drive account ..."}

This avoids confusing users with an unavailable action.

lib/files/process-and-upload.ts (2)

160-166: folderMap is declared but never populated – dead code / potential logic drift

A folderMap is initialised but no set() calls follow. Either remove it or populate it (e.g., while walking folderTree). Keeping unused maps adds cognitive noise and hints at an incomplete feature.


86-115: Possible race when two workers create the same folder concurrently

The uniqueness check loops with findFolderRecord / createFolderRecord. Without a DB-side unique index (parentId, name) two parallel uploads might still create duplicate folders between the find and create.

If not already present, add a DB unique constraint and be prepared to catch PrismaClientKnownRequestError P2002 to retry with the incremented suffix.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8423b43 and 3540ea4.

📒 Files selected for processing (39)
  • components/documents/add-document-modal.tsx (4 hunks)
  • components/documents/upload-notification-drawer.tsx (1 hunks)
  • components/google-drive-upload-progress.tsx (1 hunks)
  • components/integrations/google-drive/google-drive-picker.tsx (1 hunks)
  • components/integrations/google-drive/google-drive.tsx (1 hunks)
  • components/minimized-upload-progress.tsx (1 hunks)
  • components/settings/settings-header.tsx (1 hunks)
  • components/shared/icons/google-drive.tsx (1 hunks)
  • components/ui/badge.tsx (1 hunks)
  • components/ui/confirmation-dialog.tsx (1 hunks)
  • lib/api/documents/process-document.ts (3 hunks)
  • lib/auth/gdrive-upload-session.ts (1 hunks)
  • lib/context/upload-context.tsx (1 hunks)
  • lib/documents/create-document.ts (3 hunks)
  • lib/files/file-utils.ts (1 hunks)
  • lib/files/process-and-upload.ts (1 hunks)
  • lib/files/tus-upload.ts (4 hunks)
  • lib/google-drive.ts (1 hunks)
  • lib/hooks/use-google-drive-token.ts (1 hunks)
  • lib/hooks/use-google-drive-upload.ts (1 hunks)
  • lib/swr/use-google-drive-integration.ts (1 hunks)
  • lib/trigger/batch-file-upload.ts (1 hunks)
  • lib/utils/node-pdf-page-counter.ts (1 hunks)
  • package.json (1 hunks)
  • pages/_app.tsx (3 hunks)
  • pages/api/file/browser-upload.ts (1 hunks)
  • pages/api/integrations/google-drive/batch-upload.ts (1 hunks)
  • pages/api/integrations/google-drive/callback.ts (1 hunks)
  • pages/api/integrations/google-drive/disconnect.ts (1 hunks)
  • pages/api/integrations/google-drive/generate-state.ts (1 hunks)
  • pages/api/integrations/google-drive/index.tsx (1 hunks)
  • pages/api/integrations/google-drive/list-files.ts (1 hunks)
  • pages/api/integrations/google-drive/upload-session.ts (1 hunks)
  • pages/api/teams/[teamId]/datarooms/[id]/documents/index.ts (5 hunks)
  • pages/api/teams/[teamId]/documents/index.ts (3 hunks)
  • pages/settings/integrations.tsx (1 hunks)
  • prisma/migrations/20250424171651_google_drive/migration.sql (1 hunks)
  • prisma/schema/dataroom.prisma (2 hunks)
  • prisma/schema/schema.prisma (4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (12)
lib/swr/use-google-drive-integration.ts (2)
components/integrations/google-drive/google-drive.tsx (1)
  • GoogleDriveIntegration (110-262)
lib/utils.ts (1)
  • fetcher (34-48)
pages/_app.tsx (5)
components/ui/tooltip.tsx (1)
  • TooltipProvider (144-144)
lib/constants.ts (1)
  • EXCLUDED_PATHS (56-56)
lib/context/upload-context.tsx (1)
  • UploadProvider (27-61)
components/documents/upload-notification-drawer.tsx (1)
  • UploadNotificationDrawer (9-60)
components/theme-provider.tsx (1)
  • ThemeProvider (10-12)
pages/settings/integrations.tsx (3)
components/layouts/app.tsx (1)
  • AppLayout (9-29)
components/settings/settings-header.tsx (1)
  • SettingsHeader (8-88)
components/integrations/google-drive/google-drive.tsx (1)
  • GoogleDriveIntegration (110-262)
pages/api/integrations/google-drive/disconnect.ts (4)
pages/api/integrations/google-drive/index.tsx (1)
  • handler (10-70)
pages/api/auth/[...nextauth].ts (1)
  • authOptions (25-189)
lib/types.ts (1)
  • CustomUser (18-18)
lib/google-drive.ts (1)
  • GoogleDriveClient (10-238)
lib/context/upload-context.tsx (2)
lib/hooks/use-google-drive-upload.ts (2)
  • UploadProgress (49-65)
  • useGoogleDriveUpload (67-533)
components/documents/add-document-modal.tsx (2)
  • ProcessedFile (50-62)
  • Files (64-69)
lib/auth/gdrive-upload-session.ts (1)
lib/redis.ts (1)
  • redis (4-7)
components/minimized-upload-progress.tsx (4)
lib/hooks/use-google-drive-upload.ts (1)
  • UploadProgress (49-65)
components/ui/tooltip.tsx (4)
  • TooltipProvider (144-144)
  • Tooltip (139-139)
  • TooltipTrigger (140-140)
  • TooltipContent (143-143)
components/ui/button.tsx (1)
  • Button (71-71)
components/ui/progress.tsx (1)
  • Progress (61-61)
lib/google-drive.ts (1)
lib/constants.ts (1)
  • SUPPORTED_DOCUMENT_MIME_TYPES (63-90)
lib/hooks/use-google-drive-upload.ts (1)
components/documents/add-document-modal.tsx (2)
  • ProcessedFile (50-62)
  • Files (64-69)
components/integrations/google-drive/google-drive-picker.tsx (1)
components/ui/button.tsx (1)
  • Button (71-71)
components/documents/add-document-modal.tsx (9)
lib/context/upload-context.tsx (1)
  • useUpload (63-69)
ee/limits/swr-handler.ts (1)
  • useLimits (18-44)
lib/swr/use-billing.ts (1)
  • usePlan (72-104)
components/integrations/google-drive/google-drive.tsx (2)
  • useGoogleDriveStatus (30-52)
  • GoogleDriveIntegration (110-262)
components/integrations/google-drive/google-drive-picker.tsx (1)
  • GoogleDrivePicker (40-217)
components/ui/card.tsx (5)
  • Card (80-80)
  • CardHeader (81-81)
  • CardTitle (83-83)
  • CardDescription (84-84)
  • CardContent (85-85)
components/ui/button.tsx (1)
  • Button (71-71)
lib/constants.ts (1)
  • SUPPORTED_DOCUMENT_MIME_TYPES (63-90)
components/ui/confirmation-dialog.tsx (1)
  • ConfirmationDialog (27-83)
lib/files/process-and-upload.ts (5)
components/documents/add-document-modal.tsx (1)
  • ProcessedFile (50-62)
lib/files/file-utils.ts (2)
  • findFolderRecord (33-54)
  • createFolderRecord (4-29)
lib/google-drive.ts (1)
  • GoogleDriveClient (10-238)
lib/utils/node-pdf-page-counter.ts (1)
  • countPdfPages (1-39)
lib/files/tus-upload.ts (1)
  • resumableUpload (30-121)
🪛 Biome (1.9.4)
lib/utils/node-pdf-page-counter.ts

[error] 9-9: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 26-26: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

pages/_app.tsx

[error] 13-13: Shouldn't redeclare 'EXCLUDED_PATHS'. Consider to delete it or rename it.

'EXCLUDED_PATHS' is defined here:

(lint/suspicious/noRedeclare)

pages/api/integrations/google-drive/batch-upload.ts

[error] 63-63: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

components/documents/add-document-modal.tsx

[error] 574-574: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

lib/files/process-and-upload.ts

[error] 263-263: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (70)
components/ui/badge.tsx (1)

18-19: Good addition of a success variant for badges.

The new success variant with green styling will help provide clear visual feedback to users during Google Drive integration operations. This aligns well with the upload progress components mentioned in the summary.

package.json (1)

88-88:

✅ Verification successful

Verify googleapis version compatibility.

The addition of googleapis (v148.0.0) is appropriate for the Google Drive integration. Let's verify this is a stable version without known vulnerabilities.


🌐 Web query:

Are there any known issues or vulnerabilities with googleapis version 148.0.0?

💡 Result:

As of my knowledge cutoff in June 2024, there is no specific information regarding vulnerabilities in googleapis version 148.0.0. The latest available release at that time was version 144.0.0, which included breaking changes and updates to various APIs. (googleapis.dev)

It's important to note that vulnerabilities can be discovered after my last update. To ensure the security of your application, I recommend:

  1. Reviewing the Changelog: Check the official googleapis changelog for any updates or security advisories related to version 148.0.0.

  2. Consulting Security Databases: Utilize platforms like Snyk or GitHub Security Advisories to search for known vulnerabilities in the googleapis package.

  3. Testing Your Application: Regularly run security scans and tests on your application to identify and mitigate potential vulnerabilities.

By staying informed and proactive, you can help maintain the security and integrity of your application.

Citations:


No known vulnerabilities or compatibility issues with googleapis@148.0.0

As of May 2025, there are no publicly reported security advisories for version 148.0.0 and it aligns with the latest stable release. To finalize:

This dependency is safe to merge.

pages/api/file/browser-upload.ts (1)

15-15: Simple descriptive comment added.

The added comment helps identify the API route, which is good for codebase documentation.

components/settings/settings-header.tsx (1)

61-65: Navigation item for Google Drive integration looks good!

The new "Integrations" menu item is properly positioned between "Billing" and "Tokens" in the settings navigation. This addition follows the existing pattern and provides access to the new Google Drive integration features.

prisma/schema/dataroom.prisma (2)

39-39: Schema extension for Google Drive file ID looks good.

The optional googleDriveFileId field appropriately allows for linking DataroomDocument objects to their corresponding Google Drive files.


65-65: Schema extension for Google Drive folder ID looks good.

The optional googleDriveFolderId field appropriately allows for linking DataroomFolder objects to their corresponding Google Drive folders.

pages/api/teams/[teamId]/documents/index.ts (2)

254-255: API handler now accepts Google Drive file ID.

The document creation API properly accepts the optional googleDriveFileId parameter in the request body. This aligns with the database schema changes.

Also applies to: 265-266


289-290: Google Drive file ID is correctly passed to the document processor.

The googleDriveFileId parameter is correctly forwarded to the processDocument function.

lib/documents/create-document.ts (4)

3-12: DocumentData interface properly extended for Google Drive.

Converting from a type alias to an interface and adding the optional googleDriveFileId property correctly supports the Google Drive integration.


50-51: Google Drive file ID included in document creation payload.

The googleDriveFileId is correctly included in the JSON body sent to the backend API.


62-96:

❓ Verification inconclusive

Consider adding Google Drive support to createAgreementDocument.

The createAgreementDocument function hasn't been updated to handle Google Drive files. If agreement documents can come from Google Drive, consider adding similar support to this function.


🏁 Script executed:

#!/bin/bash
# Check if agreement documents can come from Google Drive
rg -A 3 "createAgreementDocument.*googleDrive" --type ts

Length of output: 58


Verify Google Drive support in createAgreementDocument

I searched the codebase and found no references to Google Drive in createAgreementDocument. If your app should accept agreement files sourced from Google Drive, you’ll need to extend this function to:

  • Detect Google Drive inputs (e.g. a Drive file ID or URL)
  • Fetch the file metadata/content via the Drive API
  • Generate or store a shareable link or blob URL
  • Populate the POST body (url, storageType, etc.) accordingly

Please confirm whether agreement documents may originate from Google Drive and, if so, implement these steps in lib/documents/create-document.ts (lines 62–96).


98-133:

❌ Incorrect review comment

Consider adding Google Drive support to createNewDocumentVersion.

The createNewDocumentVersion function hasn't been updated to handle Google Drive files. If document versions can be updated from Google Drive, consider adding similar support to this function.


🏁 Script executed:

#!/bin/bash
# Check if document versions can come from Google Drive
rg -A 3 "createNewDocumentVersion.*googleDrive" --type ts

Length of output: 59


🏁 Script executed:

#!/bin/bash
# Search for DocumentData type or interface definitions
rg -A 5 -B 2 "type DocumentData" --type ts
rg -A 5 -B 2 "interface DocumentData" --type ts

# Check possible values for storageType within DocumentData
rg -A 2 "storageType" --type ts

Length of output: 18973


Ignore Google Drive support suggestion
There’s no existing Google Drive integration in the DocumentStorageType enum or elsewhere in the codebase. Since createNewDocumentVersion only handles storage types defined in Prisma (e.g., S3_PATH, VERCEL_BLOB), adding “Google Drive” isn’t applicable unless you introduce it as a new storage option.

Likely an incorrect or invalid review comment.

components/shared/icons/google-drive.tsx (1)

1-39: Well-implemented Google Drive icon component.

The SVG icon implementation looks good with appropriate sizing, viewBox, and color specifications that accurately represent the Google Drive logo. The component accepts an optional className prop for styling flexibility.

lib/api/documents/process-document.ts (3)

23-23: Google Drive integration parameter properly documented.

Good addition of the Google Drive file ID parameter with clear documentation in the comment.


34-34: Parameter default value appropriately set.

The default value of null for the optional Google Drive file ID parameter is appropriate.


113-113: Conditional inclusion of Google Drive file ID is well implemented.

The use of a conditional spread operator is an elegant approach to include the Google Drive file ID only when it exists.

pages/_app.tsx (2)

77-77: Good addition of viewport meta tag.

Adding the viewport meta tag is a good practice for responsive design.


94-97: Well-integrated UploadProvider and notification drawer.

The UploadProvider is properly nested within the TeamProvider and wraps both the main component and the notification drawer. The UploadNotificationDrawer component is correctly positioned as a sibling to maintain a consistent UI hierarchy.

lib/swr/use-google-drive-integration.ts (2)

6-9: Well-typed integration response interface.

The GoogleDriveIntegrationResponse type properly defines the structure of the integration data and connection status.


11-17: Well-implemented SWR hook for Google Drive integration.

The hook follows best practices by using SWR with proper typing and configuration. Disabling revalidation on focus is appropriate for this type of integration data. The hook cleanly exposes all necessary properties (data, error, isLoading, mutate) for consumers.

pages/settings/integrations.tsx (3)

1-6: Import statements look good.

The imports are well organized, separating the hook from the components with a blank line. Imports from the project are properly prefixed with @/.


7-9: Component structure is well-defined.

The component is correctly exported as default and uses the useTeam hook to access team context.


10-32: Well-structured layout following application patterns.

The component follows the existing application layout patterns, using AppLayout as a wrapper and properly structuring the content with appropriate spacing and typography classes. The page is well-organized with a clear hierarchy and consistent styling with other settings pages.

The grid layout at line 25 is prepared for multiple integrations, though currently only contains the Google Drive integration.

pages/api/integrations/google-drive/generate-state.ts (4)

1-8: Imports are properly organized.

The imports are well-structured, grouped logically with a blank line separating different types of imports.


9-12: Handler function signature is correct.

The function is properly exported as default with the correct Next.js API handler typing.


21-24: Secure state generation for OAuth flow.

The state parameter is securely generated using a combination of user email, timestamp, and a checksum. This follows security best practices for OAuth state parameters to prevent CSRF attacks.


26-30: Method validation is correctly implemented.

The endpoint properly handles method validation, returning a 405 status and setting the Allow header for unsupported methods.

pages/api/integrations/google-drive/disconnect.ts (5)

1-7: Imports are properly organized.

The necessary dependencies for Next.js API, authentication, and Google Drive integration are correctly imported.


8-14: API method validation is correctly implemented.

The handler correctly validates that only POST requests are allowed for this endpoint.


16-22: Authentication verification is properly implemented.

The code correctly retrieves the user session and handles unauthorized access appropriately.


24-28: Google Drive disconnection implementation is clean.

The handler uses the singleton GoogleDriveClient to handle the disconnection logic and properly checks for success.


29-33: Error handling is comprehensive.

The try-catch block properly captures and logs errors, returning appropriate error responses to the client.

pages/api/integrations/google-drive/upload-session.ts (5)

1-6: Imports are properly organized.

The necessary dependencies for API routing, authentication, and session management are correctly imported.


7-18: Authentication verification is properly implemented.

The authentication check is correctly placed at the beginning of the handler to ensure all routes are protected.


19-59: GET endpoint implementation is secure and thorough.

The code properly:

  • Retrieves the session token from cookies
  • Validates the session exists and is valid
  • Verifies the session belongs to the current user
  • Clears invalid cookies when necessary
  • Returns appropriate error messages and status codes

This is a robust implementation for session retrieval.


60-90: DELETE endpoint implementation follows best practices.

The session deletion logic is well-implemented:

  • Verifies ownership before deleting
  • Always clears the cookie regardless of session existence
  • Provides appropriate success and error responses
  • Handles exceptions properly

This ensures clean session cleanup.


92-95: Method validation is correctly implemented.

The handler properly returns a 405 status for unsupported HTTP methods.

pages/api/teams/[teamId]/datarooms/[id]/documents/index.ts (5)

4-4: Proper import added for logger library

The addition of logger import from the trigger.dev SDK enhances error reporting capabilities.


105-138: Good enhancement of authentication flow

The dual authentication method implementation is well-structured and secure:

  • First tries to authenticate via API token (Bearer token)
  • Falls back to session-based authentication if no token is provided
  • Properly verifies that the token belongs to the correct team

This improvement enables programmatic access while maintaining session-based security.


141-147: Enhanced document creation with Google Drive integration

The addition of googleDriveFileId and configurable delay parameters provides excellent flexibility:

  • Allows linking documents to Google Drive files
  • Enables customizable notification delay with sensible default (10 minutes)

182-182: Google Drive file ID association enabled

The document creation data now includes the Google Drive file ID, properly implementing the Google Drive integration.


227-227: Dynamic delay configuration for notifications

Replaced hardcoded delay with configurable delayMs parameter, improving flexibility.

components/documents/upload-notification-drawer.tsx (4)

1-14: Well-structured component setup with proper imports and state management

The component correctly:

  • Imports necessary dependencies
  • Uses the upload context to access uploads state
  • Initializes local state for uploads, drawer open state, and minimized state

15-20: Effective synchronization with upload context

The useEffect hook properly:

  • Updates local state when uploads change
  • Automatically opens the drawer when uploads are added
  • Prevents unnecessary re-renders with appropriate dependency array

22-35: Proper conditional rendering and controlled closing

The component:

  • Returns null when there are no uploads or when drawer is closed
  • Prevents closing the drawer while uploads are in progress
  • Cleans up local state when closing

37-59: Well-implemented UI with dual display modes

The component offers:

  • A minimized view for less intrusive display
  • A full-featured view with detailed upload progress
  • Proper positioning and animations
  • Controls for minimizing, maximizing, and closing
components/ui/confirmation-dialog.tsx (4)

1-14: Proper imports for dialog component

The necessary imports for React, UI components, and icons are correctly included.


15-25: Well-defined props interface with optional parameters

The component's interface:

  • Provides clear required props (isOpen, onClose, onConfirm, title)
  • Includes optional props with appropriate types (confirmText, cancelText, file/folder counts, loading)
  • Follows TypeScript best practices

27-37: Good component setup with default values

The component correctly:

  • Destructures props
  • Provides sensible defaults for button text
  • Accepts optional file and folder counts
  • Supports loading state

38-83: Well-implemented dialog with conditional rendering

The dialog UI:

  • Responds to open/close state
  • Displays a header with title
  • Shows conditional description based on file/folder counts with proper pluralization
  • Includes footer with cancel and confirm buttons
  • Handles loading state with spinner and text change
  • Disables confirm button during loading
lib/hooks/use-google-drive-token.ts (3)

1-7: Proper hook setup with state initialization

The hook correctly:

  • Imports necessary React hooks
  • Initializes token state with the provided initial value
  • Tracks refresh operation state

8-29: Robust token refresh implementation

The refresh function:

  • Uses useCallback for performance optimization
  • Properly manages loading state
  • Makes an API call to refresh the token
  • Handles success by updating state
  • Provides comprehensive error handling with logging and user feedback
  • Ensures loading state is reset even if errors occur

31-36: Clean hook interface

The hook returns a well-structured object with:

  • Current token value
  • Token setter function
  • Token refresh function
  • Loading state indicator

This provides all necessary functionality for components to manage Google Drive tokens.

lib/context/upload-context.tsx (2)

13-23: LGTM: Well-defined context type with proper TypeScript typing.

The context type definition is well-structured with clear interface for managing uploads, tracking upload status, and initiating new uploads.


63-69: LGTM: Good error handling in the custom hook.

The useUpload hook properly throws an informative error when used outside the provider context, which will help developers identify integration issues.

pages/api/integrations/google-drive/batch-upload.ts (3)

13-19: LGTM: Well-configured secure cookie options.

The cookie configuration follows security best practices with HTTP-only flag, secure in production, strict same-site policy, and reasonable expiration time.


72-81: LGTM: Properly formatted cookie with security attributes.

The Set-Cookie header is correctly constructed with all security attributes and expiration time.


49-55:

❓ Verification inconclusive

Verify file size value in production.

The file size is hardcoded to 0 and URL to an empty string, which seems like placeholders. Ensure this is intentional and works correctly with the batch upload process.


🏁 Script executed:

#!/bin/bash
# Check how the batch upload process handles these placeholder values
rg -A 10 "size: 0" --glob "*.ts" --glob "*.tsx"

Length of output: 885


🏁 Script executed:

#!/bin/bash
# Show context around the filesList.map mapping
rg -A 15 -B 15 "filesList.map" pages/api/integrations/google-drive/batch-upload.ts

Length of output: 1244


Ensure actual file size and URL values are provided in batch‐upload payload

We’re currently mapping each file to

files: filesList.map(file => ({
  id: file.fileId,
  name: file.fileName,
  type: file.fileType,
  size: 0,
  url: ""
})),

– both size and url are hardcoded placeholders. Please confirm that these fields are populated downstream (e.g., in the batch‐file‐upload job or the upload session) before they’re used or returned to the client. If they aren’t, either:

  • Pass the real fileSize (e.g. file.fileSize) and construct the actual url here,
  • Or add a clear // TODO comment explaining why they remain empty and where they’ll be set.

• File: pages/api/integrations/google-drive/batch-upload.ts at the filesList.map(...) call.

pages/api/integrations/google-drive/list-files.ts (1)

83-97: LGTM: Good error handling for Google Drive specific errors.

The error handling for Google Drive connection errors is well-implemented, providing clear messages to guide the user on reconnecting or setting up their Google Drive integration.

lib/auth/gdrive-upload-session.ts (5)

9-16: LGTM: Well-defined session data schema.

The Zod schema provides strong validation for session data structure with appropriate field types.


29-30: LGTM: Secure session token generation.

Using crypto.randomBytes(32) creates a cryptographically secure random token with sufficient entropy.


67-69: LGTM: Defensive programming with explicit type checking.

The code safely handles parsing the session data by checking if it's a string before attempting to parse it as JSON.


72-75: LGTM: Proper session expiration handling.

The code correctly checks for expired sessions and removes them from Redis, which prevents access to expired sessions and cleans up the storage.


42-49: LGTM: Validation before storage and proper Redis configuration.

The code validates session data with the Zod schema before storing it, and correctly sets expiration in Redis using the pxat option.

prisma/migrations/20250424171651_google_drive/migration.sql (1)

31-34: Unique constraint limits users to a single Google account

CREATE UNIQUE INDEX "GoogleDriveIntegration_userId_key" enforces a one-to-one mapping between User and Integration.
Is multi-account linking out of scope? If not, drop the uniqueness constraint and use (userId, id) PK.

components/google-drive-upload-progress.tsx (1)

285-303: "success" variant might not exist in <Badge>

components/ui/badge.tsx usually exposes default | secondary | destructive | outline. Passing an unknown variant will drop styling or throw a type error. Confirm the design-system API or replace with an existing variant (e.g. default + green classes).

lib/files/tus-upload.ts (1)

5-16:

❌ Incorrect review comment

Buffer uploads require a Node environment – clarify execution context

Buffer is undefined in browsers; tus-js-client expects Blob/File on the client side. If this function is imported by both SSR and client bundles, a runtime reference to Buffer will break the browser build.

Options:

  1. Split the implementation (resumableUpload.browser.ts / .node.ts) and let your bundler conditionally resolve the correct file.
  2. Convert BufferBlob before instantiating tus.Upload.

Please verify where this helper runs and adjust typings or bundling targets accordingly.


I’d like to inspect the implementation to see if Buffer is ever used at runtime or only in TS types:

#!/bin/bash
set -e

# Locate the file
fd tus-upload.ts

# Show the first 200 lines to check for any runtime references to `Buffer`
sed -n '1,200p' lib/files/tus-upload.ts

To confirm whether Buffer is only in the TS type or actually used at runtime, let’s search for any Buffer references and inspect the upload logic:


🏁 Script executed:

#!/bin/bash
set -e

# 1. Check for any Buffer usage in tus-upload.ts
grep -R "Buffer" -n lib/files/tus-upload.ts || echo "No Buffer occurrences found"

# 2. Locate the tus.Upload instantiation to see how `file` is handled
grep -R -n "new tus.Upload" -n lib/files/tus-upload.ts || echo "No tus.Upload instantiation found"

# 3. (Optional) Show the full file for context if needed
# sed -n '1,200p' lib/files/tus-upload.ts

Length of output: 181


Let’s inspect the upload logic around line 50 to see if Buffer is ever referenced or handled at runtime:

#!/bin/bash
set -e

# Show lines 30–100 around the tus.Upload instantiation
sed -n '30,100p' lib/files/tus-upload.ts

Let’s inspect the upload logic around the new tus.Upload call:


🏁 Script executed:

#!/bin/bash
set -e

# Display lines 30–100 around the tus.Upload instantiation
sed -n '30,100p' lib/files/tus-upload.ts

Length of output: 2616


Type-only Buffer usage – no runtime break in browsers

The Buffer in ResumableUploadParams is purely a TypeScript annotation. After compilation, there’s no Buffer identifier in the emitted JavaScript, and the code never calls or imports Buffer at runtime. The new tus.Upload(file, …) call simply passes the file argument (whether a File or Buffer) to tus-js-client, which handles supported data types in each environment. You can safely ignore the browser-build concern.

Likely an incorrect or invalid review comment.

lib/hooks/use-google-drive-upload.ts (2)

241-249: Throttling may hide the final metadata update

The now - lastMetadataUpdate.current < 200 guard skips processing when the job is still running, but the final COMPLETED event also passes through this block. If the final update happens ≤200 ms after a previous one, UI may never receive the 100 %/completed progress.

Add an unconditional branch for terminal states:

 if (run.status === "COMPLETED" || metadata.status === "completed") {
     lastMetadataUpdate.current = now;
 } else if (now - lastMetadataUpdate.current < 200) {
     return;
 }

This guarantees the last snapshot reaches the UI.


418-441: ⚠️ Potential issue

Early-return paths leave isLoading true

startUpload sets isUploading only after all guard clauses. When a guard aborts (no files, duplicate upload, missing teamId) the flag never resets, blocking future uploads for this session.

 if (isUploading || uploadInProgress.current) {
-    toast.error("An upload is already in progress");
-    return () => { };
+    toast.error("An upload is already in progress");
+    setIsUploading(false);
+    uploadInProgress.current = false;
+    return () => {};
 }
…
 if (!filesList.length) {
-    toast.error("No files selected");
-    return () => { };
+    toast.error("No files selected");
+    setIsUploading(false);
+    uploadInProgress.current = false;
+    return () => {};
 }

Repeat for the other early exits to avoid a stuck “uploading” state.

Likely an incorrect or invalid review comment.

lib/trigger/batch-file-upload.ts (1)

223-232: Retry counter without actual retry logic

The error message "(Try ${retryCount}/3)" suggests automatic retries, but the code never dispatches another upload attempt. Either implement a retry (e.g., while (retryCount<3) loop around processAndUploadFiles) or remove the misleading messaging to avoid false expectations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants