Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions packages/storage_client/lib/src/storage_file_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,11 @@ class StorageFileApi {
},
options: options,
);
final signedUrlPath = (response as Map<String, dynamic>)['signedURL'];
final signedUrlPath =
(response as Map<String, dynamic>)['signedURL'] as String?;
if (signedUrlPath == null) {
throw StorageException('No signed URL returned by API');
}
final signedUrl = '$url$signedUrlPath';
return signedUrl;
}
Expand Down Expand Up @@ -395,11 +399,11 @@ class StorageFileApi {
options: options,
);
final List<SignedUrl> urls = (response as List).map((e) {
final signedUrlPath = e['signedURL'] as String?;
return SignedUrl(
// Prevents exceptions being thrown when null value is returned
// https://github.com/supabase/storage-api/issues/353
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should either keep this comment or remove the null catch for the path field. Or is that also null if signedURL is null?

path: e['path'] ?? '',
signedUrl: '$url${e['signedURL']}',
signedUrl: signedUrlPath != null ? '$url$signedUrlPath' : null,
error: e['error'] as String?,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the error field only exists for requesting multiple urls or would that also exist for the case above of a single url request?

);
}).toList();
return urls;
Expand Down
19 changes: 14 additions & 5 deletions packages/storage_client/lib/src/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -246,36 +246,45 @@ class SignedUrl {
/// The file path, including the current file name. For example `folder/image.png`.
final String path;

/// Full signed URL of the files.
final String signedUrl;
/// Full signed URL of the file. Null when the path does not exist or the
/// server returned an error for this item; check [error] for details.
final String? signedUrl;

/// Per-item error message returned by the server when [signedUrl] is null.
final String? error;

const SignedUrl({
required this.path,
required this.signedUrl,
this.error,
});

@override
String toString() => 'SignedUrl(path: $path, signedUrl: $signedUrl)';
String toString() =>
'SignedUrl(path: $path, signedUrl: $signedUrl, error: $error)';

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is SignedUrl &&
other.path == path &&
other.signedUrl == signedUrl;
other.signedUrl == signedUrl &&
other.error == error;
}

@override
int get hashCode => path.hashCode ^ signedUrl.hashCode;
int get hashCode => path.hashCode ^ signedUrl.hashCode ^ error.hashCode;

SignedUrl copyWith({
String? path,
String? signedUrl,
String? error,
}) {
return SignedUrl(
path: path ?? this.path,
signedUrl: signedUrl ?? this.signedUrl,
error: error ?? this.error,
);
}
}
Expand Down
43 changes: 42 additions & 1 deletion packages/storage_client/test/basic_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,51 @@ void main() {
});

test('should createSignedUrl file', () async {
customHttpClient.response = {'signedURL': 'url'};
customHttpClient.response = {'signedURL': '/signed/url'};

final response = await client.from('public').createSignedUrl('b.txt', 60);
expect(response, isA<String>());
expect(response, endsWith('/signed/url'));
});

test('createSignedUrl throws StorageException when signedURL is null',
() async {
customHttpClient.response = {'signedURL': null};

expect(
() => client.from('public').createSignedUrl('missing.txt', 60),
throwsA(isA<StorageException>()),
);
});

test(
'createSignedUrls returns null signedUrl and error for missing path',
() async {
customHttpClient.response = [
{
'path': 'exists.txt',
'signedURL':
'/storage/v1/object/sign/public/exists.txt?token=abc',
},
{
'path': 'missing.txt',
'signedURL': null,
'error': 'not_found',
},
];

final urls = await client
.from('public')
.createSignedUrls(['exists.txt', 'missing.txt'], 60);

expect(urls.length, 2);
expect(urls[0].signedUrl, isNotNull);
expect(
urls[0].signedUrl,
'$supabaseUrl/storage/v1/storage/v1/object/sign/public/exists.txt?token=abc',
);
expect(urls[1].signedUrl, isNull);
expect(urls[1].error, 'not_found');
});

test('should list files', () async {
Expand Down
Loading