-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathstorage-service.ts
More file actions
194 lines (174 loc) · 6.42 KB
/
Copy pathstorage-service.ts
File metadata and controls
194 lines (174 loc) · 6.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
/**
* IStorageService - File Storage Service Contract
*
* Defines the interface for file/object storage in ObjectStack.
* Concrete implementations (S3, Azure Blob, Local FS, etc.)
* should implement this interface.
*
* Follows Dependency Inversion Principle - plugins depend on this interface,
* not on concrete storage implementations.
*
* Aligned with CoreServiceName 'file-storage' in core-services.zod.ts.
*/
/**
* Options for uploading a file
*/
export interface StorageUploadOptions {
/** MIME content type */
contentType?: string;
/** Custom metadata key-value pairs */
metadata?: Record<string, string>;
/** Access control level */
acl?: 'private' | 'public-read';
}
/**
* Metadata about a stored file
*/
export interface StorageFileInfo {
/** File key/path */
key: string;
/** File size in bytes */
size: number;
/** MIME content type */
contentType?: string;
/** Last modified timestamp */
lastModified: Date;
/** Custom metadata */
metadata?: Record<string, string>;
}
/**
* Descriptor returned by `IStorageService.getPresignedUpload()`.
*
* Consumed by the client SDK to perform a direct browser-to-storage upload.
* Maps 1:1 onto `PresignedUrlResponse.data` defined in
* `packages/spec/src/api/storage.zod.ts`.
*/
export interface PresignedUploadDescriptor {
/** Absolute URL the client should send the bytes to */
uploadUrl: string;
/** HTTP method to use (most adapters use PUT) */
method: 'PUT' | 'POST';
/** Headers the client must include in the upload request */
headers?: Record<string, string>;
/** Time-to-live in seconds */
expiresIn: number;
/** Optional preview / download URL once the file is committed */
downloadUrl?: string;
}
/**
* Descriptor returned by `IStorageService.getPresignedDownload()`.
*/
export interface PresignedDownloadDescriptor {
/** Absolute URL the client can GET to retrieve the bytes */
downloadUrl: string;
/** Time-to-live in seconds */
expiresIn: number;
}
export interface IStorageService {
/**
* Upload a file to storage
* @param key - Storage key/path for the file
* @param data - File content as Buffer or readable stream
* @param options - Upload options (content type, metadata, ACL)
*/
upload(key: string, data: Buffer | ReadableStream, options?: StorageUploadOptions): Promise<void>;
/**
* Download a file from storage
* @param key - Storage key/path
* @returns File content as Buffer
*/
download(key: string): Promise<Buffer>;
/**
* Delete a file from storage
* @param key - Storage key/path
*/
delete(key: string): Promise<void>;
/**
* Check if a file exists in storage
* @param key - Storage key/path
* @returns True if the file exists
*/
exists(key: string): Promise<boolean>;
/**
* Get metadata about a stored file
* @param key - Storage key/path
* @returns File info including size, content type, and last modified date
*/
getInfo(key: string): Promise<StorageFileInfo>;
/**
* List files in a directory/prefix
* @param prefix - Key prefix to list
* @returns Array of file info objects
*/
list?(prefix: string): Promise<StorageFileInfo[]>;
/**
* Generate a pre-signed URL for temporary access
* @param key - Storage key/path
* @param expiresIn - URL expiration time in seconds
* @returns Pre-signed URL string
*/
getSignedUrl?(key: string, expiresIn: number): Promise<string>;
// ==========================================
// Presigned Upload / Download (browser-direct)
// ==========================================
/**
* Generate a presigned upload descriptor that allows the browser to
* upload bytes directly to the storage backend without proxying through
* the API server.
*
* For S3-compatible backends this returns the actual signed PUT URL.
* For local-filesystem backends this returns a server-mounted endpoint
* (e.g. `/api/v1/storage/_local/raw/<token>`) that accepts the bytes
* and writes them to the configured root directory.
*
* @param key - Storage key/path for the final file
* @param expiresIn - Upload URL expiration time in seconds
* @param options - Upload options (content type, metadata, ACL)
* @returns Descriptor consumed by the client SDK
*/
getPresignedUpload?(
key: string,
expiresIn: number,
options?: StorageUploadOptions,
): Promise<PresignedUploadDescriptor>;
/**
* Generate a presigned download URL for the given key.
* For local-filesystem backends this returns a server-mounted endpoint
* that streams the file when accessed within the expiration window.
*
* @param key - Storage key/path
* @param expiresIn - URL expiration time in seconds
*/
getPresignedDownload?(key: string, expiresIn: number): Promise<PresignedDownloadDescriptor>;
// ==========================================
// Chunked / Multipart Upload Methods
// ==========================================
/**
* Initiate a chunked (multipart) upload session
* @param key - Storage key/path for the final file
* @param options - Upload options (content type, metadata, ACL)
* @returns Upload session ID for use in subsequent chunk uploads
*/
initiateChunkedUpload?(key: string, options?: StorageUploadOptions): Promise<string>;
/**
* Upload a single chunk of a multipart upload
* @param uploadId - Multipart upload session ID
* @param partNumber - Part number (1-based, per S3 convention)
* @param data - Chunk content as Buffer
* @returns ETag of the uploaded chunk for assembly
*/
uploadChunk?(uploadId: string, partNumber: number, data: Buffer): Promise<string>;
/**
* Complete a chunked upload by assembling all parts
* @param uploadId - Multipart upload session ID
* @param parts - Ordered list of part numbers and their ETags
* @returns Storage key/path of the assembled file
*/
completeChunkedUpload?(uploadId: string, parts: Array<{ partNumber: number; eTag: string }>): Promise<string>;
/**
* Abort a chunked upload session and clean up uploaded parts
* @param uploadId - Multipart upload session ID
*/
abortChunkedUpload?(uploadId: string): Promise<void>;
}