Repository navigation
Expand file tree
/
Copy pathStorageClient+Buckets.swift
More file actions
236 lines (219 loc) · 9.26 KB
/
Copy pathStorageClient+Buckets.swift
File metadata and controls
236 lines (219 loc) · 9.26 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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
import Foundation
import HTTPTypes
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
/// Bucket-management operations (listing, creating, updating, emptying, and deleting) for
/// ``StorageClient``.
extension StorageClient {
/// Retrieves the Storage buckets within the project.
///
/// ```swift
/// let recent = try await storage.listBuckets(
/// options: BucketListOptions(limit: 10, sortBy: .createdAt, order: .descending))
/// ```
///
/// - Parameter options: Paging, sort and a name filter. Defaults to every bucket.
/// - Returns: The buckets the caller can see.
/// - Throws: ``StorageError`` if the request fails or the caller is not authorized.
public func listBuckets(options: BucketListOptions = BucketListOptions()) async throws
-> [Bucket]
{
try await api.execute(api.requests.listBuckets(options)).decoded()
}
/// Retrieves the details of an existing Storage bucket.
///
/// - Parameter id: The unique identifier of the bucket to retrieve.
/// - Returns: The ``Bucket`` with the given identifier.
/// - Throws: ``StorageError`` if the bucket does not exist or the caller is not authorized.
public func bucket(_ id: String) async throws -> Bucket {
try await api.execute(api.requests.bucket(id)).decoded()
}
/// The create and update body. `nil` fields are left out, so an update changes only what the
/// caller set.
struct BucketParameters: Encodable {
var id: String?
var name: String?
var `public`: Bool?
var fileSizeLimit: ByteCount?
var allowedMimeTypes: [String]?
var type: BucketType?
var versioningStatus: String?
enum CodingKeys: String, CodingKey {
case id
case name
case `public`
case fileSizeLimit = "file_size_limit"
case allowedMimeTypes = "allowed_mime_types"
case type
case versioningStatus = "versioning_status"
}
init(id: String, options: CreateBucketOptions) {
self.id = id
self.name = id
self.public = options.isPublic
self.fileSizeLimit = options.fileSizeLimit
self.allowedMimeTypes = options.allowedMimeTypes
self.type = options.type
self.versioningStatus = options.versioningStatus?.rawValue
}
init(options: UpdateBucketOptions) {
self.public = options.isPublic
self.fileSizeLimit = options.fileSizeLimit
self.allowedMimeTypes = options.allowedMimeTypes
self.versioningStatus = options.versioningStatus?.rawValue
}
var isEmpty: Bool {
`public` == nil && fileSizeLimit == nil && allowedMimeTypes == nil && versioningStatus == nil
}
}
/// Creates a new Storage bucket.
///
/// ```swift
/// try await storage.createBucket(
/// "avatars",
/// options: CreateBucketOptions(isPublic: true, fileSizeLimit: .megabytes(5))
/// )
/// ```
///
/// - Parameters:
/// - id: A unique identifier for the bucket. This also becomes the bucket name.
/// - options: Options that control visibility, file-size limits, allowed MIME types, the
/// bucket type and versioning. A `nil` field takes the server default: a private standard
/// bucket with no size or type restrictions and versioning off.
/// - Returns: The bucket name the server stored.
/// - Throws: ``StorageError`` if a bucket with the same identifier already exists, or if the
/// caller is not authorized.
@discardableResult
public func createBucket(
_ id: String, options: CreateBucketOptions = CreateBucketOptions()
) async throws -> String {
struct Response: Decodable {
let name: String
}
return try await api.execute(
api.requests.createBucket(BucketParameters(id: id, options: options))
)
.decoded(as: Response.self)
.name
}
/// Updates an existing Storage bucket's settings.
///
/// Only the fields set on `options` are sent; the others keep their current value.
///
/// ```swift
/// try await storage.updateBucket(
/// "avatars",
/// options: UpdateBucketOptions(allowedMimeTypes: ["image/png", "image/jpeg"])
/// )
/// try await storage.updateBucket(
/// "avatars", options: UpdateBucketOptions(versioningStatus: .suspended))
/// ```
///
/// - Parameters:
/// - id: The unique identifier of the bucket to update.
/// - options: The settings to change. At least one field must be set.
/// - Throws: ``StorageError`` with kind ``StorageError/Kind-swift.struct/invalidRequest`` if no
/// field is set, or if the bucket does not exist or the caller is not authorized.
public func updateBucket(_ id: String, options: UpdateBucketOptions) async throws {
let parameters = BucketParameters(options: options)
guard !parameters.isEmpty else {
throw StorageError(
kind: .invalidRequest, message: "updateBucket needs at least one field to change.")
}
try await api.execute(api.requests.updateBucket(id, parameters))
}
/// Removes all objects inside a bucket without deleting the bucket itself.
///
/// > Important: This operation is irreversible. All files in the bucket will be permanently
/// > deleted.
///
/// - Parameter id: The unique identifier of the bucket to empty.
/// - Throws: ``StorageError`` if the bucket does not exist or the caller is not authorized.
public func emptyBucket(_ id: String) async throws {
try await api.execute(api.requests.emptyBucket(id))
}
/// Deletes an existing bucket.
///
/// > Important: A bucket cannot be deleted while it contains objects. Call ``emptyBucket(_:)``
/// > first to remove all files, then delete the bucket.
///
/// - Parameter id: The unique identifier of the bucket to delete.
/// - Throws: ``StorageError`` if the bucket is not empty, does not exist, or the caller is not
/// authorized.
public func deleteBucket(_ id: String) async throws {
try await api.execute(api.requests.deleteBucket(id))
}
/// Returns the lifecycle policy of a Standard bucket, or `nil` if it has none.
///
/// - Parameter id: The unique identifier of the bucket.
/// - Returns: The lifecycle policy, or `nil` if the bucket has none.
/// - Throws: ``StorageError`` if lifecycle support is off for the project, the bucket is not a
/// Standard bucket, or the caller is not authorized.
public func lifecycle(forBucket id: String) async throws -> LifecycleConfiguration? {
do {
return try await api.execute(api.requests.lifecycle(id, method: .get))
.decoded(as: LifecycleConfiguration.self)
} catch let error as StorageError where error.code == .noSuchLifecycleConfiguration {
return nil
}
}
/// Replaces the lifecycle policy of a Standard bucket.
///
/// The policy replaces whatever the bucket had. To remove it, call
/// ``deleteLifecycle(forBucket:)``.
///
/// ```swift
/// try await storage.setLifecycle(
/// LifecycleConfiguration(rules: [
/// LifecycleRule(noncurrentVersionExpiration: NoncurrentVersionExpiration(noncurrentDays: 30))
/// ]),
/// forBucket: "documents"
/// )
/// ```
///
/// - Parameters:
/// - configuration: The policy, with 1 to 1000 rules.
/// - id: The unique identifier of the bucket.
/// - Returns: The stored policy, with the identifiers Storage generated for rules that had none.
/// - Throws: ``StorageError`` if Storage rejects the policy (no rules, more than 1000, or an
/// invalid rule), lifecycle support is off, the bucket is not a Standard bucket, or the caller
/// is not authorized.
@discardableResult
public func setLifecycle(_ configuration: LifecycleConfiguration, forBucket id: String)
async throws -> LifecycleConfiguration
{
try await api.execute(api.requests.setLifecycle(id, configuration))
.decoded(as: LifecycleConfiguration.self)
}
/// Removes the lifecycle policy of a Standard bucket. Succeeds when the bucket has none.
///
/// - Parameter id: The unique identifier of the bucket.
/// - Throws: ``StorageError`` if lifecycle support is off for the project, the bucket is not a
/// Standard bucket, or the caller is not authorized.
public func deleteLifecycle(forBucket id: String) async throws {
try await api.execute(api.requests.lifecycle(id, method: .delete))
}
/// Purges the CDN cache for every file in a bucket, or in the whole project, so the next
/// request for each one is served from Storage again. The CDN can take up to 60 seconds to
/// apply the purge.
///
/// ```swift
/// try await storage.purgeCache(bucket: "avatars")
/// try await storage.purgeCache(bucket: nil) // every bucket
/// ```
///
/// > Important: This requires the `secret` key and the `purgeCache` tenant feature. On
/// > self-hosted Storage, a CDN purge endpoint must also be configured, otherwise the request
/// > fails.
///
/// - Parameters:
/// - bucket: The unique identifier of the bucket to purge, or `nil` to purge every bucket.
/// - transformationsOnly: Pass `true` to purge only the resized and reformatted variants and
/// keep the original cached. By default, the original and all its variants are purged.
/// - Throws: ``StorageError`` if the caller is not authorized or cache purging is not enabled.
public func purgeCache(bucket: String?, transformationsOnly: Bool = false) async throws {
try await api.execute(
api.requests.purgeCache(bucket: bucket, transformationsOnly: transformationsOnly))
}
}