@wwdrew/expo-spotify-sdk 1.0.0 → 2.1.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 +92 -350
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/spotifysdk/ExpoSpotifySDKModule.kt +3 -5
- package/android/src/main/java/expo/modules/spotifysdk/SpotifyAppRemoteCoordinator.kt +6 -64
- package/android/src/main/java/expo/modules/spotifysdk/SpotifyAppRemoteErrorMapping.kt +106 -0
- package/android/src/main/java/expo/modules/spotifysdk/SpotifyTokenSwapClient.kt +2 -7
- package/app.plugin.js +1 -1
- package/build/app-remote/index.d.ts +2 -2
- package/build/app-remote/index.d.ts.map +1 -1
- package/build/app-remote/index.js +11 -24
- package/build/app-remote/index.js.map +1 -1
- package/build/auth/index.d.ts +2 -2
- package/build/auth/index.d.ts.map +1 -1
- package/build/auth/index.js +17 -34
- package/build/auth/index.js.map +1 -1
- package/build/content/index.d.ts.map +1 -1
- package/build/content/index.js +12 -25
- package/build/content/index.js.map +1 -1
- package/build/hooks/index.d.ts +4 -4
- package/build/hooks/index.d.ts.map +1 -1
- package/build/hooks/index.js +38 -115
- package/build/hooks/index.js.map +1 -1
- package/build/images/index.d.ts +2 -2
- package/build/images/index.d.ts.map +1 -1
- package/build/images/index.js +12 -25
- package/build/images/index.js.map +1 -1
- package/build/index.d.ts +0 -18
- package/build/index.d.ts.map +1 -1
- package/build/index.js +0 -27
- package/build/index.js.map +1 -1
- package/build/internal/native-errors.d.ts +14 -0
- package/build/internal/native-errors.d.ts.map +1 -0
- package/build/internal/native-errors.js +29 -0
- package/build/internal/native-errors.js.map +1 -0
- package/build/internal/sync-external-store.d.ts +14 -0
- package/build/internal/sync-external-store.d.ts.map +1 -0
- package/build/internal/sync-external-store.js +36 -0
- package/build/internal/sync-external-store.js.map +1 -0
- package/build/player/index.d.ts +1 -1
- package/build/player/index.d.ts.map +1 -1
- package/build/player/index.js +15 -27
- package/build/player/index.js.map +1 -1
- package/build/uri/index.js.map +1 -1
- package/build/user/index.d.ts +2 -2
- package/build/user/index.d.ts.map +1 -1
- package/build/user/index.js +16 -26
- package/build/user/index.js.map +1 -1
- package/ios/ExpoSpotifySDK.podspec +1 -1
- package/ios/ExpoSpotifySDKModule.swift +1 -1
- package/ios/SpotifyAppRemoteCoordinator.swift +29 -404
- package/ios/SpotifyAppRemoteErrorMapping.swift +110 -0
- package/ios/SpotifyAppRemoteErrors.swift +221 -0
- package/ios/SpotifyAppRemoteMappers.swift +88 -0
- package/package.json +28 -14
- package/plugin/build/index.d.ts +20 -3
- package/plugin/build/index.js +22 -25
- package/plugin/build/types.d.ts +17 -1
- package/plugin/build/withSpotifySdkConfig.d.ts +4 -0
- package/plugin/build/withSpotifySdkConfig.js +27 -0
- package/plugin/index.d.ts +2 -0
- package/plugin/index.js +1 -0
package/build/hooks/index.js
CHANGED
|
@@ -1,80 +1,36 @@
|
|
|
1
1
|
import { useSyncExternalStore } from "react";
|
|
2
2
|
import { AppRemote } from "../app-remote";
|
|
3
3
|
import { Auth } from "../auth";
|
|
4
|
+
import { createSyncExternalStore } from "../internal/sync-external-store";
|
|
4
5
|
import { Player } from "../player";
|
|
5
6
|
import { User } from "../user";
|
|
6
7
|
// ---------------------------------------------------------------------------
|
|
7
8
|
// Connection-state store
|
|
8
|
-
//
|
|
9
|
-
// A module-level singleton that caches the latest ConnectionState, exposes a
|
|
10
|
-
// subscribe function for useSyncExternalStore, and stays in sync via the
|
|
11
|
-
// native onConnectionStateChange event. Initialised lazily on first use.
|
|
12
9
|
// ---------------------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
const _connectionListeners = new Set();
|
|
15
|
-
let _connectionStoreInitialised = false;
|
|
16
|
-
function initConnectionStore() {
|
|
17
|
-
if (_connectionStoreInitialised)
|
|
18
|
-
return;
|
|
19
|
-
_connectionStoreInitialised = true;
|
|
20
|
-
// Seed with the current native state so the first snapshot is accurate.
|
|
10
|
+
const connectionStore = createSyncExternalStore("disconnected", (store) => {
|
|
21
11
|
AppRemote.getConnectionState().then((state) => {
|
|
22
|
-
|
|
23
|
-
_connectionState = state;
|
|
24
|
-
_connectionListeners.forEach((l) => l());
|
|
25
|
-
}
|
|
12
|
+
store.update(state);
|
|
26
13
|
});
|
|
27
14
|
AppRemote.addListener("connectionStateChange", ({ state }) => {
|
|
28
|
-
|
|
29
|
-
_connectionListeners.forEach((l) => l());
|
|
15
|
+
store.update(state);
|
|
30
16
|
});
|
|
31
|
-
}
|
|
32
|
-
function subscribeConnectionState(listener) {
|
|
33
|
-
initConnectionStore();
|
|
34
|
-
_connectionListeners.add(listener);
|
|
35
|
-
return () => _connectionListeners.delete(listener);
|
|
36
|
-
}
|
|
37
|
-
function getConnectionSnapshot() {
|
|
38
|
-
return _connectionState;
|
|
39
|
-
}
|
|
17
|
+
});
|
|
40
18
|
// ---------------------------------------------------------------------------
|
|
41
19
|
// Session store
|
|
42
20
|
// ---------------------------------------------------------------------------
|
|
43
|
-
|
|
44
|
-
const _sessionListeners = new Set();
|
|
45
|
-
let _sessionStoreInitialised = false;
|
|
46
|
-
function initSessionStore() {
|
|
47
|
-
if (_sessionStoreInitialised)
|
|
48
|
-
return;
|
|
49
|
-
_sessionStoreInitialised = true;
|
|
21
|
+
const sessionStore = createSyncExternalStore(null, (store) => {
|
|
50
22
|
Auth.addListener("sessionChange", (event) => {
|
|
51
23
|
if (event.type === "didInitiate" || event.type === "didRenew") {
|
|
52
|
-
|
|
24
|
+
store.update(event.session);
|
|
53
25
|
}
|
|
54
26
|
else {
|
|
55
|
-
|
|
27
|
+
store.update(null);
|
|
56
28
|
}
|
|
57
|
-
_sessionListeners.forEach((l) => l());
|
|
58
29
|
});
|
|
59
|
-
}
|
|
60
|
-
function subscribeSession(listener) {
|
|
61
|
-
initSessionStore();
|
|
62
|
-
_sessionListeners.add(listener);
|
|
63
|
-
return () => _sessionListeners.delete(listener);
|
|
64
|
-
}
|
|
65
|
-
function getSessionSnapshot() {
|
|
66
|
-
return _session;
|
|
67
|
-
}
|
|
30
|
+
});
|
|
68
31
|
// ---------------------------------------------------------------------------
|
|
69
32
|
// Player-state store
|
|
70
|
-
//
|
|
71
|
-
// Seeded from the first playerStateChange event after subscription. The
|
|
72
|
-
// native side automatically starts streaming player state updates once the
|
|
73
|
-
// App Remote connection is established.
|
|
74
33
|
// ---------------------------------------------------------------------------
|
|
75
|
-
let _playerState = null;
|
|
76
|
-
const _playerListeners = new Set();
|
|
77
|
-
let _playerStoreInitialised = false;
|
|
78
34
|
function normalizePlayerState(nextState, previousState) {
|
|
79
35
|
const nextName = nextState.track.name?.trim() ?? "";
|
|
80
36
|
const previousName = previousState?.track.name?.trim() ?? "";
|
|
@@ -93,95 +49,62 @@ function normalizePlayerState(nextState, previousState) {
|
|
|
93
49
|
}
|
|
94
50
|
return nextState;
|
|
95
51
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
async function hydratePlayerState() {
|
|
52
|
+
let playerHydrationVersion = 0;
|
|
53
|
+
async function hydratePlayerState(store, version) {
|
|
100
54
|
try {
|
|
101
55
|
const state = await Player.getPlayerState();
|
|
102
|
-
|
|
103
|
-
|
|
56
|
+
if (version !== playerHydrationVersion)
|
|
57
|
+
return;
|
|
58
|
+
store.update((previous) => normalizePlayerState(state, previous));
|
|
104
59
|
}
|
|
105
60
|
catch {
|
|
106
61
|
// Ignore one-shot hydration failures (e.g., connection races). Event stream
|
|
107
62
|
// updates still populate this store once available.
|
|
108
63
|
}
|
|
109
64
|
}
|
|
110
|
-
|
|
111
|
-
if (_playerStoreInitialised)
|
|
112
|
-
return;
|
|
113
|
-
_playerStoreInitialised = true;
|
|
114
|
-
// Hydrate immediately if the module is already connected before any consumer
|
|
115
|
-
// subscribes to player events.
|
|
65
|
+
const playerStore = createSyncExternalStore(null, (store) => {
|
|
116
66
|
AppRemote.getConnectionState().then((state) => {
|
|
117
67
|
if (state === "connected") {
|
|
118
|
-
|
|
68
|
+
const version = ++playerHydrationVersion;
|
|
69
|
+
hydratePlayerState(store, version).catch(() => { });
|
|
119
70
|
}
|
|
120
71
|
});
|
|
121
|
-
// Refresh the one-shot snapshot whenever App Remote reconnects, and clear on
|
|
122
|
-
// disconnect so stale "now playing" data is not retained.
|
|
123
72
|
AppRemote.addListener("connectionStateChange", ({ state }) => {
|
|
124
73
|
if (state === "connected") {
|
|
125
|
-
|
|
74
|
+
const version = ++playerHydrationVersion;
|
|
75
|
+
hydratePlayerState(store, version).catch(() => { });
|
|
126
76
|
return;
|
|
127
77
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
notifyPlayerListeners();
|
|
131
|
-
}
|
|
78
|
+
++playerHydrationVersion;
|
|
79
|
+
store.update((current) => (current === null ? current : null));
|
|
132
80
|
});
|
|
133
81
|
Player.addListener("playerStateChange", (state) => {
|
|
134
|
-
|
|
135
|
-
notifyPlayerListeners();
|
|
82
|
+
store.update((previous) => normalizePlayerState(state, previous));
|
|
136
83
|
});
|
|
137
|
-
}
|
|
138
|
-
function subscribePlayerState(listener) {
|
|
139
|
-
initPlayerStore();
|
|
140
|
-
_playerListeners.add(listener);
|
|
141
|
-
return () => _playerListeners.delete(listener);
|
|
142
|
-
}
|
|
143
|
-
function getPlayerSnapshot() {
|
|
144
|
-
return _playerState;
|
|
145
|
-
}
|
|
84
|
+
});
|
|
146
85
|
// ---------------------------------------------------------------------------
|
|
147
86
|
// Capabilities store
|
|
148
87
|
// ---------------------------------------------------------------------------
|
|
149
|
-
|
|
150
|
-
const _capabilitiesListeners = new Set();
|
|
151
|
-
let _capabilitiesStoreInitialised = false;
|
|
152
|
-
function initCapabilitiesStore() {
|
|
153
|
-
if (_capabilitiesStoreInitialised)
|
|
154
|
-
return;
|
|
155
|
-
_capabilitiesStoreInitialised = true;
|
|
88
|
+
const capabilitiesStore = createSyncExternalStore(null, (store) => {
|
|
156
89
|
User.getCapabilities()
|
|
157
90
|
.then((capabilities) => {
|
|
158
|
-
|
|
159
|
-
_capabilitiesListeners.forEach((l) => l());
|
|
91
|
+
store.update(capabilities);
|
|
160
92
|
})
|
|
161
93
|
.catch(() => {
|
|
162
94
|
// Swallow initial read failures (e.g., not connected yet). The event
|
|
163
95
|
// stream will hydrate this later.
|
|
164
96
|
});
|
|
165
97
|
User.addListener("capabilitiesChange", (capabilities) => {
|
|
166
|
-
|
|
167
|
-
_capabilitiesListeners.forEach((l) => l());
|
|
98
|
+
store.update(capabilities);
|
|
168
99
|
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
initCapabilitiesStore();
|
|
172
|
-
_capabilitiesListeners.add(listener);
|
|
173
|
-
return () => _capabilitiesListeners.delete(listener);
|
|
174
|
-
}
|
|
175
|
-
function getCapabilitiesSnapshot() {
|
|
176
|
-
return _capabilities;
|
|
177
|
-
}
|
|
178
|
-
const _libraryStores = new Map();
|
|
100
|
+
});
|
|
101
|
+
const libraryStores = new Map();
|
|
179
102
|
function getOrCreateLibraryStore(uri) {
|
|
180
103
|
const key = String(uri);
|
|
181
|
-
let store =
|
|
104
|
+
let store = libraryStores.get(key);
|
|
182
105
|
if (!store) {
|
|
183
106
|
store = { state: null, listeners: new Set(), initialised: false };
|
|
184
|
-
|
|
107
|
+
libraryStores.set(key, store);
|
|
185
108
|
}
|
|
186
109
|
return store;
|
|
187
110
|
}
|
|
@@ -193,7 +116,7 @@ function initLibraryStore(uri) {
|
|
|
193
116
|
User.getLibraryState(uri)
|
|
194
117
|
.then((state) => {
|
|
195
118
|
store.state = state;
|
|
196
|
-
store.listeners.forEach((
|
|
119
|
+
store.listeners.forEach((listener) => listener());
|
|
197
120
|
})
|
|
198
121
|
.catch(() => {
|
|
199
122
|
// Not connected / unavailable yet; listener updates can still arrive later.
|
|
@@ -201,7 +124,7 @@ function initLibraryStore(uri) {
|
|
|
201
124
|
User.addLibraryStateListener(uri, (state) => {
|
|
202
125
|
const next = getOrCreateLibraryStore(uri);
|
|
203
126
|
next.state = state;
|
|
204
|
-
next.listeners.forEach((
|
|
127
|
+
next.listeners.forEach((listener) => listener());
|
|
205
128
|
});
|
|
206
129
|
}
|
|
207
130
|
function subscribeLibraryState(uri, listener) {
|
|
@@ -210,14 +133,14 @@ function subscribeLibraryState(uri, listener) {
|
|
|
210
133
|
const store = getOrCreateLibraryStore(uri);
|
|
211
134
|
store.listeners.add(listener);
|
|
212
135
|
return () => {
|
|
213
|
-
const current =
|
|
136
|
+
const current = libraryStores.get(key);
|
|
214
137
|
if (!current)
|
|
215
138
|
return;
|
|
216
139
|
current.listeners.delete(listener);
|
|
217
140
|
};
|
|
218
141
|
}
|
|
219
142
|
function getLibrarySnapshot(uri) {
|
|
220
|
-
return
|
|
143
|
+
return libraryStores.get(String(uri))?.state ?? null;
|
|
221
144
|
}
|
|
222
145
|
// ---------------------------------------------------------------------------
|
|
223
146
|
// Public hooks
|
|
@@ -230,7 +153,7 @@ function getLibrarySnapshot(uri) {
|
|
|
230
153
|
* Built on `useSyncExternalStore` for tearing-free React rendering.
|
|
231
154
|
*/
|
|
232
155
|
export function useSession() {
|
|
233
|
-
return useSyncExternalStore(
|
|
156
|
+
return useSyncExternalStore(sessionStore.subscribe, sessionStore.getSnapshot, sessionStore.getSnapshot);
|
|
234
157
|
}
|
|
235
158
|
/**
|
|
236
159
|
* Returns the current App Remote {@link ConnectionState}
|
|
@@ -248,7 +171,7 @@ export function useSession() {
|
|
|
248
171
|
* ```
|
|
249
172
|
*/
|
|
250
173
|
export function useConnectionState() {
|
|
251
|
-
return useSyncExternalStore(
|
|
174
|
+
return useSyncExternalStore(connectionStore.subscribe, connectionStore.getSnapshot, connectionStore.getSnapshot);
|
|
252
175
|
}
|
|
253
176
|
/**
|
|
254
177
|
* Returns the latest {@link PlayerState} from the Spotify app, or `null`
|
|
@@ -270,7 +193,7 @@ export function useConnectionState() {
|
|
|
270
193
|
* ```
|
|
271
194
|
*/
|
|
272
195
|
export function usePlayerState() {
|
|
273
|
-
return useSyncExternalStore(
|
|
196
|
+
return useSyncExternalStore(playerStore.subscribe, playerStore.getSnapshot, playerStore.getSnapshot);
|
|
274
197
|
}
|
|
275
198
|
/**
|
|
276
199
|
* Returns the currently playing {@link Track}, or `null` when nothing is
|
|
@@ -312,7 +235,7 @@ export function usePlaybackPosition() {
|
|
|
312
235
|
* Derived from `User.getCapabilities()` + `User.addListener("capabilitiesChange")`.
|
|
313
236
|
*/
|
|
314
237
|
export function useCapabilities() {
|
|
315
|
-
return useSyncExternalStore(
|
|
238
|
+
return useSyncExternalStore(capabilitiesStore.subscribe, capabilitiesStore.getSnapshot, capabilitiesStore.getSnapshot);
|
|
316
239
|
}
|
|
317
240
|
/**
|
|
318
241
|
* Returns the library state for a specific URI, or `null` before the first
|
package/build/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { useSyncExternalStore } from \"react\";\n\nimport { AppRemote, ConnectionState } from \"../app-remote\";\nimport { Auth, SpotifySession } from \"../auth\";\nimport { Player, PlayerState, Track } from \"../player\";\nimport { Capabilities, LibraryState, User } from \"../user\";\nimport type { SpotifyURI as SpotifyURIType } from \"../uri\";\n\n// ---------------------------------------------------------------------------\n// Shared utilities\n// ---------------------------------------------------------------------------\n\ntype Listener = () => void;\n\n// ---------------------------------------------------------------------------\n// Connection-state store\n//\n// A module-level singleton that caches the latest ConnectionState, exposes a\n// subscribe function for useSyncExternalStore, and stays in sync via the\n// native onConnectionStateChange event. Initialised lazily on first use.\n// ---------------------------------------------------------------------------\n\nlet _connectionState: ConnectionState = \"disconnected\";\nconst _connectionListeners = new Set<Listener>();\nlet _connectionStoreInitialised = false;\n\nfunction initConnectionStore() {\n if (_connectionStoreInitialised) return;\n _connectionStoreInitialised = true;\n\n // Seed with the current native state so the first snapshot is accurate.\n AppRemote.getConnectionState().then((state) => {\n if (state !== _connectionState) {\n _connectionState = state;\n _connectionListeners.forEach((l) => l());\n }\n });\n\n AppRemote.addListener(\"connectionStateChange\", ({ state }) => {\n _connectionState = state;\n _connectionListeners.forEach((l) => l());\n });\n}\n\nfunction subscribeConnectionState(listener: Listener): () => void {\n initConnectionStore();\n _connectionListeners.add(listener);\n return () => _connectionListeners.delete(listener);\n}\n\nfunction getConnectionSnapshot(): ConnectionState {\n return _connectionState;\n}\n\n// ---------------------------------------------------------------------------\n// Session store\n// ---------------------------------------------------------------------------\n\nlet _session: SpotifySession | null = null;\nconst _sessionListeners = new Set<Listener>();\nlet _sessionStoreInitialised = false;\n\nfunction initSessionStore() {\n if (_sessionStoreInitialised) return;\n _sessionStoreInitialised = true;\n\n Auth.addListener(\"sessionChange\", (event) => {\n if (event.type === \"didInitiate\" || event.type === \"didRenew\") {\n _session = event.session;\n } else {\n _session = null;\n }\n _sessionListeners.forEach((l) => l());\n });\n}\n\nfunction subscribeSession(listener: Listener): () => void {\n initSessionStore();\n _sessionListeners.add(listener);\n return () => _sessionListeners.delete(listener);\n}\n\nfunction getSessionSnapshot(): SpotifySession | null {\n return _session;\n}\n\n// ---------------------------------------------------------------------------\n// Player-state store\n//\n// Seeded from the first playerStateChange event after subscription. The\n// native side automatically starts streaming player state updates once the\n// App Remote connection is established.\n// ---------------------------------------------------------------------------\n\nlet _playerState: PlayerState | null = null;\nconst _playerListeners = new Set<Listener>();\nlet _playerStoreInitialised = false;\n\nfunction normalizePlayerState(\n nextState: PlayerState,\n previousState: PlayerState | null,\n): PlayerState {\n const nextName = nextState.track.name?.trim() ?? \"\";\n const previousName = previousState?.track.name?.trim() ?? \"\";\n const sameTrack =\n previousState != null && previousState.track.uri === nextState.track.uri;\n\n // App Remote can occasionally emit a transient blank title between valid\n // snapshots for the same URI; keep the last non-empty title to avoid UI\n // flicker/regression in hooks consumers.\n if (sameTrack && nextName.length === 0 && previousName.length > 0) {\n return {\n ...nextState,\n track: {\n ...nextState.track,\n name: previousState.track.name,\n },\n };\n }\n\n return nextState;\n}\n\nfunction notifyPlayerListeners() {\n _playerListeners.forEach((l) => l());\n}\n\nasync function hydratePlayerState() {\n try {\n const state = await Player.getPlayerState();\n _playerState = normalizePlayerState(state, _playerState);\n notifyPlayerListeners();\n } catch {\n // Ignore one-shot hydration failures (e.g., connection races). Event stream\n // updates still populate this store once available.\n }\n}\n\nfunction initPlayerStore() {\n if (_playerStoreInitialised) return;\n _playerStoreInitialised = true;\n\n // Hydrate immediately if the module is already connected before any consumer\n // subscribes to player events.\n AppRemote.getConnectionState().then((state) => {\n if (state === \"connected\") {\n void hydratePlayerState();\n }\n });\n\n // Refresh the one-shot snapshot whenever App Remote reconnects, and clear on\n // disconnect so stale \"now playing\" data is not retained.\n AppRemote.addListener(\"connectionStateChange\", ({ state }) => {\n if (state === \"connected\") {\n void hydratePlayerState();\n return;\n }\n\n if (_playerState !== null) {\n _playerState = null;\n notifyPlayerListeners();\n }\n });\n\n Player.addListener(\"playerStateChange\", (state) => {\n _playerState = normalizePlayerState(state, _playerState);\n notifyPlayerListeners();\n });\n}\n\nfunction subscribePlayerState(listener: Listener): () => void {\n initPlayerStore();\n _playerListeners.add(listener);\n return () => _playerListeners.delete(listener);\n}\n\nfunction getPlayerSnapshot(): PlayerState | null {\n return _playerState;\n}\n\n// ---------------------------------------------------------------------------\n// Capabilities store\n// ---------------------------------------------------------------------------\n\nlet _capabilities: Capabilities | null = null;\nconst _capabilitiesListeners = new Set<Listener>();\nlet _capabilitiesStoreInitialised = false;\n\nfunction initCapabilitiesStore() {\n if (_capabilitiesStoreInitialised) return;\n _capabilitiesStoreInitialised = true;\n\n User.getCapabilities()\n .then((capabilities) => {\n _capabilities = capabilities;\n _capabilitiesListeners.forEach((l) => l());\n })\n .catch(() => {\n // Swallow initial read failures (e.g., not connected yet). The event\n // stream will hydrate this later.\n });\n\n User.addListener(\"capabilitiesChange\", (capabilities) => {\n _capabilities = capabilities;\n _capabilitiesListeners.forEach((l) => l());\n });\n}\n\nfunction subscribeCapabilities(listener: Listener): () => void {\n initCapabilitiesStore();\n _capabilitiesListeners.add(listener);\n return () => _capabilitiesListeners.delete(listener);\n}\n\nfunction getCapabilitiesSnapshot(): Capabilities | null {\n return _capabilities;\n}\n\n// ---------------------------------------------------------------------------\n// Per-URI library-state store\n// ---------------------------------------------------------------------------\n\ninterface LibraryStore {\n state: LibraryState | null;\n listeners: Set<Listener>;\n initialised: boolean;\n}\n\nconst _libraryStores = new Map<string, LibraryStore>();\n\nfunction getOrCreateLibraryStore(uri: SpotifyURIType): LibraryStore {\n const key = String(uri);\n let store = _libraryStores.get(key);\n if (!store) {\n store = { state: null, listeners: new Set(), initialised: false };\n _libraryStores.set(key, store);\n }\n return store;\n}\n\nfunction initLibraryStore(uri: SpotifyURIType) {\n const store = getOrCreateLibraryStore(uri);\n if (store.initialised) return;\n store.initialised = true;\n\n User.getLibraryState(uri)\n .then((state) => {\n store.state = state;\n store.listeners.forEach((l) => l());\n })\n .catch(() => {\n // Not connected / unavailable yet; listener updates can still arrive later.\n });\n\n User.addLibraryStateListener(uri, (state) => {\n const next = getOrCreateLibraryStore(uri);\n next.state = state;\n next.listeners.forEach((l) => l());\n });\n}\n\nfunction subscribeLibraryState(uri: SpotifyURIType, listener: Listener): () => void {\n const key = String(uri);\n initLibraryStore(uri);\n const store = getOrCreateLibraryStore(uri);\n store.listeners.add(listener);\n return () => {\n const current = _libraryStores.get(key);\n if (!current) return;\n current.listeners.delete(listener);\n };\n}\n\nfunction getLibrarySnapshot(uri: SpotifyURIType): LibraryState | null {\n return _libraryStores.get(String(uri))?.state ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Public hooks\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the current Spotify OAuth session, or `null` when not authenticated.\n * Updates automatically whenever `Auth.authenticate()` or `Auth.refresh()`\n * resolves, and on session failure.\n *\n * Built on `useSyncExternalStore` for tearing-free React rendering.\n */\nexport function useSession(): SpotifySession | null {\n return useSyncExternalStore(subscribeSession, getSessionSnapshot, getSessionSnapshot);\n}\n\n/**\n * Returns the current App Remote {@link ConnectionState}\n * (`\"disconnected\"` | `\"connecting\"` | `\"connected\"`). Updates automatically\n * on every state transition driven by `AppRemote.connect()` and `disconnect()`.\n *\n * Built on `useSyncExternalStore` for tearing-free React rendering.\n *\n * @example\n * ```tsx\n * function ConnectionBanner() {\n * const state = useConnectionState();\n * return <Text>{state === \"connected\" ? \"Connected\" : \"Disconnected\"}</Text>;\n * }\n * ```\n */\nexport function useConnectionState(): ConnectionState {\n return useSyncExternalStore(\n subscribeConnectionState,\n getConnectionSnapshot,\n getConnectionSnapshot,\n );\n}\n\n/**\n * Returns the latest {@link PlayerState} from the Spotify app, or `null`\n * before the first update arrives (i.e., before `AppRemote.connect()` resolves\n * and the native subscription emits its first event).\n *\n * Updates on every state change reported by the Spotify app (track change,\n * pause/resume, seek, shuffle/repeat toggle, etc.).\n *\n * Built on `useSyncExternalStore` for tearing-free React rendering.\n *\n * @example\n * ```tsx\n * function NowPlaying() {\n * const state = usePlayerState();\n * if (!state) return <Text>Not playing</Text>;\n * return <Text>{state.track.name} — {state.isPaused ? \"Paused\" : \"Playing\"}</Text>;\n * }\n * ```\n */\nexport function usePlayerState(): PlayerState | null {\n return useSyncExternalStore(subscribePlayerState, getPlayerSnapshot, getPlayerSnapshot);\n}\n\n/**\n * Returns the currently playing {@link Track}, or `null` when nothing is\n * playing or before the first state update arrives.\n *\n * Derived from `usePlayerState`.\n */\nexport function useCurrentTrack(): Track | null {\n return usePlayerState()?.track ?? null;\n}\n\n/**\n * Returns `true` when the Spotify player is actively playing (not paused),\n * and `false` otherwise (including before the first state update arrives).\n *\n * Derived from `usePlayerState`.\n */\nexport function useIsPlaying(): boolean {\n const state = usePlayerState();\n return state !== null && !state.isPaused;\n}\n\n/**\n * Returns the current playback position in milliseconds. Returns `0` before\n * the first state update arrives.\n *\n * **Note:** This value updates whenever the native side emits a player state\n * change (track transitions, pause/resume, seek, etc.) — not on a fixed timer.\n * For a progress bar that ticks smoothly, combine this with a local `Date.now`\n * offset and `requestAnimationFrame`.\n *\n * Derived from `usePlayerState`.\n */\nexport function usePlaybackPosition(): number {\n return usePlayerState()?.playbackPosition ?? 0;\n}\n\n/**\n * Returns the latest Spotify user capabilities, or `null` before the first\n * snapshot arrives.\n *\n * Derived from `User.getCapabilities()` + `User.addListener(\"capabilitiesChange\")`.\n */\nexport function useCapabilities(): Capabilities | null {\n return useSyncExternalStore(\n subscribeCapabilities,\n getCapabilitiesSnapshot,\n getCapabilitiesSnapshot,\n );\n}\n\n/**\n * Returns the library state for a specific URI, or `null` before the first\n * snapshot arrives.\n *\n * Derived from `User.getLibraryState(uri)` + `User.addLibraryStateListener(uri, ...)`.\n */\nexport function useLibraryState(uri: SpotifyURIType): LibraryState | null {\n return useSyncExternalStore(\n (listener) => subscribeLibraryState(uri, listener),\n () => getLibrarySnapshot(uri),\n () => getLibrarySnapshot(uri),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { useSyncExternalStore } from \"react\";\n\nimport { AppRemote, type ConnectionState } from \"../app-remote\";\nimport { Auth, type SpotifySession } from \"../auth\";\nimport { createSyncExternalStore } from \"../internal/sync-external-store\";\nimport { Player, type PlayerState, type Track } from \"../player\";\nimport type { SpotifyURI as SpotifyURIType } from \"../uri\";\nimport { type Capabilities, type LibraryState, User } from \"../user\";\n\ntype Listener = () => void;\n\n// ---------------------------------------------------------------------------\n// Connection-state store\n// ---------------------------------------------------------------------------\n\nconst connectionStore = createSyncExternalStore<ConnectionState>(\n \"disconnected\",\n (store) => {\n AppRemote.getConnectionState().then((state) => {\n store.update(state);\n });\n\n AppRemote.addListener(\"connectionStateChange\", ({ state }) => {\n store.update(state);\n });\n },\n);\n\n// ---------------------------------------------------------------------------\n// Session store\n// ---------------------------------------------------------------------------\n\nconst sessionStore = createSyncExternalStore<SpotifySession | null>(\n null,\n (store) => {\n Auth.addListener(\"sessionChange\", (event) => {\n if (event.type === \"didInitiate\" || event.type === \"didRenew\") {\n store.update(event.session);\n } else {\n store.update(null);\n }\n });\n },\n);\n\n// ---------------------------------------------------------------------------\n// Player-state store\n// ---------------------------------------------------------------------------\n\nfunction normalizePlayerState(\n nextState: PlayerState,\n previousState: PlayerState | null,\n): PlayerState {\n const nextName = nextState.track.name?.trim() ?? \"\";\n const previousName = previousState?.track.name?.trim() ?? \"\";\n const sameTrack =\n previousState != null && previousState.track.uri === nextState.track.uri;\n\n // App Remote can occasionally emit a transient blank title between valid\n // snapshots for the same URI; keep the last non-empty title to avoid UI\n // flicker/regression in hooks consumers.\n if (sameTrack && nextName.length === 0 && previousName.length > 0) {\n return {\n ...nextState,\n track: {\n ...nextState.track,\n name: previousState.track.name,\n },\n };\n }\n\n return nextState;\n}\n\nlet playerHydrationVersion = 0;\n\nasync function hydratePlayerState(\n store: ReturnType<typeof createSyncExternalStore<PlayerState | null>>,\n version: number,\n) {\n try {\n const state = await Player.getPlayerState();\n if (version !== playerHydrationVersion) return;\n store.update((previous) => normalizePlayerState(state, previous));\n } catch {\n // Ignore one-shot hydration failures (e.g., connection races). Event stream\n // updates still populate this store once available.\n }\n}\n\nconst playerStore = createSyncExternalStore<PlayerState | null>(\n null,\n (store) => {\n AppRemote.getConnectionState().then((state) => {\n if (state === \"connected\") {\n const version = ++playerHydrationVersion;\n hydratePlayerState(store, version).catch(() => {});\n }\n });\n\n AppRemote.addListener(\"connectionStateChange\", ({ state }) => {\n if (state === \"connected\") {\n const version = ++playerHydrationVersion;\n hydratePlayerState(store, version).catch(() => {});\n return;\n }\n\n ++playerHydrationVersion;\n store.update((current) => (current === null ? current : null));\n });\n\n Player.addListener(\"playerStateChange\", (state) => {\n store.update((previous) => normalizePlayerState(state, previous));\n });\n },\n);\n\n// ---------------------------------------------------------------------------\n// Capabilities store\n// ---------------------------------------------------------------------------\n\nconst capabilitiesStore = createSyncExternalStore<Capabilities | null>(\n null,\n (store) => {\n User.getCapabilities()\n .then((capabilities) => {\n store.update(capabilities);\n })\n .catch(() => {\n // Swallow initial read failures (e.g., not connected yet). The event\n // stream will hydrate this later.\n });\n\n User.addListener(\"capabilitiesChange\", (capabilities) => {\n store.update(capabilities);\n });\n },\n);\n\n// ---------------------------------------------------------------------------\n// Per-URI library-state store\n// ---------------------------------------------------------------------------\n\ninterface LibraryStore {\n state: LibraryState | null;\n listeners: Set<Listener>;\n initialised: boolean;\n}\n\nconst libraryStores = new Map<string, LibraryStore>();\n\nfunction getOrCreateLibraryStore(uri: SpotifyURIType): LibraryStore {\n const key = String(uri);\n let store = libraryStores.get(key);\n if (!store) {\n store = { state: null, listeners: new Set(), initialised: false };\n libraryStores.set(key, store);\n }\n return store;\n}\n\nfunction initLibraryStore(uri: SpotifyURIType) {\n const store = getOrCreateLibraryStore(uri);\n if (store.initialised) return;\n store.initialised = true;\n\n User.getLibraryState(uri)\n .then((state) => {\n store.state = state;\n store.listeners.forEach((listener) => listener());\n })\n .catch(() => {\n // Not connected / unavailable yet; listener updates can still arrive later.\n });\n\n User.addLibraryStateListener(uri, (state) => {\n const next = getOrCreateLibraryStore(uri);\n next.state = state;\n next.listeners.forEach((listener) => listener());\n });\n}\n\nfunction subscribeLibraryState(\n uri: SpotifyURIType,\n listener: Listener,\n): () => void {\n const key = String(uri);\n initLibraryStore(uri);\n const store = getOrCreateLibraryStore(uri);\n store.listeners.add(listener);\n return () => {\n const current = libraryStores.get(key);\n if (!current) return;\n current.listeners.delete(listener);\n };\n}\n\nfunction getLibrarySnapshot(uri: SpotifyURIType): LibraryState | null {\n return libraryStores.get(String(uri))?.state ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Public hooks\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the current Spotify OAuth session, or `null` when not authenticated.\n * Updates automatically whenever `Auth.authenticate()` or `Auth.refresh()`\n * resolves, and on session failure.\n *\n * Built on `useSyncExternalStore` for tearing-free React rendering.\n */\nexport function useSession(): SpotifySession | null {\n return useSyncExternalStore(\n sessionStore.subscribe,\n sessionStore.getSnapshot,\n sessionStore.getSnapshot,\n );\n}\n\n/**\n * Returns the current App Remote {@link ConnectionState}\n * (`\"disconnected\"` | `\"connecting\"` | `\"connected\"`). Updates automatically\n * on every state transition driven by `AppRemote.connect()` and `disconnect()`.\n *\n * Built on `useSyncExternalStore` for tearing-free React rendering.\n *\n * @example\n * ```tsx\n * function ConnectionBanner() {\n * const state = useConnectionState();\n * return <Text>{state === \"connected\" ? \"Connected\" : \"Disconnected\"}</Text>;\n * }\n * ```\n */\nexport function useConnectionState(): ConnectionState {\n return useSyncExternalStore(\n connectionStore.subscribe,\n connectionStore.getSnapshot,\n connectionStore.getSnapshot,\n );\n}\n\n/**\n * Returns the latest {@link PlayerState} from the Spotify app, or `null`\n * before the first update arrives (i.e., before `AppRemote.connect()` resolves\n * and the native subscription emits its first event).\n *\n * Updates on every state change reported by the Spotify app (track change,\n * pause/resume, seek, shuffle/repeat toggle, etc.).\n *\n * Built on `useSyncExternalStore` for tearing-free React rendering.\n *\n * @example\n * ```tsx\n * function NowPlaying() {\n * const state = usePlayerState();\n * if (!state) return <Text>Not playing</Text>;\n * return <Text>{state.track.name} — {state.isPaused ? \"Paused\" : \"Playing\"}</Text>;\n * }\n * ```\n */\nexport function usePlayerState(): PlayerState | null {\n return useSyncExternalStore(\n playerStore.subscribe,\n playerStore.getSnapshot,\n playerStore.getSnapshot,\n );\n}\n\n/**\n * Returns the currently playing {@link Track}, or `null` when nothing is\n * playing or before the first state update arrives.\n *\n * Derived from `usePlayerState`.\n */\nexport function useCurrentTrack(): Track | null {\n return usePlayerState()?.track ?? null;\n}\n\n/**\n * Returns `true` when the Spotify player is actively playing (not paused),\n * and `false` otherwise (including before the first state update arrives).\n *\n * Derived from `usePlayerState`.\n */\nexport function useIsPlaying(): boolean {\n const state = usePlayerState();\n return state !== null && !state.isPaused;\n}\n\n/**\n * Returns the current playback position in milliseconds. Returns `0` before\n * the first state update arrives.\n *\n * **Note:** This value updates whenever the native side emits a player state\n * change (track transitions, pause/resume, seek, etc.) — not on a fixed timer.\n * For a progress bar that ticks smoothly, combine this with a local `Date.now`\n * offset and `requestAnimationFrame`.\n *\n * Derived from `usePlayerState`.\n */\nexport function usePlaybackPosition(): number {\n return usePlayerState()?.playbackPosition ?? 0;\n}\n\n/**\n * Returns the latest Spotify user capabilities, or `null` before the first\n * snapshot arrives.\n *\n * Derived from `User.getCapabilities()` + `User.addListener(\"capabilitiesChange\")`.\n */\nexport function useCapabilities(): Capabilities | null {\n return useSyncExternalStore(\n capabilitiesStore.subscribe,\n capabilitiesStore.getSnapshot,\n capabilitiesStore.getSnapshot,\n );\n}\n\n/**\n * Returns the library state for a specific URI, or `null` before the first\n * snapshot arrives.\n *\n * Derived from `User.getLibraryState(uri)` + `User.addLibraryStateListener(uri, ...)`.\n */\nexport function useLibraryState(uri: SpotifyURIType): LibraryState | null {\n return useSyncExternalStore(\n (listener) => subscribeLibraryState(uri, listener),\n () => getLibrarySnapshot(uri),\n () => getLibrarySnapshot(uri),\n );\n}\n"]}
|
package/build/images/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export type { ImagesErrorCode } from "./error";
|
|
2
|
-
export { ImagesError } from "./error";
|
|
3
1
|
import type { ContentItem } from "../content";
|
|
4
2
|
import type { Track } from "../player";
|
|
3
|
+
export type { ImagesErrorCode } from "./error";
|
|
4
|
+
export { ImagesError } from "./error";
|
|
5
5
|
export type ImageSize = "small" | "medium" | "large";
|
|
6
6
|
export interface ImageResult {
|
|
7
7
|
uri: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/images/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/images/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAGvC,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,8DAA8D;AAC9D,UAAU,kBAAkB;IAC1B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,6DAA6D;AAC7D,UAAU,gBAAgB;IACxB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,MAAM,kBAAkB,GAC1B,KAAK,GACL,WAAW,GACX,gBAAgB,GAChB,kBAAkB,CAAC;AAwBvB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,MAAM;IACjB;;OAEG;0BACQ,kBAAkB,QAAQ,SAAS,KAAG,OAAO,CAAC,WAAW,CAAC;CAM7D,CAAC"}
|
package/build/images/index.js
CHANGED
|
@@ -1,33 +1,20 @@
|
|
|
1
|
-
export { ImagesError } from "./error";
|
|
2
1
|
// ---------------------------------------------------------------------------
|
|
3
2
|
// Types
|
|
4
3
|
// ---------------------------------------------------------------------------
|
|
5
4
|
import ExpoSpotifySDKModule from "../ExpoSpotifySDKModule";
|
|
5
|
+
import { createNativeErrorRethrow } from "../internal/native-errors";
|
|
6
6
|
import { ImagesError } from "./error";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
function rethrowAsImagesError(err) {
|
|
19
|
-
if (err instanceof ImagesError)
|
|
20
|
-
throw err;
|
|
21
|
-
if (err instanceof Error) {
|
|
22
|
-
const reason = unwrapReason(err.message);
|
|
23
|
-
const maybeCode = err.code;
|
|
24
|
-
if (maybeCode && VALID_IMAGE_CODES.has(maybeCode)) {
|
|
25
|
-
throw new ImagesError(maybeCode, reason);
|
|
26
|
-
}
|
|
27
|
-
throw new ImagesError("UNKNOWN", reason);
|
|
28
|
-
}
|
|
29
|
-
throw new ImagesError("UNKNOWN", String(err));
|
|
30
|
-
}
|
|
7
|
+
export { ImagesError } from "./error";
|
|
8
|
+
const rethrowAsImagesError = createNativeErrorRethrow({
|
|
9
|
+
ErrorClass: ImagesError,
|
|
10
|
+
unknownCode: "UNKNOWN",
|
|
11
|
+
validCodes: new Set([
|
|
12
|
+
"NOT_CONNECTED",
|
|
13
|
+
"INVALID_URI",
|
|
14
|
+
"IMAGE_LOAD_FAILED",
|
|
15
|
+
"UNKNOWN",
|
|
16
|
+
]),
|
|
17
|
+
});
|
|
31
18
|
function getImageIdentifier(item) {
|
|
32
19
|
const value = item?.imageIdentifier;
|
|
33
20
|
if (!value || !value.trim()) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/images/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/images/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,OAAO,oBAAoB,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,WAAW,EAAwB,MAAM,SAAS,CAAC;AAG5D,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAwBtC,MAAM,oBAAoB,GAAG,wBAAwB,CAAC;IACpD,UAAU,EAAE,WAAW;IACvB,WAAW,EAAE,SAAS;IACtB,UAAU,EAAE,IAAI,GAAG,CAAkB;QACnC,eAAe;QACf,aAAa;QACb,mBAAmB;QACnB,SAAS;KACV,CAAC;CACH,CAAC,CAAC;AAEH,SAAS,kBAAkB,CAAC,IAAwB;IAClD,MAAM,KAAK,GAAG,IAAI,EAAE,eAAe,CAAC;IACpC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,WAAW,CACnB,aAAa,EACb,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB;;OAEG;IACH,IAAI,CAAC,IAAwB,EAAE,IAAe;QAC5C,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACjD,OAAO,oBAAoB,CAAC,UAAU,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,KAAK,CACjE,oBAAoB,CACrB,CAAC;IACJ,CAAC;CACO,CAAC","sourcesContent":["// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nimport ExpoSpotifySDKModule from \"../ExpoSpotifySDKModule\";\nimport type { ContentItem } from \"../content\";\nimport { createNativeErrorRethrow } from \"../internal/native-errors\";\nimport type { Track } from \"../player\";\nimport { ImagesError, type ImagesErrorCode } from \"./error\";\n\nexport type { ImagesErrorCode } from \"./error\";\nexport { ImagesError } from \"./error\";\n\nexport type ImageSize = \"small\" | \"medium\" | \"large\";\n\nexport interface ImageResult {\n uri: string;\n}\n\n/** Minimal shape required to fetch an image by identifier. */\ninterface HasImageIdentifier {\n imageIdentifier?: string | null;\n}\n\n/** Minimal album/artist representation for image loading. */\ninterface BasicImageEntity {\n imageIdentifier?: string | null;\n}\n\nexport type ImageRepresentable =\n | Track\n | ContentItem\n | BasicImageEntity\n | HasImageIdentifier;\n\nconst rethrowAsImagesError = createNativeErrorRethrow({\n ErrorClass: ImagesError,\n unknownCode: \"UNKNOWN\",\n validCodes: new Set<ImagesErrorCode>([\n \"NOT_CONNECTED\",\n \"INVALID_URI\",\n \"IMAGE_LOAD_FAILED\",\n \"UNKNOWN\",\n ]),\n});\n\nfunction getImageIdentifier(item: ImageRepresentable): string {\n const value = item?.imageIdentifier;\n if (!value || !value.trim()) {\n throw new ImagesError(\n \"INVALID_URI\",\n \"Images.load(): item does not contain a valid imageIdentifier\",\n );\n }\n return value;\n}\n\n/**\n * Spotify Images namespace. Fetches cover art for tracks, albums, artists,\n * and content items via the App Remote SDK, writing the bitmap to a temp file\n * and returning its local URI. Requires `AppRemote.connect()` to be resolved.\n *\n * @example\n * ```ts\n * import { Images } from \"@wwdrew/expo-spotify-sdk\";\n *\n * const { uri } = await Images.load(track, \"large\");\n * ```\n */\nexport const Images = {\n /**\n * Loads a Spotify image and returns a local file URI.\n */\n load(item: ImageRepresentable, size: ImageSize): Promise<ImageResult> {\n const imageIdentifier = getImageIdentifier(item);\n return ExpoSpotifySDKModule.imagesLoad(imageIdentifier, size).catch(\n rethrowAsImagesError,\n );\n },\n} as const;\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -26,22 +26,4 @@ export type { RepeatMode, PodcastPlaybackSpeed, Artist, Album, Track, PlaybackOp
|
|
|
26
26
|
export type { Capabilities, LibraryState } from "./user";
|
|
27
27
|
export type { ContentType, ContentItem } from "./content";
|
|
28
28
|
export type { ImageSize, ImageResult, ImageRepresentable } from "./images";
|
|
29
|
-
import { Auth } from "./auth";
|
|
30
|
-
import type { AuthenticateConfig as SpotifyConfig, RefreshConfig as SpotifyRefreshConfig } from "./auth";
|
|
31
|
-
/** @deprecated Use `Auth.isAvailable()` */
|
|
32
|
-
export declare function isAvailable(): boolean;
|
|
33
|
-
/** @deprecated Use `Auth.authenticate(config)` */
|
|
34
|
-
export declare function authenticateAsync(config: SpotifyConfig): Promise<import("./auth").SpotifySession>;
|
|
35
|
-
/** @deprecated Use `Auth.cancelPending()` */
|
|
36
|
-
export declare function cancelPendingAuthAsync(): Promise<void>;
|
|
37
|
-
/** @deprecated Use `Auth.refresh(config)` */
|
|
38
|
-
export declare function refreshSessionAsync(config: SpotifyRefreshConfig): Promise<import("./auth").SpotifySession>;
|
|
39
|
-
/** @deprecated Use `Auth.addListener("sessionChange", cb)` */
|
|
40
|
-
export declare function addSessionChangeListener(listener: Parameters<typeof Auth.addListener>[1]): import("expo-modules-core").EventSubscription;
|
|
41
|
-
export type { SpotifyConfig, SpotifyRefreshConfig };
|
|
42
|
-
/**
|
|
43
|
-
* @deprecated `SpotifyErrorCode` is now `AuthErrorCode`. Import via:
|
|
44
|
-
* `import type { AuthErrorCode } from "@wwdrew/expo-spotify-sdk"`
|
|
45
|
-
*/
|
|
46
|
-
export type { AuthErrorCode as SpotifyErrorCode } from "./auth";
|
|
47
29
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,SAAS,CAAC;AAMjB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAMlC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAMvC,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAMhD,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,YAAY,EAAE,mBAAmB,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,OAAO,CAAC;AAM/E,YAAY,EACV,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAMhB,YAAY,EACV,eAAe,EACf,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAMtB,YAAY,EACV,UAAU,EACV,oBAAoB,EACpB,MAAM,EACN,KAAK,EACL,KAAK,EACL,eAAe,EACf,oBAAoB,EACpB,WAAW,EACX,cAAc,GACf,MAAM,UAAU,CAAC;AAMlB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAMzD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAM1D,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,SAAS,CAAC;AAMjB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAMlC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAMvC,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAMhD,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,YAAY,EAAE,mBAAmB,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,OAAO,CAAC;AAM/E,YAAY,EACV,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAMhB,YAAY,EACV,eAAe,EACf,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAMtB,YAAY,EACV,UAAU,EACV,oBAAoB,EACpB,MAAM,EACN,KAAK,EACL,KAAK,EACL,eAAe,EACf,oBAAoB,EACpB,WAAW,EACX,cAAc,GACf,MAAM,UAAU,CAAC;AAMlB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAMzD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAM1D,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -25,31 +25,4 @@ export { ImagesError } from "./images";
|
|
|
25
25
|
// URI helpers
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
27
27
|
export { SpotifyURI } from "./uri";
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
// v0.x backward-compatible exports (deprecated — remove at v2.0.0)
|
|
30
|
-
//
|
|
31
|
-
// These shims let existing callers continue to compile after upgrading to v1.
|
|
32
|
-
// Migrate to the namespaced API: see docs/V1_PLAN.md §8 (Migration).
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
import { Auth } from "./auth";
|
|
35
|
-
/** @deprecated Use `Auth.isAvailable()` */
|
|
36
|
-
export function isAvailable() {
|
|
37
|
-
return Auth.isAvailable();
|
|
38
|
-
}
|
|
39
|
-
/** @deprecated Use `Auth.authenticate(config)` */
|
|
40
|
-
export function authenticateAsync(config) {
|
|
41
|
-
return Auth.authenticate(config);
|
|
42
|
-
}
|
|
43
|
-
/** @deprecated Use `Auth.cancelPending()` */
|
|
44
|
-
export function cancelPendingAuthAsync() {
|
|
45
|
-
return Auth.cancelPending();
|
|
46
|
-
}
|
|
47
|
-
/** @deprecated Use `Auth.refresh(config)` */
|
|
48
|
-
export function refreshSessionAsync(config) {
|
|
49
|
-
return Auth.refresh(config);
|
|
50
|
-
}
|
|
51
|
-
/** @deprecated Use `Auth.addListener("sessionChange", cb)` */
|
|
52
|
-
export function addSessionChangeListener(listener) {
|
|
53
|
-
return Auth.addListener("sessionChange", listener);
|
|
54
|
-
}
|
|
55
28
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAE9E,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAavC,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAE9E,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAavC,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC","sourcesContent":["// ---------------------------------------------------------------------------\n// Hooks (v1 public API)\n// ---------------------------------------------------------------------------\n\nexport {\n useSession,\n useConnectionState,\n usePlayerState,\n useCurrentTrack,\n useIsPlaying,\n usePlaybackPosition,\n useCapabilities,\n useLibraryState,\n} from \"./hooks\";\n\n// ---------------------------------------------------------------------------\n// Namespaces (v1 public API)\n// ---------------------------------------------------------------------------\n\nexport { Auth } from \"./auth\";\nexport { AppRemote } from \"./app-remote\";\nexport { Player } from \"./player\";\nexport { User } from \"./user\";\nexport { Content } from \"./content\";\nexport { Images } from \"./images\";\n\n// ---------------------------------------------------------------------------\n// Error hierarchy\n// ---------------------------------------------------------------------------\n\nexport { SpotifyError } from \"./error\";\nexport { AuthError } from \"./auth\";\nexport { AppRemoteError } from \"./app-remote\";\nexport { PlayerError } from \"./player\";\nexport { UserError } from \"./user\";\nexport { ContentError } from \"./content\";\nexport { ImagesError } from \"./images\";\n\n// ---------------------------------------------------------------------------\n// Error code types\n// ---------------------------------------------------------------------------\n\nexport type { AuthErrorCode } from \"./auth\";\nexport type { AppRemoteErrorCode } from \"./app-remote\";\nexport type { PlayerErrorCode } from \"./player\";\nexport type { UserErrorCode } from \"./user\";\nexport type { ContentErrorCode } from \"./content\";\nexport type { ImagesErrorCode } from \"./images\";\n\n// ---------------------------------------------------------------------------\n// URI helpers\n// ---------------------------------------------------------------------------\n\nexport { SpotifyURI } from \"./uri\";\nexport type { SpotifyResourceType, SpotifyURI as SpotifyURIType } from \"./uri\";\n\n// ---------------------------------------------------------------------------\n// Auth types\n// ---------------------------------------------------------------------------\n\nexport type {\n SpotifySession,\n SpotifyScope,\n AuthenticateConfig,\n RefreshConfig,\n SessionChangeEvent,\n} from \"./auth\";\n\n// ---------------------------------------------------------------------------\n// App Remote types\n// ---------------------------------------------------------------------------\n\nexport type {\n ConnectionState,\n ConnectionStateChangeEvent,\n ConnectionErrorEvent,\n} from \"./app-remote\";\n\n// ---------------------------------------------------------------------------\n// Player types\n// ---------------------------------------------------------------------------\n\nexport type {\n RepeatMode,\n PodcastPlaybackSpeed,\n Artist,\n Album,\n Track,\n PlaybackOptions,\n PlaybackRestrictions,\n PlayerState,\n CrossfadeState,\n} from \"./player\";\n\n// ---------------------------------------------------------------------------\n// User types\n// ---------------------------------------------------------------------------\n\nexport type { Capabilities, LibraryState } from \"./user\";\n\n// ---------------------------------------------------------------------------\n// Content types\n// ---------------------------------------------------------------------------\n\nexport type { ContentType, ContentItem } from \"./content\";\n\n// ---------------------------------------------------------------------------\n// Images types\n// ---------------------------------------------------------------------------\n\nexport type { ImageSize, ImageResult, ImageRepresentable } from \"./images\";\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SpotifyError } from "../error";
|
|
2
|
+
export interface NativeErrorRethrowOptions<C extends string, E extends SpotifyError & {
|
|
3
|
+
code: C;
|
|
4
|
+
}> {
|
|
5
|
+
ErrorClass: new (code: C, message: string) => E;
|
|
6
|
+
validCodes: ReadonlySet<C>;
|
|
7
|
+
/** Parse legacy `"CODE: message"` prefixes embedded in native error reasons. */
|
|
8
|
+
legacyCodePrefix?: boolean;
|
|
9
|
+
unknownCode: C;
|
|
10
|
+
}
|
|
11
|
+
export declare function createNativeErrorRethrow<C extends string, E extends SpotifyError & {
|
|
12
|
+
code: C;
|
|
13
|
+
}>(options: NativeErrorRethrowOptions<C, E>): (err: unknown) => never;
|
|
14
|
+
//# sourceMappingURL=native-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-errors.d.ts","sourceRoot":"","sources":["../../src/internal/native-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAU7C,MAAM,WAAW,yBAAyB,CACxC,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,YAAY,GAAG;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE;IAEpC,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,CAAC;IAChD,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAC3B,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,EAAE,CAAC,CAAC;CAChB;AAED,wBAAgB,wBAAwB,CACtC,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,YAAY,GAAG;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,EACpC,OAAO,EAAE,yBAAyB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,KAAK,CAqBnE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const CAUSE_SEPARATOR = "→ Caused by: ";
|
|
2
|
+
const LEGACY_CODE_PREFIX_RE = /^([A-Z_][A-Z0-9_]*):\s*(.*)$/s;
|
|
3
|
+
function unwrapReason(message) {
|
|
4
|
+
const idx = message.lastIndexOf(CAUSE_SEPARATOR);
|
|
5
|
+
return idx === -1 ? message : message.slice(idx + CAUSE_SEPARATOR.length);
|
|
6
|
+
}
|
|
7
|
+
export function createNativeErrorRethrow(options) {
|
|
8
|
+
const { ErrorClass, validCodes, legacyCodePrefix, unknownCode } = options;
|
|
9
|
+
return function rethrowNativeError(err) {
|
|
10
|
+
if (err instanceof ErrorClass)
|
|
11
|
+
throw err;
|
|
12
|
+
if (err instanceof Error) {
|
|
13
|
+
const reason = unwrapReason(err.message);
|
|
14
|
+
const maybeCode = err.code;
|
|
15
|
+
if (maybeCode && validCodes.has(maybeCode)) {
|
|
16
|
+
throw new ErrorClass(maybeCode, reason);
|
|
17
|
+
}
|
|
18
|
+
if (legacyCodePrefix) {
|
|
19
|
+
const match = reason.match(LEGACY_CODE_PREFIX_RE);
|
|
20
|
+
if (match && validCodes.has(match[1])) {
|
|
21
|
+
throw new ErrorClass(match[1], match[2]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
throw new ErrorClass(unknownCode, reason);
|
|
25
|
+
}
|
|
26
|
+
throw new ErrorClass(unknownCode, String(err));
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=native-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-errors.js","sourceRoot":"","sources":["../../src/internal/native-errors.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,eAAe,CAAC;AACxC,MAAM,qBAAqB,GAAG,+BAA+B,CAAC;AAE9D,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;AAaD,MAAM,UAAU,wBAAwB,CAGtC,OAAwC;IACxC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAE1E,OAAO,SAAS,kBAAkB,CAAC,GAAY;QAC7C,IAAI,GAAG,YAAY,UAAU;YAAE,MAAM,GAAG,CAAC;QACzC,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,SAAS,GAAI,GAAiC,CAAC,IAAI,CAAC;YAC1D,IAAI,SAAS,IAAI,UAAU,CAAC,GAAG,CAAC,SAAc,CAAC,EAAE,CAAC;gBAChD,MAAM,IAAI,UAAU,CAAC,SAAc,EAAE,MAAM,CAAC,CAAC;YAC/C,CAAC;YACD,IAAI,gBAAgB,EAAE,CAAC;gBACrB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBAClD,IAAI,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAM,CAAC,EAAE,CAAC;oBAC3C,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAM,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;YACD,MAAM,IAAI,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,IAAI,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { SpotifyError } from \"../error\";\n\nconst CAUSE_SEPARATOR = \"→ Caused by: \";\nconst LEGACY_CODE_PREFIX_RE = /^([A-Z_][A-Z0-9_]*):\\s*(.*)$/s;\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\nexport interface NativeErrorRethrowOptions<\n C extends string,\n E extends SpotifyError & { code: C },\n> {\n ErrorClass: new (code: C, message: string) => E;\n validCodes: ReadonlySet<C>;\n /** Parse legacy `\"CODE: message\"` prefixes embedded in native error reasons. */\n legacyCodePrefix?: boolean;\n unknownCode: C;\n}\n\nexport function createNativeErrorRethrow<\n C extends string,\n E extends SpotifyError & { code: C },\n>(options: NativeErrorRethrowOptions<C, E>): (err: unknown) => never {\n const { ErrorClass, validCodes, legacyCodePrefix, unknownCode } = options;\n\n return function rethrowNativeError(err: unknown): never {\n if (err instanceof ErrorClass) 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 && validCodes.has(maybeCode as C)) {\n throw new ErrorClass(maybeCode as C, reason);\n }\n if (legacyCodePrefix) {\n const match = reason.match(LEGACY_CODE_PREFIX_RE);\n if (match && validCodes.has(match[1] as C)) {\n throw new ErrorClass(match[1] as C, match[2]!);\n }\n }\n throw new ErrorClass(unknownCode, reason);\n }\n throw new ErrorClass(unknownCode, String(err));\n };\n}\n"]}
|