@superfan-app/spotify-auth 0.1.22 → 0.1.24

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/.eslintrc.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('expo-module-scripts/eslintrc.base.js');
package/app.plugin.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require("./plugin/build");
@@ -0,0 +1 @@
1
+ module.exports = require('expo-module-scripts/babel.config.base');
@@ -3,6 +3,6 @@ export const SpotifyAuthContextInstance = createContext({
3
3
  accessToken: null,
4
4
  authorize: async () => { },
5
5
  isAuthenticating: false,
6
- error: null
6
+ error: null,
7
7
  });
8
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;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"]}
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"]}
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAE5E,OAAO,EAEL,kBAAkB,EAElB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAe7B;;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,CAsCxC;AAED,wBAAgB,cAAc,IAAI,kBAAkB,CAMnD"}
package/build/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from "expo-modules-core";
2
2
  import React, { useContext, useEffect, useState, useCallback } from "react";
3
- import { SpotifyAuthContextInstance } from "./SpotifyAuth.types";
3
+ import { SpotifyAuthContextInstance, } from "./SpotifyAuth.types";
4
4
  import SpotifyAuthModule from "./SpotifyAuthModule";
5
5
  // Create a properly typed emitter
6
6
  const emitter = new EventEmitter(SpotifyAuthModule);
@@ -26,7 +26,7 @@ export function SpotifyAuthProvider({ children, }) {
26
26
  await SpotifyAuthModule.authorize(config);
27
27
  }
28
28
  catch (err) {
29
- setError(err instanceof Error ? err.message : 'Authorization failed');
29
+ setError(err instanceof Error ? err.message : "Authorization failed");
30
30
  throw err;
31
31
  }
32
32
  finally {
@@ -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,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"]}
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;AAE5E,OAAO,EAGL,0BAA0B,GAE3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAKpD,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,CAC3B,KAAK,EAAE,MAAuB,EAAiB,EAAE;QAC/C,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,EACD,EAAE,CACH,CAAC;IAEF,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\";\n\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// 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(\n 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 );\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"]}
@@ -0,0 +1,13 @@
1
+ {
2
+ "platforms": [
3
+ "ios"
4
+ ],
5
+ "ios": {
6
+ "modules": [
7
+ "SpotifyAuthModule"
8
+ ],
9
+ "appDelegateSubscribers": [
10
+ "SpotifyAuthDelegate"
11
+ ]
12
+ }
13
+ }
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
12
12
  s.homepage = package['homepage']
13
13
  s.platforms = { :ios => '13.0' } # Updated minimum iOS version
14
14
  s.swift_version = '5.4'
15
- s.source = { git: 'https://github.com/william-matz/spotify-auth' }
15
+ s.source = { git: 'https://github.com/superfan-app/spotify-auth' }
16
16
  s.static_framework = true
17
17
 
18
18
  s.dependency 'ExpoModulesCore'
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@superfan-app/spotify-auth",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "Spotify OAuth module for Expo",
5
- "main": "build/index.js",
5
+ "main": "src/index.ts",
6
6
  "types": "build/index.d.ts",
7
+ "sideEffects": false,
7
8
  "scripts": {
8
9
  "build": "expo-module build",
9
10
  "clean": "expo-module clean",
@@ -37,21 +38,12 @@
37
38
  "@types/react": "^18.0.0",
38
39
  "@types/react-native": "^0.70.0",
39
40
  "expo-module-scripts": "^3.0.0",
40
- "expo-modules-core": "^1.5.0"
41
+ "expo-modules-core": "^1.5.0",
42
+ "typescript": "^5.0.0"
41
43
  },
42
44
  "peerDependencies": {
43
- "expo": ">=47.0.0",
45
+ "expo": "*",
44
46
  "react": "*",
45
- "react-native": ">=0.70.0"
46
- },
47
- "files": [
48
- "build",
49
- "ios",
50
- "android",
51
- "plugin",
52
- "!**/__tests__",
53
- "!**/__fixtures__",
54
- "!**/__mocks__",
55
- "README.md"
56
- ]
47
+ "react-native": "*"
48
+ }
57
49
  }
@@ -1,4 +1,4 @@
1
1
  import { type ConfigPlugin } from '@expo/config-plugins';
2
- import { SpotifyConfig } from './types';
2
+ import { SpotifyConfig } from './types.js';
3
3
  declare const _default: ConfigPlugin<SpotifyConfig>;
4
4
  export default _default;
@@ -1,25 +1,84 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  const config_plugins_1 = require("@expo/config-plugins");
7
- const withSpotifyQueryScheme_1 = require("./ios/withSpotifyQueryScheme");
8
- const withSpotifyURLScheme_1 = require("./ios/withSpotifyURLScheme");
9
- const withSpotifyConfig_1 = __importDefault(require("./withSpotifyConfig"));
10
4
  const pkg = require('../../package.json');
11
- function ensureDevClientInstalled(config) {
12
- const devClient = config.plugins?.find((plugin) => typeof plugin === 'string' ? plugin === 'expo-dev-client' : plugin[0] === 'expo-dev-client');
13
- if (!devClient) {
14
- config_plugins_1.WarningAggregator.addWarningIOS('spotify-auth', 'This module requires expo-dev-client to be installed. Please run: npx expo install expo-dev-client');
5
+ function validateSpotifyConfig(config) {
6
+ if (!config.clientID)
7
+ throw new Error("Spotify clientID is required");
8
+ if (!config.scheme)
9
+ throw new Error("URL scheme is required");
10
+ if (!config.callback)
11
+ throw new Error("Callback path is required");
12
+ if (!config.tokenSwapURL)
13
+ throw new Error("Token swap URL is required");
14
+ if (!config.tokenRefreshURL)
15
+ throw new Error("Token refresh URL is required");
16
+ if (!Array.isArray(config.scopes) || config.scopes.length === 0) {
17
+ throw new Error("At least one scope is required");
18
+ }
19
+ }
20
+ function validateScheme(scheme) {
21
+ if (!scheme) {
22
+ throw new Error("URL scheme is required");
23
+ }
24
+ // Ensure scheme follows URL scheme naming conventions
25
+ if (!/^[a-z][a-z0-9+.-]*$/i.test(scheme)) {
26
+ throw new Error("Invalid URL scheme format. Scheme should start with a letter and contain only letters, numbers, plus, period, or hyphen.");
15
27
  }
16
28
  }
29
+ const withSpotifyURLSchemes = (config, props) => {
30
+ return (0, config_plugins_1.withInfoPlist)(config, (config) => {
31
+ // Add URL scheme configuration
32
+ if (!config.modResults.CFBundleURLTypes) {
33
+ config.modResults.CFBundleURLTypes = [];
34
+ }
35
+ config.modResults.CFBundleURLTypes.push({
36
+ CFBundleURLSchemes: [props.scheme],
37
+ CFBundleURLName: props.scheme
38
+ });
39
+ // Add Spotify query scheme
40
+ if (!config.modResults.LSApplicationQueriesSchemes) {
41
+ config.modResults.LSApplicationQueriesSchemes = [];
42
+ }
43
+ if (!config.modResults.LSApplicationQueriesSchemes.includes('spotify')) {
44
+ config.modResults.LSApplicationQueriesSchemes.push('spotify');
45
+ }
46
+ return config;
47
+ });
48
+ };
49
+ const withSpotifyConfiguration = (config, props) => {
50
+ return (0, config_plugins_1.withInfoPlist)(config, (config) => {
51
+ // Add Spotify configuration
52
+ config.modResults.SpotifyClientID = props.clientID;
53
+ config.modResults.SpotifyScheme = props.scheme;
54
+ config.modResults.SpotifyCallback = props.callback;
55
+ config.modResults.SpotifyScopes = props.scopes;
56
+ config.modResults.tokenRefreshURL = props.tokenRefreshURL;
57
+ config.modResults.tokenSwapURL = props.tokenSwapURL;
58
+ return config;
59
+ });
60
+ };
61
+ const withIOSSettings = (config) => {
62
+ return (0, config_plugins_1.withInfoPlist)(config, (config) => {
63
+ // Set minimum iOS version and build settings
64
+ config.modResults.MinimumOSVersion = '13.0';
65
+ config.modResults.EnableBitcode = false;
66
+ config.modResults.SwiftVersion = '5.4';
67
+ config.modResults.IphoneosDeploymentTarget = '13.0';
68
+ return config;
69
+ });
70
+ };
17
71
  const withSpotifyAuth = (config, props) => {
18
- ensureDevClientInstalled(config);
19
- let modifiedConfig = (0, withSpotifyConfig_1.default)(config, props);
20
- // iOS specific
21
- modifiedConfig = (0, withSpotifyQueryScheme_1.withSpotifyQueryScheme)(modifiedConfig, props);
22
- modifiedConfig = (0, withSpotifyURLScheme_1.withSpotifyURLScheme)(modifiedConfig, props);
23
- return modifiedConfig;
72
+ // Ensure the config exists
73
+ if (!props) {
74
+ throw new Error('Missing Spotify configuration. Please provide clientID, scheme, callback, tokenSwapURL, tokenRefreshURL, and scopes in your app.config.js/app.json.');
75
+ }
76
+ validateSpotifyConfig(props);
77
+ validateScheme(props.scheme);
78
+ // Apply configurations in sequence
79
+ config = withSpotifyConfiguration(config, props);
80
+ config = withSpotifyURLSchemes(config, props);
81
+ config = withIOSSettings(config);
82
+ return config;
24
83
  };
25
84
  exports.default = (0, config_plugins_1.createRunOncePlugin)(withSpotifyAuth, pkg.name, pkg.version);
@@ -1,40 +1,96 @@
1
- import { type ConfigPlugin, createRunOncePlugin, WarningAggregator } from '@expo/config-plugins'
2
- import { type ExpoConfig } from '@expo/config-types'
3
-
4
- import { withSpotifyQueryScheme } from './ios/withSpotifyQueryScheme'
5
- import { withSpotifyURLScheme } from './ios/withSpotifyURLScheme'
6
- import { SpotifyConfig } from './types'
7
- import withSpotifyOAuthConfig from './withSpotifyConfig'
8
-
9
- const pkg: {
10
- name: string;
11
- version: string;
12
- // eslint-disable-next-line @typescript-eslint/no-var-requires
13
- } = require('../../package.json');
14
-
15
- function ensureDevClientInstalled(config: any) {
16
- const devClient = config.plugins?.find((plugin: any) =>
17
- typeof plugin === 'string' ? plugin === 'expo-dev-client' : plugin[0] === 'expo-dev-client'
18
- );
19
-
20
- if (!devClient) {
21
- WarningAggregator.addWarningIOS(
22
- 'spotify-auth',
23
- 'This module requires expo-dev-client to be installed. Please run: npx expo install expo-dev-client'
24
- );
1
+ import { type ConfigPlugin, createRunOncePlugin, withInfoPlist } from '@expo/config-plugins'
2
+ import { SpotifyConfig } from './types.js'
3
+
4
+ const pkg = require('../../package.json');
5
+
6
+ function validateSpotifyConfig(config: SpotifyConfig) {
7
+ if (!config.clientID) throw new Error("Spotify clientID is required")
8
+ if (!config.scheme) throw new Error("URL scheme is required")
9
+ if (!config.callback) throw new Error("Callback path is required")
10
+ if (!config.tokenSwapURL) throw new Error("Token swap URL is required")
11
+ if (!config.tokenRefreshURL) throw new Error("Token refresh URL is required")
12
+ if (!Array.isArray(config.scopes) || config.scopes.length === 0) {
13
+ throw new Error("At least one scope is required")
25
14
  }
26
15
  }
27
16
 
28
- const withSpotifyAuth: ConfigPlugin<SpotifyConfig> = (config, props) => {
29
- ensureDevClientInstalled(config);
17
+ function validateScheme(scheme: string) {
18
+ if (!scheme) {
19
+ throw new Error("URL scheme is required");
20
+ }
30
21
 
31
- let modifiedConfig = withSpotifyOAuthConfig(config as ExpoConfig, props) as any;
22
+ // Ensure scheme follows URL scheme naming conventions
23
+ if (!/^[a-z][a-z0-9+.-]*$/i.test(scheme)) {
24
+ throw new Error("Invalid URL scheme format. Scheme should start with a letter and contain only letters, numbers, plus, period, or hyphen.");
25
+ }
26
+ }
32
27
 
33
- // iOS specific
34
- modifiedConfig = withSpotifyQueryScheme(modifiedConfig, props);
35
- modifiedConfig = withSpotifyURLScheme(modifiedConfig, props);
28
+ const withSpotifyURLSchemes: ConfigPlugin<SpotifyConfig> = (config, props) => {
29
+ return withInfoPlist(config, (config) => {
30
+ // Add URL scheme configuration
31
+ if (!config.modResults.CFBundleURLTypes) {
32
+ config.modResults.CFBundleURLTypes = [];
33
+ }
34
+ config.modResults.CFBundleURLTypes.push({
35
+ CFBundleURLSchemes: [props.scheme],
36
+ CFBundleURLName: props.scheme
37
+ });
36
38
 
37
- return modifiedConfig;
38
- }
39
+ // Add Spotify query scheme
40
+ if (!config.modResults.LSApplicationQueriesSchemes) {
41
+ config.modResults.LSApplicationQueriesSchemes = [];
42
+ }
43
+ if (!config.modResults.LSApplicationQueriesSchemes.includes('spotify')) {
44
+ config.modResults.LSApplicationQueriesSchemes.push('spotify');
45
+ }
46
+
47
+ return config;
48
+ });
49
+ };
50
+
51
+ const withSpotifyConfiguration: ConfigPlugin<SpotifyConfig> = (config, props) => {
52
+ return withInfoPlist(config, (config) => {
53
+ // Add Spotify configuration
54
+ config.modResults.SpotifyClientID = props.clientID;
55
+ config.modResults.SpotifyScheme = props.scheme;
56
+ config.modResults.SpotifyCallback = props.callback;
57
+ config.modResults.SpotifyScopes = props.scopes;
58
+ config.modResults.tokenRefreshURL = props.tokenRefreshURL;
59
+ config.modResults.tokenSwapURL = props.tokenSwapURL;
60
+
61
+ return config;
62
+ });
63
+ };
64
+
65
+ const withIOSSettings: ConfigPlugin = (config) => {
66
+ return withInfoPlist(config, (config) => {
67
+ // Set minimum iOS version and build settings
68
+ config.modResults.MinimumOSVersion = '13.0';
69
+ config.modResults.EnableBitcode = false;
70
+ config.modResults.SwiftVersion = '5.4';
71
+ config.modResults.IphoneosDeploymentTarget = '13.0';
72
+
73
+ return config;
74
+ });
75
+ };
76
+
77
+ const withSpotifyAuth: ConfigPlugin<SpotifyConfig> = (config, props) => {
78
+ // Ensure the config exists
79
+ if (!props) {
80
+ throw new Error(
81
+ 'Missing Spotify configuration. Please provide clientID, scheme, callback, tokenSwapURL, tokenRefreshURL, and scopes in your app.config.js/app.json.'
82
+ );
83
+ }
84
+
85
+ validateSpotifyConfig(props);
86
+ validateScheme(props.scheme);
87
+
88
+ // Apply configurations in sequence
89
+ config = withSpotifyConfiguration(config, props);
90
+ config = withSpotifyURLSchemes(config, props);
91
+ config = withIOSSettings(config);
92
+
93
+ return config;
94
+ };
39
95
 
40
96
  export default createRunOncePlugin(withSpotifyAuth, pkg.name, pkg.version);
@@ -1 +1 @@
1
- {"root":["./src/index.ts","./src/prebuild.ts","./src/types.ts","./src/withSpotifyConfig.ts","./src/ios/withSpotifyQueryScheme.ts","./src/ios/withSpotifyURLScheme.ts"],"version":"5.7.2"}
1
+ {"root":["./src/index.ts","./src/types.ts"],"version":"5.7.2"}
@@ -0,0 +1,81 @@
1
+ import { createContext } from "react";
2
+
3
+ /**
4
+ * Event data structure for Spotify authorization events
5
+ */
6
+ export interface SpotifyAuthEvent {
7
+ success: boolean;
8
+ token: string | null;
9
+ error?: string;
10
+ }
11
+
12
+ /**
13
+ * Data returned from the Spotify authorization process
14
+ */
15
+ export interface SpotifyAuthorizationData {
16
+ /** Whether the authorization was successful */
17
+ success: boolean;
18
+ /** The access token if authorization was successful, null otherwise */
19
+ token: string | null;
20
+ /** Error message if authorization failed */
21
+ error?: string;
22
+ }
23
+
24
+ /**
25
+ * Configuration for the authorization request
26
+ */
27
+ export interface AuthorizeConfig {
28
+ /** Spotify Client ID */
29
+ clientId: string;
30
+ /** OAuth redirect URL */
31
+ redirectUrl: string;
32
+ /** Whether to show the auth dialog */
33
+ showDialog?: boolean;
34
+ }
35
+
36
+ /**
37
+ * Props for the SpotifyAuthView component
38
+ */
39
+ export interface SpotifyAuthViewProps {
40
+ /** The name identifier for the auth view */
41
+ name: string;
42
+ }
43
+
44
+ /**
45
+ * Context for Spotify authentication state and actions
46
+ */
47
+ export interface SpotifyAuthContext {
48
+ /** The current Spotify access token, null if not authenticated */
49
+ accessToken: string | null;
50
+ /** Function to initiate Spotify authorization */
51
+ authorize: (config: AuthorizeConfig) => Promise<void>;
52
+ /** Whether authorization is in progress */
53
+ isAuthenticating: boolean;
54
+ /** Last error that occurred during authentication */
55
+ error: string | null;
56
+ }
57
+
58
+ export const SpotifyAuthContextInstance = createContext<SpotifyAuthContext>({
59
+ accessToken: null,
60
+ authorize: async () => {},
61
+ isAuthenticating: false,
62
+ error: null,
63
+ });
64
+
65
+ export interface SpotifyAuthOptions {
66
+ clientId: string;
67
+ redirectUrl: string;
68
+ showDialog?: boolean;
69
+ tokenRefreshFunction?: (data: SpotifyTokenResponse) => void;
70
+ }
71
+
72
+ /**
73
+ * Response data from Spotify token endpoint
74
+ */
75
+ export interface SpotifyTokenResponse {
76
+ access_token: string;
77
+ token_type: string;
78
+ expires_in: number;
79
+ refresh_token?: string;
80
+ scope: string;
81
+ }
@@ -0,0 +1,6 @@
1
+ import { requireNativeModule } from "expo-modules-core";
2
+
3
+ // This call loads the native module object from the JSI.
4
+ export default requireNativeModule("SpotifyAuth");
5
+
6
+ export const AuthEventName = "onSpotifyAuth" as const;
@@ -0,0 +1,14 @@
1
+ import { requireNativeViewManager } from "expo-modules-core";
2
+ import * as React from "react";
3
+ import { ViewProps } from "react-native";
4
+
5
+ import { SpotifyAuthViewProps } from "./SpotifyAuth.types";
6
+
7
+ const NativeView: React.ComponentType<SpotifyAuthViewProps & ViewProps> =
8
+ requireNativeViewManager("SpotifyAuth");
9
+
10
+ export default function SpotifyAuthView(
11
+ props: SpotifyAuthViewProps,
12
+ ): JSX.Element {
13
+ return <NativeView {...props} />;
14
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,83 @@
1
+ import { EventEmitter } from "expo-modules-core";
2
+ import React, { useContext, useEffect, useState, useCallback } from "react";
3
+
4
+ import {
5
+ SpotifyAuthorizationData,
6
+ SpotifyAuthContext,
7
+ SpotifyAuthContextInstance,
8
+ type AuthorizeConfig,
9
+ } from "./SpotifyAuth.types";
10
+ import SpotifyAuthModule from "./SpotifyAuthModule";
11
+
12
+ // First define the event name as a string literal type
13
+ type SpotifyAuthEventName = "onSpotifyAuth"; // This should match SpotifyAuthModule.AuthEventName
14
+
15
+ // Create a properly typed emitter
16
+ const emitter = new EventEmitter(SpotifyAuthModule);
17
+
18
+ function addAuthListener(listener: (data: SpotifyAuthorizationData) => void) {
19
+ // Assert the event name is of the correct type
20
+ const eventName = SpotifyAuthModule.AuthEventName as SpotifyAuthEventName;
21
+ return emitter.addListener(eventName, listener);
22
+ }
23
+
24
+ /**
25
+ * Prompts the user to log in to Spotify and authorize your application.
26
+ */
27
+ export function authorize(config: AuthorizeConfig): void {
28
+ SpotifyAuthModule.authorize(config);
29
+ }
30
+
31
+ interface SpotifyAuthProviderProps {
32
+ children: React.ReactNode;
33
+ }
34
+
35
+ export function SpotifyAuthProvider({
36
+ children,
37
+ }: SpotifyAuthProviderProps): JSX.Element {
38
+ const [token, setToken] = useState<string | null>(null);
39
+ const [isAuthenticating, setIsAuthenticating] = useState(false);
40
+ const [error, setError] = useState<string | null>(null);
41
+
42
+ const authorize = useCallback(
43
+ async (config: AuthorizeConfig): Promise<void> => {
44
+ try {
45
+ setIsAuthenticating(true);
46
+ setError(null);
47
+ await SpotifyAuthModule.authorize(config);
48
+ } catch (err) {
49
+ setError(err instanceof Error ? err.message : "Authorization failed");
50
+ throw err;
51
+ } finally {
52
+ setIsAuthenticating(false);
53
+ }
54
+ },
55
+ [],
56
+ );
57
+
58
+ useEffect(() => {
59
+ const subscription = addAuthListener((data) => {
60
+ setToken(data.token);
61
+ if (data.error) {
62
+ console.error(`Spotify auth error: ${data.error}`);
63
+ }
64
+ });
65
+ return () => subscription.remove();
66
+ }, []);
67
+
68
+ return (
69
+ <SpotifyAuthContextInstance.Provider
70
+ value={{ accessToken: token, authorize, isAuthenticating, error }}
71
+ >
72
+ {children}
73
+ </SpotifyAuthContextInstance.Provider>
74
+ );
75
+ }
76
+
77
+ export function useSpotifyAuth(): SpotifyAuthContext {
78
+ const context = useContext(SpotifyAuthContextInstance);
79
+ if (!context) {
80
+ throw new Error("useSpotifyAuth must be used within a SpotifyAuthProvider");
81
+ }
82
+ return context;
83
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ // @generated by expo-module-scripts
2
+ {
3
+ "extends": "expo-module-scripts/tsconfig.base",
4
+ "compilerOptions": {
5
+ "outDir": "./build"
6
+ },
7
+ "include": ["./src"],
8
+ "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9
+ }
@@ -1,3 +0,0 @@
1
- import { ConfigPlugin } from "expo/config-plugins";
2
- import { SpotifyConfig } from "../types";
3
- export declare const withSpotifyQueryScheme: ConfigPlugin<SpotifyConfig>;
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withSpotifyQueryScheme = void 0;
4
- const config_plugins_1 = require("expo/config-plugins");
5
- const spotifyScheme = "spotify";
6
- const withSpotifyQueryScheme = (config) => (0, config_plugins_1.withInfoPlist)(config, (config) => {
7
- if (!config.modResults.LSApplicationQueriesSchemes) {
8
- config.modResults.LSApplicationQueriesSchemes = [];
9
- }
10
- if (!config.modResults.LSApplicationQueriesSchemes.includes(spotifyScheme)) {
11
- config.modResults.LSApplicationQueriesSchemes.push(spotifyScheme);
12
- }
13
- return config;
14
- });
15
- exports.withSpotifyQueryScheme = withSpotifyQueryScheme;
@@ -1,3 +0,0 @@
1
- import { type ConfigPlugin } from "expo/config-plugins";
2
- import { SpotifyConfig } from "../types";
3
- export declare const withSpotifyURLScheme: ConfigPlugin<SpotifyConfig>;
@@ -1,29 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withSpotifyURLScheme = void 0;
4
- const config_plugins_1 = require("expo/config-plugins");
5
- function validateScheme(scheme) {
6
- if (!scheme) {
7
- throw new Error("URL scheme is required");
8
- }
9
- // Ensure scheme follows URL scheme naming conventions
10
- if (!/^[a-z][a-z0-9+.-]*$/i.test(scheme)) {
11
- throw new Error("Invalid URL scheme format. Scheme should start with a letter and contain only letters, numbers, plus, period, or hyphen.");
12
- }
13
- }
14
- const withSpotifyURLScheme = (config, { scheme }) => {
15
- validateScheme(scheme);
16
- return (0, config_plugins_1.withInfoPlist)(config, (config) => {
17
- const bundleId = config.ios?.bundleIdentifier;
18
- const urlType = {
19
- CFBundleURLName: bundleId,
20
- CFBundleURLSchemes: [scheme],
21
- };
22
- if (!config.modResults.CFBundleURLTypes) {
23
- config.modResults.CFBundleURLTypes = [];
24
- }
25
- config.modResults.CFBundleURLTypes.push(urlType);
26
- return config;
27
- });
28
- };
29
- exports.withSpotifyURLScheme = withSpotifyURLScheme;
@@ -1,3 +0,0 @@
1
- import { ConfigPlugin } from '@expo/config-plugins';
2
- import { SpotifyConfig } from './types';
3
- export declare const withPreBuildConfig: ConfigPlugin<SpotifyConfig>;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withPreBuildConfig = void 0;
4
- const config_plugins_1 = require("@expo/config-plugins");
5
- const withPreBuildConfig = (config, props) => {
6
- return (0, config_plugins_1.withInfoPlist)(config, (config) => {
7
- // Set minimum iOS version in Info.plist
8
- config.modResults.MinimumOSVersion = '13.0';
9
- // Add build-related keys
10
- config.modResults.EnableBitcode = false;
11
- config.modResults.SwiftVersion = '5.4';
12
- config.modResults.IphoneosDeploymentTarget = '13.0';
13
- return config;
14
- });
15
- };
16
- exports.withPreBuildConfig = withPreBuildConfig;
@@ -1,4 +0,0 @@
1
- import { ConfigPlugin } from '@expo/config-plugins';
2
- import { SpotifyConfig } from './types';
3
- declare const _default: ConfigPlugin<SpotifyConfig>;
4
- export default _default;
@@ -1,75 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const config_plugins_1 = require("@expo/config-plugins");
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function validateSpotifyConfig(config) {
10
- if (!config.clientID)
11
- throw new Error("Spotify clientID is required");
12
- if (!config.scheme)
13
- throw new Error("URL scheme is required");
14
- if (!config.callback)
15
- throw new Error("Callback path is required");
16
- if (!config.tokenSwapURL)
17
- throw new Error("Token swap URL is required");
18
- if (!config.tokenRefreshURL)
19
- throw new Error("Token refresh URL is required");
20
- if (!Array.isArray(config.scopes) || config.scopes.length === 0) {
21
- throw new Error("At least one scope is required");
22
- }
23
- }
24
- const withSpotifyOAuthConfigIOS = (config, spotifyConfig) => {
25
- validateSpotifyConfig(spotifyConfig);
26
- return (0, config_plugins_1.withInfoPlist)(config, (config) => {
27
- config.modResults.SpotifyClientID = spotifyConfig.clientID;
28
- config.modResults.SpotifyScheme = spotifyConfig.scheme;
29
- config.modResults.SpotifyCallback = spotifyConfig.callback;
30
- config.modResults.SpotifyScopes = spotifyConfig.scopes;
31
- config.modResults.tokenRefreshURL = spotifyConfig.tokenRefreshURL;
32
- config.modResults.tokenSwapURL = spotifyConfig.tokenSwapURL;
33
- // Add URL scheme to Info.plist
34
- const urlTypes = config.modResults.CFBundleURLTypes || [];
35
- urlTypes.push({
36
- CFBundleURLSchemes: [spotifyConfig.scheme],
37
- CFBundleURLName: spotifyConfig.scheme
38
- });
39
- config.modResults.CFBundleURLTypes = urlTypes;
40
- return config;
41
- });
42
- };
43
- const withCleanup = (config) => {
44
- return (0, config_plugins_1.withDangerousMod)(config, [
45
- 'ios',
46
- async (config) => {
47
- const platformRoot = path_1.default.join(config.modRequest.projectRoot, 'ios');
48
- // Clean build directories
49
- const buildDirs = [
50
- path_1.default.join(platformRoot, 'build'),
51
- path_1.default.join(platformRoot, 'Pods'),
52
- path_1.default.join(platformRoot, 'DerivedData')
53
- ];
54
- for (const dir of buildDirs) {
55
- if (fs_1.default.existsSync(dir)) {
56
- fs_1.default.rmdirSync(dir, { recursive: true });
57
- }
58
- }
59
- return config;
60
- },
61
- ]);
62
- };
63
- const withSpotifyAuth = (config, props) => {
64
- // Ensure the config exists
65
- if (!props) {
66
- throw new Error('Missing Spotify configuration. Please provide clientID, scheme, callback, tokenSwapURL, tokenRefreshURL, and scopes in your app.config.js/app.json.');
67
- }
68
- return (0, config_plugins_1.withPlugins)(config, [
69
- // Clean up first
70
- withCleanup,
71
- // Apply Spotify configurations
72
- [withSpotifyOAuthConfigIOS, props]
73
- ]);
74
- };
75
- exports.default = (0, config_plugins_1.createRunOncePlugin)(withSpotifyAuth, 'spotify-auth', '0.1.21');
@@ -1,18 +0,0 @@
1
- import { ConfigPlugin, withInfoPlist } from "expo/config-plugins";
2
-
3
- import { SpotifyConfig } from "../types";
4
-
5
- const spotifyScheme = "spotify";
6
-
7
- export const withSpotifyQueryScheme: ConfigPlugin<SpotifyConfig> = (config) =>
8
- withInfoPlist(config, (config) => {
9
- if (!config.modResults.LSApplicationQueriesSchemes) {
10
- config.modResults.LSApplicationQueriesSchemes = [];
11
- }
12
-
13
- if (!config.modResults.LSApplicationQueriesSchemes.includes(spotifyScheme)) {
14
- config.modResults.LSApplicationQueriesSchemes.push(spotifyScheme)
15
- }
16
-
17
- return config;
18
- });
@@ -1,36 +0,0 @@
1
- import { type ConfigPlugin, withInfoPlist } from "expo/config-plugins";
2
-
3
- import { SpotifyConfig } from "../types";
4
-
5
- function validateScheme(scheme: string) {
6
- if (!scheme) {
7
- throw new Error("URL scheme is required");
8
- }
9
-
10
- // Ensure scheme follows URL scheme naming conventions
11
- if (!/^[a-z][a-z0-9+.-]*$/i.test(scheme)) {
12
- throw new Error("Invalid URL scheme format. Scheme should start with a letter and contain only letters, numbers, plus, period, or hyphen.");
13
- }
14
- }
15
-
16
- export const withSpotifyURLScheme: ConfigPlugin<SpotifyConfig> = (
17
- config,
18
- { scheme }
19
- ) => {
20
- validateScheme(scheme);
21
-
22
- return withInfoPlist(config, (config) => {
23
- const bundleId = config.ios?.bundleIdentifier;
24
- const urlType = {
25
- CFBundleURLName: bundleId,
26
- CFBundleURLSchemes: [scheme],
27
- };
28
- if (!config.modResults.CFBundleURLTypes) {
29
- config.modResults.CFBundleURLTypes = [];
30
- }
31
-
32
- config.modResults.CFBundleURLTypes.push(urlType);
33
-
34
- return config;
35
- });
36
- };
@@ -1,16 +0,0 @@
1
- import { ConfigPlugin, withInfoPlist } from '@expo/config-plugins';
2
- import { SpotifyConfig } from './types';
3
-
4
- export const withPreBuildConfig: ConfigPlugin<SpotifyConfig> = (config, props) => {
5
- return withInfoPlist(config, (config) => {
6
- // Set minimum iOS version in Info.plist
7
- config.modResults.MinimumOSVersion = '13.0';
8
-
9
- // Add build-related keys
10
- config.modResults.EnableBitcode = false;
11
- config.modResults.SwiftVersion = '5.4';
12
- config.modResults.IphoneosDeploymentTarget = '13.0';
13
-
14
- return config;
15
- });
16
- };
@@ -1,81 +0,0 @@
1
- import { ConfigPlugin, withPlugins, createRunOncePlugin, withDangerousMod, withInfoPlist } from '@expo/config-plugins';
2
- import { SpotifyConfig } from './types';
3
- import fs from 'fs';
4
- import path from 'path';
5
-
6
- function validateSpotifyConfig(config: SpotifyConfig) {
7
- if (!config.clientID) throw new Error("Spotify clientID is required")
8
- if (!config.scheme) throw new Error("URL scheme is required")
9
- if (!config.callback) throw new Error("Callback path is required")
10
- if (!config.tokenSwapURL) throw new Error("Token swap URL is required")
11
- if (!config.tokenRefreshURL) throw new Error("Token refresh URL is required")
12
- if (!Array.isArray(config.scopes) || config.scopes.length === 0) {
13
- throw new Error("At least one scope is required")
14
- }
15
- }
16
-
17
- const withSpotifyOAuthConfigIOS: ConfigPlugin<SpotifyConfig> = (config, spotifyConfig) => {
18
- validateSpotifyConfig(spotifyConfig);
19
-
20
- return withInfoPlist(config, (config) => {
21
- config.modResults.SpotifyClientID = spotifyConfig.clientID;
22
- config.modResults.SpotifyScheme = spotifyConfig.scheme;
23
- config.modResults.SpotifyCallback = spotifyConfig.callback;
24
- config.modResults.SpotifyScopes = spotifyConfig.scopes;
25
- config.modResults.tokenRefreshURL = spotifyConfig.tokenRefreshURL;
26
- config.modResults.tokenSwapURL = spotifyConfig.tokenSwapURL;
27
-
28
- // Add URL scheme to Info.plist
29
- const urlTypes = config.modResults.CFBundleURLTypes || [];
30
- urlTypes.push({
31
- CFBundleURLSchemes: [spotifyConfig.scheme],
32
- CFBundleURLName: spotifyConfig.scheme
33
- });
34
- config.modResults.CFBundleURLTypes = urlTypes;
35
-
36
- return config;
37
- });
38
- };
39
-
40
- const withCleanup: ConfigPlugin = (config) => {
41
- return withDangerousMod(config, [
42
- 'ios',
43
- async (config) => {
44
- const platformRoot = path.join(config.modRequest.projectRoot, 'ios');
45
-
46
- // Clean build directories
47
- const buildDirs = [
48
- path.join(platformRoot, 'build'),
49
- path.join(platformRoot, 'Pods'),
50
- path.join(platformRoot, 'DerivedData')
51
- ];
52
-
53
- for (const dir of buildDirs) {
54
- if (fs.existsSync(dir)) {
55
- fs.rmdirSync(dir, { recursive: true });
56
- }
57
- }
58
-
59
- return config;
60
- },
61
- ]);
62
- };
63
-
64
- const withSpotifyAuth: ConfigPlugin<SpotifyConfig> = (config, props) => {
65
- // Ensure the config exists
66
- if (!props) {
67
- throw new Error(
68
- 'Missing Spotify configuration. Please provide clientID, scheme, callback, tokenSwapURL, tokenRefreshURL, and scopes in your app.config.js/app.json.'
69
- );
70
- }
71
-
72
- return withPlugins(config, [
73
- // Clean up first
74
- withCleanup,
75
-
76
- // Apply Spotify configurations
77
- [withSpotifyOAuthConfigIOS, props]
78
- ]);
79
- };
80
-
81
- export default createRunOncePlugin(withSpotifyAuth, 'spotify-auth', '0.1.21');