playkit-sdk 1.2.11 → 1.2.13
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/dist/playkit-sdk.cjs.js +90 -66
- package/dist/playkit-sdk.cjs.js.map +1 -1
- package/dist/playkit-sdk.d.ts +21 -3
- package/dist/playkit-sdk.esm.js +90 -66
- package/dist/playkit-sdk.esm.js.map +1 -1
- package/dist/playkit-sdk.umd.js +90 -66
- package/dist/playkit-sdk.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/playkit-sdk.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* playkit-sdk v1.2.
|
|
2
|
+
* playkit-sdk v1.2.13
|
|
3
3
|
* PlayKit SDK for JavaScript
|
|
4
4
|
* @license SEE LICENSE IN LICENSE
|
|
5
5
|
*/
|
|
@@ -2051,53 +2051,56 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2051
2051
|
*
|
|
2052
2052
|
* @param options - Flow options
|
|
2053
2053
|
* @returns Promise resolving to DeviceAuthResult with tokens
|
|
2054
|
-
* @throws PlayKitError if a flow is already in progress
|
|
2055
2054
|
*/
|
|
2056
2055
|
async startFlow(options = {}) {
|
|
2057
|
-
//
|
|
2058
|
-
if (DeviceAuthFlowManager.
|
|
2059
|
-
this.logger.
|
|
2060
|
-
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2056
|
+
// If a flow is already in progress, return the shared promise so all callers get the same result
|
|
2057
|
+
if (DeviceAuthFlowManager.currentFlowPromise) {
|
|
2058
|
+
this.logger.debug('Device auth flow already in progress, waiting for existing flow');
|
|
2059
|
+
return DeviceAuthFlowManager.currentFlowPromise;
|
|
2060
|
+
}
|
|
2061
|
+
// Store the flow promise so subsequent calls can await the same result
|
|
2062
|
+
const flowPromise = this.executeFlow(options);
|
|
2063
|
+
DeviceAuthFlowManager.currentFlowPromise = flowPromise;
|
|
2063
2064
|
DeviceAuthFlowManager.activeInstance = this;
|
|
2065
|
+
try {
|
|
2066
|
+
return await flowPromise;
|
|
2067
|
+
}
|
|
2068
|
+
finally {
|
|
2069
|
+
// Clean up static state when flow completes (success or failure)
|
|
2070
|
+
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2071
|
+
DeviceAuthFlowManager.activeInstance = null;
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Internal method that executes the actual device auth flow
|
|
2076
|
+
* @private
|
|
2077
|
+
*/
|
|
2078
|
+
async executeFlow(options = {}) {
|
|
2064
2079
|
this.aborted = false;
|
|
2065
2080
|
this.currentLanguage = this.detectLanguage();
|
|
2066
2081
|
const scope = options.scope || 'player:play';
|
|
2067
2082
|
const openBrowser = options.openBrowser || this.defaultOpenBrowser.bind(this);
|
|
2068
|
-
// Helper to reset static flags when flow completes early (before polling)
|
|
2069
|
-
const resetFlowStateEarly = () => {
|
|
2070
|
-
DeviceAuthFlowManager.isFlowInProgress = false;
|
|
2071
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2072
|
-
};
|
|
2073
2083
|
// Generate PKCE parameters (outside try block so codeVerifier is accessible for polling)
|
|
2074
2084
|
const codeVerifier = this.generateCodeVerifier();
|
|
2075
2085
|
const codeChallenge = await this.generateCodeChallenge(codeVerifier);
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
});
|
|
2091
|
-
|
|
2092
|
-
const error = await initResponse.json().catch(() => ({ error_description: 'Failed to initiate device auth' }));
|
|
2093
|
-
throw new PlayKitError(error.error_description || 'Failed to initiate device auth', error.error || 'INIT_FAILED', initResponse.status);
|
|
2094
|
-
}
|
|
2095
|
-
initData = await initResponse.json();
|
|
2096
|
-
}
|
|
2097
|
-
catch (err) {
|
|
2098
|
-
resetFlowStateEarly();
|
|
2099
|
-
throw err;
|
|
2086
|
+
// Step 1: Initiate device auth session
|
|
2087
|
+
const initResponse = await fetch(`${this.baseURL}/api/device-auth/initiate`, {
|
|
2088
|
+
method: 'POST',
|
|
2089
|
+
headers: {
|
|
2090
|
+
'Content-Type': 'application/json',
|
|
2091
|
+
},
|
|
2092
|
+
body: JSON.stringify({
|
|
2093
|
+
game_id: this.gameId,
|
|
2094
|
+
code_challenge: codeChallenge,
|
|
2095
|
+
code_challenge_method: 'S256',
|
|
2096
|
+
scope,
|
|
2097
|
+
}),
|
|
2098
|
+
});
|
|
2099
|
+
if (!initResponse.ok) {
|
|
2100
|
+
const error = await initResponse.json().catch(() => ({ error_description: 'Failed to initiate device auth' }));
|
|
2101
|
+
throw new PlayKitError(error.error_description || 'Failed to initiate device auth', error.error || 'INIT_FAILED', initResponse.status);
|
|
2100
2102
|
}
|
|
2103
|
+
const initData = await initResponse.json();
|
|
2101
2104
|
const { session_id, auth_url, poll_interval, expires_in, game } = initData;
|
|
2102
2105
|
// Update poll interval from server
|
|
2103
2106
|
if (poll_interval) {
|
|
@@ -2129,7 +2132,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2129
2132
|
}
|
|
2130
2133
|
catch (err) {
|
|
2131
2134
|
this.closeModal();
|
|
2132
|
-
resetFlowStateEarly();
|
|
2133
2135
|
throw err;
|
|
2134
2136
|
}
|
|
2135
2137
|
// User clicked login - open browser (in user click context, won't be blocked)
|
|
@@ -2141,23 +2143,16 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2141
2143
|
}
|
|
2142
2144
|
// Step 3: Poll for authorization
|
|
2143
2145
|
const expiresAt = Date.now() + (expires_in || 600) * 1000;
|
|
2144
|
-
// Helper to reset static flags when flow completes
|
|
2145
|
-
const resetFlowState = () => {
|
|
2146
|
-
DeviceAuthFlowManager.isFlowInProgress = false;
|
|
2147
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2148
|
-
};
|
|
2149
2146
|
return new Promise((resolve, reject) => {
|
|
2150
2147
|
const poll = async () => {
|
|
2151
2148
|
if (this.aborted) {
|
|
2152
2149
|
this.closeModal();
|
|
2153
|
-
resetFlowState();
|
|
2154
2150
|
reject(new PlayKitError('Device auth flow was cancelled', 'CANCELLED'));
|
|
2155
2151
|
return;
|
|
2156
2152
|
}
|
|
2157
2153
|
// Check if session expired
|
|
2158
2154
|
if (Date.now() >= expiresAt) {
|
|
2159
2155
|
this.showModalError('expired', () => { });
|
|
2160
|
-
resetFlowState();
|
|
2161
2156
|
reject(new PlayKitError('Device auth session expired', 'EXPIRED'));
|
|
2162
2157
|
return;
|
|
2163
2158
|
}
|
|
@@ -2185,7 +2180,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2185
2180
|
}
|
|
2186
2181
|
this.emit('poll_status', 'authorized');
|
|
2187
2182
|
this.emit('authenticated', pollData);
|
|
2188
|
-
resetFlowState();
|
|
2189
2183
|
resolve({
|
|
2190
2184
|
access_token: pollData.access_token,
|
|
2191
2185
|
token_type: pollData.token_type,
|
|
@@ -2214,7 +2208,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2214
2208
|
options.onPollStatus('denied');
|
|
2215
2209
|
}
|
|
2216
2210
|
this.emit('poll_status', 'denied');
|
|
2217
|
-
resetFlowState();
|
|
2218
2211
|
reject(new PlayKitError(pollData.error_description || 'User denied authorization', 'ACCESS_DENIED'));
|
|
2219
2212
|
}
|
|
2220
2213
|
else if (error === 'expired_token') {
|
|
@@ -2223,12 +2216,10 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2223
2216
|
options.onPollStatus('expired');
|
|
2224
2217
|
}
|
|
2225
2218
|
this.emit('poll_status', 'expired');
|
|
2226
|
-
resetFlowState();
|
|
2227
2219
|
reject(new PlayKitError(pollData.error_description || 'Session expired', 'EXPIRED'));
|
|
2228
2220
|
}
|
|
2229
2221
|
else {
|
|
2230
2222
|
this.showModalError('failed', () => { });
|
|
2231
|
-
resetFlowState();
|
|
2232
2223
|
reject(new PlayKitError(pollData.error_description || 'Device auth failed', error || 'POLL_FAILED', pollResponse.status));
|
|
2233
2224
|
}
|
|
2234
2225
|
}
|
|
@@ -2253,11 +2244,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2253
2244
|
clearTimeout(this.pollTimeoutId);
|
|
2254
2245
|
this.pollTimeoutId = null;
|
|
2255
2246
|
}
|
|
2256
|
-
// Reset static flags if this is the active instance
|
|
2257
|
-
if (DeviceAuthFlowManager.activeInstance === this) {
|
|
2258
|
-
DeviceAuthFlowManager.isFlowInProgress = false;
|
|
2259
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2260
|
-
}
|
|
2261
2247
|
this.emit('cancelled');
|
|
2262
2248
|
}
|
|
2263
2249
|
/**
|
|
@@ -2272,7 +2258,7 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2272
2258
|
* Check if a device auth flow is currently in progress (static method)
|
|
2273
2259
|
*/
|
|
2274
2260
|
static isInProgress() {
|
|
2275
|
-
return DeviceAuthFlowManager.
|
|
2261
|
+
return DeviceAuthFlowManager.currentFlowPromise !== null;
|
|
2276
2262
|
}
|
|
2277
2263
|
/**
|
|
2278
2264
|
* Initiate device auth without opening browser or showing UI.
|
|
@@ -2423,8 +2409,8 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2423
2409
|
});
|
|
2424
2410
|
}
|
|
2425
2411
|
}
|
|
2426
|
-
/**
|
|
2427
|
-
DeviceAuthFlowManager.
|
|
2412
|
+
/** Shared promise for the current flow - allows multiple callers to await the same result */
|
|
2413
|
+
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2428
2414
|
/** Reference to the currently active instance */
|
|
2429
2415
|
DeviceAuthFlowManager.activeInstance = null;
|
|
2430
2416
|
|
|
@@ -2442,6 +2428,10 @@ class AuthManager extends EventEmitter {
|
|
|
2442
2428
|
this.authFlowManager = null;
|
|
2443
2429
|
this.deviceAuthFlowManager = null;
|
|
2444
2430
|
this.logger = Logger.getLogger('AuthManager');
|
|
2431
|
+
/** Shared promise for current device auth flow - allows multiple callers to await the same result */
|
|
2432
|
+
this.currentDeviceAuthFlowPromise = null;
|
|
2433
|
+
/** Shared promise for current auth flow (startAuthFlow) - allows multiple callers to await the same result */
|
|
2434
|
+
this.currentAuthFlowPromise = null;
|
|
2445
2435
|
this.config = config;
|
|
2446
2436
|
// Create TokenStorage with appropriate mode for server vs browser environment
|
|
2447
2437
|
this.storage = new TokenStorage({
|
|
@@ -2550,12 +2540,27 @@ class AuthManager extends EventEmitter {
|
|
|
2550
2540
|
* @deprecated 'headless' authentication is deprecated and will be removed in v2.0. Use 'device' instead.
|
|
2551
2541
|
*/
|
|
2552
2542
|
async startAuthFlow(authMethod = 'device') {
|
|
2553
|
-
|
|
2554
|
-
if (this.
|
|
2555
|
-
|
|
2556
|
-
this.
|
|
2557
|
-
|
|
2543
|
+
// If a flow is already in progress, return the shared promise so all callers await the same result
|
|
2544
|
+
if (this.currentAuthFlowPromise) {
|
|
2545
|
+
this.logger.debug('Auth flow already in progress, waiting for existing flow');
|
|
2546
|
+
return this.currentAuthFlowPromise;
|
|
2547
|
+
}
|
|
2548
|
+
// Store the flow promise so subsequent calls can await the same result
|
|
2549
|
+
const flowPromise = this.executeAuthFlow(authMethod);
|
|
2550
|
+
this.currentAuthFlowPromise = flowPromise;
|
|
2551
|
+
try {
|
|
2552
|
+
return await flowPromise;
|
|
2553
|
+
}
|
|
2554
|
+
finally {
|
|
2555
|
+
this.currentAuthFlowPromise = null;
|
|
2558
2556
|
}
|
|
2557
|
+
}
|
|
2558
|
+
/**
|
|
2559
|
+
* Internal method that executes the actual auth flow
|
|
2560
|
+
* @private
|
|
2561
|
+
*/
|
|
2562
|
+
async executeAuthFlow(authMethod = 'device') {
|
|
2563
|
+
var _a, _b;
|
|
2559
2564
|
// Deprecation warning for headless auth
|
|
2560
2565
|
if (authMethod === 'headless') {
|
|
2561
2566
|
this.logger.warn('"headless" authentication is deprecated and will be removed in v2.0. ' +
|
|
@@ -2808,10 +2813,27 @@ class AuthManager extends EventEmitter {
|
|
|
2808
2813
|
* ```
|
|
2809
2814
|
*/
|
|
2810
2815
|
async startDeviceAuthFlow(options = {}) {
|
|
2811
|
-
|
|
2812
|
-
if (this.
|
|
2813
|
-
|
|
2816
|
+
// If a flow is already in progress, return the shared promise so all callers get the same result
|
|
2817
|
+
if (this.currentDeviceAuthFlowPromise) {
|
|
2818
|
+
this.logger.debug('Device auth flow already in progress, waiting for existing flow');
|
|
2819
|
+
return this.currentDeviceAuthFlowPromise;
|
|
2820
|
+
}
|
|
2821
|
+
// Store the flow promise so subsequent calls can await the same result
|
|
2822
|
+
const flowPromise = this.executeDeviceAuthFlow(options);
|
|
2823
|
+
this.currentDeviceAuthFlowPromise = flowPromise;
|
|
2824
|
+
try {
|
|
2825
|
+
return await flowPromise;
|
|
2814
2826
|
}
|
|
2827
|
+
finally {
|
|
2828
|
+
this.currentDeviceAuthFlowPromise = null;
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
/**
|
|
2832
|
+
* Internal method that executes the actual device auth flow
|
|
2833
|
+
* @private
|
|
2834
|
+
*/
|
|
2835
|
+
async executeDeviceAuthFlow(options = {}) {
|
|
2836
|
+
var _a;
|
|
2815
2837
|
try {
|
|
2816
2838
|
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
2817
2839
|
const result = await this.deviceAuthFlowManager.startFlow(options);
|
|
@@ -2864,8 +2886,10 @@ class AuthManager extends EventEmitter {
|
|
|
2864
2886
|
* ```
|
|
2865
2887
|
*/
|
|
2866
2888
|
async initiateDeviceAuth(scope = 'player:play') {
|
|
2889
|
+
// If there's an existing manager, clean it up first (allows restarting flow)
|
|
2867
2890
|
if (this.deviceAuthFlowManager) {
|
|
2868
|
-
|
|
2891
|
+
this.logger.debug('Cleaning up existing device auth manager before initiating new flow');
|
|
2892
|
+
this.deviceAuthFlowManager.destroy();
|
|
2869
2893
|
}
|
|
2870
2894
|
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
2871
2895
|
return this.deviceAuthFlowManager.initiateAuth(scope);
|