UNPKG

@joouis/msal-react-utility

Version:

The utility package for @azure/msal-react.

238 lines (226 loc) 7.87 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { RequestInProgressError: () => RequestInProgressError, TokenType: () => TokenType, getResponseData: () => getResponseData, sleep: () => sleep, useEventCallback: () => useEventCallback, useFetchWithStatus: () => useFetchWithStatus, useFetchWithToken: () => useFetchWithToken, useGetToken: () => useGetToken }); module.exports = __toCommonJS(src_exports); // src/hooks/useEventCallback.ts var import_react = require("react"); function useEventCallback(handler) { const handlerRef = (0, import_react.useRef)(handler); (0, import_react.useLayoutEffect)(() => { handlerRef.current = handler; }); return (0, import_react.useCallback)((...args) => { const handle = handlerRef.current; return handle(...args); }, []); } // src/hooks/useFetchWithStatus.ts var import_react4 = __toESM(require("react"), 1); // src/hooks/useFetchWithToken.ts var import_react3 = require("react"); // src/hooks/useGetToken.ts var import_react2 = require("react"); var import_msal_react = require("@azure/msal-react"); var import_msal_browser = require("@azure/msal-browser"); // src/utilities/sleep.ts var sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // src/inteface.ts var TokenType = /* @__PURE__ */ ((TokenType2) => { TokenType2["id"] = "id"; TokenType2["access"] = "access"; return TokenType2; })(TokenType || {}); var RequestInProgressError = class extends Error { constructor() { super("Request is in progress!"); } }; // src/hooks/useGetToken.ts var useGetToken = (defaultRequestConfigs) => { const { instance, inProgress, accounts } = (0, import_msal_react.useMsal)(); const inProgressRef = (0, import_react2.useRef)(inProgress); const account = accounts[0]; (0, import_react2.useEffect)(() => { inProgressRef.current = inProgress; }, [inProgress]); const getToken = useEventCallback(async (opts) => { const { tokenType = "access" /* access */, requestConfigs } = opts || {}; while (inProgressRef.current !== import_msal_browser.InteractionStatus.None) { await sleep(100); } const configs = { scopes: ["User.Read"], prompt: "select_account", ...defaultRequestConfigs, ...requestConfigs }; try { const activeAccount = instance.getActiveAccount() || account; if (!activeAccount) { await instance.loginRedirect(); } const resp = await instance.acquireTokenSilent({ account: activeAccount, ...configs }); if (tokenType === "access") { return resp.accessToken; } if (!resp.idToken) { throw new Error("ID token is not available"); } const idTokenExp = resp.idTokenClaims.exp; if (resp.fromCache && idTokenExp * 1e3 - Date.now() < 2 * 60 * 1e3) { return await getToken({ tokenType: "id" /* id */, requestConfigs: { ...configs, forceRefresh: true } }); } return resp.idToken; } catch (error) { console.error(`[getToken] ${error}`); if (error instanceof import_msal_browser.InteractionRequiredAuthError) { await instance.acquireTokenRedirect(configs); } else if (error instanceof import_msal_browser.BrowserAuthError && error.errorCode === import_msal_browser.BrowserAuthErrorCodes.interactionInProgress) { await sleep(12e4); } else { throw error; } } }); return getToken; }; // src/hooks/useFetchWithToken.ts var useFetchWithToken = (tokenRequestConfigs) => { const getToken = useGetToken(tokenRequestConfigs); return (0, import_react3.useCallback)( async (input, init, getTokenOpts) => { try { const token = await getToken(getTokenOpts); if (!token) { throw new Error("Failed to fetch token"); } return fetch(input, { ...init, headers: { Authorization: `Bearer ${token}`, // User can override token ...init?.headers } }); } catch (error) { console.error(`[useFetchWithToken] ${error}`); const { name, message } = error; return new Response(name, { status: 401, statusText: message }); } }, [getToken] ); }; // src/utilities/getResponseData.ts var getResponseData = async (response) => { let data; const contentType = response.headers.get("Content-Type") || ""; if (contentType.includes("application/json")) { data = await response.json(); } else if (contentType.includes("text/")) { data = await response.text(); } else if (contentType.includes("application/octet-stream")) { data = await response.arrayBuffer(); } else if (contentType.includes("application/xml") || contentType.includes("text/xml")) { data = await response.text(); } else if (contentType.startsWith("image/") || contentType.startsWith("video/") || contentType.startsWith("audio/") || contentType.includes("application/pdf")) { data = await response.blob(); } else { try { data = await response.json(); } catch (e) { data = await response.text(); } } return data; }; // src/hooks/useFetchWithStatus.ts var useFetchWithStatus = (input, init) => { const [isLoading, setIsLoading] = import_react4.default.useState(false); const isLoadingRef = import_react4.default.useRef(false); const fetchWithToken = useFetchWithToken(); const _fetch = useEventCallback(async (payload, getTokenOpts) => { if (isLoadingRef.current) { throw new RequestInProgressError(); } setIsLoading(true); isLoadingRef.current = true; const requestInit = !init && !payload ? void 0 : { ...init, ...payload }; try { const response = await fetchWithToken(input, requestInit, getTokenOpts); if (!response.ok) { throw new Error(`Failed to fetch data: ${response.statusText}`, { cause: response }); } const data = await getResponseData(response); return data; } catch (error) { throw error; } finally { setIsLoading(false); isLoadingRef.current = false; } }); return { isLoading, _fetch }; }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { RequestInProgressError, TokenType, getResponseData, sleep, useEventCallback, useFetchWithStatus, useFetchWithToken, useGetToken });