@wwdrew/expo-spotify-sdk 0.7.1 → 1.0.0
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 +388 -108
- package/android/build.gradle +10 -0
- package/android/consumer-rules.pro +5 -0
- package/android/libs/SETUP.md +29 -0
- package/android/src/main/java/expo/modules/spotifysdk/ExpoSpotifySDKModule.kt +149 -12
- package/android/src/main/java/expo/modules/spotifysdk/SpotifyAppRemoteCoordinator.kt +556 -0
- package/android/src/main/java/expo/modules/spotifysdk/SpotifyConfig.kt +1 -0
- package/android/src/main/java/expo/modules/spotifysdk/SpotifyErrors.kt +112 -0
- package/build/ExpoSpotifySDK.types.d.ts +12 -0
- package/build/ExpoSpotifySDK.types.d.ts.map +1 -1
- package/build/ExpoSpotifySDK.types.js.map +1 -1
- package/build/ExpoSpotifySDKModule.web.d.ts +23 -0
- package/build/ExpoSpotifySDKModule.web.d.ts.map +1 -1
- package/build/ExpoSpotifySDKModule.web.js +74 -5
- package/build/ExpoSpotifySDKModule.web.js.map +1 -1
- package/build/app-remote/error.d.ts +8 -0
- package/build/app-remote/error.d.ts.map +1 -0
- package/build/app-remote/error.js +10 -0
- package/build/app-remote/error.js.map +1 -0
- package/build/app-remote/index.d.ts +79 -0
- package/build/app-remote/index.d.ts.map +1 -0
- package/build/app-remote/index.js +110 -0
- package/build/app-remote/index.js.map +1 -0
- package/build/auth/error.d.ts +8 -0
- package/build/auth/error.d.ts.map +1 -0
- package/build/auth/error.js +10 -0
- package/build/auth/error.js.map +1 -0
- package/build/auth/index.d.ts +124 -0
- package/build/auth/index.d.ts.map +1 -0
- package/build/auth/index.js +162 -0
- package/build/auth/index.js.map +1 -0
- package/build/content/error.d.ts +8 -0
- package/build/content/error.d.ts.map +1 -0
- package/build/content/error.js +10 -0
- package/build/content/error.js.map +1 -0
- package/build/content/index.d.ts +38 -0
- package/build/content/index.d.ts.map +1 -0
- package/build/content/index.js +56 -0
- package/build/content/index.js.map +1 -0
- package/build/error.d.ts +24 -0
- package/build/error.d.ts.map +1 -0
- package/build/error.js +25 -0
- package/build/error.js.map +1 -0
- package/build/hooks/index.d.ts +90 -0
- package/build/hooks/index.d.ts.map +1 -0
- package/build/hooks/index.js +326 -0
- package/build/hooks/index.js.map +1 -0
- package/build/images/error.d.ts +8 -0
- package/build/images/error.d.ts.map +1 -0
- package/build/images/error.js +10 -0
- package/build/images/error.js.map +1 -0
- package/build/images/index.d.ts +36 -0
- package/build/images/index.d.ts.map +1 -0
- package/build/images/index.js +59 -0
- package/build/images/index.js.map +1 -0
- package/build/index.d.ts +44 -42
- package/build/index.d.ts.map +1 -1
- package/build/index.js +49 -122
- package/build/index.js.map +1 -1
- package/build/player/error.d.ts +8 -0
- package/build/player/error.d.ts.map +1 -0
- package/build/player/error.js +10 -0
- package/build/player/error.js.map +1 -0
- package/build/player/index.d.ts +140 -0
- package/build/player/index.d.ts.map +1 -0
- package/build/player/index.js +136 -0
- package/build/player/index.js.map +1 -0
- package/build/uri/index.d.ts +55 -0
- package/build/uri/index.d.ts.map +1 -0
- package/build/uri/index.js +57 -0
- package/build/uri/index.js.map +1 -0
- package/build/user/error.d.ts +8 -0
- package/build/user/error.d.ts.map +1 -0
- package/build/user/error.js +10 -0
- package/build/user/error.js.map +1 -0
- package/build/user/index.d.ts +44 -0
- package/build/user/index.d.ts.map +1 -0
- package/build/user/index.js +97 -0
- package/build/user/index.js.map +1 -0
- package/ios/ExpoSpotifySDKModule.swift +233 -6
- package/ios/SPTScopeSerializer.swift +5 -0
- package/ios/SpotifyAppRemoteCoordinator.swift +939 -0
- package/ios/SpotifyAuthCoordinator.swift +67 -13
- package/ios/SpotifyTokenRefreshClient.swift +32 -1
- package/package.json +4 -3
|
@@ -28,6 +28,18 @@ export interface SpotifyRefreshConfig {
|
|
|
28
28
|
refreshToken: string;
|
|
29
29
|
/** URL of your token refresh server endpoint. */
|
|
30
30
|
tokenRefreshURL: string;
|
|
31
|
+
/**
|
|
32
|
+
* Scopes that were granted by the previous session. Used as a fallback
|
|
33
|
+
* when the refresh response omits the `scope` field (which most
|
|
34
|
+
* `accounts.spotify.com` refresh responses do — Spotify only returns
|
|
35
|
+
* `scope` when the granted scope set has changed).
|
|
36
|
+
*
|
|
37
|
+
* If omitted, the returned `SpotifySession.scopes` will be `[]` whenever
|
|
38
|
+
* the refresh response also omits `scope` — silently losing scope
|
|
39
|
+
* information you held a moment ago. Pass through the previous session's
|
|
40
|
+
* `scopes` to avoid that.
|
|
41
|
+
*/
|
|
42
|
+
scopes?: SpotifyScope[];
|
|
31
43
|
}
|
|
32
44
|
/**
|
|
33
45
|
* Configuration accepted by `authenticateAsync`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoSpotifySDK.types.d.ts","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B,GAC7B,oBAAoB,GACpB,WAAW,GACX,uBAAuB,GACvB,6BAA6B,GAC7B,yBAAyB,GACzB,wBAAwB,GACxB,oBAAoB,GACpB,kBAAkB,GAClB,eAAe,GACf,2BAA2B,GAC3B,qBAAqB,GACrB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,CAAC;AAExB;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,kBAAkB,GAClB,gBAAgB,GAChB,eAAe,GACf,mBAAmB,GACnB,wBAAwB,GACxB,uBAAuB,GACvB,YAAY,GACZ,SAAS,CAAC;AAEd;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GACjC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE5E;;;GAGG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,IAAI,EAAE,gBAAgB,CAAC;gBAE3B,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM;CAKpD"}
|
|
1
|
+
{"version":3,"file":"ExpoSpotifySDK.types.d.ts","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B,GAC7B,oBAAoB,GACpB,WAAW,GACX,uBAAuB,GACvB,6BAA6B,GAC7B,yBAAyB,GACzB,wBAAwB,GACxB,oBAAoB,GACpB,kBAAkB,GAClB,eAAe,GACf,2BAA2B,GAC3B,qBAAqB,GACrB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,CAAC;AAExB;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,kBAAkB,GAClB,gBAAgB,GAChB,eAAe,GACf,mBAAmB,GACnB,wBAAwB,GACxB,uBAAuB,GACvB,YAAY,GACZ,SAAS,CAAC;AAEd;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GACjC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE5E;;;GAGG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,IAAI,EAAE,gBAAgB,CAAC;gBAE3B,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM;CAKpD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoSpotifySDK.types.js","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ExpoSpotifySDK.types.js","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"AA2HA;;;GAGG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrB,IAAI,CAAmB;IAEvC,YAAY,IAAsB,EAAE,OAAe;QACjD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF","sourcesContent":["/**\n * Result of a successful Spotify authentication.\n *\n * The shape is identical across iOS and Android. On the Android implicit\n * (TOKEN) flow `refreshToken` is `null` and `scopes` reflects what was\n * *requested*, not granted — see the README's \"Android implicit flow is not\n * recommended\" section.\n */\nexport interface SpotifySession {\n /** OAuth access token. */\n accessToken: string;\n /**\n * OAuth refresh token. `null` on Android when no `tokenSwapURL` is provided\n * (the Spotify Android SDK does not expose a refresh token for implicit\n * grants — see the README).\n */\n refreshToken: string | null;\n /** Expiration timestamp as Unix epoch milliseconds. */\n expirationDate: number;\n /** Scopes the access token was granted (or requested, on Android implicit). */\n scopes: SpotifyScope[];\n}\n\n/**\n * Configuration accepted by `refreshSessionAsync`.\n */\nexport interface SpotifyRefreshConfig {\n /** The refresh token from a previous `authenticateAsync` call. */\n refreshToken: string;\n /** URL of your token refresh server endpoint. */\n tokenRefreshURL: string;\n /**\n * Scopes that were granted by the previous session. Used as a fallback\n * when the refresh response omits the `scope` field (which most\n * `accounts.spotify.com` refresh responses do — Spotify only returns\n * `scope` when the granted scope set has changed).\n *\n * If omitted, the returned `SpotifySession.scopes` will be `[]` whenever\n * the refresh response also omits `scope` — silently losing scope\n * information you held a moment ago. Pass through the previous session's\n * `scopes` to avoid that.\n */\n scopes?: SpotifyScope[];\n}\n\n/**\n * Configuration accepted by `authenticateAsync`.\n */\nexport interface SpotifyConfig {\n /** OAuth scopes to request. Must contain at least one entry. */\n scopes: SpotifyScope[];\n /**\n * If supplied, requests an authorization code rather than an implicit\n * token, then POSTs the code to this URL to exchange it for tokens.\n * **Required on Android** to receive a usable `refreshToken`.\n */\n tokenSwapURL?: string;\n /**\n * Used by the iOS SDK to refresh access tokens automatically, and by\n * `refreshSessionAsync` on both platforms.\n */\n tokenRefreshURL?: string;\n /**\n * If `true`, forces Spotify to show the authorization dialog even when\n * the user already has an active session. Defaults to `false`.\n *\n * Maps to `SPTSessionManager.alwaysShowAuthorizationDialog` on iOS and\n * `AuthorizationRequest.Builder.setShowDialog(true)` on Android.\n */\n showDialog?: boolean;\n}\n\n/**\n * Spotify OAuth scope identifiers that are valid through the iOS, Android\n * and Web auth flows. See https://developer.spotify.com/documentation/web-api/concepts/scopes\n */\nexport type SpotifyScope =\n | \"ugc-image-upload\"\n | \"user-read-playback-state\"\n | \"user-modify-playback-state\"\n | \"user-read-currently-playing\"\n | \"app-remote-control\"\n | \"streaming\"\n | \"playlist-read-private\"\n | \"playlist-read-collaborative\"\n | \"playlist-modify-private\"\n | \"playlist-modify-public\"\n | \"user-follow-modify\"\n | \"user-follow-read\"\n | \"user-top-read\"\n | \"user-read-recently-played\"\n | \"user-library-modify\"\n | \"user-library-read\"\n | \"user-read-email\"\n | \"user-read-private\";\n\n/**\n * JS-side error code constants thrown via `Promise.reject(new Error(...))`\n * by the native modules.\n */\nexport type SpotifyErrorCode =\n | \"USER_CANCELLED\"\n | \"AUTH_IN_PROGRESS\"\n | \"INVALID_CONFIG\"\n | \"NETWORK_ERROR\"\n | \"TOKEN_SWAP_FAILED\"\n | \"TOKEN_SWAP_PARSE_ERROR\"\n | \"SPOTIFY_NOT_INSTALLED\"\n | \"AUTH_ERROR\"\n | \"UNKNOWN\";\n\n/**\n * Payload delivered to `addSessionChangeListener` subscribers.\n *\n * - `didInitiate` — a new session was created by `authenticateAsync`\n * - `didRenew` — an existing session was refreshed by `refreshSessionAsync`\n * - `didFail` — an auth or refresh attempt failed\n */\nexport type SpotifySessionChangeEvent =\n | { type: \"didInitiate\"; session: SpotifySession }\n | { type: \"didRenew\"; session: SpotifySession }\n | { type: \"didFail\"; error: { code: SpotifyErrorCode; message: string } };\n\n/**\n * Error subclass thrown by `authenticateAsync` and `refreshSessionAsync`\n * carrying a structured `code` field for branching.\n */\nexport class SpotifyError extends Error {\n public readonly code: SpotifyErrorCode;\n\n constructor(code: SpotifyErrorCode, message: string) {\n super(message);\n this.name = \"SpotifyError\";\n this.code = code;\n }\n}\n"]}
|
|
@@ -2,6 +2,29 @@ declare const _default: {
|
|
|
2
2
|
isAvailable(): boolean;
|
|
3
3
|
authenticateAsync(): Promise<never>;
|
|
4
4
|
refreshSessionAsync(): Promise<never>;
|
|
5
|
+
appRemoteConnect(): Promise<never>;
|
|
6
|
+
appRemoteDisconnect(): Promise<never>;
|
|
7
|
+
appRemoteIsConnected(): boolean;
|
|
8
|
+
appRemoteGetConnectionState(): Promise<"disconnected">;
|
|
9
|
+
playerPlay(): Promise<never>;
|
|
10
|
+
playerPause(): Promise<never>;
|
|
11
|
+
playerResume(): Promise<never>;
|
|
12
|
+
playerSkipNext(): Promise<never>;
|
|
13
|
+
playerSkipPrevious(): Promise<never>;
|
|
14
|
+
playerSeekTo(): Promise<never>;
|
|
15
|
+
playerSetShuffle(): Promise<never>;
|
|
16
|
+
playerSetRepeatMode(): Promise<never>;
|
|
17
|
+
playerSetPodcastPlaybackSpeed(): Promise<never>;
|
|
18
|
+
playerQueue(): Promise<never>;
|
|
19
|
+
playerGetPlayerState(): Promise<never>;
|
|
20
|
+
playerGetCrossfadeState(): Promise<never>;
|
|
21
|
+
userGetCapabilities(): Promise<never>;
|
|
22
|
+
userGetLibraryState(): Promise<never>;
|
|
23
|
+
userAddToLibrary(): Promise<never>;
|
|
24
|
+
userRemoveFromLibrary(): Promise<never>;
|
|
25
|
+
contentGetRecommendedContentItems(): Promise<never>;
|
|
26
|
+
contentGetChildren(): Promise<never>;
|
|
27
|
+
imagesLoad(): Promise<never>;
|
|
5
28
|
addListener(): {
|
|
6
29
|
remove(): void;
|
|
7
30
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoSpotifySDKModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoSpotifySDKModule.web.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"ExpoSpotifySDKModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoSpotifySDKModule.web.ts"],"names":[],"mappings":";mBAQiB,OAAO;yBAGD,OAAO,CAAC,KAAK,CAAC;2BAGZ,OAAO,CAAC,KAAK,CAAC;wBAGjB,OAAO,CAAC,KAAK,CAAC;2BAGX,OAAO,CAAC,KAAK,CAAC;4BAGb,OAAO;mCAGA,OAAO,CAAC,cAAc,CAAC;kBAGxC,OAAO,CAAC,KAAK,CAAC;mBAGb,OAAO,CAAC,KAAK,CAAC;oBAGb,OAAO,CAAC,KAAK,CAAC;sBAGZ,OAAO,CAAC,KAAK,CAAC;0BAGV,OAAO,CAAC,KAAK,CAAC;oBAGpB,OAAO,CAAC,KAAK,CAAC;wBAGV,OAAO,CAAC,KAAK,CAAC;2BAGX,OAAO,CAAC,KAAK,CAAC;qCAGJ,OAAO,CAAC,KAAK,CAAC;mBAGhC,OAAO,CAAC,KAAK,CAAC;4BAGL,OAAO,CAAC,KAAK,CAAC;+BAGX,OAAO,CAAC,KAAK,CAAC;2BAGlB,OAAO,CAAC,KAAK,CAAC;2BAGd,OAAO,CAAC,KAAK,CAAC;wBAGjB,OAAO,CAAC,KAAK,CAAC;6BAGT,OAAO,CAAC,KAAK,CAAC;yCAGF,OAAO,CAAC,KAAK,CAAC;0BAG7B,OAAO,CAAC,KAAK,CAAC;kBAGtB,OAAO,CAAC,KAAK,CAAC;mBAGb;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE;uBAGd,IAAI;;AAlFzB,wBAqFE"}
|
|
@@ -1,16 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
function unsupported(method) {
|
|
2
|
+
return new Error(`[expo-spotify-sdk] ${method} is not supported on web. ` +
|
|
3
|
+
"This library targets iOS and Android only.");
|
|
4
4
|
}
|
|
5
5
|
export default {
|
|
6
6
|
isAvailable() {
|
|
7
7
|
return false;
|
|
8
8
|
},
|
|
9
9
|
authenticateAsync() {
|
|
10
|
-
return Promise.reject(
|
|
10
|
+
return Promise.reject(unsupported("authenticateAsync"));
|
|
11
11
|
},
|
|
12
12
|
refreshSessionAsync() {
|
|
13
|
-
return Promise.reject(
|
|
13
|
+
return Promise.reject(unsupported("refreshSessionAsync"));
|
|
14
|
+
},
|
|
15
|
+
appRemoteConnect() {
|
|
16
|
+
return Promise.reject(unsupported("appRemoteConnect"));
|
|
17
|
+
},
|
|
18
|
+
appRemoteDisconnect() {
|
|
19
|
+
return Promise.reject(unsupported("appRemoteDisconnect"));
|
|
20
|
+
},
|
|
21
|
+
appRemoteIsConnected() {
|
|
22
|
+
return false;
|
|
23
|
+
},
|
|
24
|
+
appRemoteGetConnectionState() {
|
|
25
|
+
return Promise.resolve("disconnected");
|
|
26
|
+
},
|
|
27
|
+
playerPlay() {
|
|
28
|
+
return Promise.reject(unsupported("playerPlay"));
|
|
29
|
+
},
|
|
30
|
+
playerPause() {
|
|
31
|
+
return Promise.reject(unsupported("playerPause"));
|
|
32
|
+
},
|
|
33
|
+
playerResume() {
|
|
34
|
+
return Promise.reject(unsupported("playerResume"));
|
|
35
|
+
},
|
|
36
|
+
playerSkipNext() {
|
|
37
|
+
return Promise.reject(unsupported("playerSkipNext"));
|
|
38
|
+
},
|
|
39
|
+
playerSkipPrevious() {
|
|
40
|
+
return Promise.reject(unsupported("playerSkipPrevious"));
|
|
41
|
+
},
|
|
42
|
+
playerSeekTo() {
|
|
43
|
+
return Promise.reject(unsupported("playerSeekTo"));
|
|
44
|
+
},
|
|
45
|
+
playerSetShuffle() {
|
|
46
|
+
return Promise.reject(unsupported("playerSetShuffle"));
|
|
47
|
+
},
|
|
48
|
+
playerSetRepeatMode() {
|
|
49
|
+
return Promise.reject(unsupported("playerSetRepeatMode"));
|
|
50
|
+
},
|
|
51
|
+
playerSetPodcastPlaybackSpeed() {
|
|
52
|
+
return Promise.reject(unsupported("playerSetPodcastPlaybackSpeed"));
|
|
53
|
+
},
|
|
54
|
+
playerQueue() {
|
|
55
|
+
return Promise.reject(unsupported("playerQueue"));
|
|
56
|
+
},
|
|
57
|
+
playerGetPlayerState() {
|
|
58
|
+
return Promise.reject(unsupported("playerGetPlayerState"));
|
|
59
|
+
},
|
|
60
|
+
playerGetCrossfadeState() {
|
|
61
|
+
return Promise.reject(unsupported("playerGetCrossfadeState"));
|
|
62
|
+
},
|
|
63
|
+
userGetCapabilities() {
|
|
64
|
+
return Promise.reject(unsupported("userGetCapabilities"));
|
|
65
|
+
},
|
|
66
|
+
userGetLibraryState() {
|
|
67
|
+
return Promise.reject(unsupported("userGetLibraryState"));
|
|
68
|
+
},
|
|
69
|
+
userAddToLibrary() {
|
|
70
|
+
return Promise.reject(unsupported("userAddToLibrary"));
|
|
71
|
+
},
|
|
72
|
+
userRemoveFromLibrary() {
|
|
73
|
+
return Promise.reject(unsupported("userRemoveFromLibrary"));
|
|
74
|
+
},
|
|
75
|
+
contentGetRecommendedContentItems() {
|
|
76
|
+
return Promise.reject(unsupported("contentGetRecommendedContentItems"));
|
|
77
|
+
},
|
|
78
|
+
contentGetChildren() {
|
|
79
|
+
return Promise.reject(unsupported("contentGetChildren"));
|
|
80
|
+
},
|
|
81
|
+
imagesLoad() {
|
|
82
|
+
return Promise.reject(unsupported("imagesLoad"));
|
|
14
83
|
},
|
|
15
84
|
addListener() {
|
|
16
85
|
return { remove() { } };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoSpotifySDKModule.web.js","sourceRoot":"","sources":["../src/ExpoSpotifySDKModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ExpoSpotifySDKModule.web.js","sourceRoot":"","sources":["../src/ExpoSpotifySDKModule.web.ts"],"names":[],"mappings":"AAAA,SAAS,WAAW,CAAC,MAAc;IACjC,OAAO,IAAI,KAAK,CACd,sBAAsB,MAAM,4BAA4B;QACtD,4CAA4C,CAC/C,CAAC;AACJ,CAAC;AAED,eAAe;IACb,WAAW;QACT,OAAO,KAAK,CAAC;IACf,CAAC;IACD,iBAAiB;QACf,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC1D,CAAC;IACD,mBAAmB;QACjB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,gBAAgB;QACd,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,mBAAmB;QACjB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,oBAAoB;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,2BAA2B;QACzB,OAAO,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACzC,CAAC;IACD,UAAU;QACR,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC;IACnD,CAAC;IACD,WAAW;QACT,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,YAAY;QACV,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,cAAc;QACZ,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,kBAAkB;QAChB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,YAAY;QACV,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,gBAAgB;QACd,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,mBAAmB;QACjB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,6BAA6B;QAC3B,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,+BAA+B,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,WAAW;QACT,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,oBAAoB;QAClB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,uBAAuB;QACrB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,mBAAmB;QACjB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,mBAAmB;QACjB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,gBAAgB;QACd,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,qBAAqB;QACnB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,iCAAiC;QAC/B,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,mCAAmC,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,kBAAkB;QAChB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,UAAU;QACR,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC;IACnD,CAAC;IACD,WAAW;QACT,OAAO,EAAE,MAAM,KAAI,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,eAAe;QACb,WAAW;IACb,CAAC;CACF,CAAC","sourcesContent":["function unsupported(method: string): Error {\n return new Error(\n `[expo-spotify-sdk] ${method} is not supported on web. ` +\n \"This library targets iOS and Android only.\",\n );\n}\n\nexport default {\n isAvailable(): boolean {\n return false;\n },\n authenticateAsync(): Promise<never> {\n return Promise.reject(unsupported(\"authenticateAsync\"));\n },\n refreshSessionAsync(): Promise<never> {\n return Promise.reject(unsupported(\"refreshSessionAsync\"));\n },\n appRemoteConnect(): Promise<never> {\n return Promise.reject(unsupported(\"appRemoteConnect\"));\n },\n appRemoteDisconnect(): Promise<never> {\n return Promise.reject(unsupported(\"appRemoteDisconnect\"));\n },\n appRemoteIsConnected(): boolean {\n return false;\n },\n appRemoteGetConnectionState(): Promise<\"disconnected\"> {\n return Promise.resolve(\"disconnected\");\n },\n playerPlay(): Promise<never> {\n return Promise.reject(unsupported(\"playerPlay\"));\n },\n playerPause(): Promise<never> {\n return Promise.reject(unsupported(\"playerPause\"));\n },\n playerResume(): Promise<never> {\n return Promise.reject(unsupported(\"playerResume\"));\n },\n playerSkipNext(): Promise<never> {\n return Promise.reject(unsupported(\"playerSkipNext\"));\n },\n playerSkipPrevious(): Promise<never> {\n return Promise.reject(unsupported(\"playerSkipPrevious\"));\n },\n playerSeekTo(): Promise<never> {\n return Promise.reject(unsupported(\"playerSeekTo\"));\n },\n playerSetShuffle(): Promise<never> {\n return Promise.reject(unsupported(\"playerSetShuffle\"));\n },\n playerSetRepeatMode(): Promise<never> {\n return Promise.reject(unsupported(\"playerSetRepeatMode\"));\n },\n playerSetPodcastPlaybackSpeed(): Promise<never> {\n return Promise.reject(unsupported(\"playerSetPodcastPlaybackSpeed\"));\n },\n playerQueue(): Promise<never> {\n return Promise.reject(unsupported(\"playerQueue\"));\n },\n playerGetPlayerState(): Promise<never> {\n return Promise.reject(unsupported(\"playerGetPlayerState\"));\n },\n playerGetCrossfadeState(): Promise<never> {\n return Promise.reject(unsupported(\"playerGetCrossfadeState\"));\n },\n userGetCapabilities(): Promise<never> {\n return Promise.reject(unsupported(\"userGetCapabilities\"));\n },\n userGetLibraryState(): Promise<never> {\n return Promise.reject(unsupported(\"userGetLibraryState\"));\n },\n userAddToLibrary(): Promise<never> {\n return Promise.reject(unsupported(\"userAddToLibrary\"));\n },\n userRemoveFromLibrary(): Promise<never> {\n return Promise.reject(unsupported(\"userRemoveFromLibrary\"));\n },\n contentGetRecommendedContentItems(): Promise<never> {\n return Promise.reject(unsupported(\"contentGetRecommendedContentItems\"));\n },\n contentGetChildren(): Promise<never> {\n return Promise.reject(unsupported(\"contentGetChildren\"));\n },\n imagesLoad(): Promise<never> {\n return Promise.reject(unsupported(\"imagesLoad\"));\n },\n addListener(): { remove(): void } {\n return { remove() {} };\n },\n removeListeners(): void {\n /* no-op */\n },\n};\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SpotifyError } from "../error";
|
|
2
|
+
export type AppRemoteErrorCode = "CONNECTION_FAILED" | "CONNECTION_LOST" | "NOT_CONNECTED" | "UNKNOWN";
|
|
3
|
+
export declare class AppRemoteError extends SpotifyError {
|
|
4
|
+
readonly namespace: "AppRemote";
|
|
5
|
+
readonly code: AppRemoteErrorCode;
|
|
6
|
+
constructor(code: AppRemoteErrorCode, message: string);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/app-remote/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,kBAAkB,GAC1B,mBAAmB,GACnB,iBAAiB,GACjB,eAAe,GACf,SAAS,CAAC;AAEd,qBAAa,cAAe,SAAQ,YAAY;IAC9C,QAAQ,CAAC,SAAS,EAAG,WAAW,CAAU;IAC1C,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;gBAEtB,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM;CAItD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/app-remote/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAQxC,MAAM,OAAO,cAAe,SAAQ,YAAY;IACrC,SAAS,GAAG,WAAoB,CAAC;IACjC,IAAI,CAAqB;IAElC,YAAY,IAAwB,EAAE,OAAe;QACnD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF","sourcesContent":["import { SpotifyError } from \"../error\";\n\nexport type AppRemoteErrorCode =\n | \"CONNECTION_FAILED\"\n | \"CONNECTION_LOST\"\n | \"NOT_CONNECTED\"\n | \"UNKNOWN\";\n\nexport class AppRemoteError extends SpotifyError {\n readonly namespace = \"AppRemote\" as const;\n readonly code: AppRemoteErrorCode;\n\n constructor(code: AppRemoteErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { EventSubscription } from "expo-modules-core";
|
|
2
|
+
import { AppRemoteErrorCode } from "./error";
|
|
3
|
+
export type { AppRemoteErrorCode } from "./error";
|
|
4
|
+
export { AppRemoteError } from "./error";
|
|
5
|
+
/** Current state of the IPC connection to the Spotify app. */
|
|
6
|
+
export type ConnectionState = "disconnected" | "connecting" | "connected";
|
|
7
|
+
/** Payload of the `connectionStateChange` event. */
|
|
8
|
+
export interface ConnectionStateChangeEvent {
|
|
9
|
+
state: ConnectionState;
|
|
10
|
+
}
|
|
11
|
+
/** Payload of the `connectionError` event. */
|
|
12
|
+
export interface ConnectionErrorEvent {
|
|
13
|
+
code: AppRemoteErrorCode;
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Spotify App Remote namespace. Manages the IPC connection to the running
|
|
18
|
+
* Spotify app. All `Player`, `User`, `Content`, and `Images` calls require an
|
|
19
|
+
* active connection established via `AppRemote.connect()`.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { AppRemote } from "@wwdrew/expo-spotify-sdk";
|
|
24
|
+
*
|
|
25
|
+
* // Connect using the access token from Auth.authenticate()
|
|
26
|
+
* await AppRemote.connect(session.accessToken);
|
|
27
|
+
*
|
|
28
|
+
* const sub = AppRemote.addListener("connectionStateChange", ({ state }) => {
|
|
29
|
+
* console.log("connection state:", state);
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // later:
|
|
33
|
+
* await AppRemote.disconnect();
|
|
34
|
+
* sub.remove();
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare const AppRemote: {
|
|
38
|
+
/**
|
|
39
|
+
* Opens a connection to the running Spotify app using the provided access
|
|
40
|
+
* token. Resolves when the connection is established; rejects with an
|
|
41
|
+
* {@link AppRemoteError} if the connection fails.
|
|
42
|
+
*
|
|
43
|
+
* **Android note:** The access token is accepted for API parity with iOS but
|
|
44
|
+
* the Android App Remote SDK does not accept it directly — it uses the
|
|
45
|
+
* session cached in the Spotify app from your earlier `Auth.authenticate()`
|
|
46
|
+
* call. Ensure `Auth.authenticate()` has succeeded before calling `connect()`.
|
|
47
|
+
*
|
|
48
|
+
* Calling `connect()` while already connected is a no-op.
|
|
49
|
+
*/
|
|
50
|
+
readonly connect: (accessToken: string) => Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Disconnects from the Spotify app. Safe to call when already disconnected.
|
|
53
|
+
* Resolves once the disconnection is complete.
|
|
54
|
+
*/
|
|
55
|
+
readonly disconnect: () => Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Returns `true` if currently connected to the Spotify app.
|
|
58
|
+
* This is a synchronous snapshot — subscribe to `"connectionStateChange"`
|
|
59
|
+
* for reactive updates.
|
|
60
|
+
*/
|
|
61
|
+
readonly isConnected: () => boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Returns the current {@link ConnectionState} synchronously.
|
|
64
|
+
* Subscribe to `"connectionStateChange"` for reactive updates.
|
|
65
|
+
*/
|
|
66
|
+
readonly getConnectionState: () => Promise<ConnectionState>;
|
|
67
|
+
/**
|
|
68
|
+
* Subscribes to connection lifecycle events.
|
|
69
|
+
*
|
|
70
|
+
* | Event | Payload | When |
|
|
71
|
+
* |---|---|---|
|
|
72
|
+
* | `"connectionStateChange"` | `{ state: ConnectionState }` | State transitions |
|
|
73
|
+
* | `"connectionError"` | `{ code, message }` | Connection failures and drops |
|
|
74
|
+
*
|
|
75
|
+
* Returns a `Subscription` — call `.remove()` to unsubscribe.
|
|
76
|
+
*/
|
|
77
|
+
readonly addListener: <E extends "connectionStateChange" | "connectionError">(event: E, listener: E extends "connectionStateChange" ? (event: ConnectionStateChangeEvent) => void : (event: ConnectionErrorEvent) => void) => EventSubscription;
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app-remote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAkB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE7D,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAMzC,8DAA8D;AAC9D,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,CAAC;AAE1E,oDAAoD;AACpD,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAqCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,SAAS;IACpB;;;;;;;;;;;OAWG;oCACkB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAM3C;;;OAGG;+BACW,OAAO,CAAC,IAAI,CAAC;IAI3B;;;;OAIG;gCACY,OAAO;IAItB;;;OAGG;uCACmB,OAAO,CAAC,eAAe,CAAC;IAI9C;;;;;;;;;OASG;2BACS,CAAC,SAAS,uBAAuB,GAAG,iBAAiB,SACxD,CAAC,YACE,CAAC,SAAS,uBAAuB,GACvC,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,GAC3C,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,KACxC,iBAAiB;CAUZ,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import ExpoSpotifySDKModule from "../ExpoSpotifySDKModule";
|
|
2
|
+
import { AppRemoteError } from "./error";
|
|
3
|
+
export { AppRemoteError } from "./error";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Internal helpers
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
const VALID_APPREMOTE_CODES = new Set([
|
|
8
|
+
"CONNECTION_FAILED",
|
|
9
|
+
"CONNECTION_LOST",
|
|
10
|
+
"NOT_CONNECTED",
|
|
11
|
+
"UNKNOWN",
|
|
12
|
+
]);
|
|
13
|
+
const CAUSE_SEPARATOR = "→ Caused by: ";
|
|
14
|
+
function unwrapReason(message) {
|
|
15
|
+
const idx = message.lastIndexOf(CAUSE_SEPARATOR);
|
|
16
|
+
return idx === -1 ? message : message.slice(idx + CAUSE_SEPARATOR.length);
|
|
17
|
+
}
|
|
18
|
+
function rethrowAsAppRemoteError(err) {
|
|
19
|
+
if (err instanceof AppRemoteError)
|
|
20
|
+
throw err;
|
|
21
|
+
if (err instanceof Error) {
|
|
22
|
+
const reason = unwrapReason(err.message);
|
|
23
|
+
const maybeCode = err.code;
|
|
24
|
+
if (maybeCode && VALID_APPREMOTE_CODES.has(maybeCode)) {
|
|
25
|
+
throw new AppRemoteError(maybeCode, reason);
|
|
26
|
+
}
|
|
27
|
+
throw new AppRemoteError("UNKNOWN", reason);
|
|
28
|
+
}
|
|
29
|
+
throw new AppRemoteError("UNKNOWN", String(err));
|
|
30
|
+
}
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// AppRemote namespace
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Spotify App Remote namespace. Manages the IPC connection to the running
|
|
36
|
+
* Spotify app. All `Player`, `User`, `Content`, and `Images` calls require an
|
|
37
|
+
* active connection established via `AppRemote.connect()`.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { AppRemote } from "@wwdrew/expo-spotify-sdk";
|
|
42
|
+
*
|
|
43
|
+
* // Connect using the access token from Auth.authenticate()
|
|
44
|
+
* await AppRemote.connect(session.accessToken);
|
|
45
|
+
*
|
|
46
|
+
* const sub = AppRemote.addListener("connectionStateChange", ({ state }) => {
|
|
47
|
+
* console.log("connection state:", state);
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* // later:
|
|
51
|
+
* await AppRemote.disconnect();
|
|
52
|
+
* sub.remove();
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const AppRemote = {
|
|
56
|
+
/**
|
|
57
|
+
* Opens a connection to the running Spotify app using the provided access
|
|
58
|
+
* token. Resolves when the connection is established; rejects with an
|
|
59
|
+
* {@link AppRemoteError} if the connection fails.
|
|
60
|
+
*
|
|
61
|
+
* **Android note:** The access token is accepted for API parity with iOS but
|
|
62
|
+
* the Android App Remote SDK does not accept it directly — it uses the
|
|
63
|
+
* session cached in the Spotify app from your earlier `Auth.authenticate()`
|
|
64
|
+
* call. Ensure `Auth.authenticate()` has succeeded before calling `connect()`.
|
|
65
|
+
*
|
|
66
|
+
* Calling `connect()` while already connected is a no-op.
|
|
67
|
+
*/
|
|
68
|
+
connect(accessToken) {
|
|
69
|
+
return ExpoSpotifySDKModule.appRemoteConnect(accessToken).catch(rethrowAsAppRemoteError);
|
|
70
|
+
},
|
|
71
|
+
/**
|
|
72
|
+
* Disconnects from the Spotify app. Safe to call when already disconnected.
|
|
73
|
+
* Resolves once the disconnection is complete.
|
|
74
|
+
*/
|
|
75
|
+
disconnect() {
|
|
76
|
+
return ExpoSpotifySDKModule.appRemoteDisconnect();
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* Returns `true` if currently connected to the Spotify app.
|
|
80
|
+
* This is a synchronous snapshot — subscribe to `"connectionStateChange"`
|
|
81
|
+
* for reactive updates.
|
|
82
|
+
*/
|
|
83
|
+
isConnected() {
|
|
84
|
+
return ExpoSpotifySDKModule.appRemoteIsConnected();
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* Returns the current {@link ConnectionState} synchronously.
|
|
88
|
+
* Subscribe to `"connectionStateChange"` for reactive updates.
|
|
89
|
+
*/
|
|
90
|
+
getConnectionState() {
|
|
91
|
+
return ExpoSpotifySDKModule.appRemoteGetConnectionState();
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* Subscribes to connection lifecycle events.
|
|
95
|
+
*
|
|
96
|
+
* | Event | Payload | When |
|
|
97
|
+
* |---|---|---|
|
|
98
|
+
* | `"connectionStateChange"` | `{ state: ConnectionState }` | State transitions |
|
|
99
|
+
* | `"connectionError"` | `{ code, message }` | Connection failures and drops |
|
|
100
|
+
*
|
|
101
|
+
* Returns a `Subscription` — call `.remove()` to unsubscribe.
|
|
102
|
+
*/
|
|
103
|
+
addListener(event, listener) {
|
|
104
|
+
const nativeEvent = event === "connectionStateChange"
|
|
105
|
+
? "onConnectionStateChange"
|
|
106
|
+
: "onConnectionError";
|
|
107
|
+
return ExpoSpotifySDKModule.addListener(nativeEvent, listener);
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/app-remote/index.ts"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAsB,MAAM,SAAS,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAoBzC,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAqB;IACxD,mBAAmB;IACnB,iBAAiB;IACjB,eAAe;IACf,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,eAAe,CAAC;AAExC,SAAS,YAAY,CAAC,OAAe;IACnC,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IACjD,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,uBAAuB,CAAC,GAAY;IAC3C,IAAI,GAAG,YAAY,cAAc;QAAE,MAAM,GAAG,CAAC;IAC7C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,SAAS,GAAI,GAAiC,CAAC,IAAI,CAAC;QAC1D,IAAI,SAAS,IAAI,qBAAqB,CAAC,GAAG,CAAC,SAA+B,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,cAAc,CAAC,SAA+B,EAAE,MAAM,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,IAAI,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,IAAI,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,WAAmB;QACzB,OAAO,oBAAoB,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,KAAK,CAC7D,uBAAuB,CACxB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,UAAU;QACR,OAAO,oBAAoB,CAAC,mBAAmB,EAAE,CAAC;IACpD,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,OAAO,oBAAoB,CAAC,oBAAoB,EAAE,CAAC;IACrD,CAAC;IAED;;;OAGG;IACH,kBAAkB;QAChB,OAAO,oBAAoB,CAAC,2BAA2B,EAAE,CAAC;IAC5D,CAAC;IAED;;;;;;;;;OASG;IACH,WAAW,CACT,KAAQ,EACR,QAEyC;QAEzC,MAAM,WAAW,GACf,KAAK,KAAK,uBAAuB;YAC/B,CAAC,CAAC,yBAAyB;YAC3B,CAAC,CAAC,mBAAmB,CAAC;QAC1B,OAAO,oBAAoB,CAAC,WAAW,CACrC,WAAW,EACX,QAAoC,CAChB,CAAC;IACzB,CAAC;CACO,CAAC","sourcesContent":["import { EventSubscription } from \"expo-modules-core\";\n\nimport ExpoSpotifySDKModule from \"../ExpoSpotifySDKModule\";\nimport { AppRemoteError, AppRemoteErrorCode } from \"./error\";\n\nexport type { AppRemoteErrorCode } from \"./error\";\nexport { AppRemoteError } from \"./error\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Current state of the IPC connection to the Spotify app. */\nexport type ConnectionState = \"disconnected\" | \"connecting\" | \"connected\";\n\n/** Payload of the `connectionStateChange` event. */\nexport interface ConnectionStateChangeEvent {\n state: ConnectionState;\n}\n\n/** Payload of the `connectionError` event. */\nexport interface ConnectionErrorEvent {\n code: AppRemoteErrorCode;\n message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst VALID_APPREMOTE_CODES = new Set<AppRemoteErrorCode>([\n \"CONNECTION_FAILED\",\n \"CONNECTION_LOST\",\n \"NOT_CONNECTED\",\n \"UNKNOWN\",\n]);\n\nconst CAUSE_SEPARATOR = \"→ Caused by: \";\n\nfunction unwrapReason(message: string): string {\n const idx = message.lastIndexOf(CAUSE_SEPARATOR);\n return idx === -1 ? message : message.slice(idx + CAUSE_SEPARATOR.length);\n}\n\nfunction rethrowAsAppRemoteError(err: unknown): never {\n if (err instanceof AppRemoteError) throw err;\n if (err instanceof Error) {\n const reason = unwrapReason(err.message);\n const maybeCode = (err as Error & { code?: string }).code;\n if (maybeCode && VALID_APPREMOTE_CODES.has(maybeCode as AppRemoteErrorCode)) {\n throw new AppRemoteError(maybeCode as AppRemoteErrorCode, reason);\n }\n throw new AppRemoteError(\"UNKNOWN\", reason);\n }\n throw new AppRemoteError(\"UNKNOWN\", String(err));\n}\n\n// ---------------------------------------------------------------------------\n// AppRemote namespace\n// ---------------------------------------------------------------------------\n\n/**\n * Spotify App Remote namespace. Manages the IPC connection to the running\n * Spotify app. All `Player`, `User`, `Content`, and `Images` calls require an\n * active connection established via `AppRemote.connect()`.\n *\n * @example\n * ```ts\n * import { AppRemote } from \"@wwdrew/expo-spotify-sdk\";\n *\n * // Connect using the access token from Auth.authenticate()\n * await AppRemote.connect(session.accessToken);\n *\n * const sub = AppRemote.addListener(\"connectionStateChange\", ({ state }) => {\n * console.log(\"connection state:\", state);\n * });\n *\n * // later:\n * await AppRemote.disconnect();\n * sub.remove();\n * ```\n */\nexport const AppRemote = {\n /**\n * Opens a connection to the running Spotify app using the provided access\n * token. Resolves when the connection is established; rejects with an\n * {@link AppRemoteError} if the connection fails.\n *\n * **Android note:** The access token is accepted for API parity with iOS but\n * the Android App Remote SDK does not accept it directly — it uses the\n * session cached in the Spotify app from your earlier `Auth.authenticate()`\n * call. Ensure `Auth.authenticate()` has succeeded before calling `connect()`.\n *\n * Calling `connect()` while already connected is a no-op.\n */\n connect(accessToken: string): Promise<void> {\n return ExpoSpotifySDKModule.appRemoteConnect(accessToken).catch(\n rethrowAsAppRemoteError,\n );\n },\n\n /**\n * Disconnects from the Spotify app. Safe to call when already disconnected.\n * Resolves once the disconnection is complete.\n */\n disconnect(): Promise<void> {\n return ExpoSpotifySDKModule.appRemoteDisconnect();\n },\n\n /**\n * Returns `true` if currently connected to the Spotify app.\n * This is a synchronous snapshot — subscribe to `\"connectionStateChange\"`\n * for reactive updates.\n */\n isConnected(): boolean {\n return ExpoSpotifySDKModule.appRemoteIsConnected();\n },\n\n /**\n * Returns the current {@link ConnectionState} synchronously.\n * Subscribe to `\"connectionStateChange\"` for reactive updates.\n */\n getConnectionState(): Promise<ConnectionState> {\n return ExpoSpotifySDKModule.appRemoteGetConnectionState();\n },\n\n /**\n * Subscribes to connection lifecycle events.\n *\n * | Event | Payload | When |\n * |---|---|---|\n * | `\"connectionStateChange\"` | `{ state: ConnectionState }` | State transitions |\n * | `\"connectionError\"` | `{ code, message }` | Connection failures and drops |\n *\n * Returns a `Subscription` — call `.remove()` to unsubscribe.\n */\n addListener<E extends \"connectionStateChange\" | \"connectionError\">(\n event: E,\n listener: E extends \"connectionStateChange\"\n ? (event: ConnectionStateChangeEvent) => void\n : (event: ConnectionErrorEvent) => void,\n ): EventSubscription {\n const nativeEvent =\n event === \"connectionStateChange\"\n ? \"onConnectionStateChange\"\n : \"onConnectionError\";\n return ExpoSpotifySDKModule.addListener(\n nativeEvent,\n listener as (event: unknown) => void,\n ) as EventSubscription;\n },\n} as const;\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SpotifyError } from "../error";
|
|
2
|
+
export type AuthErrorCode = "USER_CANCELLED" | "AUTH_IN_PROGRESS" | "INVALID_CONFIG" | "NETWORK_ERROR" | "TOKEN_SWAP_FAILED" | "TOKEN_SWAP_PARSE_ERROR" | "SPOTIFY_NOT_INSTALLED" | "AUTH_ERROR" | "UNKNOWN";
|
|
3
|
+
export declare class AuthError extends SpotifyError {
|
|
4
|
+
readonly namespace: "Auth";
|
|
5
|
+
readonly code: AuthErrorCode;
|
|
6
|
+
constructor(code: AuthErrorCode, message: string);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/auth/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,aAAa,GACrB,gBAAgB,GAChB,kBAAkB,GAClB,gBAAgB,GAChB,eAAe,GACf,mBAAmB,GACnB,wBAAwB,GACxB,uBAAuB,GACvB,YAAY,GACZ,SAAS,CAAC;AAEd,qBAAa,SAAU,SAAQ,YAAY;IACzC,QAAQ,CAAC,SAAS,EAAG,MAAM,CAAU;IACrC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;gBAEjB,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM;CAIjD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/auth/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAaxC,MAAM,OAAO,SAAU,SAAQ,YAAY;IAChC,SAAS,GAAG,MAAe,CAAC;IAC5B,IAAI,CAAgB;IAE7B,YAAY,IAAmB,EAAE,OAAe;QAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF","sourcesContent":["import { SpotifyError } from \"../error\";\n\nexport type AuthErrorCode =\n | \"USER_CANCELLED\"\n | \"AUTH_IN_PROGRESS\"\n | \"INVALID_CONFIG\"\n | \"NETWORK_ERROR\"\n | \"TOKEN_SWAP_FAILED\"\n | \"TOKEN_SWAP_PARSE_ERROR\"\n | \"SPOTIFY_NOT_INSTALLED\"\n | \"AUTH_ERROR\"\n | \"UNKNOWN\";\n\nexport class AuthError extends SpotifyError {\n readonly namespace = \"Auth\" as const;\n readonly code: AuthErrorCode;\n\n constructor(code: AuthErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n"]}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { EventSubscription } from "expo-modules-core";
|
|
2
|
+
import { AuthErrorCode } from "./error";
|
|
3
|
+
export type { AuthErrorCode } from "./error";
|
|
4
|
+
export { AuthError } from "./error";
|
|
5
|
+
export interface SpotifySession {
|
|
6
|
+
/** OAuth access token. */
|
|
7
|
+
accessToken: string;
|
|
8
|
+
/**
|
|
9
|
+
* OAuth refresh token. `null` on Android when no `tokenSwapURL` is provided
|
|
10
|
+
* (the Spotify Android SDK does not expose a refresh token for implicit
|
|
11
|
+
* grants).
|
|
12
|
+
*/
|
|
13
|
+
refreshToken: string | null;
|
|
14
|
+
/** Expiration timestamp as Unix epoch milliseconds. */
|
|
15
|
+
expirationDate: number;
|
|
16
|
+
/** Scopes the access token was granted (or requested, on Android implicit). */
|
|
17
|
+
scopes: SpotifyScope[];
|
|
18
|
+
}
|
|
19
|
+
export type SpotifyScope = "ugc-image-upload" | "user-read-playback-state" | "user-modify-playback-state" | "user-read-currently-playing" | "app-remote-control" | "streaming" | "playlist-read-private" | "playlist-read-collaborative" | "playlist-modify-private" | "playlist-modify-public" | "user-follow-modify" | "user-follow-read" | "user-top-read" | "user-read-recently-played" | "user-library-modify" | "user-library-read" | "user-read-email" | "user-read-private";
|
|
20
|
+
export interface AuthenticateConfig {
|
|
21
|
+
/** OAuth scopes to request. Must contain at least one entry. */
|
|
22
|
+
scopes: SpotifyScope[];
|
|
23
|
+
/**
|
|
24
|
+
* If supplied, requests an authorization code rather than an implicit
|
|
25
|
+
* token, then POSTs the code to this URL to exchange it for tokens.
|
|
26
|
+
* **Required on Android** to receive a usable `refreshToken`.
|
|
27
|
+
*/
|
|
28
|
+
tokenSwapURL?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Used by the iOS SDK to refresh access tokens automatically, and by
|
|
31
|
+
* `Auth.refresh()` on both platforms.
|
|
32
|
+
*/
|
|
33
|
+
tokenRefreshURL?: string;
|
|
34
|
+
/**
|
|
35
|
+
* If `true`, forces Spotify to show the authorization dialog even when the
|
|
36
|
+
* user already has an active session. Defaults to `false`.
|
|
37
|
+
*/
|
|
38
|
+
showDialog?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface RefreshConfig {
|
|
41
|
+
/** The refresh token from a previous `Auth.authenticate()` call. */
|
|
42
|
+
refreshToken: string;
|
|
43
|
+
/** URL of your token refresh server endpoint. */
|
|
44
|
+
tokenRefreshURL: string;
|
|
45
|
+
/**
|
|
46
|
+
* Scopes that were granted by the previous session. Used as a fallback when
|
|
47
|
+
* the refresh response omits the `scope` field.
|
|
48
|
+
*/
|
|
49
|
+
scopes?: SpotifyScope[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Payload delivered to `Auth.addListener("sessionChange", ...)` subscribers.
|
|
53
|
+
*/
|
|
54
|
+
export type SessionChangeEvent = {
|
|
55
|
+
type: "didInitiate";
|
|
56
|
+
session: SpotifySession;
|
|
57
|
+
} | {
|
|
58
|
+
type: "didRenew";
|
|
59
|
+
session: SpotifySession;
|
|
60
|
+
} | {
|
|
61
|
+
type: "didFail";
|
|
62
|
+
error: {
|
|
63
|
+
code: AuthErrorCode;
|
|
64
|
+
message: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Spotify Auth namespace. Handles OAuth authentication and session lifecycle.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* import { Auth } from "@wwdrew/expo-spotify-sdk";
|
|
73
|
+
*
|
|
74
|
+
* const session = await Auth.authenticate({ scopes: ["streaming"] });
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare const Auth: {
|
|
78
|
+
/**
|
|
79
|
+
* Returns `true` if the Spotify app is installed on the device.
|
|
80
|
+
*/
|
|
81
|
+
readonly isAvailable: () => boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Starts a Spotify OAuth flow. Resolves with a {@link SpotifySession};
|
|
84
|
+
* rejects with an {@link AuthError} carrying a `code`.
|
|
85
|
+
*/
|
|
86
|
+
readonly authenticate: (config: AuthenticateConfig) => Promise<SpotifySession>;
|
|
87
|
+
/**
|
|
88
|
+
* Exchanges a refresh token for a new access token via your token refresh
|
|
89
|
+
* server. Resolves with a fresh {@link SpotifySession}; rejects with an
|
|
90
|
+
* {@link AuthError}.
|
|
91
|
+
*/
|
|
92
|
+
readonly refresh: (config: RefreshConfig) => Promise<SpotifySession>;
|
|
93
|
+
/**
|
|
94
|
+
* Forcibly cancel any in-flight `Auth.authenticate()` call. No-op on
|
|
95
|
+
* Android (the Android coordinator self-cleans via structured concurrency).
|
|
96
|
+
*
|
|
97
|
+
* Use before `Auth.authenticate()` to defensively clear any leaked iOS
|
|
98
|
+
* coordinator state (the `SPTSessionManager` delegate callbacks are not
|
|
99
|
+
* guaranteed to fire).
|
|
100
|
+
*/
|
|
101
|
+
readonly cancelPending: () => Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Subscribes to session lifecycle events.
|
|
104
|
+
*
|
|
105
|
+
* Events fire for every `Auth.authenticate()` and `Auth.refresh()` call,
|
|
106
|
+
* regardless of whether the call was awaited. Useful for persisting tokens
|
|
107
|
+
* in a central store without coupling the store to the call sites.
|
|
108
|
+
*
|
|
109
|
+
* Returns a `Subscription` — call `.remove()` to unsubscribe.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const sub = Auth.addListener("sessionChange", (event) => {
|
|
114
|
+
* if (event.type === "didInitiate" || event.type === "didRenew") {
|
|
115
|
+
* store.setSession(event.session);
|
|
116
|
+
* }
|
|
117
|
+
* });
|
|
118
|
+
* // later:
|
|
119
|
+
* sub.remove();
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
readonly addListener: (event: "sessionChange", listener: (event: SessionChangeEvent) => void) => EventSubscription;
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAY,MAAM,mBAAmB,CAAC;AAGhE,OAAO,EAAa,aAAa,EAAE,MAAM,SAAS,CAAC;AAEnD,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAMpC,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B,GAC7B,oBAAoB,GACpB,WAAW,GACX,uBAAuB,GACvB,6BAA6B,GAC7B,yBAAyB,GACzB,wBAAwB,GACxB,oBAAoB,GACpB,kBAAkB,GAClB,eAAe,GACf,2BAA2B,GAC3B,qBAAqB,GACrB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,CAAC;AAExB,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,eAAe,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAgFzE;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI;IACf;;OAEG;gCACY,OAAO;IAItB;;;OAGG;oCACkB,kBAAkB,KAAG,OAAO,CAAC,cAAc,CAAC;IAmBjE;;;;OAIG;+BACa,aAAa,KAAG,OAAO,CAAC,cAAc,CAAC;IAgBvD;;;;;;;OAOG;kCACc,OAAO,CAAC,IAAI,CAAC;IAO9B;;;;;;;;;;;;;;;;;;;OAmBG;kCAEM,eAAe,YACZ,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,KAC5C,iBAAiB;CAMZ,CAAC"}
|