Skip to content

feat(uploads): add createFromBuffer for programmatic GridFS storage#3290

Merged
PierreBrisorgueil merged 3 commits intomasterfrom
feat/create-from-buffer
Mar 24, 2026
Merged

feat(uploads): add createFromBuffer for programmatic GridFS storage#3290
PierreBrisorgueil merged 3 commits intomasterfrom
feat/create-from-buffer

Conversation

@PierreBrisorgueil
Copy link
Contributor

@PierreBrisorgueil PierreBrisorgueil commented Mar 24, 2026

Summary

Adds a createFromBuffer method to the uploads module, enabling programmatic file storage in GridFS without requiring an HTTP multipart upload. Closes #3289.

  • lib/services/gridfs.js — new uploadFromBuffer(buffer, filename, bucketName) helper that opens a GridFS upload stream and writes a Buffer directly
  • modules/uploads/config/config.uploads.js — adds createFromBuffer configuration (allowed MIME types, max file size) alongside existing upload config
  • modules/uploads/services/uploads.service.js — new createFromBuffer({ buffer, filename, contentType, metadata }) service method that validates inputs, calls the GridFS helper, and returns the stored file document
  • modules/uploads/tests/uploads.createFromBuffer.unit.tests.js — comprehensive unit tests covering success path, missing-buffer/filename validation, MIME-type rejection, and file-size limit enforcement

Test plan

  • npm run lint passes (0 errors)
  • npm test passes (269 tests, including the new createFromBuffer tests)

Summary by CodeRabbit

  • New Features

    • Added programmatic buffer upload support (store uploads from in-memory buffers).
    • Added "snapshot" upload option supporting JPEG and PNG with a 5MB file-size limit.
  • Tests

    • Added unit tests covering successful snapshot uploads, filename generation, size/type validations, and error handling.

Copilot AI review requested due to automatic review settings March 24, 2026 18:22
@coderabbitai
Copy link

coderabbitai bot commented Mar 24, 2026

Warning

Rate limit exceeded

@PierreBrisorgueil has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 57 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0bf3200e-4ede-4804-abb9-57973c648405

📥 Commits

Reviewing files that changed from the base of the PR and between d4c3dc3 and cbccbb6.

📒 Files selected for processing (1)
  • modules/uploads/tests/uploads.createFromBuffer.unit.tests.js

Walkthrough

Adds programmatic buffer upload support: a GridFS helper createFromBuffer and an UploadsService.createFromBuffer that validate config-driven kinds/formats/limits, generate filenames, store buffers to GridFS with metadata, and includes unit tests for success and failure cases.

Changes

Cohort / File(s) Summary
GridFS Service
lib/services/gridfs.js
Added createFromBuffer(buffer, filename, contentType, metadata = {}) — creates a GridFSBucket, opens an upload stream with a new ObjectId, pipes a Readable from the buffer into the stream, and resolves with the stored Uploads document on finish.
Uploads Configuration
modules/uploads/config/config.uploads.js
Added config.uploads.snapshot with kind: 'snapshot', formats: ['image/jpeg','image/png'], and limits.fileSize: 5 * 1024 * 1024.
Uploads Service
modules/uploads/services/uploads.service.js
Added createFromBuffer(buffer, contentType, kind, metadata = {}) — validates buffer type, kind presence, allowed formats, and file size limits; generates random filename (MIME→ext mapping); delegates storage to gridfs.createFromBuffer; included in default export.
Unit Tests
modules/uploads/tests/uploads.createFromBuffer.unit.tests.js
New Jest suite covering successful JPEG/PNG uploads, filename/metadata assertions, and failure cases: oversize buffer, disallowed content type, unknown kind, missing/invalid buffer, and misconfigured kind formats.

Sequence Diagram

sequenceDiagram
    participant Client as Service Consumer
    participant UploadSvc as Uploads Service
    participant Config as Configuration
    participant GridFS as GridFS Service
    participant Stream as Node Stream
    Client->>UploadSvc: createFromBuffer(buffer, contentType, kind, metadata)
    UploadSvc->>Config: load kind config
    alt kind missing
        UploadSvc-->>Client: AppError 422
    else kind found
        UploadSvc->>Config: check contentType in formats
        alt disallowed contentType
            UploadSvc-->>Client: AppError 422
        else allowed
            UploadSvc->>UploadSvc: check file size vs limits
            alt exceeds limit
                UploadSvc-->>Client: AppError 422
            else within limit
                UploadSvc->>UploadSvc: generate filename
                UploadSvc->>GridFS: createFromBuffer(buffer, filename, contentType, metadata)
                GridFS->>Stream: create upload stream with ObjectId
                GridFS->>Stream: pipe Readable(buffer) into upload stream
                Stream-->>GridFS: finish event
                GridFS->>GridFS: query Uploads collection for document
                GridFS-->>UploadSvc: return stored document
                UploadSvc-->>Client: return stored document
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description covers Summary, Test plan, and implementation details across all changed files, but omits several required template sections like Scope, Validation, Guardrails, and Notes for reviewers. Complete the PR description by adding missing sections: Scope (modules impacted, cross-module impact, risk level), full Validation checklist, Guardrails review, and Notes for reviewers with security/mergeability considerations.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a createFromBuffer method for programmatic GridFS storage in the uploads module.
Linked Issues check ✅ Passed All code changes directly implement the objectives from issue #3289: GridFS helper for buffer uploads, snapshot config with MIME types and size limits, uploads service with validation, and comprehensive unit tests.
Out of Scope Changes check ✅ Passed All changes are within scope: GridFS helper, config addition, service method, and tests align with issue #3289 objectives; no unrelated changes detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/create-from-buffer

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the uploads module to support programmatic creation of GridFS-backed uploads from an in-memory Buffer, enabling internal services/workers to persist generated assets without going through multipart HTTP upload.

Changes:

  • Added createFromBuffer helper to lib/services/gridfs.js to write buffers into the uploads GridFS bucket.
  • Added a new snapshot upload kind to uploads configuration with allowed MIME types and size limits.
  • Added UploadsService.createFromBuffer(...) plus unit tests for the new service path.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
lib/services/gridfs.js Adds buffer-to-GridFS upload helper and returns stored upload document.
modules/uploads/config/config.uploads.js Adds snapshot upload kind config (formats + size limit).
modules/uploads/services/uploads.service.js Adds service method to validate kind/content-type/size and delegate to GridFS helper.
modules/uploads/tests/uploads.createFromBuffer.unit.tests.js Adds unit tests for new service method behavior (success + some validation cases).

Copy link

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@modules/uploads/services/uploads.service.js`:
- Around line 81-83: Extract the inline MIME_TO_EXT map out of the function into
a module-level constant (e.g., MIME_TO_EXT) or into a shared utility module and
import it into uploads.service.js, then replace the inline definition with a
reference to that constant where ext is computed (the current code using
MIME_TO_EXT[contentType] || 'bin' that feeds into filename =
`${crypto.randomBytes(32).toString('hex')}.${ext}`); ensure the constant is
exported if moved to a shared util and update any imports accordingly.
- Around line 69-79: The createFromBuffer function assumes buffer is a valid
Buffer but can throw a TypeError when buffer is null/undefined or not a Buffer;
add an explicit validation at the top of createFromBuffer using
Buffer.isBuffer(buffer) (or equivalent) and throw an AppError with code
'SERVICE_ERROR' and status 422 if the check fails, and only access buffer.length
after this validation; update any relevant tests or callers if needed to ensure
they pass a proper Buffer to createFromBuffer.
- Around line 69-87: The createFromBuffer function currently assumes
kindConfig.formats exists and calls .includes, which can throw a TypeError if
formats is missing; add a defensive check that verifies kindConfig.formats is an
Array (or non-empty) before using .includes and throw the same AppError used for
invalid content types (e.g., `Upload: content type ... not allowed for kind
...`) when formats is missing or not an array; locate the check around the
existing use of kindConfig.formats in createFromBuffer and use kindConfig (from
config.uploads?.[kind]) to validate formats first, then proceed to the existing
includes check and subsequent logic.

In `@modules/uploads/tests/uploads.createFromBuffer.unit.tests.js`:
- Around line 73-130: Add tests that assert UploadsService.createFromBuffer
rejects when buffer input is null, undefined, or an empty Buffer; call
UploadsService.createFromBuffer with null, undefined, and Buffer.alloc(0) using
a valid contentType and kind, assert each invocation rejects (using
rejects.toThrow or similar), and verify mockGridfs.createFromBuffer was not
called; place them alongside the existing tests so they cover input validation
for UploadsService.createFromBuffer and reference mockGridfs.createFromBuffer to
assert no upstream storage call occurs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 500a8755-18e2-412b-9e88-db4ba9a54d1c

📥 Commits

Reviewing files that changed from the base of the PR and between a83606c and 80117d7.

📒 Files selected for processing (4)
  • lib/services/gridfs.js
  • modules/uploads/config/config.uploads.js
  • modules/uploads/services/uploads.service.js
  • modules/uploads/tests/uploads.createFromBuffer.unit.tests.js

…ty, tests

- Fix Readable.from(buffer) → Readable.from([buffer]) to avoid byte-by-byte iteration
- Add readable error handler for reliable Promise rejection on stream failures
- Add Buffer.isBuffer validation with clear AppError (422) for invalid inputs
- Add defensive Array.isArray check for kindConfig.formats
- Extract MIME_TO_EXT map to module-level constant
- Add tests for null/undefined buffer, non-Buffer input, and missing formats
Copy link

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@modules/uploads/tests/uploads.createFromBuffer.unit.tests.js`:
- Around line 144-150: Add a unit test for UploadsService.createFromBuffer to
cover an empty Buffer case: call createFromBuffer with Buffer.alloc(0), the MIME
and type strings, then assert mockGridfs.createFromBuffer was called once and
that the buffer argument passed into mockGridfs.createFromBuffer has length 0
(verifying the empty buffer is forwarded/stored). This ensures
UploadsService.createFromBuffer and mockGridfs.createFromBuffer handle 0-byte
buffers as expected.
- Around line 152-160: Add a concise comment above the runtime mutation in the
test 'should throw error when kind has no formats configured' explaining that
mockConfig.uploads is mutated at runtime because UploadsService.reads config
dynamically; e.g., clarify that setting mockConfig.uploads.broken = { kind:
'broken', limits: { fileSize: 1024 } } happens after import so the service will
pick up the change and the test then calls UploadsService.createFromBuffer and
asserts mockGridfs.createFromBuffer is not invoked.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5b965882-a4c6-4df6-b38d-aab6b429f52a

📥 Commits

Reviewing files that changed from the base of the PR and between 80117d7 and d4c3dc3.

📒 Files selected for processing (3)
  • lib/services/gridfs.js
  • modules/uploads/services/uploads.service.js
  • modules/uploads/tests/uploads.createFromBuffer.unit.tests.js

@PierreBrisorgueil PierreBrisorgueil merged commit cf58689 into master Mar 24, 2026
3 checks passed
@PierreBrisorgueil PierreBrisorgueil deleted the feat/create-from-buffer branch March 24, 2026 18:52
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.

feat(uploads): add createFromBuffer to GridFS for programmatic file storage

2 participants