mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-21 05:06:41 +02:00
style: auto-format codebase with Prettier
Applied formatting to 1487+ files using pnpm format:write - TypeScript/JavaScript files - Svelte components - Astro pages - JSON configs - Markdown docs 13 files still need manual review (Astro JSX comments)
This commit is contained in:
parent
0241f5554c
commit
d36b321d9d
3952 changed files with 661498 additions and 739751 deletions
|
|
@ -4,157 +4,157 @@ import type { DecodedToken, UserData } from '../types';
|
|||
* Decode a JWT token payload
|
||||
*/
|
||||
export function decodeToken(token: string): DecodedToken | null {
|
||||
try {
|
||||
const parts = token.split('.');
|
||||
if (parts.length !== 3) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const parts = token.split('.');
|
||||
if (parts.length !== 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const base64Url = parts[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
const base64Url = parts[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
// Add padding if needed
|
||||
const padding = base64.length % 4;
|
||||
const paddedBase64 = padding ? base64 + '='.repeat(4 - padding) : base64;
|
||||
// Add padding if needed
|
||||
const padding = base64.length % 4;
|
||||
const paddedBase64 = padding ? base64 + '='.repeat(4 - padding) : base64;
|
||||
|
||||
// Decode base64 - atob is available in browsers, Node.js 16+, and React Native
|
||||
const payload: DecodedToken = JSON.parse(atob(paddedBase64));
|
||||
// Decode base64 - atob is available in browsers, Node.js 16+, and React Native
|
||||
const payload: DecodedToken = JSON.parse(atob(paddedBase64));
|
||||
|
||||
return payload;
|
||||
} catch (error) {
|
||||
console.error('Error decoding JWT token:', error);
|
||||
return null;
|
||||
}
|
||||
return payload;
|
||||
} catch (error) {
|
||||
console.error('Error decoding JWT token:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a token is valid locally (not expired)
|
||||
*/
|
||||
export function isTokenValidLocally(token: string, bufferSeconds: number = 10): boolean {
|
||||
try {
|
||||
const payload = decodeToken(token);
|
||||
if (!payload || !payload.exp) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const payload = decodeToken(token);
|
||||
if (!payload || !payload.exp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bufferTime = bufferSeconds * 1000;
|
||||
const expiryTime = payload.exp * 1000;
|
||||
const currentTime = Date.now();
|
||||
const bufferTime = bufferSeconds * 1000;
|
||||
const expiryTime = payload.exp * 1000;
|
||||
const currentTime = Date.now();
|
||||
|
||||
return currentTime < expiryTime - bufferTime;
|
||||
} catch (error) {
|
||||
console.debug('Error validating token locally:', error);
|
||||
return false;
|
||||
}
|
||||
return currentTime < expiryTime - bufferTime;
|
||||
} catch (error) {
|
||||
console.debug('Error validating token locally:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a token is expired
|
||||
*/
|
||||
export function isTokenExpired(token: string): boolean {
|
||||
return !isTokenValidLocally(token, 0);
|
||||
return !isTokenValidLocally(token, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract user data from a JWT token
|
||||
*/
|
||||
export function getUserFromToken(token: string, storedEmail?: string): UserData | null {
|
||||
try {
|
||||
const payload = decodeToken(token);
|
||||
if (!payload) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const payload = decodeToken(token);
|
||||
if (!payload) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get email from various sources
|
||||
let email = payload.email || '';
|
||||
if (!email && payload.user_metadata?.email) {
|
||||
email = payload.user_metadata.email;
|
||||
}
|
||||
if (!email && storedEmail) {
|
||||
email = storedEmail;
|
||||
}
|
||||
// Get email from various sources
|
||||
let email = payload.email || '';
|
||||
if (!email && payload.user_metadata?.email) {
|
||||
email = payload.user_metadata.email;
|
||||
}
|
||||
if (!email && storedEmail) {
|
||||
email = storedEmail;
|
||||
}
|
||||
|
||||
return {
|
||||
id: payload.sub,
|
||||
email: email || 'user@example.com',
|
||||
role: payload.role || 'user',
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error extracting user from token:', error);
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: payload.sub,
|
||||
email: email || 'user@example.com',
|
||||
role: payload.role || 'user',
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error extracting user from token:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token expiration time in milliseconds
|
||||
*/
|
||||
export function getTokenExpirationTime(token: string): number | null {
|
||||
const payload = decodeToken(token);
|
||||
if (!payload || !payload.exp) {
|
||||
return null;
|
||||
}
|
||||
return payload.exp * 1000;
|
||||
const payload = decodeToken(token);
|
||||
if (!payload || !payload.exp) {
|
||||
return null;
|
||||
}
|
||||
return payload.exp * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time until token expiration in milliseconds
|
||||
*/
|
||||
export function getTimeUntilExpiration(token: string): number {
|
||||
const expirationTime = getTokenExpirationTime(token);
|
||||
if (!expirationTime) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(0, expirationTime - Date.now());
|
||||
const expirationTime = getTokenExpirationTime(token);
|
||||
if (!expirationTime) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(0, expirationTime - Date.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is B2B based on JWT claims
|
||||
*/
|
||||
export function isB2BUser(token: string): boolean {
|
||||
const payload = decodeToken(token);
|
||||
if (!payload) {
|
||||
return false;
|
||||
}
|
||||
const payload = decodeToken(token);
|
||||
if (!payload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle different types for is_b2b
|
||||
return payload.is_b2b === true || payload.is_b2b === 'true' || payload.is_b2b === 1;
|
||||
// Handle different types for is_b2b
|
||||
return payload.is_b2b === true || payload.is_b2b === 'true' || payload.is_b2b === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get B2B information from JWT claims
|
||||
*/
|
||||
export function getB2BInfo(token: string): {
|
||||
disableRevenueCat: boolean;
|
||||
organizationId?: string;
|
||||
plan?: string;
|
||||
role?: string;
|
||||
disableRevenueCat: boolean;
|
||||
organizationId?: string;
|
||||
plan?: string;
|
||||
role?: string;
|
||||
} | null {
|
||||
const payload = decodeToken(token);
|
||||
if (!payload?.app_settings?.b2b) {
|
||||
return null;
|
||||
}
|
||||
const payload = decodeToken(token);
|
||||
if (!payload?.app_settings?.b2b) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const b2bSettings = payload.app_settings.b2b;
|
||||
return {
|
||||
disableRevenueCat: !!b2bSettings.disableRevenueCat,
|
||||
organizationId: b2bSettings.organizationId,
|
||||
plan: b2bSettings.plan,
|
||||
role: b2bSettings.role,
|
||||
};
|
||||
const b2bSettings = payload.app_settings.b2b;
|
||||
return {
|
||||
disableRevenueCat: !!b2bSettings.disableRevenueCat,
|
||||
organizationId: b2bSettings.organizationId,
|
||||
plan: b2bSettings.plan,
|
||||
role: b2bSettings.role,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if RevenueCat should be disabled for this token
|
||||
*/
|
||||
export function shouldDisableRevenueCat(token: string): boolean {
|
||||
const b2bInfo = getB2BInfo(token);
|
||||
return b2bInfo?.disableRevenueCat ?? false;
|
||||
const b2bInfo = getB2BInfo(token);
|
||||
return b2bInfo?.disableRevenueCat ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get app settings from JWT claims
|
||||
*/
|
||||
export function getAppSettings(token: string): Record<string, unknown> | null {
|
||||
const payload = decodeToken(token);
|
||||
return payload?.app_settings || null;
|
||||
const payload = decodeToken(token);
|
||||
return payload?.app_settings || null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue