All files / stores useTokenStore.ts

88.23% Statements 30/34
66.66% Branches 6/9
80% Functions 4/5
88.23% Lines 30/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 671x 1x 1x                     1x 1x 1x 2x 2x           2x 1x 1x             2x 1x 1x 1x 1x 1x           2x     2x 1x 1x 1x             1x 2x 2x     2x 2x 1x 1x 1x  
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
import { TOKEN_STORE_IDENTIFIER, TokenStore } from "~/types/TokenStore";
 
/**
 * A Zustand store for managing the authentication token state of the application.
 * The store persists the token state in localStorage.
 *
 * @example
 * ```typescript
 * const token = useTokenStore((state) => state.getToken());
 * ```
 */
export const useTokenStore = create<TokenStore>()(
	persist(
		(set, get) => ({
			token: null,
			_expiry: null,
 
			/**
			 * Returns the current authentication token.
			 * @returns {string | null} The current authentication token or null if no token is set.
			 */
			getToken: (): string | null => {
				return get().token;
			},
 
			/**
			 * Updates the current token and its expiration time.
			 * @param {string} newToken The new token to be stored.
			 * @param {number} expiry The Unix timestamp (in milliseconds) when the token expires.
			 */
			updateToken: (newToken: string, expiry?: number) => {
				set({
					token: newToken,
					_expiry: expiry ?? Number.MAX_SAFE_INTEGER,
				});
			},
 
			/**
			 * Resets the current token and its expiration time.
			 * Sets the token and expiry to null, effectively invalidating the token.
			 */
			resetToken: () => {
				set({ token: null, _expiry: null });
			},
		}),
		{
			name: TOKEN_STORE_IDENTIFIER,
			storage: createJSONStorage(() => localStorage),
 
			/**
			 * Handles the rehydration of the token store from storage.
			 * Checks if the stored token is expired during rehydration and resets it if necessary.
			 * This ensures that any expired tokens are not used when the store is rehydrated.
			 */
			onRehydrateStorage: () => {
				return (state) => {
					if (state && state._expiry && Date.now() >= state._expiry) {
						state.resetToken();
					}
				};
			},
		},
	),
);