Skip to content

Conversation

@melihciray
Copy link

This pull request introduces the new objectPrefix feature to the S3Store, allowing users to organize uploaded files in logical folder structures within their S3 bucket. The changes are fully backward compatible and include updates to the implementation, documentation, and usage examples to support and demonstrate this feature.

S3Store Implementation Updates

  • Added an optional objectPrefix property to the Options type and the S3Store class, initialized in the constructor and defaulting to an empty string for backward compatibility. All S3 object key generation methods (infoKey, partKey, and all S3 operations) now use this prefix to create pseudo-directory structures. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

Documentation and Example Additions

  • Added comprehensive documentation summarizing the new feature, including usage, migration tips, benefits, and testing recommendations in IMPLEMENTATION_SUMMARY.md, OBJECT_PREFIX_EXAMPLE.md, and QUICK_REFERENCE.md. These docs explain how folder structures are created, provide before-and-after examples, and detail use cases such as multi-tenant, date-based, and environment-based organization. [1] [2] [3]
  • Added a new examples.ts file with practical code samples for various usage scenarios, including multi-tenant, environment-based, per-user uploads, document type segregation, and lifecycle policy-friendly structures.

Backward Compatibility and Migration

  • Ensured that if objectPrefix is not provided, files are stored at the bucket root, maintaining current behavior. Documentation provides migration strategies for existing setups. [1] [2]

Benefits and Best Practices

  • Documented the organizational, security, cost, and lifecycle management advantages of using prefixes, and provided best practices for their usage (e.g., using trailing slashes for folder-like structures). [1] [2]

Testing and S3 Console Visualization

  • Included recommendations for testing with various prefix configurations and visual examples of how files will appear in the S3 console with and without prefixes. [1] [2]

Let me know if you have questions about how the prefixing logic works or how to use it in your own code!

@changeset-bot
Copy link

changeset-bot bot commented Oct 14, 2025

⚠️ No Changeset found

Latest commit: 2447985

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Oct 14, 2025

Walkthrough

Adds optional objectPrefix support to S3Store, updates key generation to prepend the prefix, and refactors S3 operations to use centralized key helpers. Introduces new examples demonstrating various prefix strategies and adds documentation explaining configuration, usage, and migration. Public API updated to include objectPrefix in Options and a class property.

Changes

Cohort / File(s) Summary of changes
Core S3Store implementation
packages/s3-store/src/index.ts
Adds objectPrefix?: string to Options; adds protected objectPrefix: string to S3Store; initializes prefix in constructor; updates infoKey and partKey to prepend prefix; routes S3 operations through these helpers for consistent prefixed keys.
Examples and usage
packages/s3-store/examples.ts
New example file showing multiple S3Store instantiations with different objectPrefix strategies (env-, date-, user-, and type-based), Express/TUS integration, per-user middleware, and lifecycle policy comments.
Documentation
packages/s3-store/OBJECT_PREFIX_EXAMPLE.md, packages/s3-store/QUICK_REFERENCE.md, packages/s3-store/IMPLEMENTATION_SUMMARY.md
Adds and updates docs explaining the objectPrefix option, usage scenarios, bucket layout impacts, tips (trailing slash, backward compatibility), migration notes, and a high-level implementation summary.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title mentions S3 file upload into a specified path, which loosely corresponds to the new objectPrefix feature for organizing S3 keys, but it does not use the correct terminology or clearly highlight the addition of an objectPrefix option on the S3Store. This wording may mislead readers into thinking the change centers on generic file path handling rather than introducing a structured prefix configuration. Although it touches on uploading to a path, it fails to succinctly summarize the main enhancement of adding an objectPrefix to the Options type and S3Store class. A more accurate title would directly reference the objectPrefix feature and its integration with S3Store.
Description Check ✅ Passed The PR description accurately describes the addition of the objectPrefix feature to S3Store, including implementation details, documentation updates, examples, and backward compatibility, all of which align with the raw summary of changes. It clearly outlines the feature’s purpose, usage scenarios, migration guidance, and benefits, offering sufficient context for reviewers. The level of detail exceeds the minimum requirement but remains relevant and on-topic for this pull request.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/s3-store/src/index.ts (1)

758-771: Bug: double-prefixing in deleteExpired leads to orphaned objects.

expiredUpload.Key already includes the prefix; passing it to infoKey/partKey re-applies objectPrefix, generating wrong keys (e.g., uploads/uploads/.info). Delete will miss targets.

Apply this fix to derive related keys from the full S3 key without re-prefixing:

-          all.push(
-            {
-              key: this.infoKey(expiredUpload.Key as string),
-            },
-            {
-              key: this.partKey(expiredUpload.Key as string, true),
-            }
-          )
+          const mainKey = expiredUpload.Key as string
+          all.push(
+            { key: `${mainKey}.info` },
+            { key: `${mainKey}.part` }
+          )

Consider adding a small helper to avoid future drift, e.g., infoKeyFromObjectKey(key) and partKeyFromObjectKey(key, true).

🧹 Nitpick comments (4)
packages/s3-store/OBJECT_PREFIX_EXAMPLE.md (1)

31-37: Add language to fenced code blocks (markdownlint MD040).

Label the directory tree code blocks as text to satisfy MD040.

-```
+```text
 my-bucket/
   ├── file-id-1
   ├── file-id-1.info
   ├── file-id-2
   └── file-id-2.info

```diff
-```
+```text
 my-bucket/
   └── uploads/
       ├── file-id-1
       ├── file-id-1.info
       ├── file-id-2
       └── file-id-2.info

```diff
-```
+```text
 my-bucket/
   └── my-app/
       └── uploads/
           └── 2024/
               ├── file-id-1
               ├── file-id-1.info
               ├── file-id-2
               └── file-id-2.info


Also applies to: 40-47, 50-59

</blockquote></details>
<details>
<summary>packages/s3-store/QUICK_REFERENCE.md (1)</summary><blockquote>

`72-79`: **Specify language for console directory trees (markdownlint MD040).**

Use text for these blocks.



```diff
-```
+```text
 📁 my-bucket
   └── 📁 uploads
       ├── 📄 file-abc123
       ├── 📄 file-abc123.info
       ├── 📄 file-xyz789
       └── 📄 file-xyz789.info

```diff
-```
+```text
 📁 my-bucket
   ├── 📄 file-abc123
   ├── 📄 file-abc123.info
   ├── 📄 file-xyz789
   └── 📄 file-xyz789.info


Also applies to: 83-89

</blockquote></details>
<details>
<summary>packages/s3-store/IMPLEMENTATION_SUMMARY.md (1)</summary><blockquote>

`65-71`: **Add language identifiers to directory tree code blocks (MD040).**

Mark the folder trees as text.



```diff
-```
+```text
 my-bucket/
   ├── file-abc123
   ├── file-abc123.info
   ├── file-xyz789
   └── file-xyz789.info

```diff
-```
+```text
 my-bucket/
   └── uploads/
       ├── file-abc123
       ├── file-abc123.info
       ├── file-xyz789
       └── file-xyz789.info

```diff
-```
+```text
 my-bucket/
   └── my-app/
       └── uploads/
           └── 2024/
               ├── file-abc123
               ├── file-abc123.info
               ├── file-xyz789
               └── file-xyz789.info


Also applies to: 74-81, 84-93

</blockquote></details>
<details>
<summary>packages/s3-store/examples.ts (1)</summary><blockquote>

`87-113`: **Avoid per-request server instantiation.**

Creating a new Server and S3Store on every /user-uploads request is expensive. Cache per-user instances or reuse a shared Server with dynamic datastore resolution.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: Path: .coderabbit.yml

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 15b9c6063212e628cbcf97e51296575207f20948 and 24479853d1a55d0f18e054cc5bc13c5634d7a0dc.

</details>

<details>
<summary>📒 Files selected for processing (5)</summary>

* `packages/s3-store/IMPLEMENTATION_SUMMARY.md` (1 hunks)
* `packages/s3-store/OBJECT_PREFIX_EXAMPLE.md` (1 hunks)
* `packages/s3-store/QUICK_REFERENCE.md` (1 hunks)
* `packages/s3-store/examples.ts` (1 hunks)
* `packages/s3-store/src/index.ts` (11 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code graph analysis (1)</summary>

<details>
<summary>packages/s3-store/examples.ts (1)</summary><blockquote>

<details>
<summary>packages/s3-store/src/index.ts (1)</summary>

* `S3Store` (101-838)

</details>

</blockquote></details>

</details><details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>

<details>
<summary>packages/s3-store/QUICK_REFERENCE.md</summary>

72-72: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

---

83-83: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>
<details>
<summary>packages/s3-store/IMPLEMENTATION_SUMMARY.md</summary>

65-65: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

---

74-74: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

---

84-84: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>
<details>
<summary>packages/s3-store/OBJECT_PREFIX_EXAMPLE.md</summary>

31-31: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

---

40-40: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

---

50-50: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>packages/s3-store/src/index.ts (2)</summary><blockquote>

`224-237`: **Key helpers look good.**

infoKey/partKey correctly prepend objectPrefix and preserve .part behavior.

---

`467-471`: **Consistent use of key helpers.**

All S3 operations now use partKey/infoKey; this maintains prefix correctness end-to-end.




Also applies to: 493-499, 557-562, 585-590, 696-714

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@Murderlon
Copy link
Member

Already supported as discussed in #805

@Murderlon Murderlon closed this Oct 16, 2025
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