@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 CHANGED
@@ -1,67 +1,234 @@
1
- # spotify-auth
1
+ # @superfan-app/spotify-auth
2
2
 
3
- A React Native module for Spotify authentication, built with Expo modules.
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
- # Installation
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
- npm install @superfan-app/spotify-auth
18
+ npx expo install @superfan-app/spotify-auth
9
19
  ```
10
20
 
11
- # Configuration
21
+ This module requires the Expo Development Client (not compatible with Expo Go):
12
22
 
13
- ### iOS
23
+ ```bash
24
+ npx expo install expo-dev-client
25
+ ```
14
26
 
15
- 1. Run `npx pod-install` after installing the npm package.
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
- 2. Add the following to your `Info.plist`:
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
- ```xml
20
- <key>SpotifyClientID</key>
21
- <string>YOUR_CLIENT_ID</string>
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
- # Usage
64
+ 1. Wrap your app with the provider:
34
65
 
35
66
  ```tsx
36
- import { SpotifyAuthProvider, useSpotifyAuth } from '@superfan-app/spotify-auth';
67
+ import { SpotifyAuthProvider } from '@superfan-app/spotify-auth';
37
68
 
38
- // Wrap your app with the provider
39
- function App() {
69
+ export default function App() {
40
70
  return (
41
71
  <SpotifyAuthProvider>
42
- <YourApp />
72
+ <MainApp />
43
73
  </SpotifyAuthProvider>
44
74
  );
45
75
  }
76
+ ```
46
77
 
47
- // Use the hook in your components
48
- function YourApp() {
49
- const { accessToken, authorize } = useSpotifyAuth();
78
+ 2. Use the hook in your components:
50
79
 
51
- const handleLogin = () => {
52
- authorize();
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 <Button onPress={handleLogin} title="Login with Spotify" />;
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
- The module provides:
64
- - `SpotifyAuthProvider`: Context provider that manages the Spotify authentication state
65
- - `useSpotifyAuth`: Hook that provides:
66
- - `accessToken`: Current Spotify access token (null if not authenticated)
67
- - `authorize()`: Function to initiate Spotify authorization
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;CACvB;AAED,eAAO,MAAM,0BAA0B,6CAGrC,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
+ {"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;AAgCtC,MAAM,CAAC,MAAM,0BAA0B,GAAG,aAAa,CAAqB;IAC1E,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC;CACrB,CAAC,CAAC","sourcesContent":["import { createContext } from \"react\";\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 * 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: () => void;\n}\n\nexport const SpotifyAuthContextInstance = createContext<SpotifyAuthContext>({\n accessToken: null,\n authorize: () => { },\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"]}
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAE/D,OAAO,EAEL,kBAAkB,EAEnB,MAAM,qBAAqB,CAAC;AA2B7B,UAAU,wBAAwB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,GACT,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CAoBxC;AAED,wBAAgB,cAAc,IAAI,kBAAkB,CAMnD"}
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, } from "./SpotifyAuth.types";
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
  }
@@ -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;AAE/D,OAAO,EAGL,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAUpD,kCAAkC;AAClC,MAAM,OAAO,GAAG,IAAI,YAAY,EAAiB,CAAC;AAElD,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,SAAS,SAAS;IAChB,iBAAiB,CAAC,SAAS,EAAE,CAAC;AAChC,CAAC;AAMD,MAAM,UAAU,mBAAmB,CAAC,EAClC,QAAQ,GACiB;IACzB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,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,CAAC,CAEzC;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 } from \"react\";\n\nimport {\n SpotifyAuthorizationData,\n SpotifyAuthContext,\n SpotifyAuthContextInstance,\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<SpotifyEvents>();\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 */\nfunction authorize(): void {\n SpotifyAuthModule.authorize();\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\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 }}\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"]}
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"]}
@@ -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, '15.1'
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