@wwdrew/expo-spotify-sdk 2.2.3 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,14 +5,16 @@ enum SpotifyRefreshError: Error {
5
5
  case invalidURL(String)
6
6
  case network(Error)
7
7
  case http(status: Int, body: String?)
8
+ case refreshTokenExpired
8
9
  case parse(String)
9
10
 
10
11
  var code: String {
11
12
  switch self {
12
- case .invalidURL: return "INVALID_CONFIG"
13
- case .network: return "NETWORK_ERROR"
14
- case .http: return "TOKEN_SWAP_FAILED"
15
- case .parse: return "TOKEN_SWAP_PARSE_ERROR"
13
+ case .invalidURL: return "INVALID_CONFIG"
14
+ case .network: return "NETWORK_ERROR"
15
+ case .http: return "TOKEN_SWAP_FAILED"
16
+ case .refreshTokenExpired: return "REFRESH_TOKEN_EXPIRED"
17
+ case .parse: return "TOKEN_SWAP_PARSE_ERROR"
16
18
  }
17
19
  }
18
20
 
@@ -21,10 +23,12 @@ enum SpotifyRefreshError: Error {
21
23
  case .invalidURL(let s):
22
24
  return "Invalid token refresh URL: \(s)"
23
25
  case .network(let err):
24
- return err.localizedDescription
26
+ return (err as NSError).safeLocalizedDescription
25
27
  case .http(let status, let body):
26
28
  let trimmed = body.map { String($0.prefix(512)) } ?? ""
27
29
  return "Token refresh server returned HTTP \(status)\(trimmed.isEmpty ? "" : ": \(trimmed)")"
30
+ case .refreshTokenExpired:
31
+ return "The refresh token is no longer valid (expired or revoked). The user must sign in again."
28
32
  case .parse(let m):
29
33
  return m
30
34
  }
@@ -106,6 +110,13 @@ struct SpotifyTokenRefreshClient {
106
110
  }
107
111
  guard (200..<300).contains(http.statusCode) else {
108
112
  let body = String(data: data, encoding: .utf8)
113
+ // Spotify returns `invalid_grant` (HTTP 400) when the refresh token has
114
+ // expired or been revoked — the user must re-authenticate. Surface this
115
+ // as a dedicated code rather than a generic token-swap failure so callers
116
+ // can branch to sign-in without inspecting the message string.
117
+ if let body, body.range(of: "invalid_grant", options: .caseInsensitive) != nil {
118
+ throw SpotifyRefreshError.refreshTokenExpired
119
+ }
109
120
  throw SpotifyRefreshError.http(status: http.statusCode, body: body)
110
121
  }
111
122
 
@@ -116,7 +127,9 @@ struct SpotifyTokenRefreshClient {
116
127
  }
117
128
  json = parsed
118
129
  } catch {
119
- throw SpotifyRefreshError.parse("Refresh response was not valid JSON: \(error.localizedDescription)")
130
+ throw SpotifyRefreshError.parse(
131
+ "Refresh response was not valid JSON: \((error as NSError).safeLocalizedDescription)"
132
+ )
120
133
  }
121
134
 
122
135
  guard let accessToken = (json["access_token"] as? String), !accessToken.isEmpty else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wwdrew/expo-spotify-sdk",
3
- "version": "2.2.3",
3
+ "version": "2.3.1",
4
4
  "description": "Expo module wrapping the native Spotify iOS (v5) and Android (v4) SDKs for OAuth authentication and App Remote playback control",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",