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.d.ts
CHANGED
|
@@ -927,8 +927,8 @@ interface DeviceAuthInitResult {
|
|
|
927
927
|
game?: GameInfo;
|
|
928
928
|
}
|
|
929
929
|
declare class DeviceAuthFlowManager extends EventEmitter {
|
|
930
|
-
/**
|
|
931
|
-
private static
|
|
930
|
+
/** Shared promise for the current flow - allows multiple callers to await the same result */
|
|
931
|
+
private static currentFlowPromise;
|
|
932
932
|
/** Reference to the currently active instance */
|
|
933
933
|
private static activeInstance;
|
|
934
934
|
private baseURL;
|
|
@@ -985,9 +985,13 @@ declare class DeviceAuthFlowManager extends EventEmitter {
|
|
|
985
985
|
*
|
|
986
986
|
* @param options - Flow options
|
|
987
987
|
* @returns Promise resolving to DeviceAuthResult with tokens
|
|
988
|
-
* @throws PlayKitError if a flow is already in progress
|
|
989
988
|
*/
|
|
990
989
|
startFlow(options?: DeviceAuthFlowOptions): Promise<DeviceAuthResult>;
|
|
990
|
+
/**
|
|
991
|
+
* Internal method that executes the actual device auth flow
|
|
992
|
+
* @private
|
|
993
|
+
*/
|
|
994
|
+
private executeFlow;
|
|
991
995
|
/**
|
|
992
996
|
* Cancel the ongoing device auth flow
|
|
993
997
|
*/
|
|
@@ -1063,6 +1067,10 @@ declare class AuthManager extends EventEmitter {
|
|
|
1063
1067
|
private authFlowManager;
|
|
1064
1068
|
private deviceAuthFlowManager;
|
|
1065
1069
|
private logger;
|
|
1070
|
+
/** Shared promise for current device auth flow - allows multiple callers to await the same result */
|
|
1071
|
+
private currentDeviceAuthFlowPromise;
|
|
1072
|
+
/** Shared promise for current auth flow (startAuthFlow) - allows multiple callers to await the same result */
|
|
1073
|
+
private currentAuthFlowPromise;
|
|
1066
1074
|
constructor(config: SDKConfig);
|
|
1067
1075
|
/**
|
|
1068
1076
|
* Initialize authentication
|
|
@@ -1075,6 +1083,11 @@ declare class AuthManager extends EventEmitter {
|
|
|
1075
1083
|
* @deprecated 'headless' authentication is deprecated and will be removed in v2.0. Use 'device' instead.
|
|
1076
1084
|
*/
|
|
1077
1085
|
startAuthFlow(authMethod?: 'device' | 'headless'): Promise<void>;
|
|
1086
|
+
/**
|
|
1087
|
+
* Internal method that executes the actual auth flow
|
|
1088
|
+
* @private
|
|
1089
|
+
*/
|
|
1090
|
+
private executeAuthFlow;
|
|
1078
1091
|
/**
|
|
1079
1092
|
* Exchange JWT for player token
|
|
1080
1093
|
*/
|
|
@@ -1153,6 +1166,11 @@ declare class AuthManager extends EventEmitter {
|
|
|
1153
1166
|
* ```
|
|
1154
1167
|
*/
|
|
1155
1168
|
startDeviceAuthFlow(options?: DeviceAuthFlowOptions): Promise<DeviceAuthResult>;
|
|
1169
|
+
/**
|
|
1170
|
+
* Internal method that executes the actual device auth flow
|
|
1171
|
+
* @private
|
|
1172
|
+
*/
|
|
1173
|
+
private executeDeviceAuthFlow;
|
|
1156
1174
|
/**
|
|
1157
1175
|
* Cancel ongoing device auth flow
|
|
1158
1176
|
*/
|
package/dist/playkit-sdk.esm.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
|
*/
|
|
@@ -2047,53 +2047,56 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2047
2047
|
*
|
|
2048
2048
|
* @param options - Flow options
|
|
2049
2049
|
* @returns Promise resolving to DeviceAuthResult with tokens
|
|
2050
|
-
* @throws PlayKitError if a flow is already in progress
|
|
2051
2050
|
*/
|
|
2052
2051
|
async startFlow(options = {}) {
|
|
2053
|
-
//
|
|
2054
|
-
if (DeviceAuthFlowManager.
|
|
2055
|
-
this.logger.
|
|
2056
|
-
|
|
2057
|
-
}
|
|
2058
|
-
|
|
2052
|
+
// If a flow is already in progress, return the shared promise so all callers get the same result
|
|
2053
|
+
if (DeviceAuthFlowManager.currentFlowPromise) {
|
|
2054
|
+
this.logger.debug('Device auth flow already in progress, waiting for existing flow');
|
|
2055
|
+
return DeviceAuthFlowManager.currentFlowPromise;
|
|
2056
|
+
}
|
|
2057
|
+
// Store the flow promise so subsequent calls can await the same result
|
|
2058
|
+
const flowPromise = this.executeFlow(options);
|
|
2059
|
+
DeviceAuthFlowManager.currentFlowPromise = flowPromise;
|
|
2059
2060
|
DeviceAuthFlowManager.activeInstance = this;
|
|
2061
|
+
try {
|
|
2062
|
+
return await flowPromise;
|
|
2063
|
+
}
|
|
2064
|
+
finally {
|
|
2065
|
+
// Clean up static state when flow completes (success or failure)
|
|
2066
|
+
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2067
|
+
DeviceAuthFlowManager.activeInstance = null;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
/**
|
|
2071
|
+
* Internal method that executes the actual device auth flow
|
|
2072
|
+
* @private
|
|
2073
|
+
*/
|
|
2074
|
+
async executeFlow(options = {}) {
|
|
2060
2075
|
this.aborted = false;
|
|
2061
2076
|
this.currentLanguage = this.detectLanguage();
|
|
2062
2077
|
const scope = options.scope || 'player:play';
|
|
2063
2078
|
const openBrowser = options.openBrowser || this.defaultOpenBrowser.bind(this);
|
|
2064
|
-
// Helper to reset static flags when flow completes early (before polling)
|
|
2065
|
-
const resetFlowStateEarly = () => {
|
|
2066
|
-
DeviceAuthFlowManager.isFlowInProgress = false;
|
|
2067
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2068
|
-
};
|
|
2069
2079
|
// Generate PKCE parameters (outside try block so codeVerifier is accessible for polling)
|
|
2070
2080
|
const codeVerifier = this.generateCodeVerifier();
|
|
2071
2081
|
const codeChallenge = await this.generateCodeChallenge(codeVerifier);
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
});
|
|
2087
|
-
|
|
2088
|
-
const error = await initResponse.json().catch(() => ({ error_description: 'Failed to initiate device auth' }));
|
|
2089
|
-
throw new PlayKitError(error.error_description || 'Failed to initiate device auth', error.error || 'INIT_FAILED', initResponse.status);
|
|
2090
|
-
}
|
|
2091
|
-
initData = await initResponse.json();
|
|
2092
|
-
}
|
|
2093
|
-
catch (err) {
|
|
2094
|
-
resetFlowStateEarly();
|
|
2095
|
-
throw err;
|
|
2082
|
+
// Step 1: Initiate device auth session
|
|
2083
|
+
const initResponse = await fetch(`${this.baseURL}/api/device-auth/initiate`, {
|
|
2084
|
+
method: 'POST',
|
|
2085
|
+
headers: {
|
|
2086
|
+
'Content-Type': 'application/json',
|
|
2087
|
+
},
|
|
2088
|
+
body: JSON.stringify({
|
|
2089
|
+
game_id: this.gameId,
|
|
2090
|
+
code_challenge: codeChallenge,
|
|
2091
|
+
code_challenge_method: 'S256',
|
|
2092
|
+
scope,
|
|
2093
|
+
}),
|
|
2094
|
+
});
|
|
2095
|
+
if (!initResponse.ok) {
|
|
2096
|
+
const error = await initResponse.json().catch(() => ({ error_description: 'Failed to initiate device auth' }));
|
|
2097
|
+
throw new PlayKitError(error.error_description || 'Failed to initiate device auth', error.error || 'INIT_FAILED', initResponse.status);
|
|
2096
2098
|
}
|
|
2099
|
+
const initData = await initResponse.json();
|
|
2097
2100
|
const { session_id, auth_url, poll_interval, expires_in, game } = initData;
|
|
2098
2101
|
// Update poll interval from server
|
|
2099
2102
|
if (poll_interval) {
|
|
@@ -2125,7 +2128,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2125
2128
|
}
|
|
2126
2129
|
catch (err) {
|
|
2127
2130
|
this.closeModal();
|
|
2128
|
-
resetFlowStateEarly();
|
|
2129
2131
|
throw err;
|
|
2130
2132
|
}
|
|
2131
2133
|
// User clicked login - open browser (in user click context, won't be blocked)
|
|
@@ -2137,23 +2139,16 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2137
2139
|
}
|
|
2138
2140
|
// Step 3: Poll for authorization
|
|
2139
2141
|
const expiresAt = Date.now() + (expires_in || 600) * 1000;
|
|
2140
|
-
// Helper to reset static flags when flow completes
|
|
2141
|
-
const resetFlowState = () => {
|
|
2142
|
-
DeviceAuthFlowManager.isFlowInProgress = false;
|
|
2143
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2144
|
-
};
|
|
2145
2142
|
return new Promise((resolve, reject) => {
|
|
2146
2143
|
const poll = async () => {
|
|
2147
2144
|
if (this.aborted) {
|
|
2148
2145
|
this.closeModal();
|
|
2149
|
-
resetFlowState();
|
|
2150
2146
|
reject(new PlayKitError('Device auth flow was cancelled', 'CANCELLED'));
|
|
2151
2147
|
return;
|
|
2152
2148
|
}
|
|
2153
2149
|
// Check if session expired
|
|
2154
2150
|
if (Date.now() >= expiresAt) {
|
|
2155
2151
|
this.showModalError('expired', () => { });
|
|
2156
|
-
resetFlowState();
|
|
2157
2152
|
reject(new PlayKitError('Device auth session expired', 'EXPIRED'));
|
|
2158
2153
|
return;
|
|
2159
2154
|
}
|
|
@@ -2181,7 +2176,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2181
2176
|
}
|
|
2182
2177
|
this.emit('poll_status', 'authorized');
|
|
2183
2178
|
this.emit('authenticated', pollData);
|
|
2184
|
-
resetFlowState();
|
|
2185
2179
|
resolve({
|
|
2186
2180
|
access_token: pollData.access_token,
|
|
2187
2181
|
token_type: pollData.token_type,
|
|
@@ -2210,7 +2204,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2210
2204
|
options.onPollStatus('denied');
|
|
2211
2205
|
}
|
|
2212
2206
|
this.emit('poll_status', 'denied');
|
|
2213
|
-
resetFlowState();
|
|
2214
2207
|
reject(new PlayKitError(pollData.error_description || 'User denied authorization', 'ACCESS_DENIED'));
|
|
2215
2208
|
}
|
|
2216
2209
|
else if (error === 'expired_token') {
|
|
@@ -2219,12 +2212,10 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2219
2212
|
options.onPollStatus('expired');
|
|
2220
2213
|
}
|
|
2221
2214
|
this.emit('poll_status', 'expired');
|
|
2222
|
-
resetFlowState();
|
|
2223
2215
|
reject(new PlayKitError(pollData.error_description || 'Session expired', 'EXPIRED'));
|
|
2224
2216
|
}
|
|
2225
2217
|
else {
|
|
2226
2218
|
this.showModalError('failed', () => { });
|
|
2227
|
-
resetFlowState();
|
|
2228
2219
|
reject(new PlayKitError(pollData.error_description || 'Device auth failed', error || 'POLL_FAILED', pollResponse.status));
|
|
2229
2220
|
}
|
|
2230
2221
|
}
|
|
@@ -2249,11 +2240,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2249
2240
|
clearTimeout(this.pollTimeoutId);
|
|
2250
2241
|
this.pollTimeoutId = null;
|
|
2251
2242
|
}
|
|
2252
|
-
// Reset static flags if this is the active instance
|
|
2253
|
-
if (DeviceAuthFlowManager.activeInstance === this) {
|
|
2254
|
-
DeviceAuthFlowManager.isFlowInProgress = false;
|
|
2255
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2256
|
-
}
|
|
2257
2243
|
this.emit('cancelled');
|
|
2258
2244
|
}
|
|
2259
2245
|
/**
|
|
@@ -2268,7 +2254,7 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2268
2254
|
* Check if a device auth flow is currently in progress (static method)
|
|
2269
2255
|
*/
|
|
2270
2256
|
static isInProgress() {
|
|
2271
|
-
return DeviceAuthFlowManager.
|
|
2257
|
+
return DeviceAuthFlowManager.currentFlowPromise !== null;
|
|
2272
2258
|
}
|
|
2273
2259
|
/**
|
|
2274
2260
|
* Initiate device auth without opening browser or showing UI.
|
|
@@ -2419,8 +2405,8 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2419
2405
|
});
|
|
2420
2406
|
}
|
|
2421
2407
|
}
|
|
2422
|
-
/**
|
|
2423
|
-
DeviceAuthFlowManager.
|
|
2408
|
+
/** Shared promise for the current flow - allows multiple callers to await the same result */
|
|
2409
|
+
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2424
2410
|
/** Reference to the currently active instance */
|
|
2425
2411
|
DeviceAuthFlowManager.activeInstance = null;
|
|
2426
2412
|
|
|
@@ -2438,6 +2424,10 @@ class AuthManager extends EventEmitter {
|
|
|
2438
2424
|
this.authFlowManager = null;
|
|
2439
2425
|
this.deviceAuthFlowManager = null;
|
|
2440
2426
|
this.logger = Logger.getLogger('AuthManager');
|
|
2427
|
+
/** Shared promise for current device auth flow - allows multiple callers to await the same result */
|
|
2428
|
+
this.currentDeviceAuthFlowPromise = null;
|
|
2429
|
+
/** Shared promise for current auth flow (startAuthFlow) - allows multiple callers to await the same result */
|
|
2430
|
+
this.currentAuthFlowPromise = null;
|
|
2441
2431
|
this.config = config;
|
|
2442
2432
|
// Create TokenStorage with appropriate mode for server vs browser environment
|
|
2443
2433
|
this.storage = new TokenStorage({
|
|
@@ -2546,12 +2536,27 @@ class AuthManager extends EventEmitter {
|
|
|
2546
2536
|
* @deprecated 'headless' authentication is deprecated and will be removed in v2.0. Use 'device' instead.
|
|
2547
2537
|
*/
|
|
2548
2538
|
async startAuthFlow(authMethod = 'device') {
|
|
2549
|
-
|
|
2550
|
-
if (this.
|
|
2551
|
-
|
|
2552
|
-
this.
|
|
2553
|
-
|
|
2539
|
+
// If a flow is already in progress, return the shared promise so all callers await the same result
|
|
2540
|
+
if (this.currentAuthFlowPromise) {
|
|
2541
|
+
this.logger.debug('Auth flow already in progress, waiting for existing flow');
|
|
2542
|
+
return this.currentAuthFlowPromise;
|
|
2543
|
+
}
|
|
2544
|
+
// Store the flow promise so subsequent calls can await the same result
|
|
2545
|
+
const flowPromise = this.executeAuthFlow(authMethod);
|
|
2546
|
+
this.currentAuthFlowPromise = flowPromise;
|
|
2547
|
+
try {
|
|
2548
|
+
return await flowPromise;
|
|
2549
|
+
}
|
|
2550
|
+
finally {
|
|
2551
|
+
this.currentAuthFlowPromise = null;
|
|
2554
2552
|
}
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* Internal method that executes the actual auth flow
|
|
2556
|
+
* @private
|
|
2557
|
+
*/
|
|
2558
|
+
async executeAuthFlow(authMethod = 'device') {
|
|
2559
|
+
var _a, _b;
|
|
2555
2560
|
// Deprecation warning for headless auth
|
|
2556
2561
|
if (authMethod === 'headless') {
|
|
2557
2562
|
this.logger.warn('"headless" authentication is deprecated and will be removed in v2.0. ' +
|
|
@@ -2804,10 +2809,27 @@ class AuthManager extends EventEmitter {
|
|
|
2804
2809
|
* ```
|
|
2805
2810
|
*/
|
|
2806
2811
|
async startDeviceAuthFlow(options = {}) {
|
|
2807
|
-
|
|
2808
|
-
if (this.
|
|
2809
|
-
|
|
2812
|
+
// If a flow is already in progress, return the shared promise so all callers get the same result
|
|
2813
|
+
if (this.currentDeviceAuthFlowPromise) {
|
|
2814
|
+
this.logger.debug('Device auth flow already in progress, waiting for existing flow');
|
|
2815
|
+
return this.currentDeviceAuthFlowPromise;
|
|
2816
|
+
}
|
|
2817
|
+
// Store the flow promise so subsequent calls can await the same result
|
|
2818
|
+
const flowPromise = this.executeDeviceAuthFlow(options);
|
|
2819
|
+
this.currentDeviceAuthFlowPromise = flowPromise;
|
|
2820
|
+
try {
|
|
2821
|
+
return await flowPromise;
|
|
2810
2822
|
}
|
|
2823
|
+
finally {
|
|
2824
|
+
this.currentDeviceAuthFlowPromise = null;
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
/**
|
|
2828
|
+
* Internal method that executes the actual device auth flow
|
|
2829
|
+
* @private
|
|
2830
|
+
*/
|
|
2831
|
+
async executeDeviceAuthFlow(options = {}) {
|
|
2832
|
+
var _a;
|
|
2811
2833
|
try {
|
|
2812
2834
|
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
2813
2835
|
const result = await this.deviceAuthFlowManager.startFlow(options);
|
|
@@ -2860,8 +2882,10 @@ class AuthManager extends EventEmitter {
|
|
|
2860
2882
|
* ```
|
|
2861
2883
|
*/
|
|
2862
2884
|
async initiateDeviceAuth(scope = 'player:play') {
|
|
2885
|
+
// If there's an existing manager, clean it up first (allows restarting flow)
|
|
2863
2886
|
if (this.deviceAuthFlowManager) {
|
|
2864
|
-
|
|
2887
|
+
this.logger.debug('Cleaning up existing device auth manager before initiating new flow');
|
|
2888
|
+
this.deviceAuthFlowManager.destroy();
|
|
2865
2889
|
}
|
|
2866
2890
|
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
2867
2891
|
return this.deviceAuthFlowManager.initiateAuth(scope);
|