-
Notifications
You must be signed in to change notification settings - Fork 1
feat(storage): add copy, move, and setObjectAccess; deprecate updateObject #97
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
Changes from all commits
db35b92
3d7c94c
79d2d96
d2e363a
8390715
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@tigrisdata/storage': minor | ||
| --- | ||
|
|
||
| Add `copy(src, dest, options?)` and `move(src, dest, options?)` for copying and moving objects within or across buckets. Add `setObjectAccess(path, { access })` for changing object ACLs. Deprecate `updateObject`; use `setObjectAccess` for ACL changes and `move` for renames. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import { TigrisHeaders } from '@shared/headers'; | ||
| import { handleError } from '@shared/utils'; | ||
| import { config, missingConfigError } from '../config'; | ||
| import { createStorageClient } from '../http-client'; | ||
| import type { TigrisStorageConfig, TigrisStorageResponse } from '../types'; | ||
|
|
||
| export type CopyOptions = { | ||
| config?: TigrisStorageConfig; | ||
| /** Source bucket. Defaults to `config.bucket`. */ | ||
| srcBucket?: string; | ||
| /** Destination bucket. Defaults to `srcBucket` (same-bucket copy). */ | ||
| destBucket?: string; | ||
| }; | ||
|
|
||
| export type CopyResponse = { | ||
| src: string; | ||
| dest: string; | ||
| }; | ||
|
|
||
| export async function copy( | ||
| src: string, | ||
| dest: string, | ||
| options?: CopyOptions | ||
| ): Promise<TigrisStorageResponse<CopyResponse, Error>> { | ||
| return copyOrMove(src, dest, false, options); | ||
| } | ||
|
|
||
| export async function copyOrMove( | ||
| src: string, | ||
| dest: string, | ||
| rename: boolean, | ||
| options?: CopyOptions | ||
| ): Promise<TigrisStorageResponse<CopyResponse, Error>> { | ||
| if (!src || !dest) { | ||
| return { error: new Error('src and dest are required') }; | ||
| } | ||
|
|
||
| const srcBucket = | ||
| options?.srcBucket ?? options?.config?.bucket ?? config.bucket; | ||
|
|
||
| if (!srcBucket) { | ||
| return missingConfigError('bucket'); | ||
| } | ||
|
|
||
| const destBucket = options?.destBucket ?? srcBucket; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Empty
|
||
|
|
||
| if (srcBucket === destBucket && src === dest) { | ||
| return { error: new Error('src and dest must differ') }; | ||
| } | ||
|
|
||
| const { data: storageHttpClient, error: storageHttpClientError } = | ||
| createStorageClient(options?.config); | ||
|
|
||
| if (storageHttpClientError) { | ||
| return { error: storageHttpClientError }; | ||
| } | ||
|
|
||
| const headers: Record<string, string> = { | ||
| [TigrisHeaders.COPY_SOURCE]: `${srcBucket}/${encodeURIComponent(src)}`, | ||
| }; | ||
|
|
||
| if (rename) { | ||
| headers[TigrisHeaders.RENAME] = 'true'; | ||
| } | ||
|
|
||
| try { | ||
| const response = await storageHttpClient.request({ | ||
| method: 'PUT', | ||
| path: `/${destBucket}/${encodeURIComponent(dest)}?x-id=CopyObject`, | ||
| headers, | ||
| }); | ||
|
|
||
| if (response.error) { | ||
| return { error: response.error }; | ||
| } | ||
| } catch (error) { | ||
| return handleError(error as Error); | ||
| } | ||
|
|
||
| return { | ||
| data: { | ||
| src: `${srcBucket}/${src}`, | ||
| dest: `${destBucket}/${dest}`, | ||
| }, | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import type { TigrisStorageResponse } from '../types'; | ||
| import { type CopyOptions, type CopyResponse, copyOrMove } from './copy'; | ||
|
|
||
| export type MoveOptions = CopyOptions; | ||
| export type MoveResponse = CopyResponse; | ||
|
|
||
| export async function move( | ||
| src: string, | ||
| dest: string, | ||
| options?: MoveOptions | ||
| ): Promise<TigrisStorageResponse<MoveResponse, Error>> { | ||
| return copyOrMove(src, dest, true, options); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import { PutObjectAclCommand } from '@aws-sdk/client-s3'; | ||
| import { handleError } from '@shared/utils'; | ||
| import { config, missingConfigError } from '../../config'; | ||
| import { createTigrisClient } from '../../tigris-client'; | ||
| import type { TigrisStorageConfig, TigrisStorageResponse } from '../../types'; | ||
|
|
||
| export type SetObjectAccessOptions = { | ||
| config?: TigrisStorageConfig; | ||
| access: 'public' | 'private'; | ||
| }; | ||
|
|
||
| export type SetObjectAccessResponse = { | ||
| path: string; | ||
| }; | ||
|
|
||
| export async function setObjectAccess( | ||
| path: string, | ||
| options: SetObjectAccessOptions | ||
| ): Promise<TigrisStorageResponse<SetObjectAccessResponse, Error>> { | ||
| if (!options?.access) { | ||
| return { error: new Error('No access option provided') }; | ||
| } | ||
|
designcode marked this conversation as resolved.
|
||
|
|
||
| const bucket = options?.config?.bucket ?? config.bucket; | ||
|
|
||
| if (!bucket) { | ||
| return missingConfigError('bucket'); | ||
| } | ||
|
|
||
| const { data: tigrisClient, error } = createTigrisClient(options?.config); | ||
|
|
||
| if (error) { | ||
| return { error }; | ||
| } | ||
|
|
||
| try { | ||
| await tigrisClient.send( | ||
| new PutObjectAclCommand({ | ||
| Bucket: bucket, | ||
| Key: path, | ||
| ACL: options.access === 'public' ? 'public-read' : 'private', | ||
| }) | ||
| ); | ||
| } catch (error) { | ||
| return handleError(error as Error); | ||
| } | ||
|
|
||
| return { | ||
| data: { | ||
| path, | ||
| }, | ||
| }; | ||
| } | ||


Uh oh!
There was an error while loading. Please reload this page.