Skip to content

Commit

Permalink
more alignment with the JS SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
dshukertjr committed Aug 6, 2024
1 parent 28cf157 commit a267895
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 44 deletions.
10 changes: 9 additions & 1 deletion packages/gotrue/lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:gotrue/src/types/api_version.dart';
import 'package:gotrue/src/types/auth_response.dart';
import 'package:gotrue/src/version.dart';

Expand All @@ -22,7 +23,14 @@ class Constants {
static const autoRefreshTickThreshold = 3;

/// The name of the header that contains API version.
static const apiVersionHeaderName = 'x-supabase-api-version';
static const apiVersionHeaderName = 'X-Supabase-Api-Version';
}

class ApiVersions {
static final v20240101 = ApiVersion(
name: '2024-01-01',
timestamp: DateTime.parse('2024-01-01T00:00:00.0Z'),
);
}

enum AuthChangeEvent {
Expand Down
10 changes: 4 additions & 6 deletions packages/gotrue/lib/src/fetch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ class GotrueFetch {

String? errorCode;

final ApiVersion? version = ApiVersion.fromResponse(error);
final responseApiVersion = ApiVersion.fromResponse(error);

if (version?.isSameOrAfter(ApiVersions.v20240101) ?? false) {
if (responseApiVersion?.isSameOrAfter(ApiVersions.v20240101) ?? false) {
errorCode = _getErrorCode(data, 'code');
} else {
errorCode = _getErrorCode(data, 'error_code');
Expand All @@ -86,23 +86,21 @@ class GotrueFetch {
throw AuthWeakPasswordException(
message: _getErrorMessage(data),
statusCode: error.statusCode.toString(),
errorCode: ErrorCode.weakPassword.code,
reasons: List<String>.from(data['weak_password']['reasons']),
);
}
} else if (errorCode == ErrorCode.weakPassword.code) {
throw AuthWeakPasswordException(
message: _getErrorMessage(data),
statusCode: error.statusCode.toString(),
errorCode: errorCode,
reasons: List<String>.from(data['weak_password']?['reasons'] ?? []),
);
}

throw AuthApiException(
_getErrorMessage(data),
statusCode: error.statusCode.toString(),
errorCode: errorCode,
code: errorCode,
);
}

Expand All @@ -115,7 +113,7 @@ class GotrueFetch {

// Set the API version header if not already set
if (!headers.containsKey(Constants.apiVersionHeaderName)) {
headers[Constants.apiVersionHeaderName] = ApiVersions.v20240101.asString;
headers[Constants.apiVersionHeaderName] = ApiVersions.v20240101.name;
}

if (options?.jwt != null) {
Expand Down
2 changes: 1 addition & 1 deletion packages/gotrue/lib/src/gotrue_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ class GoTrueClient {
throw AuthException(
errorDescription,
statusCode: errorCode,
errorCode: error,
code: error,
);
}

Expand Down
30 changes: 13 additions & 17 deletions packages/gotrue/lib/src/types/api_version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,36 @@ const String _apiVersionRegex =
r'^2[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-9]|3[0-1])';

/// Represents the API versions supported by the package.
class ApiVersions {
const ApiVersions._();
static ApiVersion v20240101 = ApiVersion(DateTime(2024, 1, 1));
}

/// Represents the API version specified by a [date] in the format YYYY-MM-DD.
/// Represents the API version specified by a [name] in the format YYYY-MM-DD.
class ApiVersion {
ApiVersion(this.date);
const ApiVersion({
required this.name,
required this.timestamp,
});

final String name;
final DateTime timestamp;

/// Parses the API version from the string date.
static ApiVersion? fromString(String version) {
if (!RegExp(_apiVersionRegex).hasMatch(version)) {
return null;
}

final DateTime? date = DateTime.tryParse(version);
if (date == null) return null;
return ApiVersion(date);
final DateTime? timestamp = DateTime.tryParse('${version}T00:00:00.0Z');
if (timestamp == null) return null;
return ApiVersion(name: version, timestamp: timestamp);
}

/// Parses the API version from the response headers.
static ApiVersion? fromResponse(Response response) {
final String? version = response.headers[Constants.apiVersionHeaderName];
final version = response.headers[Constants.apiVersionHeaderName];
return version != null ? fromString(version) : null;
}

final DateTime date;

/// Return only the date part of the DateTime.
String get asString => date.toIso8601String().split('T').first;

/// Returns true if this version is the same or after [other].
bool isSameOrAfter(ApiVersion other) {
return date.isAfter(other.date) || date == other.date;
return timestamp.isAfter(other.timestamp) || name == other.name;
}
}
24 changes: 12 additions & 12 deletions packages/gotrue/lib/src/types/auth_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ class AuthException implements Exception {
/// Error code associated with the error. Most errors coming from
/// HTTP responses will have a code, though some errors that occur
/// before a response is received will not have one present.
final String? errorCode;
/// In that case [statusCode] will also be null.
///
/// Find the full list of error codes in our documentation.
/// https://supabase.com/docs/reference/dart/auth-error-codes
final String? code;

const AuthException(this.message, {this.statusCode, this.errorCode});
const AuthException(this.message, {this.statusCode, this.code});

@override
String toString() =>
'AuthException(message: $message, statusCode: $statusCode, errorCode: $errorCode)';
'AuthException(message: $message, statusCode: $statusCode, errorCode: $code)';

@override
bool operator ==(Object other) {
Expand All @@ -25,12 +29,11 @@ class AuthException implements Exception {
return other is AuthException &&
other.message == message &&
other.statusCode == statusCode &&
other.errorCode == errorCode;
other.code == code;
}

@override
int get hashCode =>
message.hashCode ^ statusCode.hashCode ^ errorCode.hashCode;
int get hashCode => message.hashCode ^ statusCode.hashCode ^ code.hashCode;
}

class AuthPKCEGrantCodeExchangeError extends AuthException {
Expand All @@ -42,20 +45,18 @@ class AuthSessionMissingException extends AuthException {
: super(
message ?? 'Auth session missing!',
statusCode: '400',
errorCode: ErrorCode.sessionNotFound.code,
);
}

class AuthRetryableFetchException extends AuthException {
AuthRetryableFetchException({
String message = 'AuthRetryableFetchException',
super.statusCode,
super.errorCode,
}) : super(message);
}

class AuthApiException extends AuthException {
AuthApiException(super.message, {super.statusCode, super.errorCode});
AuthApiException(super.message, {super.statusCode, super.code});
}

class AuthUnknownException extends AuthException {
Expand All @@ -70,8 +71,7 @@ class AuthWeakPasswordException extends AuthException {

AuthWeakPasswordException({
required String message,
required String statusCode,
required super.statusCode,
required this.reasons,
String? errorCode,
}) : super(message, statusCode: statusCode, errorCode: errorCode);
}) : super(message, code: ErrorCode.weakPassword.code);
}
2 changes: 1 addition & 1 deletion packages/gotrue/lib/src/types/error_code.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import 'package:collection/collection.dart';

enum ErrorCode {
unknown('unknown'),
unexpectedFailure('unexpected_failure'),
validationFailed('validation_failed'),
badJson('bad_json'),
Expand Down Expand Up @@ -43,6 +42,7 @@ enum ErrorCode {
smsSendFailed('sms_send_failed'),
emailNotConfirmed('email_not_confirmed'),
phoneNotConfirmed('phone_not_confirmed'),
reauthNonceMissing('reauth_nonce_missing'),
samlRelayStateNotFound('saml_relay_state_not_found'),
samlRelayStateExpired('saml_relay_state_expired'),
samlIdpNotFound('saml_idp_not_found'),
Expand Down
4 changes: 2 additions & 2 deletions packages/gotrue/test/api_version_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ void main() {
Constants.apiVersionHeaderName: validHeader,
});
final version = ApiVersion.fromResponse(response);
expect(version?.date, DateTime(2024, 1, 1));
expect(version?.asString, validHeader);
expect(version?.name, validHeader);
expect(version?.timestamp, DateTime(2024, 1, 1));
});

test('should return null object for invalid header', () {
Expand Down
6 changes: 3 additions & 3 deletions packages/gotrue/test/client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void main() {
fail('signUp with weak password should throw exception');
} on AuthException catch (error) {
expect(error, isA<AuthWeakPasswordException>());
expect(error.errorCode, ErrorCode.weakPassword.code);
expect(error.code, ErrorCode.weakPassword.code);
} catch (error) {
fail('signUp threw ${error.runtimeType} instead of AuthException');
}
Expand Down Expand Up @@ -142,7 +142,7 @@ void main() {
} on AuthException catch (error) {
expect(error.message, errorMessage);
expect(error.statusCode, '401');
expect(error.errorCode, 'unauthorized_client');
expect(error.code, 'unauthorized_client');
} catch (error) {
fail(
'getSessionFromUrl threw ${error.runtimeType} instead of AuthException');
Expand Down Expand Up @@ -317,7 +317,7 @@ void main() {
await client.updateUser(UserAttributes(password: password));
fail('updateUser did not throw');
} on AuthException catch (error) {
expect(error.errorCode, ErrorCode.samePassword.code);
expect(error.code, ErrorCode.samePassword.code);
}
});

Expand Down
2 changes: 1 addition & 1 deletion packages/gotrue/test/fetch_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Future<void> _testFetchRequest(Client client) async {
try {
await fetch.request(_mockUrl, RequestMethodType.get);
} on AuthException catch (error) {
expect(error.errorCode, 'weak_password');
expect(error.code, 'weak_password');
expect(error.message, 'error_message');
} catch (error) {
fail('Should have thrown AuthException');
Expand Down

0 comments on commit a267895

Please sign in to comment.