diff --git a/static_src/SugoiAuthProvider2.ts b/static_src/SugoiAuthProvider2.ts new file mode 100644 index 0000000..6b3355f --- /dev/null +++ b/static_src/SugoiAuthProvider2.ts @@ -0,0 +1,64 @@ +import type { AccessTokenMaybeWithUserId, AccessTokenWithUserId, AuthProvider } from "@twurple/auth"; +import type { UserIdResolvable } from "@twurple/api" +import * as TwitchAuth from "./TwitchAuth"; + +function getTwurpleProxy(token: TwitchAuth.TwitchToken): AccessTokenWithUserId { + return new Proxy(token, { + get(target, name, receiver) { + return target[name.toString().replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`) as keyof TwitchAuth.TwitchToken] + } + }) as unknown as AccessTokenWithUserId +} + +export class SugoiAuthProvider implements AuthProvider { + #token: TwitchAuth.TwitchToken | Promise | null = null; + clientId: string; + constructor(clientId:string,proxyOrigin?:string) { + this.clientId = clientId; + if (proxyOrigin) TwitchAuth.setProxyOrigin(proxyOrigin); + this.#token=TwitchAuth.getUserTokenPassive(clientId).catch() + } + #authorize(scopes: string[]) { + const promise = TwitchAuth.requestAuthCode(this.clientId, ...scopes) + this.#token = promise + return promise + } + /** + * Checks cached token for given scopes, and redirects to authorization page on failure. + * You should only call this from your configured redirect uri. + * + * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#get-the-user-to-authorize-your-app + */ + async getAuthorization(...scopes: string[]): Promise { + const token = await this.#token + if(!token) return this.#authorize(scopes) + for (const scope of scopes) { + if (!token.scope!.includes(scope)) { + return this.#authorize(scopes) + } + } + } + getCurrentScopesForUser(user: UserIdResolvable):string[] { + if (!this.#token || this.#token instanceof Promise) throw new Error("unauthorized") + return this.#token.scope || [] + } + async getAccessTokenForUser(user: UserIdResolvable, ...scopeSets: (string[] | undefined)[]): Promise { + const token = await this.#token + if (!token) return null + return getTwurpleProxy(token) + } + async getAnyAccessToken(user?: UserIdResolvable): Promise { + const token = await this.#token + if (!token) throw new Error("unauthorized") + return getTwurpleProxy(token) + } + async refreshAccessTokenForUser(user: UserIdResolvable): Promise { + const token=await this.#token + if (!token) throw new Error("unauthorized") + if (!token.refresh_token) throw new Error("missing refresh token") + this.#token = await TwitchAuth.refreshToken(this.clientId, token.refresh_token) + return getTwurpleProxy(this.#token) + } +} + +export default SugoiAuthProvider \ No newline at end of file diff --git a/static_src/index.ts b/static_src/index.ts index 1872eb5..51c2a9e 100644 --- a/static_src/index.ts +++ b/static_src/index.ts @@ -1,4 +1,5 @@ export { default as SugoiAuthProvider } from "./SugoiAuthProvider" +export { default as SugoiAuthProvider2 } from "./SugoiAuthProvider2" export { default as WebStorage } from "./WebStorage" export * as TwitchAuth from "./TwitchAuth" export * as tba from "./tba" \ No newline at end of file