diff --git a/static/WebStorage.mjs b/static/WebStorage.mjs index cd3a351..452ebef 100644 --- a/static/WebStorage.mjs +++ b/static/WebStorage.mjs @@ -1,16 +1,30 @@ +/** + * @callback fetch + * @param {RequestInfo} resource + * @param {RequestInit} options + * @returns {Promise} + */ + export default class WebStorage { - #origin=new URL(import.meta.url).origin + #origin = new URL(import.meta.url).origin /** @type {import('@twurple/auth').AuthProvider} */ #auth_provider = null; /** @type {Cache} */ #cache = null + /** @type {fetch} */ + #fetch = null /** - * - * @param {import('@twurple/auth').AuthProvider} auth_provider + * Creates a fetch request wrapper that returns cached responses when the server can't be reached. + * When only a path is provided, the origin defaults to the same origin this module was loaded from. + * When the origin matches this script, authorization headers are added automatically. + * You can also use this for GET requests to any orgigin, but other methods may have unknown behavior. + * @param {import('@twurple/auth').AuthProvider} auth_provider used to add the authentication header to requests for web storage + * @param {fetch} fetch defaults to `globalThis.fetch`, allows you to further customize fetch behavior via chaining, for example with `fetch-retry` */ - constructor(auth_provider) { + constructor(auth_provider, fetch = globalThis.fetch) { + this.#fetch = fetch this.#auth_provider = auth_provider auth_provider.getAccessTokenForUser() .then(token => caches.open(token.userId + '/' + auth_provider.clientId)) @@ -19,21 +33,23 @@ export default class WebStorage { /** * - * @param {String} resource + * @param {String | URL} resource * @param {RequestInit} options */ async fetch(resource, options) { - const token = await this.#auth_provider.getAccessTokenForUser() - if (!options.headers) { - options.headers = {} - } - options.headers['authorization'] = 'OAuth ' + token.accessToken resource = new URL(resource, this.#origin) + if (resource.origin == this.#origin) { + const token = await this.#auth_provider.getAccessTokenForUser() + if (!options.headers) { + options.headers = {} + } + options.headers['authorization'] = 'OAuth ' + token.accessToken + } if ('method' in options) { switch (options.method) { case 'PUT': case 'POST': { - const response = await fetch(resource, options) + const response = await this.#fetch(resource, options) if (!response.ok) { return response } @@ -42,7 +58,7 @@ export default class WebStorage { return response } case 'DELETE': { - const response = await fetch(resource, options) + const response = await this.#fetch(resource, options) if (!response.ok) { return response } @@ -51,7 +67,7 @@ export default class WebStorage { } } } - return fetch(resource, options).then( + return this.#fetch(resource, options).then( response => { this.#cache.put(resource, response) return response