feat: support addressing objects by versionId - #1341
Conversation
455fc8e to
72f2b66
Compare
There was a problem hiding this comment.
Pull request overview
Adds API-level and storage-layer support for pinning object operations to a specific object version via versionId / sourceVersionId, laying groundwork for multi-version objects while keeping current behavior intact.
Changes:
- Extend object routes (get/head/info, signed URLs, copy/move, delete) to accept a version identifier and pass it through to storage lookups.
- Update storage/database lookup and update paths to optionally filter by
version, and includeversionIdin signed download tokens. - Add new tenant migration indexes to support version-aware addressing and future versioning constraints.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/test/object.test.ts | Adds integration tests covering version-pinned get/info/public get/copy/move/delete and signed URL flows. |
| src/storage/object.ts | Plumbs optional version IDs through findObject, deleteObject, copyObject, moveObject, and signed URL creation. |
| src/storage/database/pg.ts | Extends findObject and updateObject queries to optionally constrain by version. |
| src/storage/database/adapter.ts | Updates the Database interface to accept optional version parameters for findObject and updateObject. |
| src/internal/database/migrations/types.ts | Registers new migration IDs for added object/version indexes. |
| src/internal/auth/jwt.ts | Extends SignedToken to optionally carry versionId. |
| src/http/routes/object/moveObject.ts | Accepts sourceVersionId and forwards it to storage move operation. |
| src/http/routes/object/getSignedURL.ts | Accepts versionId for signed URL generation and forwards it to storage signing. |
| src/http/routes/object/getSignedObject.ts | Uses versionId from verified token to fetch the pinned object version before rendering. |
| src/http/routes/object/getPublicObject.ts | Accepts versionId query param and passes it to object lookup. |
| src/http/routes/object/getObjectInfo.ts | Extends query schema and passes versionId to object info lookup. |
| src/http/routes/object/getObject.ts | Accepts versionId query param and passes it to object lookup. |
| src/http/routes/object/deleteObject.ts | Accepts versionId query param and forwards it to storage delete operation. |
| src/http/routes/object/copyObject.ts | Accepts sourceVersionId and forwards it to storage copy operation. |
| migrations/tenant/0064-objects-key-version-index.sql | Adds a unique index on (bucket_id, name, version) to support version addressing. |
| migrations/tenant/0065-objects-current-version-index.sql | Adds a unique index enforcing a single current (unarchived) row per (bucket_id, name). |
| migrations/tenant/0066-objects-null-version-index.sql | Adds a unique partial index for non-versioned objects keyed by (bucket_id, name). |
Suppressed comments (1)
src/storage/database/pg.ts:1191
versionis gated by a truthy check, so a provided empty string (e.g.?versionId=) would be ignored and the lookup would fall back to the unpinned object. Use an undefined check so any provided value participates in the WHERE clause.
if (version) {
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Coverage Report for CI Build 33077727119Coverage increased (+0.04%) to 81.355%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats💛 - Coveralls |
922e71e to
2f920dc
Compare
efd3bda to
39413e4
Compare
Signed-off-by: Ferhat Elmas <elmas.ferhat@gmail.com>
1816632 to
b90e390
Compare
| type: 'object', | ||
| properties: { | ||
| download: { type: 'string', examples: ['filename.jpg', null] }, | ||
| versionId: { type: 'string', examples: ['eaa8bdb5-2e00-4767-b5a9-d2502efe2196'] }, |
There was a problem hiding this comment.
realized we're missing it in the other endpoint #1350
| return result.rows | ||
| } | ||
|
|
||
| async updateObjectMetadata(bucketId: string, objectName: string, metadata: ObjectMetadata) { |
There was a problem hiding this comment.
this isn't updated for version but it's dead code so fine, I think it's better to drop, will do
What kind of change does this PR introduce?
Feature
What is the current behavior?
Currently we don't allow users to specify version id
What is the new behavior?
Can now pin get, head, info, sign, copy, move, delete, and deleteObjectets to a specific object version via versionId. Also added additional indexes.
Additional context
Left out S3 API changes for now as well. Will be done in a follow up PR.
Only one version can exist per object today, so
versionIdjust reselects the same object you'd already get by default but this lays groundwork for real multi-version support later.