Skip to content

fix: address code review feedback on copyObject, e2e helpers, and tests#3

Merged
Cybersoulja merged 2 commits intomainfrom
claude/add-claude-documentation-CRHnS
Apr 13, 2026
Merged

fix: address code review feedback on copyObject, e2e helpers, and tests#3
Cybersoulja merged 2 commits intomainfrom
claude/add-claude-documentation-CRHnS

Conversation

@Cybersoulja
Copy link
Copy Markdown
Owner

@Cybersoulja Cybersoulja commented Apr 13, 2026

  • helpers.ts: replace browser-only btoa/unescape with Node-safe
    Buffer.from(...).toString('base64') in encodeKey and seedEmail
  • copyObject.ts: wrap atob decoding in try/catch, return 400 with
    descriptive messages for invalid sourceKey/destinationKey; return
    c.json({ success: true }) instead of raw R2Object for consistency
  • multipart.test.ts: add test for non-base64 httpMetadata in
    CreateUpload to complement the existing malformed-JSON test
  • object.test.ts: add test asserting Content-Disposition sanitizes
    non-ASCII and quote characters in filename while preserving the
    original key in the RFC 5987 filename* parameter
  • FileOptions.vue: stop folder duplication on first copy failure and
    show an error notification instead of silently continuing

https://claude.ai/code/session_018aqegB3K211sW1c1xf8Eux

Summary by Sourcery

Document test suites and API surface, harden copy operation and multipart upload validation, improve folder copy UX, and add regression coverage for headers and metadata handling.

New Features:

  • Expand CLAUDE.md with detailed worker/dashboard module layout, routing, testing structure, environment bindings, debugging guidance, and security notes.

Bug Fixes:

  • Prevent folder duplication from continuing after the first copy failure and surface an error notification instead of always showing success.
  • Return structured 400 errors from the copy endpoint when source or destination keys are not valid base64-encoded values, and normalize its success response shape.
  • Validate multipart upload httpMetadata as base64 and return a 400 error when it is invalid.

Enhancements:

  • Align E2E helper key and metadata encoding with the dashboard’s Node-safe base64 encoding implementation.
  • Add tests to ensure Content-Disposition sanitizes non-ASCII and quote characters while preserving the original key in the RFC 5987 filename* parameter.
  • Return a simple JSON success object from the copy endpoint instead of the raw R2 object for response consistency.

Documentation:

  • Clarify project structure, API routes and handlers, key types and dependencies, testing strategy, email integration, environment bindings, debugging steps, and security considerations in CLAUDE.md.

Tests:

  • Augment integration tests for multipart uploads and object downloads to cover invalid httpMetadata encoding and Content-Disposition header behavior.

claude added 2 commits April 6, 2026 02:15
- helpers.ts: replace browser-only btoa/unescape with Node-safe
  Buffer.from(...).toString('base64') in encodeKey and seedEmail
- copyObject.ts: wrap atob decoding in try/catch, return 400 with
  descriptive messages for invalid sourceKey/destinationKey; return
  c.json({ success: true }) instead of raw R2Object for consistency
- multipart.test.ts: add test for non-base64 httpMetadata in
  CreateUpload to complement the existing malformed-JSON test
- object.test.ts: add test asserting Content-Disposition sanitizes
  non-ASCII and quote characters in filename while preserving the
  original key in the RFC 5987 filename* parameter
- FileOptions.vue: stop folder duplication on first copy failure and
  show an error notification instead of silently continuing

https://claude.ai/code/session_018aqegB3K211sW1c1xf8Eux
Expands documentation to reflect the latest codebase including:
- Complete API route table with all methods, paths, and handlers
- Full TypeScript type definitions (R2ExplorerConfig, ShareMetadata, AppEnv)
- Detailed testing infrastructure (worker integration, dashboard unit/component, E2E)
- Dashboard router routes and appUtils.js function inventory
- Email integration details (receive/send flow)
- Module directory layout for worker src/
- Environment bindings (wrangler.toml) example
- Debugging tips and security considerations
- Key dependencies for both worker and dashboard packages

https://claude.ai/code/session_01Fc3LXwYaGM3GKyCQiiQMPa
@gitnotebooks
Copy link
Copy Markdown

gitnotebooks bot commented Apr 13, 2026

Review these changes at https://app.gitnotebooks.com/Cybersoulja/R2-Explorer/pull/3

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 13, 2026

Reviewer's Guide

Addresses review feedback around key encoding/decoding robustness, copyObject error handling/response shape, test coverage for edge cases, and UX for folder copy failures, plus expands CLAUDE.md documentation and project overview details.

Sequence diagram for folder duplication error handling in FileOptions component

sequenceDiagram
  actor User
  participant FileOptions as FileOptions
  participant ApiHandler as ApiHandler
  participant CopyObjectEndpoint as CopyObjectEndpoint
  participant R2Bucket as R2Bucket
  participant Notifier as Notifier

  User->>FileOptions: Click duplicateFolder
  FileOptions->>ApiHandler: createFolder(destPrefix, selectedBucket)
  ApiHandler->>CopyObjectEndpoint: POST create folder placeholder
  CopyObjectEndpoint->>R2Bucket: put(destPrefix placeholder)
  R2Bucket-->>CopyObjectEndpoint: ok
  CopyObjectEndpoint-->>ApiHandler: json success
  ApiHandler-->>FileOptions: resolved

  loop for each innerFile in folderContents
    FileOptions->>FileOptions: compute newKey from sourcePrefix and destPrefix
    alt innerFile is file
      FileOptions->>ApiHandler: copyObject(selectedBucket, innerFile.key, newKey)
      ApiHandler->>CopyObjectEndpoint: POST /api/buckets/:bucket/copy
      CopyObjectEndpoint->>R2Bucket: get(sourceKey)
      alt get succeeds
        R2Bucket-->>CopyObjectEndpoint: object
        CopyObjectEndpoint->>R2Bucket: put(destinationKey, body, metadata)
        R2Bucket-->>CopyObjectEndpoint: ok
        CopyObjectEndpoint-->>ApiHandler: json success
        ApiHandler-->>FileOptions: resolved
        FileOptions->>Notifier: show progress percent
      else get or put fails
        R2Bucket-->>CopyObjectEndpoint: error
        CopyObjectEndpoint-->>ApiHandler: error response
        ApiHandler-->>FileOptions: throw error
        FileOptions->>FileOptions: set failed true
        FileOptions->>Notifier: show negative error notification
        FileOptions->>FileOptions: break loop
      end
    else innerFile is folder
      FileOptions->>Notifier: show progress percent
    end
  end

  alt failed is false
    FileOptions->>Notifier: show success Folder duplicated
  else failed is true
    FileOptions->>Notifier: do not show success notification
  end
Loading

Sequence diagram for CopyObject endpoint with key decoding validation

sequenceDiagram
  participant ApiHandler as ApiHandler
  participant CopyObjectEndpoint as CopyObjectEndpoint
  participant R2Bucket as R2Bucket

  ApiHandler->>CopyObjectEndpoint: POST /api/buckets/:bucket/copy with base64 keys
  alt invalid sourceKey base64
    CopyObjectEndpoint->>CopyObjectEndpoint: atob(sourceKey) throws
    CopyObjectEndpoint-->>ApiHandler: HTTP 400 Invalid sourceKey
  else valid sourceKey base64
    CopyObjectEndpoint->>CopyObjectEndpoint: decode sourceKey
    alt invalid destinationKey base64
      CopyObjectEndpoint->>CopyObjectEndpoint: atob(destinationKey) throws
      CopyObjectEndpoint-->>ApiHandler: HTTP 400 Invalid destinationKey
    else valid destinationKey base64
      CopyObjectEndpoint->>R2Bucket: get(sourceKey)
      alt object not found
        R2Bucket-->>CopyObjectEndpoint: null
        CopyObjectEndpoint-->>ApiHandler: HTTP 404 Object not found
      else object found
        R2Bucket-->>CopyObjectEndpoint: object with body and metadata
        CopyObjectEndpoint->>R2Bucket: put(destinationKey, body, metadata)
        R2Bucket-->>CopyObjectEndpoint: ok
        CopyObjectEndpoint-->>ApiHandler: json { success: true }
      end
    end
  end
Loading

Updated class diagram for CopyObject handler and related types

classDiagram
  class OpenAPIRoute {
    <<abstract>>
  }

  class CopyObject {
    +handle(c)
  }

  class R2Bucket {
    +get(key)
    +put(key, body, options)
  }

  class HTTPException {
    +HTTPException(status, options)
  }

  CopyObject --|> OpenAPIRoute
  CopyObject --> R2Bucket : uses
  CopyObject --> HTTPException : throws

  class CopyObjectHandleFlow {
    +validateBody()
    +decodeSourceKey()
    +decodeDestinationKey()
    +getSourceObject()
    +copyToDestination()
    +returnJsonSuccess()
  }

  CopyObjectHandleFlow <-- CopyObject : handle delegates logic
  CopyObjectHandleFlow --> HTTPException : 400 invalid keys
  CopyObjectHandleFlow --> HTTPException : 404 object not found
  CopyObjectHandleFlow --> R2Bucket : get and put operations
Loading

File-Level Changes

Change Details Files
Harden copyObject endpoint decoding and response semantics.
  • Wrap base64 decoding of sourceKey and destinationKey in try/catch blocks
  • Return HTTP 400 with descriptive error messages when either key is not valid base64
  • Stop returning the raw R2Object from bucket.put and instead return a JSON { success: true } payload for successful copies
packages/worker/src/modules/buckets/copyObject.ts
Improve robustness and Node compatibility of test/e2e helpers for key and metadata encoding.
  • Replace browser-only btoa/unescape usage with Buffer.from(...).toString('base64') in the E2E encodeKey helper
  • Use Buffer-based base64 encoding for seedEmail custom metadata to match dashboard behavior and work in Node
packages/dashboard/e2e/helpers.ts
Tighten multipart and object endpoint test coverage for error cases and header behavior.
  • Add multipart create test asserting a 400 and error message when httpMetadata query param is not valid base64
  • Add object endpoint test verifying Content-Disposition sanitizes non-ASCII and quote characters while preserving the original key in the RFC 5987 filename* parameter
packages/worker/tests/integration/multipart.test.ts
packages/worker/tests/integration/object.test.ts
Improve UX for folder copy operation failures in the dashboard.
  • Wrap per-file copy calls during folder duplication in a try/catch
  • Stop the loop on first failure, show a negative notification with the failing key, and avoid the misleading success toast when any copy failed
packages/dashboard/src/components/files/FileOptions.vue
Expand and refine project documentation and architecture overview in CLAUDE.md.
  • Clarify package version, API route table with handlers, and module layout
  • Document worker/dashboard/e2e tests, email integration, build pipeline, environment bindings, debugging tips, security considerations, and important files
  • Add Biome disabled rules and minor formatting fixes
CLAUDE.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Cybersoulja Cybersoulja merged commit c31ea2c into main Apr 13, 2026
3 of 4 checks passed
Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In FileOptions.vue, consider simplifying the failure branch in the folder-copy loop by returning early from the method inside the catch block instead of using a separate failed flag plus break, which will make the control flow easier to follow.
  • There are multiple base64 encode/decode implementations across the codebase (worker routes, dashboard appUtils, e2e helpers); introducing a shared utility for key encoding/decoding would reduce the risk of subtle inconsistencies and keep future changes centralized.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `FileOptions.vue`, consider simplifying the failure branch in the folder-copy loop by returning early from the method inside the catch block instead of using a separate `failed` flag plus `break`, which will make the control flow easier to follow.
- There are multiple base64 encode/decode implementations across the codebase (worker routes, dashboard `appUtils`, e2e helpers); introducing a shared utility for key encoding/decoding would reduce the risk of subtle inconsistencies and keep future changes centralized.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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