@twurple/auth
Advanced tools
Comparing version 6.2.0 to 7.0.0-pre.0
@@ -81,3 +81,3 @@ import type { Logger } from '@d-fischer/logger'; | ||
*/ | ||
export declare function loadAndCompareTokenInfo(clientId: string, token: string, userId?: string, loadedScopes?: string[], requestedScopeSets?: string[][]): Promise<[string[] | undefined, string]>; | ||
export declare function loadAndCompareTokenInfo(clientId: string, token: string, userId?: string, loadedScopes?: string[], requestedScopeSets?: Array<string[] | undefined>): Promise<[string[] | undefined, string]>; | ||
//# sourceMappingURL=helpers.d.ts.map |
@@ -155,3 +155,3 @@ "use strict"; | ||
throw new InvalidTokenTypeError_1.InvalidTokenTypeError(`This call requires an AuthProvider that supports intents. | ||
Please provide an auth provider that does, such as \`RefreshingAuthProvider\`.`); | ||
Please use an auth provider that does, such as \`RefreshingAuthProvider\`.`); | ||
} | ||
@@ -258,3 +258,3 @@ try { | ||
if (requestedScopeSets) { | ||
compareScopeSets(scopesToCompare, requestedScopeSets); | ||
compareScopeSets(scopesToCompare, requestedScopeSets.filter((val) => Boolean(val))); | ||
} | ||
@@ -261,0 +261,0 @@ return [scopesToCompare, userInfo.userId]; |
@@ -10,3 +10,3 @@ export type { AccessToken, AccessTokenMaybeWithUserId, AccessTokenWithUserId, ExpireableAccessToken } from './AccessToken'; | ||
export { RefreshingAuthProvider } from './providers/RefreshingAuthProvider'; | ||
export type { RefreshConfig } from './providers/RefreshingAuthProvider'; | ||
export type { RefreshingAuthProviderConfig } from './providers/RefreshingAuthProvider'; | ||
export { StaticAuthProvider } from './providers/StaticAuthProvider'; | ||
@@ -13,0 +13,0 @@ export { InvalidTokenError } from './errors/InvalidTokenError'; |
@@ -38,5 +38,10 @@ import { type UserIdResolvable } from '@twurple/common'; | ||
* | ||
* @param scopes The requested scope(s). | ||
* @param scopeSets The requested scopes. | ||
* | ||
* Each given parameter is an array of scopes, of which you should pick one to actually request. | ||
* | ||
* The recommendation is to pick the first one | ||
* unless the provider already has one of the requested scopes for the given user. | ||
*/ | ||
getAccessTokenForUser: (user: UserIdResolvable, scopes?: string[]) => Promise<AccessTokenWithUserId | null>; | ||
getAccessTokenForUser: (user: UserIdResolvable, ...scopeSets: Array<string[] | undefined>) => Promise<AccessTokenWithUserId | null>; | ||
/** | ||
@@ -55,5 +60,10 @@ * Fetches a token for a user identified by the given intent defined by the provider. | ||
* @param intent The intent to fetch a token for. | ||
* @param scopes The requested scopes. | ||
* @param scopeSets The requested scopes. | ||
* | ||
* Each given parameter is an array of scopes, of which you should pick one to actually request. | ||
* | ||
* The recommendation is to pick the first one | ||
* unless the provider already has one of the requested scopes for the resolved user. | ||
*/ | ||
getAccessTokenForIntent?: (intent: string, scopes?: string[]) => Promise<AccessTokenWithUserId | null>; | ||
getAccessTokenForIntent?: (intent: string, ...scopeSets: Array<string[] | undefined>) => Promise<AccessTokenWithUserId | null>; | ||
/** | ||
@@ -60,0 +70,0 @@ * Fetches an app token. |
import type { MakeOptional } from '@d-fischer/shared-utils'; | ||
import { EventEmitter } from '@d-fischer/typed-event-emitter'; | ||
import { type UserIdResolvable } from '@twurple/common'; | ||
import type { AccessToken, AccessTokenMaybeWithUserId, AccessTokenWithUserId } from '../AccessToken'; | ||
import { type AuthProvider } from './AuthProvider'; | ||
declare type OnRefreshCallbackWithUserId = (userId: string, token: AccessToken) => void; | ||
declare type OnRefreshCallbackWithoutUserId = (token: AccessToken) => void; | ||
declare type OnRefreshCallback = OnRefreshCallbackWithUserId | OnRefreshCallbackWithoutUserId; | ||
/** | ||
* Configuration for the {@link RefreshingAuthProvider}. | ||
*/ | ||
export interface RefreshConfig { | ||
export interface RefreshingAuthProviderConfig { | ||
/** | ||
@@ -21,17 +19,8 @@ * The client ID of your application. | ||
/** | ||
* A callback that is called whenever the auth provider refreshes the token, | ||
* e.g. to save the new data in your database. | ||
* A valid redirect URI for your application. | ||
* | ||
* @param userId The ID of the user. | ||
* @param token The token data. | ||
* Only required if you use `addUserForCode`. | ||
*/ | ||
onRefresh?: OnRefreshCallback; | ||
redirectUri?: string; | ||
/** | ||
* A callback that is called whenever the auth provider fails to refresh the token, | ||
* e.g. to notify the user or remove them from your database. | ||
* | ||
* @param userId The ID of the user. | ||
*/ | ||
onRefreshFailure?: (userId: string) => void; | ||
/** | ||
* The scopes to be implied by the provider's app access token. | ||
@@ -45,5 +34,6 @@ */ | ||
*/ | ||
export declare class RefreshingAuthProvider implements AuthProvider { | ||
export declare class RefreshingAuthProvider extends EventEmitter implements AuthProvider { | ||
private readonly _clientId; | ||
private readonly _clientSecret; | ||
private readonly _redirectUri?; | ||
private readonly _userAccessTokens; | ||
@@ -56,5 +46,16 @@ private readonly _userTokenFetchers; | ||
private readonly _appImpliedScopes; | ||
private readonly _onRefresh?; | ||
private readonly _onRefreshFailure?; | ||
/** | ||
* Fires when a user token is refreshed. | ||
* | ||
* @param userId The ID of the user whose token wasn't successfully refreshed. | ||
* @param token The refreshed token data. | ||
*/ | ||
readonly onRefresh: import("@d-fischer/typed-event-emitter").EventBinder<[userId: string, token: AccessToken]>; | ||
/** | ||
* Fires when a user token fails to refresh. | ||
* | ||
* @param userId The ID of the user whose token wasn't successfully refreshed. | ||
*/ | ||
readonly onRefreshFailure: import("@d-fischer/typed-event-emitter").EventBinder<[userId: string]>; | ||
/** | ||
* Creates a new auth provider based on the given one that can automatically | ||
@@ -65,3 +66,3 @@ * refresh access tokens. | ||
*/ | ||
constructor(refreshConfig: RefreshConfig); | ||
constructor(refreshConfig: RefreshingAuthProviderConfig); | ||
/** | ||
@@ -86,6 +87,18 @@ * Adds the given user with their corresponding token to the provider. | ||
* | ||
* Any intents that were already set before will be overwritten to point to this user instead. | ||
* Any intents that were already set before will be overwritten to point to the associated user instead. | ||
*/ | ||
addUserForToken(initialToken: MakeOptional<AccessToken, 'accessToken' | 'scope'>, intents?: string[]): Promise<string>; | ||
/** | ||
* Gets an OAuth token from the given authorization code and adds the user to the provider. | ||
* | ||
* An authorization code can be obtained using the | ||
* [OAuth Authorization Code flow](https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow). | ||
* | ||
* @param code The authorization code. | ||
* @param intents The intents to add to the user. | ||
* | ||
* Any intents that were already set before will be overwritten to point to the associated user instead. | ||
*/ | ||
addUserForCode(code: string, intents?: string[]): Promise<string>; | ||
/** | ||
* Checks whether a user was added to the provider. | ||
@@ -153,5 +166,5 @@ * | ||
* @param user The user to get an access token for. | ||
* @param scopes The requested scopes. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
getAccessTokenForUser(user: UserIdResolvable, scopes?: string[]): Promise<AccessTokenWithUserId | null>; | ||
getAccessTokenForUser(user: UserIdResolvable, ...scopeSets: Array<string[] | undefined>): Promise<AccessTokenWithUserId | null>; | ||
/** | ||
@@ -161,5 +174,5 @@ * Fetches a token for a user identified by the given intent. | ||
* @param intent The intent to fetch a token for. | ||
* @param scopes The requested scopes. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
getAccessTokenForIntent(intent: string, scopes?: string[]): Promise<AccessTokenWithUserId | null>; | ||
getAccessTokenForIntent(intent: string, ...scopeSets: Array<string[] | undefined>): Promise<AccessTokenWithUserId | null>; | ||
/** | ||
@@ -179,3 +192,2 @@ * Fetches any token to use with a request that supports both user and app tokens, | ||
private _checkIntermediateUserRemoval; | ||
private _callOnRefresh; | ||
private _fetchUserToken; | ||
@@ -186,3 +198,2 @@ private _refreshUserTokenWithCallback; | ||
} | ||
export {}; | ||
//# sourceMappingURL=RefreshingAuthProvider.d.ts.map |
@@ -6,2 +6,3 @@ "use strict"; | ||
const shared_utils_1 = require("@d-fischer/shared-utils"); | ||
const typed_event_emitter_1 = require("@d-fischer/typed-event-emitter"); | ||
const common_1 = require("@twurple/common"); | ||
@@ -19,3 +20,3 @@ const AccessToken_1 = require("../AccessToken"); | ||
*/ | ||
let RefreshingAuthProvider = class RefreshingAuthProvider { | ||
let RefreshingAuthProvider = class RefreshingAuthProvider extends typed_event_emitter_1.EventEmitter { | ||
/** | ||
@@ -29,2 +30,3 @@ * Creates a new auth provider based on the given one that can automatically | ||
var _a; | ||
super(); | ||
this._userAccessTokens = new Map(); | ||
@@ -34,5 +36,18 @@ this._userTokenFetchers = new Map(); | ||
this._userIdToIntents = new Map(); | ||
/** | ||
* Fires when a user token is refreshed. | ||
* | ||
* @param userId The ID of the user whose token wasn't successfully refreshed. | ||
* @param token The refreshed token data. | ||
*/ | ||
this.onRefresh = this.registerEvent(); | ||
/** | ||
* Fires when a user token fails to refresh. | ||
* | ||
* @param userId The ID of the user whose token wasn't successfully refreshed. | ||
*/ | ||
this.onRefreshFailure = this.registerEvent(); | ||
this._clientId = refreshConfig.clientId; | ||
this._clientSecret = refreshConfig.clientSecret; | ||
this._onRefresh = refreshConfig.onRefresh; | ||
this._redirectUri = refreshConfig.redirectUri; | ||
this._appImpliedScopes = (_a = refreshConfig.appImpliedScopes) !== null && _a !== void 0 ? _a : []; | ||
@@ -75,3 +90,3 @@ this._appTokenFetcher = new TokenFetcher_1.TokenFetcher(async (scopes) => await this._fetchAppToken(scopes)); | ||
* | ||
* Any intents that were already set before will be overwritten to point to this user instead. | ||
* Any intents that were already set before will be overwritten to point to the associated user instead. | ||
*/ | ||
@@ -97,3 +112,3 @@ async addUserForToken(initialToken, intents) { | ||
const tokenInfo = await (0, helpers_1.getTokenInfo)(refreshedToken.accessToken); | ||
this._callOnRefresh(tokenInfo.userId, refreshedToken); | ||
this.emit(this.onRefresh, tokenInfo.userId, refreshedToken); | ||
tokenWithInfo = [refreshedToken, tokenInfo]; | ||
@@ -115,2 +130,20 @@ } | ||
/** | ||
* Gets an OAuth token from the given authorization code and adds the user to the provider. | ||
* | ||
* An authorization code can be obtained using the | ||
* [OAuth Authorization Code flow](https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow). | ||
* | ||
* @param code The authorization code. | ||
* @param intents The intents to add to the user. | ||
* | ||
* Any intents that were already set before will be overwritten to point to the associated user instead. | ||
*/ | ||
async addUserForCode(code, intents) { | ||
if (!this._redirectUri) { | ||
throw new Error('This method requires you to pass a `redirectUri` as a configuration property'); | ||
} | ||
const token = await (0, helpers_1.exchangeCode)(this._clientId, this._clientSecret, code, this._redirectUri); | ||
return await this.addUserForToken(token, intents); | ||
} | ||
/** | ||
* Checks whether a user was added to the provider. | ||
@@ -211,3 +244,3 @@ * | ||
}); | ||
this._callOnRefresh(userId, tokenData); | ||
this.emit(this.onRefresh, userId, tokenData); | ||
return { | ||
@@ -253,5 +286,5 @@ ...tokenData, | ||
* @param user The user to get an access token for. | ||
* @param scopes The requested scopes. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
async getAccessTokenForUser(user, scopes) { | ||
async getAccessTokenForUser(user, ...scopeSets) { | ||
const fetcher = this._userTokenFetchers.get((0, common_1.extractUserId)(user)); | ||
@@ -261,3 +294,3 @@ if (!fetcher) { | ||
} | ||
return await fetcher.fetch(scopes); | ||
return await fetcher.fetch(...scopeSets); | ||
} | ||
@@ -268,5 +301,5 @@ /** | ||
* @param intent The intent to fetch a token for. | ||
* @param scopes The requested scopes. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
async getAccessTokenForIntent(intent, scopes) { | ||
async getAccessTokenForIntent(intent, ...scopeSets) { | ||
if (!this._intentToUserId.has(intent)) { | ||
@@ -276,3 +309,3 @@ return null; | ||
const userId = this._intentToUserId.get(intent); | ||
const newToken = await this.getAccessTokenForUser(userId, scopes); | ||
const newToken = await this.getAccessTokenForUser(userId, ...scopeSets); | ||
if (!newToken) { | ||
@@ -324,14 +357,2 @@ throw new common_1.HellFreezesOverError(`Found intent ${intent} corresponding to user ID ${userId} but no token was found`); | ||
} | ||
_callOnRefresh(userId, tokenData) { | ||
if (this._onRefresh) { | ||
if (this._onRefresh.length < 2) { | ||
// eslint-disable-next-line no-console | ||
console.warn('DEPRECATION WARNING: please update your onRefresh callback to take a user ID as first parameter'); | ||
this._onRefresh(tokenData); | ||
} | ||
else { | ||
this._onRefresh(userId, tokenData); | ||
} | ||
} | ||
} | ||
async _fetchUserToken(userId, scopeSets) { | ||
@@ -372,3 +393,2 @@ const previousToken = this._userAccessTokens.get(userId); | ||
async _refreshUserTokenWithCallback(userId, refreshToken) { | ||
var _a; | ||
try { | ||
@@ -378,3 +398,3 @@ return await (0, helpers_1.refreshUserToken)(this.clientId, this._clientSecret, refreshToken); | ||
catch (e) { | ||
(_a = this._onRefreshFailure) === null || _a === void 0 ? void 0 : _a.call(this, userId); | ||
this.emit(this.onRefreshFailure, userId); | ||
throw e; | ||
@@ -381,0 +401,0 @@ } |
@@ -40,6 +40,6 @@ import { type UserIdResolvable } from '@twurple/common'; | ||
* | ||
* @param intent Ignored. | ||
* @param scopes The requested scopes. | ||
* @param user Ignored. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
getAccessTokenForIntent(intent: string, scopes?: string[]): Promise<AccessTokenWithUserId>; | ||
getAccessTokenForUser(user: UserIdResolvable, ...scopeSets: Array<string[] | undefined>): Promise<AccessTokenWithUserId>; | ||
/** | ||
@@ -51,6 +51,6 @@ * Gets the static access token. | ||
* | ||
* @param user Ignored. | ||
* @param scopes The requested scopes. | ||
* @param intent Ignored. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
getAccessTokenForUser(user: UserIdResolvable, scopes?: string[]): Promise<AccessTokenWithUserId>; | ||
getAccessTokenForIntent(intent: string, ...scopeSets: Array<string[] | undefined>): Promise<AccessTokenWithUserId>; | ||
/** | ||
@@ -57,0 +57,0 @@ * Gets the static access token. |
@@ -55,7 +55,7 @@ "use strict"; | ||
* | ||
* @param intent Ignored. | ||
* @param scopes The requested scopes. | ||
* @param user Ignored. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
async getAccessTokenForIntent(intent, scopes) { | ||
return await this._getAccessToken(scopes); | ||
async getAccessTokenForUser(user, ...scopeSets) { | ||
return await this._getAccessToken(scopeSets); | ||
} | ||
@@ -68,7 +68,7 @@ /** | ||
* | ||
* @param user Ignored. | ||
* @param scopes The requested scopes. | ||
* @param intent Ignored. | ||
* @param scopeSets The requested scopes. | ||
*/ | ||
async getAccessTokenForUser(user, scopes) { | ||
return await this._getAccessToken(scopes); | ||
async getAccessTokenForIntent(intent, ...scopeSets) { | ||
return await this._getAccessToken(scopeSets); | ||
} | ||
@@ -88,4 +88,4 @@ /** | ||
} | ||
async _getAccessToken(requestedScopes) { | ||
const [scopes, userId] = await (0, helpers_1.loadAndCompareTokenInfo)(this._clientId, this._accessToken.accessToken, this._userId, this._scopes, requestedScopes ? [requestedScopes] : []); | ||
async _getAccessToken(requestedScopeSets) { | ||
const [scopes, userId] = await (0, helpers_1.loadAndCompareTokenInfo)(this._clientId, this._accessToken.accessToken, this._userId, this._scopes, requestedScopeSets); | ||
this._scopes = scopes; | ||
@@ -92,0 +92,0 @@ this._userId = userId; |
@@ -10,4 +10,4 @@ import type { AccessToken } from './AccessToken'; | ||
constructor(executor: (scopeSets: string[][]) => Promise<T>); | ||
fetch(scopes?: string[]): Promise<T>; | ||
fetch(...scopeSets: Array<string[] | undefined>): Promise<T>; | ||
} | ||
//# sourceMappingURL=TokenFetcher.d.ts.map |
@@ -14,13 +14,14 @@ "use strict"; | ||
} | ||
async fetch(scopes) { | ||
async fetch(...scopeSets) { | ||
var _a; | ||
const filteredScopeSets = scopeSets.filter((val) => Boolean(val)); | ||
if (this._newTokenPromise) { | ||
if (!(scopes === null || scopes === void 0 ? void 0 : scopes.length)) { | ||
if (!filteredScopeSets.length) { | ||
return await this._newTokenPromise; | ||
} | ||
if (this._queueExecutor) { | ||
this._queuedScopeSets.push(scopes); | ||
this._queuedScopeSets.push(...filteredScopeSets); | ||
} | ||
else { | ||
this._queuedScopeSets = [scopes]; | ||
this._queuedScopeSets = [...filteredScopeSets]; | ||
} | ||
@@ -55,3 +56,3 @@ if (!this._queuePromise) { | ||
} | ||
this._newTokenScopeSets = (scopes === null || scopes === void 0 ? void 0 : scopes.length) ? [scopes] : []; | ||
this._newTokenScopeSets = [...filteredScopeSets]; | ||
const { promise, resolve, reject } = (0, shared_utils_1.promiseWithResolvers)(); | ||
@@ -58,0 +59,0 @@ this._newTokenPromise = promise; |
{ | ||
"name": "@twurple/auth", | ||
"version": "6.2.0", | ||
"version": "7.0.0-pre.0", | ||
"publishConfig": { | ||
@@ -38,4 +38,5 @@ "access": "public" | ||
"@d-fischer/shared-utils": "^3.6.1", | ||
"@twurple/api-call": "6.2.0", | ||
"@twurple/common": "6.2.0", | ||
"@d-fischer/typed-event-emitter": "^3.3.1", | ||
"@twurple/api-call": "7.0.0-pre.0", | ||
"@twurple/common": "7.0.0-pre.0", | ||
"tslib": "^2.0.3" | ||
@@ -42,0 +43,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
139679
3421
6
1
+ Added@d-fischer/typed-event-emitter@3.3.3(transitive)
+ Added@twurple/api-call@7.0.0-pre.0(transitive)
+ Added@twurple/common@7.0.0-pre.0(transitive)
- Removed@twurple/api-call@6.2.0(transitive)
- Removed@twurple/common@6.2.0(transitive)
Updated@twurple/common@7.0.0-pre.0