+ return getInternalUrl(bucketInfo, objectStorageKey)
+}
+
+async function applyOnPrefix (options: {
+ prefix: string
+ bucketInfo: BucketInfo
+ commandBuilder: (obj: _Object) => Parameters<S3Client['send']>[0]
+
+ continuationToken?: string
+}) {
+ const { prefix, bucketInfo, commandBuilder, continuationToken } = options
+
+ const s3Client = getClient()
+
+ const commandPrefix = bucketInfo.PREFIX + prefix
+ const listCommand = new ListObjectsV2Command({
+ Bucket: bucketInfo.BUCKET_NAME,
+ Prefix: commandPrefix,
+ ContinuationToken: continuationToken
+ })
+
+ const listedObjects = await s3Client.send(listCommand)
+
+ if (isArray(listedObjects.Contents) !== true) {
+ const message = `Cannot apply function on ${commandPrefix} prefix in bucket ${bucketInfo.BUCKET_NAME}: no files listed.`
+
+ logger.error(message, { response: listedObjects, ...lTags() })
+ throw new Error(message)
+ }
+
+ for (const object of listedObjects.Contents) {
+ const command = commandBuilder(object)
+
+ await s3Client.send(command)
+ }
+
+ // Repeat if not all objects could be listed at once (limit of 1000?)
+ if (listedObjects.IsTruncated) {
+ await applyOnPrefix({ ...options, continuationToken: listedObjects.ContinuationToken })
+ }
+}
+
+function getACL (isPrivate: boolean) {
+ return isPrivate
+ ? CONFIG.OBJECT_STORAGE.UPLOAD_ACL.PRIVATE
+ : CONFIG.OBJECT_STORAGE.UPLOAD_ACL.PUBLIC