user/sessions.js

/**
 * @module Sessions
 */
import { DELETE, POST } from '../../infrastructure/http/HttpClient'
import { globalConfig } from '../config.js'
import { clearAllCachedData } from '../dataContext.js'
import { setUserPinnedProgressRow } from '../progress-row/base.js'
import './types.js'

/**
 * Exported functions that are excluded from index generation.
 *
 * @type {string[]}
 */
const excludeFromGeneratedIndex = []

/**
 * Authenticates the User.
 *
 * @param {string} email - User's email
 * @param {string} password - User's password
 * @param {string|null} deviceName -  Device name for the user
 * @param {string|null} deviceToken - Firebase token for the device
 * @param {string|null} platform - Device platform
 *
 * @returns {Promise<AuthResponse>} - User data and authentication token
 *
 * @example
 * login('john@doe.com', 'music123')
 *   .then(content => console.log(content))
 *   .catch(error => console.error(error));
 */
export async function login(email, password, deviceName, deviceToken, platform) {
  const baseUrl = `${globalConfig.baseUrl}/api/user-management-system`
  const data = await POST(`${baseUrl}/v1/sessions`, {
    email: email,
    password: password,
    device_name: deviceName,
    device_token: deviceToken,
    platform: platform,
  })

  return data
}
//Removing 3rdParty OAuth2 for now => https://musora.atlassian.net/browse/BEH-624?focusedCommentId=21492
/*export async function loginWithProvider(provider, providerIdToken, deviceToken, deviceName, platform) {
  const baseUrl = `${globalConfig.baseUrl}/api/user-management-system`

  try {
    const response = await fetch(`${baseUrl}/v1/auth/${provider}/mobile`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Client-Platform': 'mobile',
      },
      body: JSON.stringify({
        id_token: providerIdToken,
        device_name: deviceName,
        firebase_token: deviceToken,
        platform,
      }),
    })

    if (!response.ok) {
      const errorBody = await response.json().catch(() => ({}))
      throw new Error(errorBody.error || `Login failed with status ${response.status}`)
    }

    return await response.json()
  } catch (err) {
    console.error('loginWithProvider failed', err)
    throw err
  }
}*/

/**
 * Logs the user out of the current session.
 * Clears all cached data to prevent data leakage between users.
 *
 * @returns {Promise<void>}
 *
 * @example
 * logout()
 *   .then()
 *   .catch(error => console.error(error));
 */
export async function logout() {
  const baseUrl = `${globalConfig.baseUrl}/api/user-management-system`
  await DELETE(`${baseUrl}/v1/sessions`)

  // Clear all locally cached data to prevent data leakage between users
  await clearAllCachedData()
}

/**
 * @param {number} userId
 * @param {string} redirectTo
 * @returns {Promise<string>}
 *
 * @example
 * const authUrl = await generateAuthSessionUrl(592656, 'https://app.musora.com/drumeo')
 */
export async function generateAuthSessionUrl(userId, redirectTo) {
  const baseUrl = `${globalConfig.baseUrl}/api/user-management-system`

  const headers = {
    'Content-Type': 'application/json',
  }

  if (globalConfig.isMA) {
    headers.Authorization = `Bearer ${globalConfig.sessionConfig.authToken}`
  }

  // generate auth key
  const response = await fetch(`${baseUrl}/v1/auth-key`, {
    method: 'GET',
    headers,
    credentials: globalConfig.isMA ? undefined : 'include',
  })

  if (!response.ok) {
    throw new Error(`Failed to generate auth key: ${response.status}`)
  }

  const authKeyResponse = await response.json()
  const authKey = authKeyResponse.data || authKeyResponse.auth_key

  const absoluteRedirectTo = new URL(redirectTo)
  const relativeRedirectTo = absoluteRedirectTo.pathname + absoluteRedirectTo.search

  const params = new URLSearchParams({
    user_id: userId.toString(),
    auth_key: authKey,
    redirect_to: relativeRedirectTo,
  })

  // generate link that will *consume* the auth key
  if (globalConfig.isMA) {
    if (!absoluteRedirectTo.hostname.endsWith('.musora.com')) {
      throw new Error('Bad redirect URL - must be a musora.com domain')
    }

    return `${absoluteRedirectTo.origin}/auth?${params.toString()}`
  } else {
    throw new Error("Not implemented - MA deep links don't accept auth keys")
  }
}