diff --git a/static/SugoiAuthProvider.js.map b/static/SugoiAuthProvider.js.map index fdfc3c7..26bd03b 100644 --- a/static/SugoiAuthProvider.js.map +++ b/static/SugoiAuthProvider.js.map @@ -1,6 +1,6 @@ { "version": 3, - "sources": ["../node_modules/fetch-retry/dist/fetch-retry.umd.js", "TwitchAuth.ts", "SugoiAuthProvider.ts"], + "sources": ["../node_modules/fetch-retry/dist/fetch-retry.umd.js", "../static_src/TwitchAuth.ts", "../static_src/SugoiAuthProvider.ts"], "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.fetchRetry = factory());\n})(this, (function () { 'use strict';\n\n var fetchRetry = function (fetch, defaults) {\n defaults = defaults || {};\n if (typeof fetch !== 'function') {\n throw new ArgumentError('fetch must be a function');\n }\n\n if (typeof defaults !== 'object') {\n throw new ArgumentError('defaults must be an object');\n }\n\n if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {\n throw new ArgumentError('retries must be a positive integer');\n }\n\n if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {\n throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');\n }\n\n if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {\n throw new ArgumentError('retryOn property expects an array or function');\n }\n\n var baseDefaults = {\n retries: 3,\n retryDelay: 1000,\n retryOn: [],\n };\n\n defaults = Object.assign(baseDefaults, defaults);\n\n return function fetchRetry(input, init) {\n var retries = defaults.retries;\n var retryDelay = defaults.retryDelay;\n var retryOn = defaults.retryOn;\n\n if (init && init.retries !== undefined) {\n if (isPositiveInteger(init.retries)) {\n retries = init.retries;\n } else {\n throw new ArgumentError('retries must be a positive integer');\n }\n }\n\n if (init && init.retryDelay !== undefined) {\n if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {\n retryDelay = init.retryDelay;\n } else {\n throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');\n }\n }\n\n if (init && init.retryOn) {\n if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {\n retryOn = init.retryOn;\n } else {\n throw new ArgumentError('retryOn property expects an array or function');\n }\n }\n\n // eslint-disable-next-line no-undef\n return new Promise(function (resolve, reject) {\n var wrappedFetch = function (attempt) {\n // As of node 18, this is no longer needed since node comes with native support for fetch:\n /* istanbul ignore next */\n var _input =\n typeof Request !== 'undefined' && input instanceof Request\n ? input.clone()\n : input;\n fetch(_input, init)\n .then(function (response) {\n if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {\n resolve(response);\n } else if (typeof retryOn === 'function') {\n try {\n // eslint-disable-next-line no-undef\n return Promise.resolve(retryOn(attempt, null, response))\n .then(function (retryOnResponse) {\n if(retryOnResponse) {\n retry(attempt, null, response);\n } else {\n resolve(response);\n }\n }).catch(reject);\n } catch (error) {\n reject(error);\n }\n } else {\n if (attempt < retries) {\n retry(attempt, null, response);\n } else {\n resolve(response);\n }\n }\n })\n .catch(function (error) {\n if (typeof retryOn === 'function') {\n try {\n // eslint-disable-next-line no-undef\n Promise.resolve(retryOn(attempt, error, null))\n .then(function (retryOnResponse) {\n if(retryOnResponse) {\n retry(attempt, error, null);\n } else {\n reject(error);\n }\n })\n .catch(function(error) {\n reject(error);\n });\n } catch(error) {\n reject(error);\n }\n } else if (attempt < retries) {\n retry(attempt, error, null);\n } else {\n reject(error);\n }\n });\n };\n\n function retry(attempt, error, response) {\n var delay = (typeof retryDelay === 'function') ?\n retryDelay(attempt, error, response) : retryDelay;\n setTimeout(function () {\n wrappedFetch(++attempt);\n }, delay);\n }\n\n wrappedFetch(0);\n });\n };\n };\n\n function isPositiveInteger(value) {\n return Number.isInteger(value) && value >= 0;\n }\n\n function ArgumentError(message) {\n this.name = 'ArgumentError';\n this.message = message;\n }\n\n return fetchRetry;\n\n}));\n", "import fetch_retry from 'fetch-retry'\nconst fetch = fetch_retry(globalThis.fetch, {\n retries: 10,\n retryDelay: attempts => attempts * 1000\n})\n\nexport interface TwitchToken {\n access_token: string\n expires_in: number\n obtainment_timestamp: number\n token_type: string\n user_id?: number\n scope?: Array\n refresh_token?: string\n login?: string\n client_id?: string\n}\n\nexport interface AuthCode {\n code: string\n scope: string\n}\n\nconst redirect_uri = location.origin + location.pathname\nconst proxy_uri = new URL('/oauth2/token', import.meta.url)\n\n/**\n * Timestamp and return the token\n * @param {TwitchToken} token \n * @returns {TwitchToken}\n */\nfunction stamp(token: TwitchToken): TwitchToken {\n token.obtainment_timestamp = Date.now()\n return token\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#client-credentials-grant-flow\n * @param {string} client_id \n * @returns {Promise}\n */\nexport function getAppToken(client_id: string): Promise {\n const searchParams = new URLSearchParams({\n client_id: client_id,\n grant_type: 'client_credentials'\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString(),\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n const token = await response.json()\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#implicit-grant-flow\n * @param {string} client_id \n * @param {Array|string} scopes \n * @returns {Promise}\n */\nexport function requestAccessToken(client_id: string, ...scopes: Array) {\n console.debug('requesting access token')\n const url = new URL('https://id.twitch.tv/oauth2/authorize')\n url.searchParams.append('response_type', 'token')\n url.searchParams.append('client_id', client_id)\n url.searchParams.append('scope', scopes.join(' '))\n location.assign(url + '&redirect_uri=' + redirect_uri)\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#get-the-user-to-authorize-your-app\n * @param {string} client_id \n * @param {Array|string} scopes \n * @returns {Promise}\n */\nexport function requestAuthCode(client_id: string, ...scopes: Array): Promise {\n console.debug('requesting authorization code')\n const url = new URL('https://id.twitch.tv/oauth2/authorize')\n url.searchParams.append('response_type', 'code')\n url.searchParams.append('client_id', client_id)\n url.searchParams.append('scope', scopes.join(' ').trim())\n location.assign(url + '&redirect_uri=' + redirect_uri)\n return new Promise(()=>{})\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#use-the-authorization-code-to-get-a-token\n * @param {string} client_id \n * @param {string} code \n * @returns {Promise}\n */\nexport function exchangeCode(client_id: string, code: string): Promise {\n console.debug('exchanging authorization code')\n const searchParams = new URLSearchParams({\n client_id: client_id,\n code: code,\n grant_type: 'authorization_code'\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString() + '&redirect_uri=' + redirect_uri,\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n const token = await response.json()\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/validate-tokens/#how-to-validate-a-token\n * @param {string} access_token \n * @returns {TwitchToken}\n */\nexport async function validateToken(access_token: string): Promise {\n console.debug('validating token')\n return fetch('https://id.twitch.tv/oauth2/validate', {\n headers: { authorization: 'OAuth ' + access_token }\n }).then(async response => {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n /** @type {TwitchToken} */\n const token: any = await response.json()\n token.access_token = access_token\n token.scope = token.scopes\n delete token.scopes\n token.token_type = 'bearer'\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/refresh-tokens/#how-to-use-a-refresh-token\n * @param {string} client_id \n * @param {string} refresh_token \n * @returns {Promise}\n */\nexport function refreshToken(client_id: string, refresh_token: string): Promise {\n console.debug('refreshing token')\n const searchParams = new URLSearchParams({\n client_id: client_id,\n grant_type: 'refresh_token',\n refresh_token: refresh_token\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString(),\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n return await response.json()\n })\n}\n\n/**\n * This function checks the url search parameters and hash for an auth code,\n * refresh token, access token, or error message, in that order,\n * and if it finds none of those, starts the auth code grant flow.\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow\n * @param {string} client_id \n * @returns {TwitchToken}\n */\nexport async function getUserToken(client_id: string, ...scopes): Promise {\n const token=await getUserTokenPassive(client_id, ...scopes)\n if(!token){\n return requestAuthCode(client_id, ...scopes)\n }\n return token\n}\n\n/**\n * This function checks the url search parameters and hash for an auth code,\n * refresh token, access token, or error message, in that order.\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow\n * @param {string} client_id \n * @returns {TwitchToken}\n */\nexport async function getUserTokenPassive(client_id: string, ...scopes): Promise{\n console.debug('scopes requested:',...scopes)\n const params = new URLSearchParams(location.search + '&' + location.hash.substring(1))\n if (params.has('code')) {\n const code = params.get('code')\n history.replaceState(null, '', redirect_uri)\n return exchangeCode(client_id, code)\n }\n if (params.has('refresh_token')) {\n return refreshToken(client_id, params.get('refresh_token'))\n }\n if (params.has('access_token')) {\n return validateToken(params.get('access_token'))\n }\n if (params.has('error')) {\n const error_message = params.get('error') + ': ' + params.get('error_description')\n history.replaceState(null, '', redirect_uri)\n throw new Error(error_message)\n }\n return null\n}\n\nexport default getUserToken", "import * as TwitchAuth from \"./TwitchAuth.ts\";\nimport { AccessTokenMaybeWithUserId, AuthProvider, AccessToken, AccessTokenWithUserId } from \"@twurple/auth\";\n\ntype Token = TwitchAuth.TwitchToken & AccessTokenMaybeWithUserId\n\nfunction getTwurpleProxy(token: TwitchAuth.TwitchToken): Token {\n return new Proxy(token, {\n get(target, name, receiver) {\n return target[name.toString().replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)]\n }\n }) as Token\n}\n\nfunction hasScopes(token: Token, ...scopes: string[]) {\n if (!token) {\n return false\n }\n if (!scopes) {\n return true\n }\n for (const scope of scopes) {\n if (!token.scope.includes(scope)) {\n return false\n }\n }\n return true\n}\n\nexport default class SugoiAuthProvider implements AuthProvider {\n\n #token: Token\n clientId: string;\n\n constructor(client_id: string) {\n this.clientId = client_id\n }\n\n #setToken = (token: Token) => {\n this.#token = token\n return token\n }\n\n async addUser(...scopes: string[]) {\n this.#token = await TwitchAuth.getUserToken(this.clientId, ...scopes).then(getTwurpleProxy).then(this.#setToken)\n return this.#token\n }\n\n async addUserForToken(token: TwitchAuth.TwitchToken) {\n if (token.refresh_token) {\n this.#token = await TwitchAuth.refreshToken(this.clientId, token.refresh_token).then(getTwurpleProxy).then(this.#setToken)\n return this.#token\n }\n this.#token = await TwitchAuth.validateToken(token.access_token).then(getTwurpleProxy).then(this.#setToken)\n return this.#token\n }\n\n removeUser() {\n this.#token = null\n }\n\n async getAccessTokenForUser(user: string | number, ...scopeSets: string[][]) {\n if ((!scopeSets[0]) && (this.#token)) {\n return this.#token as AccessTokenWithUserId\n }\n for (const scopes of scopeSets) {\n if (hasScopes(this.#token, ...scopes)) {\n return this.#token as AccessTokenWithUserId\n }\n }\n this.#token = await TwitchAuth.getUserTokenPassive(this.clientId, ...(scopeSets[0] || [])).then(getTwurpleProxy).then(this.#setToken)\n return this.#token as AccessTokenWithUserId\n }\n\n async getAnyAccessToken(user: string | number) {\n return this.#token || TwitchAuth.getAppToken(this.clientId).then(getTwurpleProxy)\n }\n\n getCurrentScopesForUser(user: string | number) {\n if (!this.#token || this.#token instanceof Promise) {\n return []\n }\n return this.#token.scope\n }\n\n async refreshAccessTokenForUser(user: string | number) {\n this.#token = await TwitchAuth.refreshToken(this.clientId, this.#token.refresh_token).then(this.#setToken)\n return this.#token as AccessTokenWithUserId\n }\n}"], "mappings": "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", "names": ["require_fetch_retry_umd", "__commonJSMin", "exports", "module", "global", "factory", "fetchRetry", "fetch", "defaults", "ArgumentError", "isPositiveInteger", "baseDefaults", "input", "init", "retries", "retryDelay", "retryOn", "resolve", "reject", "wrappedFetch", "attempt", "_input", "response", "retryOnResponse", "retry", "error", "delay", "value", "message", "import_fetch_retry", "fetch", "fetch_retry", "attempts", "redirect_uri", "proxy_uri", "stamp", "token", "getAppToken", "client_id", "searchParams", "response", "requestAuthCode", "client_id", "scopes", "url", "redirect_uri", "exchangeCode", "code", "searchParams", "fetch", "proxy_uri", "response", "token", "stamp", "validateToken", "access_token", "refreshToken", "refresh_token", "getUserToken", "getUserTokenPassive", "params", "error_message", "getTwurpleProxy", "token", "target", "name", "receiver", "letter", "hasScopes", "scopes", "scope", "_token", "_setToken", "SugoiAuthProvider", "client_id", "__privateAdd", "__privateSet", "getUserToken", "__privateGet", "refreshToken", "validateToken", "user", "scopeSets", "getUserTokenPassive", "getAppToken"] diff --git a/static/TwitchAuth.js.map b/static/TwitchAuth.js.map index c04a96f..70895d7 100644 --- a/static/TwitchAuth.js.map +++ b/static/TwitchAuth.js.map @@ -1,6 +1,6 @@ { "version": 3, - "sources": ["../node_modules/fetch-retry/dist/fetch-retry.umd.js", "TwitchAuth.ts"], + "sources": ["../node_modules/fetch-retry/dist/fetch-retry.umd.js", "../static_src/TwitchAuth.ts"], "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.fetchRetry = factory());\n})(this, (function () { 'use strict';\n\n var fetchRetry = function (fetch, defaults) {\n defaults = defaults || {};\n if (typeof fetch !== 'function') {\n throw new ArgumentError('fetch must be a function');\n }\n\n if (typeof defaults !== 'object') {\n throw new ArgumentError('defaults must be an object');\n }\n\n if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {\n throw new ArgumentError('retries must be a positive integer');\n }\n\n if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {\n throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');\n }\n\n if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {\n throw new ArgumentError('retryOn property expects an array or function');\n }\n\n var baseDefaults = {\n retries: 3,\n retryDelay: 1000,\n retryOn: [],\n };\n\n defaults = Object.assign(baseDefaults, defaults);\n\n return function fetchRetry(input, init) {\n var retries = defaults.retries;\n var retryDelay = defaults.retryDelay;\n var retryOn = defaults.retryOn;\n\n if (init && init.retries !== undefined) {\n if (isPositiveInteger(init.retries)) {\n retries = init.retries;\n } else {\n throw new ArgumentError('retries must be a positive integer');\n }\n }\n\n if (init && init.retryDelay !== undefined) {\n if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {\n retryDelay = init.retryDelay;\n } else {\n throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');\n }\n }\n\n if (init && init.retryOn) {\n if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {\n retryOn = init.retryOn;\n } else {\n throw new ArgumentError('retryOn property expects an array or function');\n }\n }\n\n // eslint-disable-next-line no-undef\n return new Promise(function (resolve, reject) {\n var wrappedFetch = function (attempt) {\n // As of node 18, this is no longer needed since node comes with native support for fetch:\n /* istanbul ignore next */\n var _input =\n typeof Request !== 'undefined' && input instanceof Request\n ? input.clone()\n : input;\n fetch(_input, init)\n .then(function (response) {\n if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {\n resolve(response);\n } else if (typeof retryOn === 'function') {\n try {\n // eslint-disable-next-line no-undef\n return Promise.resolve(retryOn(attempt, null, response))\n .then(function (retryOnResponse) {\n if(retryOnResponse) {\n retry(attempt, null, response);\n } else {\n resolve(response);\n }\n }).catch(reject);\n } catch (error) {\n reject(error);\n }\n } else {\n if (attempt < retries) {\n retry(attempt, null, response);\n } else {\n resolve(response);\n }\n }\n })\n .catch(function (error) {\n if (typeof retryOn === 'function') {\n try {\n // eslint-disable-next-line no-undef\n Promise.resolve(retryOn(attempt, error, null))\n .then(function (retryOnResponse) {\n if(retryOnResponse) {\n retry(attempt, error, null);\n } else {\n reject(error);\n }\n })\n .catch(function(error) {\n reject(error);\n });\n } catch(error) {\n reject(error);\n }\n } else if (attempt < retries) {\n retry(attempt, error, null);\n } else {\n reject(error);\n }\n });\n };\n\n function retry(attempt, error, response) {\n var delay = (typeof retryDelay === 'function') ?\n retryDelay(attempt, error, response) : retryDelay;\n setTimeout(function () {\n wrappedFetch(++attempt);\n }, delay);\n }\n\n wrappedFetch(0);\n });\n };\n };\n\n function isPositiveInteger(value) {\n return Number.isInteger(value) && value >= 0;\n }\n\n function ArgumentError(message) {\n this.name = 'ArgumentError';\n this.message = message;\n }\n\n return fetchRetry;\n\n}));\n", "import fetch_retry from 'fetch-retry'\nconst fetch = fetch_retry(globalThis.fetch, {\n retries: 10,\n retryDelay: attempts => attempts * 1000\n})\n\nexport interface TwitchToken {\n access_token: string\n expires_in: number\n obtainment_timestamp: number\n token_type: string\n user_id?: number\n scope?: Array\n refresh_token?: string\n login?: string\n client_id?: string\n}\n\nexport interface AuthCode {\n code: string\n scope: string\n}\n\nconst redirect_uri = location.origin + location.pathname\nconst proxy_uri = new URL('/oauth2/token', import.meta.url)\n\n/**\n * Timestamp and return the token\n * @param {TwitchToken} token \n * @returns {TwitchToken}\n */\nfunction stamp(token: TwitchToken): TwitchToken {\n token.obtainment_timestamp = Date.now()\n return token\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#client-credentials-grant-flow\n * @param {string} client_id \n * @returns {Promise}\n */\nexport function getAppToken(client_id: string): Promise {\n const searchParams = new URLSearchParams({\n client_id: client_id,\n grant_type: 'client_credentials'\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString(),\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n const token = await response.json()\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#implicit-grant-flow\n * @param {string} client_id \n * @param {Array|string} scopes \n * @returns {Promise}\n */\nexport function requestAccessToken(client_id: string, ...scopes: Array) {\n console.debug('requesting access token')\n const url = new URL('https://id.twitch.tv/oauth2/authorize')\n url.searchParams.append('response_type', 'token')\n url.searchParams.append('client_id', client_id)\n url.searchParams.append('scope', scopes.join(' '))\n location.assign(url + '&redirect_uri=' + redirect_uri)\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#get-the-user-to-authorize-your-app\n * @param {string} client_id \n * @param {Array|string} scopes \n * @returns {Promise}\n */\nexport function requestAuthCode(client_id: string, ...scopes: Array): Promise {\n console.debug('requesting authorization code')\n const url = new URL('https://id.twitch.tv/oauth2/authorize')\n url.searchParams.append('response_type', 'code')\n url.searchParams.append('client_id', client_id)\n url.searchParams.append('scope', scopes.join(' ').trim())\n location.assign(url + '&redirect_uri=' + redirect_uri)\n return new Promise(()=>{})\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#use-the-authorization-code-to-get-a-token\n * @param {string} client_id \n * @param {string} code \n * @returns {Promise}\n */\nexport function exchangeCode(client_id: string, code: string): Promise {\n console.debug('exchanging authorization code')\n const searchParams = new URLSearchParams({\n client_id: client_id,\n code: code,\n grant_type: 'authorization_code'\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString() + '&redirect_uri=' + redirect_uri,\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n const token = await response.json()\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/validate-tokens/#how-to-validate-a-token\n * @param {string} access_token \n * @returns {TwitchToken}\n */\nexport async function validateToken(access_token: string): Promise {\n console.debug('validating token')\n return fetch('https://id.twitch.tv/oauth2/validate', {\n headers: { authorization: 'OAuth ' + access_token }\n }).then(async response => {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n /** @type {TwitchToken} */\n const token: any = await response.json()\n token.access_token = access_token\n token.scope = token.scopes\n delete token.scopes\n token.token_type = 'bearer'\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/refresh-tokens/#how-to-use-a-refresh-token\n * @param {string} client_id \n * @param {string} refresh_token \n * @returns {Promise}\n */\nexport function refreshToken(client_id: string, refresh_token: string): Promise {\n console.debug('refreshing token')\n const searchParams = new URLSearchParams({\n client_id: client_id,\n grant_type: 'refresh_token',\n refresh_token: refresh_token\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString(),\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n return await response.json()\n })\n}\n\n/**\n * This function checks the url search parameters and hash for an auth code,\n * refresh token, access token, or error message, in that order,\n * and if it finds none of those, starts the auth code grant flow.\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow\n * @param {string} client_id \n * @returns {TwitchToken}\n */\nexport async function getUserToken(client_id: string, ...scopes): Promise {\n const token=await getUserTokenPassive(client_id, ...scopes)\n if(!token){\n return requestAuthCode(client_id, ...scopes)\n }\n return token\n}\n\n/**\n * This function checks the url search parameters and hash for an auth code,\n * refresh token, access token, or error message, in that order.\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow\n * @param {string} client_id \n * @returns {TwitchToken}\n */\nexport async function getUserTokenPassive(client_id: string, ...scopes): Promise{\n console.debug('scopes requested:',...scopes)\n const params = new URLSearchParams(location.search + '&' + location.hash.substring(1))\n if (params.has('code')) {\n const code = params.get('code')\n history.replaceState(null, '', redirect_uri)\n return exchangeCode(client_id, code)\n }\n if (params.has('refresh_token')) {\n return refreshToken(client_id, params.get('refresh_token'))\n }\n if (params.has('access_token')) {\n return validateToken(params.get('access_token'))\n }\n if (params.has('error')) {\n const error_message = params.get('error') + ': ' + params.get('error_description')\n history.replaceState(null, '', redirect_uri)\n throw new Error(error_message)\n }\n return null\n}\n\nexport default getUserToken"], "mappings": "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", "names": ["require_fetch_retry_umd", "__commonJSMin", "exports", "module", "global", "factory", "fetchRetry", "fetch", "defaults", "ArgumentError", "isPositiveInteger", "baseDefaults", "input", "init", "retries", "retryDelay", "retryOn", "resolve", "reject", "wrappedFetch", "attempt", "_input", "response", "retryOnResponse", "retry", "error", "delay", "value", "message", "import_fetch_retry", "fetch", "fetch_retry", "attempts", "redirect_uri", "proxy_uri", "stamp", "token", "getAppToken", "client_id", "searchParams", "response", "requestAccessToken", "scopes", "url", "requestAuthCode", "exchangeCode", "code", "validateToken", "access_token", "refreshToken", "refresh_token", "getUserToken", "getUserTokenPassive", "params", "error_message", "TwitchAuth_default"] diff --git a/static/WebStorage.js.map b/static/WebStorage.js.map index b779028..2193f42 100644 --- a/static/WebStorage.js.map +++ b/static/WebStorage.js.map @@ -1,6 +1,6 @@ { "version": 3, - "sources": ["WebStorage.ts"], + "sources": ["../static_src/WebStorage.ts"], "sourcesContent": ["/**\n * @callback fetch\n * @param {RequestInfo} resource\n * @param {RequestInit} options\n * @returns {Promise}\n */\n\nexport default class WebStorage {\n\n #origin = new URL(import.meta.url).origin\n #auth_provider: import('@twurple/auth').AuthProvider = null;\n #cache: Cache = null\n #fetch: typeof globalThis.fetch = null\n\n /**\n * Creates a fetch request wrapper that returns cached responses when the server can't be reached.\n * When only a path is provided, the origin defaults to the same origin this module was loaded from.\n * When the origin matches this script, authorization headers are added automatically.\n * You can also use this for GET requests to any orgigin, but other methods may have unknown behavior.\n * @param {import('@twurple/auth').AuthProvider} auth_provider used to add the authentication header to requests for web storage\n * @param {fetch} fetch defaults to `globalThis.fetch`, allows you to further customize fetch behavior via chaining, for example with `fetch-retry`\n */\n constructor(auth_provider: import('@twurple/auth').AuthProvider, fetch: typeof globalThis.fetch = (resource,options)=>{return globalThis.fetch(resource,options)}) {\n this.#fetch = fetch\n this.#auth_provider = auth_provider\n auth_provider.getAccessTokenForUser(undefined)\n .then(token => caches.open(token.userId + '/' + auth_provider.clientId))\n .then(cache => this.#cache = cache)\n }\n\n /**\n * \n * @param {String | URL} resource \n * @param {RequestInit} options \n */\n async fetch(resource: string | URL, options: RequestInit={}) {\n resource = new URL(resource, this.#origin)\n if (resource.origin == this.#origin) {\n const token = await this.#auth_provider.getAccessTokenForUser(undefined)\n if (!options.headers) {\n options.headers = {}\n }\n options.headers['authorization'] = 'OAuth ' + token.accessToken\n }\n if ('method' in options) {\n switch (options.method) {\n case 'PUT':\n case 'POST': {\n const response = await this.#fetch(resource, options)\n if (!response.ok) {\n return response\n }\n const blob = await new Request(resource, options).blob()\n this.#cache.put(resource, new Response(blob))\n return response\n }\n case 'DELETE': {\n const response = await this.#fetch(resource, options)\n if (!response.ok) {\n return response\n }\n this.#cache.delete(resource)\n return response\n }\n }\n }\n return this.#fetch(resource, options)\n .then(async response => {\n if (response.status >= 500) {\n throw new Error(response.statusText + '\\n' + await response.text())\n }\n this.#cache.put(resource, response.clone())\n return response\n }).catch(error => {\n console.warn(error)\n return this.#cache.match(resource)\n }\n )\n }\n}"], "mappings": "2UAAA,IAAAA,EAAAC,EAAAC,EAAAC,EAOqBC,EAArB,KAAgC,CAe5B,YAAYC,EAAqDC,EAAiC,CAACC,EAASC,IAAkB,WAAW,MAAMD,EAASC,CAAO,EAAI,CAbnKC,EAAA,KAAAT,EAAU,IAAI,IAAI,YAAY,GAAG,EAAE,QACnCS,EAAA,KAAAR,EAAuD,MACvDQ,EAAA,KAAAP,EAAgB,MAChBO,EAAA,KAAAN,EAAkC,MAW9BO,EAAA,KAAKP,EAASG,GACdI,EAAA,KAAKT,EAAiBI,GACtBA,EAAc,sBAAsB,MAAS,EACxC,KAAKM,GAAS,OAAO,KAAKA,EAAM,OAAS,IAAMN,EAAc,QAAQ,CAAC,EACtE,KAAKO,GAASF,EAAA,KAAKR,EAASU,EAAK,CAC1C,CAOA,MAAM,MAAML,EAAwBC,EAAqB,CAAC,EAAG,CAEzD,GADAD,EAAW,IAAI,IAAIA,EAAUM,EAAA,KAAKb,EAAO,EACrCO,EAAS,QAAUM,EAAA,KAAKb,GAAS,CACjC,IAAMW,EAAQ,MAAME,EAAA,KAAKZ,GAAe,sBAAsB,MAAS,EAClEO,EAAQ,UACTA,EAAQ,QAAU,CAAC,GAEvBA,EAAQ,QAAQ,cAAmB,SAAWG,EAAM,WACxD,CACA,GAAI,WAAYH,EACZ,OAAQA,EAAQ,OAAQ,CACpB,IAAK,MACL,IAAK,OAAQ,CACT,IAAMM,EAAW,MAAMD,EAAA,KAAKV,GAAL,UAAYI,EAAUC,GAC7C,GAAI,CAACM,EAAS,GACV,OAAOA,EAEX,IAAMC,EAAO,MAAM,IAAI,QAAQR,EAAUC,CAAO,EAAE,KAAK,EACvD,OAAAK,EAAA,KAAKX,GAAO,IAAIK,EAAU,IAAI,SAASQ,CAAI,CAAC,EACrCD,CACX,CACA,IAAK,SAAU,CACX,IAAMA,EAAW,MAAMD,EAAA,KAAKV,GAAL,UAAYI,EAAUC,GAC7C,OAAKM,EAAS,IAGdD,EAAA,KAAKX,GAAO,OAAOK,CAAQ,EACpBO,CACX,CACJ,CAEJ,OAAOD,EAAA,KAAKV,GAAL,UAAYI,EAAUC,GACxB,KAAK,MAAMM,GAAY,CACpB,GAAIA,EAAS,QAAU,IACnB,MAAM,IAAI,MAAMA,EAAS,WAAa;AAAA,EAAO,MAAMA,EAAS,KAAK,CAAC,EAEtE,OAAAD,EAAA,KAAKX,GAAO,IAAIK,EAAUO,EAAS,MAAM,CAAC,EACnCA,CACX,CAAC,EAAE,MAAME,IACL,QAAQ,KAAKA,CAAK,EACXH,EAAA,KAAKX,GAAO,MAAMK,CAAQ,EAEzC,CACJ,CACJ,EAtEIP,EAAA,YACAC,EAAA,YACAC,EAAA,YACAC,EAAA", "names": ["_origin", "_auth_provider", "_cache", "_fetch", "WebStorage", "auth_provider", "fetch", "resource", "options", "__privateAdd", "__privateSet", "token", "cache", "__privateGet", "response", "blob", "error"] diff --git a/static/tba.js.map b/static/tba.js.map index 0f5e31c..9c4ee3d 100644 --- a/static/tba.js.map +++ b/static/tba.js.map @@ -1,6 +1,6 @@ { "version": 3, - "sources": ["../node_modules/fetch-retry/dist/fetch-retry.umd.js", "TwitchAuth.ts", "tba.ts"], + "sources": ["../node_modules/fetch-retry/dist/fetch-retry.umd.js", "../static_src/TwitchAuth.ts", "../static_src/tba.ts"], "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.fetchRetry = factory());\n})(this, (function () { 'use strict';\n\n var fetchRetry = function (fetch, defaults) {\n defaults = defaults || {};\n if (typeof fetch !== 'function') {\n throw new ArgumentError('fetch must be a function');\n }\n\n if (typeof defaults !== 'object') {\n throw new ArgumentError('defaults must be an object');\n }\n\n if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {\n throw new ArgumentError('retries must be a positive integer');\n }\n\n if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {\n throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');\n }\n\n if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {\n throw new ArgumentError('retryOn property expects an array or function');\n }\n\n var baseDefaults = {\n retries: 3,\n retryDelay: 1000,\n retryOn: [],\n };\n\n defaults = Object.assign(baseDefaults, defaults);\n\n return function fetchRetry(input, init) {\n var retries = defaults.retries;\n var retryDelay = defaults.retryDelay;\n var retryOn = defaults.retryOn;\n\n if (init && init.retries !== undefined) {\n if (isPositiveInteger(init.retries)) {\n retries = init.retries;\n } else {\n throw new ArgumentError('retries must be a positive integer');\n }\n }\n\n if (init && init.retryDelay !== undefined) {\n if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {\n retryDelay = init.retryDelay;\n } else {\n throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');\n }\n }\n\n if (init && init.retryOn) {\n if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {\n retryOn = init.retryOn;\n } else {\n throw new ArgumentError('retryOn property expects an array or function');\n }\n }\n\n // eslint-disable-next-line no-undef\n return new Promise(function (resolve, reject) {\n var wrappedFetch = function (attempt) {\n // As of node 18, this is no longer needed since node comes with native support for fetch:\n /* istanbul ignore next */\n var _input =\n typeof Request !== 'undefined' && input instanceof Request\n ? input.clone()\n : input;\n fetch(_input, init)\n .then(function (response) {\n if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {\n resolve(response);\n } else if (typeof retryOn === 'function') {\n try {\n // eslint-disable-next-line no-undef\n return Promise.resolve(retryOn(attempt, null, response))\n .then(function (retryOnResponse) {\n if(retryOnResponse) {\n retry(attempt, null, response);\n } else {\n resolve(response);\n }\n }).catch(reject);\n } catch (error) {\n reject(error);\n }\n } else {\n if (attempt < retries) {\n retry(attempt, null, response);\n } else {\n resolve(response);\n }\n }\n })\n .catch(function (error) {\n if (typeof retryOn === 'function') {\n try {\n // eslint-disable-next-line no-undef\n Promise.resolve(retryOn(attempt, error, null))\n .then(function (retryOnResponse) {\n if(retryOnResponse) {\n retry(attempt, error, null);\n } else {\n reject(error);\n }\n })\n .catch(function(error) {\n reject(error);\n });\n } catch(error) {\n reject(error);\n }\n } else if (attempt < retries) {\n retry(attempt, error, null);\n } else {\n reject(error);\n }\n });\n };\n\n function retry(attempt, error, response) {\n var delay = (typeof retryDelay === 'function') ?\n retryDelay(attempt, error, response) : retryDelay;\n setTimeout(function () {\n wrappedFetch(++attempt);\n }, delay);\n }\n\n wrappedFetch(0);\n });\n };\n };\n\n function isPositiveInteger(value) {\n return Number.isInteger(value) && value >= 0;\n }\n\n function ArgumentError(message) {\n this.name = 'ArgumentError';\n this.message = message;\n }\n\n return fetchRetry;\n\n}));\n", "import fetch_retry from 'fetch-retry'\nconst fetch = fetch_retry(globalThis.fetch, {\n retries: 10,\n retryDelay: attempts => attempts * 1000\n})\n\nexport interface TwitchToken {\n access_token: string\n expires_in: number\n obtainment_timestamp: number\n token_type: string\n user_id?: number\n scope?: Array\n refresh_token?: string\n login?: string\n client_id?: string\n}\n\nexport interface AuthCode {\n code: string\n scope: string\n}\n\nconst redirect_uri = location.origin + location.pathname\nconst proxy_uri = new URL('/oauth2/token', import.meta.url)\n\n/**\n * Timestamp and return the token\n * @param {TwitchToken} token \n * @returns {TwitchToken}\n */\nfunction stamp(token: TwitchToken): TwitchToken {\n token.obtainment_timestamp = Date.now()\n return token\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#client-credentials-grant-flow\n * @param {string} client_id \n * @returns {Promise}\n */\nexport function getAppToken(client_id: string): Promise {\n const searchParams = new URLSearchParams({\n client_id: client_id,\n grant_type: 'client_credentials'\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString(),\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n const token = await response.json()\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#implicit-grant-flow\n * @param {string} client_id \n * @param {Array|string} scopes \n * @returns {Promise}\n */\nexport function requestAccessToken(client_id: string, ...scopes: Array) {\n console.debug('requesting access token')\n const url = new URL('https://id.twitch.tv/oauth2/authorize')\n url.searchParams.append('response_type', 'token')\n url.searchParams.append('client_id', client_id)\n url.searchParams.append('scope', scopes.join(' '))\n location.assign(url + '&redirect_uri=' + redirect_uri)\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#get-the-user-to-authorize-your-app\n * @param {string} client_id \n * @param {Array|string} scopes \n * @returns {Promise}\n */\nexport function requestAuthCode(client_id: string, ...scopes: Array): Promise {\n console.debug('requesting authorization code')\n const url = new URL('https://id.twitch.tv/oauth2/authorize')\n url.searchParams.append('response_type', 'code')\n url.searchParams.append('client_id', client_id)\n url.searchParams.append('scope', scopes.join(' ').trim())\n location.assign(url + '&redirect_uri=' + redirect_uri)\n return new Promise(()=>{})\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#use-the-authorization-code-to-get-a-token\n * @param {string} client_id \n * @param {string} code \n * @returns {Promise}\n */\nexport function exchangeCode(client_id: string, code: string): Promise {\n console.debug('exchanging authorization code')\n const searchParams = new URLSearchParams({\n client_id: client_id,\n code: code,\n grant_type: 'authorization_code'\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString() + '&redirect_uri=' + redirect_uri,\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n const token = await response.json()\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/validate-tokens/#how-to-validate-a-token\n * @param {string} access_token \n * @returns {TwitchToken}\n */\nexport async function validateToken(access_token: string): Promise {\n console.debug('validating token')\n return fetch('https://id.twitch.tv/oauth2/validate', {\n headers: { authorization: 'OAuth ' + access_token }\n }).then(async response => {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n /** @type {TwitchToken} */\n const token: any = await response.json()\n token.access_token = access_token\n token.scope = token.scopes\n delete token.scopes\n token.token_type = 'bearer'\n return stamp(token)\n })\n}\n\n/**\n * https://dev.twitch.tv/docs/authentication/refresh-tokens/#how-to-use-a-refresh-token\n * @param {string} client_id \n * @param {string} refresh_token \n * @returns {Promise}\n */\nexport function refreshToken(client_id: string, refresh_token: string): Promise {\n console.debug('refreshing token')\n const searchParams = new URLSearchParams({\n client_id: client_id,\n grant_type: 'refresh_token',\n refresh_token: refresh_token\n })\n return fetch(proxy_uri, {\n method: 'POST',\n body: searchParams.toString(),\n headers: { 'content-type': 'application/x-www-form-urlencoded' }\n }).then(async function (response) {\n if (!response.ok) {\n throw new Error(await response.text())\n }\n return await response.json()\n })\n}\n\n/**\n * This function checks the url search parameters and hash for an auth code,\n * refresh token, access token, or error message, in that order,\n * and if it finds none of those, starts the auth code grant flow.\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow\n * @param {string} client_id \n * @returns {TwitchToken}\n */\nexport async function getUserToken(client_id: string, ...scopes): Promise {\n const token=await getUserTokenPassive(client_id, ...scopes)\n if(!token){\n return requestAuthCode(client_id, ...scopes)\n }\n return token\n}\n\n/**\n * This function checks the url search parameters and hash for an auth code,\n * refresh token, access token, or error message, in that order.\n * https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow\n * @param {string} client_id \n * @returns {TwitchToken}\n */\nexport async function getUserTokenPassive(client_id: string, ...scopes): Promise{\n console.debug('scopes requested:',...scopes)\n const params = new URLSearchParams(location.search + '&' + location.hash.substring(1))\n if (params.has('code')) {\n const code = params.get('code')\n history.replaceState(null, '', redirect_uri)\n return exchangeCode(client_id, code)\n }\n if (params.has('refresh_token')) {\n return refreshToken(client_id, params.get('refresh_token'))\n }\n if (params.has('access_token')) {\n return validateToken(params.get('access_token'))\n }\n if (params.has('error')) {\n const error_message = params.get('error') + ': ' + params.get('error_description')\n history.replaceState(null, '', redirect_uri)\n throw new Error(error_message)\n }\n return null\n}\n\nexport default getUserToken", "import * as TwitchAuth from './TwitchAuth.ts'\n\ninterface AuthHeaders {\n 'Authorization': string,\n 'Client-ID': string\n}\n\ninterface Token extends TwitchAuth.TwitchToken {\n auth_headers: AuthHeaders\n}\n\nlet token: Token=null;\n\nexport function request_auth(client_id: string,scope: string,redirect_uri=location.origin+location.pathname){\n return TwitchAuth.requestAuthCode(client_id,...scope.split(' '))\n}\n\nexport function get_url_params(){\n return Object.fromEntries(new URLSearchParams(location.search))\n}\n\nexport async function fetch_tokens(client_id: string,code: string,redirect_uri=location.origin+location.pathname): Promise{\n client_id=client_id\n token=await TwitchAuth.exchangeCode(client_id,code) as Token\n token.client_id=client_id\n return token\n}\n\nexport function get_headers(tokens: Token): AuthHeaders{\n return {\n 'Authorization':'Bearer '+tokens.access_token,\n 'Client-ID':tokens.client_id\n }\n}\n\nexport async function validate_tokens(tokens: Token): Promise{\n const validation=await TwitchAuth.validateToken(tokens.access_token)\n Object.assign(tokens,validation)\n tokens.scope=validation.scope\n tokens.auth_headers=get_headers(tokens)\n token=tokens\n return token\n}\n\nexport function set_local_tokens(client_id: string,tokens: Token){\n token=tokens\n return token\n}\n\nexport function get_local_tokens(client_id: string){\n return token\n}\n\nexport async function refresh_tokens(client_id: string,refresh_token: string){\n token=await TwitchAuth.refreshToken(client_id,refresh_token) as Token\n return token\n}\n\nexport function set_refresh_timeout(client_id: string,tokens: Token){\n return setTimeout(()=>{\n TwitchAuth.refreshToken(client_id,tokens.refresh_token)\n .then(new_tokens=>Object.assign(tokens,new_tokens))\n },tokens.expires_in*999)\n}\n\nexport async function get_tokens(client_id: string,scope='',redirect_uri=location.origin+location.pathname,auth_return=false){\n token=await TwitchAuth.getUserToken(client_id,...scope.split(' ')).then(validate_tokens)\n set_refresh_timeout(client_id,token)\n return token\n}\n\nexport default get_tokens"], "mappings": "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", "names": ["require_fetch_retry_umd", "__commonJSMin", "exports", "module", "global", "factory", "fetchRetry", "fetch", "defaults", "ArgumentError", "isPositiveInteger", "baseDefaults", "input", "init", "retries", "retryDelay", "retryOn", "resolve", "reject", "wrappedFetch", "attempt", "_input", "response", "retryOnResponse", "retry", "error", "delay", "value", "message", "import_fetch_retry", "fetch", "fetch_retry", "attempts", "redirect_uri", "proxy_uri", "stamp", "token", "requestAuthCode", "client_id", "scopes", "url", "redirect_uri", "exchangeCode", "code", "searchParams", "fetch", "proxy_uri", "response", "token", "stamp", "validateToken", "access_token", "refreshToken", "refresh_token", "getUserToken", "getUserTokenPassive", "params", "error_message", "token", "request_auth", "client_id", "scope", "redirect_uri", "requestAuthCode", "get_url_params", "fetch_tokens", "code", "exchangeCode", "get_headers", "tokens", "validate_tokens", "validation", "validateToken", "set_local_tokens", "get_local_tokens", "refresh_tokens", "refresh_token", "refreshToken", "set_refresh_timeout", "new_tokens", "get_tokens", "auth_return", "getUserToken", "tba_default"] diff --git a/wrangler.jsonc b/wrangler.jsonc index 96d1ca8..7127682 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -8,6 +8,7 @@ "main": "src/index.ts", "compatibility_date": "2025-10-14", "workers_dev": false, + "preview_urls": false, "compatibility_flags": [ "global_fetch_strictly_public" ],