@superfan-app/spotify-auth 0.1.21 → 0.1.22
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.
- package/README.md +206 -39
- package/build/SpotifyAuth.types.d.ts +24 -1
- package/build/SpotifyAuth.types.d.ts.map +1 -1
- package/build/SpotifyAuth.types.js +3 -1
- package/build/SpotifyAuth.types.js.map +1 -1
- package/build/index.d.ts +5 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +22 -6
- package/build/index.js.map +1 -1
- package/ios/SpotifyAuth.podspec +20 -3
- package/ios/SpotifyAuthAuth.swift +386 -33
- package/ios/SpotifyAuthModule.swift +94 -20
- package/package.json +30 -27
- package/plugin/build/index.js +15 -5
- package/plugin/build/ios/withSpotifyURLScheme.js +10 -0
- package/plugin/build/prebuild.d.ts +3 -0
- package/plugin/build/prebuild.js +16 -0
- package/plugin/build/types.d.ts +65 -2
- package/plugin/build/withSpotifyConfig.d.ts +3 -2
- package/plugin/build/withSpotifyConfig.js +61 -6
- package/plugin/src/index.ts +22 -6
- package/plugin/src/ios/withSpotifyURLScheme.ts +13 -0
- package/plugin/src/prebuild.ts +16 -0
- package/plugin/src/types.ts +70 -2
- package/plugin/src/withSpotifyConfig.ts +67 -6
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/app.plugin.js +0 -1
- package/src/SpotifyAuth.types.ts +0 -54
- package/src/SpotifyAuthModule.ts +0 -6
- package/src/SpotifyAuthView.tsx +0 -14
- package/src/index.tsx +0 -69
package/README.md
CHANGED
|
@@ -1,67 +1,234 @@
|
|
|
1
|
-
# spotify-auth
|
|
1
|
+
# @superfan-app/spotify-auth
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A modern Expo module for Spotify authentication in React Native apps. This module provides a seamless OAuth flow with proper token management and automatic refresh handling.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 Complete Spotify OAuth implementation
|
|
8
|
+
- 🔄 Automatic token refresh
|
|
9
|
+
- 📱 iOS support via native SDK
|
|
10
|
+
- ⚡️ Modern Expo development workflow
|
|
11
|
+
- 🛡️ Secure token storage
|
|
12
|
+
- 🔧 TypeScript support
|
|
13
|
+
- 📝 Comprehensive error handling
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
6
16
|
|
|
7
17
|
```bash
|
|
8
|
-
|
|
18
|
+
npx expo install @superfan-app/spotify-auth
|
|
9
19
|
```
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
This module requires the Expo Development Client (not compatible with Expo Go):
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
```bash
|
|
24
|
+
npx expo install expo-dev-client
|
|
25
|
+
```
|
|
14
26
|
|
|
15
|
-
|
|
27
|
+
## Configuration
|
|
28
|
+
|
|
29
|
+
1. Create a Spotify application in the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard)
|
|
30
|
+
|
|
31
|
+
2. Configure your app.json/app.config.js:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"expo": {
|
|
36
|
+
"plugins": [
|
|
37
|
+
[
|
|
38
|
+
"@superfan-app/spotify-auth",
|
|
39
|
+
{
|
|
40
|
+
"clientID": "your_spotify_client_id",
|
|
41
|
+
"scheme": "your-app-scheme",
|
|
42
|
+
"callback": "callback",
|
|
43
|
+
"tokenSwapURL": "https://your-backend.com/swap",
|
|
44
|
+
"tokenRefreshURL": "https://your-backend.com/refresh",
|
|
45
|
+
"scopes": [
|
|
46
|
+
"user-read-email",
|
|
47
|
+
"streaming"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
16
55
|
|
|
17
|
-
|
|
56
|
+
3. Set up your redirect URI in the Spotify Dashboard:
|
|
57
|
+
- Format: `your-app-scheme://callback`
|
|
58
|
+
- Example: `my-spotify-app://callback`
|
|
18
59
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<key>SpotifyScheme</key>
|
|
23
|
-
<string>YOUR_URL_SCHEME</string>
|
|
24
|
-
<key>SpotifyCallback</key>
|
|
25
|
-
<string>YOUR_CALLBACK_PATH</string>
|
|
26
|
-
<key>SpotifyScopes</key>
|
|
27
|
-
<array>
|
|
28
|
-
<string>user-read-private</string>
|
|
29
|
-
<!-- Add other required scopes -->
|
|
30
|
-
</array>
|
|
31
|
-
```
|
|
60
|
+
4. Implement token swap/refresh endpoints on your backend (see Backend Requirements below)
|
|
61
|
+
|
|
62
|
+
## Usage
|
|
32
63
|
|
|
33
|
-
|
|
64
|
+
1. Wrap your app with the provider:
|
|
34
65
|
|
|
35
66
|
```tsx
|
|
36
|
-
import { SpotifyAuthProvider
|
|
67
|
+
import { SpotifyAuthProvider } from '@superfan-app/spotify-auth';
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
function App() {
|
|
69
|
+
export default function App() {
|
|
40
70
|
return (
|
|
41
71
|
<SpotifyAuthProvider>
|
|
42
|
-
<
|
|
72
|
+
<MainApp />
|
|
43
73
|
</SpotifyAuthProvider>
|
|
44
74
|
);
|
|
45
75
|
}
|
|
76
|
+
```
|
|
46
77
|
|
|
47
|
-
|
|
48
|
-
function YourApp() {
|
|
49
|
-
const { accessToken, authorize } = useSpotifyAuth();
|
|
78
|
+
2. Use the hook in your components:
|
|
50
79
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
80
|
+
```tsx
|
|
81
|
+
import { useSpotifyAuth } from '@superfan-app/spotify-auth';
|
|
82
|
+
|
|
83
|
+
function MainScreen() {
|
|
84
|
+
const {
|
|
85
|
+
accessToken,
|
|
86
|
+
authorize,
|
|
87
|
+
isAuthenticating,
|
|
88
|
+
error
|
|
89
|
+
} = useSpotifyAuth();
|
|
90
|
+
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (!accessToken && !isAuthenticating) {
|
|
93
|
+
authorize();
|
|
94
|
+
}
|
|
95
|
+
}, []);
|
|
96
|
+
|
|
97
|
+
if (isAuthenticating) {
|
|
98
|
+
return <ActivityIndicator />;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (error) {
|
|
102
|
+
return <Text>Error: {error}</Text>;
|
|
103
|
+
}
|
|
54
104
|
|
|
55
105
|
if (!accessToken) {
|
|
56
|
-
return <
|
|
106
|
+
return <Text>Not authenticated</Text>;
|
|
57
107
|
}
|
|
58
108
|
|
|
59
|
-
return <YourAuthenticatedApp />;
|
|
109
|
+
return <YourAuthenticatedApp token={accessToken} />;
|
|
60
110
|
}
|
|
61
111
|
```
|
|
62
112
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
113
|
+
## API Reference
|
|
114
|
+
|
|
115
|
+
### SpotifyAuthProvider
|
|
116
|
+
|
|
117
|
+
Provider component that manages authentication state.
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<SpotifyAuthProvider>
|
|
121
|
+
{children}
|
|
122
|
+
</SpotifyAuthProvider>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### useSpotifyAuth()
|
|
126
|
+
|
|
127
|
+
Hook for accessing authentication state and methods.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
- \`accessToken: string | null\` - Current Spotify access token
|
|
131
|
+
- \`authorize(): Promise<void>\` - Start authentication flow
|
|
132
|
+
- \`isAuthenticating: boolean\` - Authentication in progress
|
|
133
|
+
- \`error: string | null\` - Last error message
|
|
134
|
+
|
|
135
|
+
### Available Scopes
|
|
136
|
+
|
|
137
|
+
All standard Spotify scopes are supported:
|
|
138
|
+
- \`app-remote-control\`
|
|
139
|
+
- \`playlist-modify-private\`
|
|
140
|
+
- \`playlist-modify-public\`
|
|
141
|
+
- \`playlist-read-collaborative\`
|
|
142
|
+
- \`playlist-read-private\`
|
|
143
|
+
- \`streaming\`
|
|
144
|
+
- \`user-follow-modify\`
|
|
145
|
+
- \`user-follow-read\`
|
|
146
|
+
- \`user-library-modify\`
|
|
147
|
+
- \`user-library-read\`
|
|
148
|
+
- \`user-modify-playback-state\`
|
|
149
|
+
- \`user-read-currently-playing\`
|
|
150
|
+
- \`user-read-email\`
|
|
151
|
+
- \`user-read-playback-position\`
|
|
152
|
+
- \`user-read-playback-state\`
|
|
153
|
+
- \`user-read-private\`
|
|
154
|
+
- \`user-read-recently-played\`
|
|
155
|
+
- \`user-top-read\`
|
|
156
|
+
|
|
157
|
+
## Backend Requirements
|
|
158
|
+
|
|
159
|
+
You need to implement two endpoints:
|
|
160
|
+
|
|
161
|
+
1. Token Swap Endpoint (\`tokenSwapURL\`):
|
|
162
|
+
- Receives authorization code
|
|
163
|
+
- Exchanges it for access/refresh tokens using your client secret
|
|
164
|
+
- Returns tokens to the app
|
|
165
|
+
|
|
166
|
+
2. Token Refresh Endpoint (\`tokenRefreshURL\`):
|
|
167
|
+
- Receives refresh token
|
|
168
|
+
- Gets new access token from Spotify
|
|
169
|
+
- Returns new access token to the app
|
|
170
|
+
|
|
171
|
+
Example response format for both endpoints:
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"access_token": "new_access_token",
|
|
175
|
+
"refresh_token": "new_refresh_token",
|
|
176
|
+
"expires_in": 3600
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Development Workflow
|
|
181
|
+
|
|
182
|
+
1. Clean installation:
|
|
183
|
+
```bash
|
|
184
|
+
npm install
|
|
185
|
+
npm run build
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
2. Clean build:
|
|
189
|
+
```bash
|
|
190
|
+
npx expo prebuild --clean
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
3. Run on iOS:
|
|
194
|
+
```bash
|
|
195
|
+
npx expo run:ios
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Troubleshooting
|
|
199
|
+
|
|
200
|
+
### Common Issues
|
|
201
|
+
|
|
202
|
+
1. "Cannot find native module 'SpotifyAuth'":
|
|
203
|
+
```bash
|
|
204
|
+
npx expo prebuild --clean
|
|
205
|
+
npx expo run:ios
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
2. Build errors:
|
|
209
|
+
```bash
|
|
210
|
+
npm run clean
|
|
211
|
+
npm run build
|
|
212
|
+
npx expo prebuild --clean
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
3. Authentication errors:
|
|
216
|
+
- Verify your client ID
|
|
217
|
+
- Check redirect URI in Spotify Dashboard
|
|
218
|
+
- Ensure HTTPS for token endpoints
|
|
219
|
+
- Verify requested scopes
|
|
220
|
+
|
|
221
|
+
## Security
|
|
222
|
+
|
|
223
|
+
- Access tokens are stored in memory
|
|
224
|
+
- Refresh tokens are securely stored in Keychain
|
|
225
|
+
- HTTPS required for token endpoints
|
|
226
|
+
- Automatic token refresh
|
|
227
|
+
- Proper error handling and recovery
|
|
228
|
+
|
|
229
|
+
## Requirements
|
|
230
|
+
|
|
231
|
+
- Expo SDK 47+
|
|
232
|
+
- iOS 13.0+
|
|
233
|
+
- Node.js 14.0+
|
|
234
|
+
- Expo Development Client
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event data structure for Spotify authorization events
|
|
3
|
+
*/
|
|
4
|
+
export interface SpotifyAuthEvent {
|
|
5
|
+
success: boolean;
|
|
6
|
+
token: string | null;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
1
9
|
/**
|
|
2
10
|
* Data returned from the Spotify authorization process
|
|
3
11
|
*/
|
|
@@ -9,6 +17,17 @@ export interface SpotifyAuthorizationData {
|
|
|
9
17
|
/** Error message if authorization failed */
|
|
10
18
|
error?: string;
|
|
11
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Configuration for the authorization request
|
|
22
|
+
*/
|
|
23
|
+
export interface AuthorizeConfig {
|
|
24
|
+
/** Spotify Client ID */
|
|
25
|
+
clientId: string;
|
|
26
|
+
/** OAuth redirect URL */
|
|
27
|
+
redirectUrl: string;
|
|
28
|
+
/** Whether to show the auth dialog */
|
|
29
|
+
showDialog?: boolean;
|
|
30
|
+
}
|
|
12
31
|
/**
|
|
13
32
|
* Props for the SpotifyAuthView component
|
|
14
33
|
*/
|
|
@@ -23,7 +42,11 @@ export interface SpotifyAuthContext {
|
|
|
23
42
|
/** The current Spotify access token, null if not authenticated */
|
|
24
43
|
accessToken: string | null;
|
|
25
44
|
/** Function to initiate Spotify authorization */
|
|
26
|
-
authorize: () => void
|
|
45
|
+
authorize: (config: AuthorizeConfig) => Promise<void>;
|
|
46
|
+
/** Whether authorization is in progress */
|
|
47
|
+
isAuthenticating: boolean;
|
|
48
|
+
/** Last error that occurred during authentication */
|
|
49
|
+
error: string | null;
|
|
27
50
|
}
|
|
28
51
|
export declare const SpotifyAuthContextInstance: import("react").Context<SpotifyAuthContext>;
|
|
29
52
|
export interface SpotifyAuthOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpotifyAuth.types.d.ts","sourceRoot":"","sources":["../src/SpotifyAuth.types.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iDAAiD;IACjD,SAAS,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"SpotifyAuth.types.d.ts","sourceRoot":"","sources":["../src/SpotifyAuth.types.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iDAAiD;IACjD,SAAS,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,2CAA2C;IAC3C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qDAAqD;IACrD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,0BAA0B,6CAKrC,CAAC;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC7D;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createContext } from "react";
|
|
2
2
|
export const SpotifyAuthContextInstance = createContext({
|
|
3
3
|
accessToken: null,
|
|
4
|
-
authorize: () => { },
|
|
4
|
+
authorize: async () => { },
|
|
5
|
+
isAuthenticating: false,
|
|
6
|
+
error: null
|
|
5
7
|
});
|
|
6
8
|
//# sourceMappingURL=SpotifyAuth.types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpotifyAuth.types.js","sourceRoot":"","sources":["../src/SpotifyAuth.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SpotifyAuth.types.js","sourceRoot":"","sources":["../src/SpotifyAuth.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAyDtC,MAAM,CAAC,MAAM,0BAA0B,GAAG,aAAa,CAAqB;IAC1E,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;IACzB,gBAAgB,EAAE,KAAK;IACvB,KAAK,EAAE,IAAI;CACZ,CAAC,CAAC","sourcesContent":["import { createContext } from \"react\";\n\n/**\n * Event data structure for Spotify authorization events\n */\nexport interface SpotifyAuthEvent {\n success: boolean;\n token: string | null;\n error?: string;\n}\n\n/**\n * Data returned from the Spotify authorization process\n */\nexport interface SpotifyAuthorizationData {\n /** Whether the authorization was successful */\n success: boolean;\n /** The access token if authorization was successful, null otherwise */\n token: string | null;\n /** Error message if authorization failed */\n error?: string;\n}\n\n/**\n * Configuration for the authorization request\n */\nexport interface AuthorizeConfig {\n /** Spotify Client ID */\n clientId: string;\n /** OAuth redirect URL */\n redirectUrl: string;\n /** Whether to show the auth dialog */\n showDialog?: boolean;\n}\n\n/**\n * Props for the SpotifyAuthView component\n */\nexport interface SpotifyAuthViewProps {\n /** The name identifier for the auth view */\n name: string;\n}\n\n/**\n * Context for Spotify authentication state and actions\n */\nexport interface SpotifyAuthContext {\n /** The current Spotify access token, null if not authenticated */\n accessToken: string | null;\n /** Function to initiate Spotify authorization */\n authorize: (config: AuthorizeConfig) => Promise<void>;\n /** Whether authorization is in progress */\n isAuthenticating: boolean;\n /** Last error that occurred during authentication */\n error: string | null;\n}\n\nexport const SpotifyAuthContextInstance = createContext<SpotifyAuthContext>({\n accessToken: null,\n authorize: async () => {},\n isAuthenticating: false,\n error: null\n});\n\nexport interface SpotifyAuthOptions {\n clientId: string;\n redirectUrl: string;\n showDialog?: boolean;\n tokenRefreshFunction?: (data: SpotifyTokenResponse) => void;\n}\n\n/**\n * Response data from Spotify token endpoint\n */\nexport interface SpotifyTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n scope: string;\n}\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { SpotifyAuthContext } from "./SpotifyAuth.types";
|
|
2
|
+
import { SpotifyAuthContext, type AuthorizeConfig } from "./SpotifyAuth.types";
|
|
3
|
+
/**
|
|
4
|
+
* Prompts the user to log in to Spotify and authorize your application.
|
|
5
|
+
*/
|
|
6
|
+
export declare function authorize(config: AuthorizeConfig): void;
|
|
3
7
|
interface SpotifyAuthProviderProps {
|
|
4
8
|
children: React.ReactNode;
|
|
5
9
|
}
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAC5E,OAAO,EAEL,kBAAkB,EAElB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAoB7B;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAEvD;AAED,UAAU,wBAAwB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,GACT,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CAmCxC;AAED,wBAAgB,cAAc,IAAI,kBAAkB,CAMnD"}
|
package/build/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { EventEmitter } from "expo-modules-core";
|
|
2
|
-
import React, { useContext, useEffect, useState } from "react";
|
|
3
|
-
import { SpotifyAuthContextInstance
|
|
2
|
+
import React, { useContext, useEffect, useState, useCallback } from "react";
|
|
3
|
+
import { SpotifyAuthContextInstance } from "./SpotifyAuth.types";
|
|
4
4
|
import SpotifyAuthModule from "./SpotifyAuthModule";
|
|
5
5
|
// Create a properly typed emitter
|
|
6
|
-
const emitter = new EventEmitter();
|
|
6
|
+
const emitter = new EventEmitter(SpotifyAuthModule);
|
|
7
7
|
function addAuthListener(listener) {
|
|
8
8
|
// Assert the event name is of the correct type
|
|
9
9
|
const eventName = SpotifyAuthModule.AuthEventName;
|
|
@@ -12,11 +12,27 @@ function addAuthListener(listener) {
|
|
|
12
12
|
/**
|
|
13
13
|
* Prompts the user to log in to Spotify and authorize your application.
|
|
14
14
|
*/
|
|
15
|
-
function authorize() {
|
|
16
|
-
SpotifyAuthModule.authorize();
|
|
15
|
+
export function authorize(config) {
|
|
16
|
+
SpotifyAuthModule.authorize(config);
|
|
17
17
|
}
|
|
18
18
|
export function SpotifyAuthProvider({ children, }) {
|
|
19
19
|
const [token, setToken] = useState(null);
|
|
20
|
+
const [isAuthenticating, setIsAuthenticating] = useState(false);
|
|
21
|
+
const [error, setError] = useState(null);
|
|
22
|
+
const authorize = useCallback(async (config) => {
|
|
23
|
+
try {
|
|
24
|
+
setIsAuthenticating(true);
|
|
25
|
+
setError(null);
|
|
26
|
+
await SpotifyAuthModule.authorize(config);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
setError(err instanceof Error ? err.message : 'Authorization failed');
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
setIsAuthenticating(false);
|
|
34
|
+
}
|
|
35
|
+
}, []);
|
|
20
36
|
useEffect(() => {
|
|
21
37
|
const subscription = addAuthListener((data) => {
|
|
22
38
|
setToken(data.token);
|
|
@@ -26,7 +42,7 @@ export function SpotifyAuthProvider({ children, }) {
|
|
|
26
42
|
});
|
|
27
43
|
return () => subscription.remove();
|
|
28
44
|
}, []);
|
|
29
|
-
return (<SpotifyAuthContextInstance.Provider value={{ accessToken: token, authorize }}>
|
|
45
|
+
return (<SpotifyAuthContextInstance.Provider value={{ accessToken: token, authorize, isAuthenticating, error }}>
|
|
30
46
|
{children}
|
|
31
47
|
</SpotifyAuthContextInstance.Provider>);
|
|
32
48
|
}
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC5E,OAAO,EAGL,0BAA0B,EAE3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAUpD,kCAAkC;AAClC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,iBAAiB,CAAC,CAAC;AAEpD,SAAS,eAAe,CAAC,QAAkD;IACzE,+CAA+C;IAC/C,MAAM,SAAS,GAAG,iBAAiB,CAAC,aAAqC,CAAC;IAC1E,OAAO,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,MAAuB;IAC/C,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAMD,MAAM,UAAU,mBAAmB,CAAC,EAClC,QAAQ,GACiB;IACzB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,EAAE,MAAuB,EAAiB,EAAE;QAC7E,IAAI,CAAC;YACH,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,MAAM,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;YACtE,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5C,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;IACrC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,CAAC,0BAA0B,CAAC,QAAQ,CAClC,KAAK,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAElE;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CACvC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,UAAU,CAAC,0BAA0B,CAAC,CAAC;IACvD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import { EventEmitter } from \"expo-modules-core\";\nimport React, { useContext, useEffect, useState, useCallback } from \"react\";\nimport {\n SpotifyAuthorizationData,\n SpotifyAuthContext,\n SpotifyAuthContextInstance,\n type AuthorizeConfig\n} from \"./SpotifyAuth.types\";\nimport SpotifyAuthModule from \"./SpotifyAuthModule\";\n\n// First define the event name as a string literal type\ntype SpotifyAuthEventName = \"onSpotifyAuth\"; // This should match SpotifyAuthModule.AuthEventName\n\n// Then use that type for events\ntype SpotifyEvents = {\n [K in SpotifyAuthEventName]: (data: SpotifyAuthorizationData) => void;\n};\n\n// Create a properly typed emitter\nconst emitter = new EventEmitter(SpotifyAuthModule);\n\nfunction addAuthListener(listener: (data: SpotifyAuthorizationData) => void) {\n // Assert the event name is of the correct type\n const eventName = SpotifyAuthModule.AuthEventName as SpotifyAuthEventName;\n return emitter.addListener(eventName, listener);\n}\n\n/**\n * Prompts the user to log in to Spotify and authorize your application.\n */\nexport function authorize(config: AuthorizeConfig): void {\n SpotifyAuthModule.authorize(config);\n}\n\ninterface SpotifyAuthProviderProps {\n children: React.ReactNode;\n}\n\nexport function SpotifyAuthProvider({\n children,\n}: SpotifyAuthProviderProps): JSX.Element {\n const [token, setToken] = useState<string | null>(null);\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const authorize = useCallback(async (config: AuthorizeConfig): Promise<void> => {\n try {\n setIsAuthenticating(true);\n setError(null);\n await SpotifyAuthModule.authorize(config);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Authorization failed');\n throw err;\n } finally {\n setIsAuthenticating(false);\n }\n }, []);\n\n useEffect(() => {\n const subscription = addAuthListener((data) => {\n setToken(data.token);\n if (data.error) {\n console.error(`Spotify auth error: ${data.error}`);\n }\n });\n return () => subscription.remove();\n }, []);\n\n return (\n <SpotifyAuthContextInstance.Provider\n value={{ accessToken: token, authorize, isAuthenticating, error }}\n >\n {children}\n </SpotifyAuthContextInstance.Provider>\n );\n}\n\nexport function useSpotifyAuth(): SpotifyAuthContext {\n const context = useContext(SpotifyAuthContextInstance);\n if (!context) {\n throw new Error(\"useSpotifyAuth must be used within a SpotifyAuthProvider\");\n }\n return context;\n}\n"]}
|
package/ios/SpotifyAuth.podspec
CHANGED
|
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package['license']
|
|
11
11
|
s.author = package['author']
|
|
12
12
|
s.homepage = package['homepage']
|
|
13
|
-
s.platforms = :ios
|
|
13
|
+
s.platforms = { :ios => '13.0' } # Updated minimum iOS version
|
|
14
14
|
s.swift_version = '5.4'
|
|
15
15
|
s.source = { git: 'https://github.com/william-matz/spotify-auth' }
|
|
16
16
|
s.static_framework = true
|
|
@@ -20,13 +20,30 @@ Pod::Spec.new do |s|
|
|
|
20
20
|
# Swift/Objective-C compatibility
|
|
21
21
|
s.pod_target_xcconfig = {
|
|
22
22
|
'DEFINES_MODULE' => 'YES',
|
|
23
|
-
'SWIFT_COMPILATION_MODE' => 'wholemodule'
|
|
23
|
+
'SWIFT_COMPILATION_MODE' => 'wholemodule',
|
|
24
|
+
'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_ROOT)/../../node_modules/@superfan-app/spotify-auth/ios/Frameworks"',
|
|
25
|
+
'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/../../node_modules/@superfan-app/spotify-auth/ios/Frameworks/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers"',
|
|
26
|
+
'ENABLE_BITCODE' => 'NO',
|
|
27
|
+
'IPHONEOS_DEPLOYMENT_TARGET' => '13.0',
|
|
28
|
+
'SWIFT_VERSION' => '5.4'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
s.user_target_xcconfig = {
|
|
32
|
+
'ENABLE_BITCODE' => 'NO',
|
|
33
|
+
'IPHONEOS_DEPLOYMENT_TARGET' => '13.0'
|
|
24
34
|
}
|
|
25
35
|
|
|
26
36
|
s.source_files = "**/*.{h,m,swift}"
|
|
27
|
-
s.exclude_files = ["Frameworks/SpotifyiOS.xcframework/**/*.h"]
|
|
28
37
|
s.vendored_frameworks = 'Frameworks/SpotifyiOS.xcframework'
|
|
29
38
|
s.preserve_paths = [
|
|
30
39
|
'Frameworks/*.xcframework',
|
|
31
40
|
]
|
|
41
|
+
|
|
42
|
+
# Post install hooks
|
|
43
|
+
def s.post_install(target)
|
|
44
|
+
target.build_configurations.each do |config|
|
|
45
|
+
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
|
46
|
+
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
|
|
47
|
+
end
|
|
48
|
+
end
|
|
32
49
|
end
|