/** * Assets Service * * Handles all asset-related API operations including CRUD and inheritance. */ import { NO_BACKEND_MODE, API_ENDPOINTS, MOCK_CONFIG, buildApiUrl, getApiHeaders, logApiDebug, } from '../config'; // ============================================================================= // Type Definitions // ============================================================================= export interface Asset { id: number; title: string; author_id: number; private_key_shard: string; content_outer_encrypted: string; heir_email?: string; } export interface AssetCreate { title: string; private_key_shard: string; content_inner_encrypted: string; } export interface AssetClaim { asset_id: number; private_key_shard: string; } export interface AssetClaimResponse { asset_id: number; title: string; decrypted_content: string; server_shard_key: string; } export interface AssetAssign { asset_id: number; heir_email: string; } // ============================================================================= // Mock Data // ============================================================================= const MOCK_ASSETS: Asset[] = [ { id: 1, title: 'Mock Asset 1', author_id: MOCK_CONFIG.USER.id, private_key_shard: 'mock_shard_1', content_outer_encrypted: 'mock_encrypted_content_1', heir_email: 'heir@example.com', }, { id: 2, title: 'Mock Asset 2', author_id: MOCK_CONFIG.USER.id, private_key_shard: 'mock_shard_2', content_outer_encrypted: 'mock_encrypted_content_2', }, ]; // ============================================================================= // Assets Service // ============================================================================= export const assetsService = { /** * Get all assets for the current user * @param token - JWT token for authentication * @returns Array of user's assets */ async getMyAssets(token: string): Promise { if (NO_BACKEND_MODE) { logApiDebug('Get Assets', 'Using mock mode'); return new Promise((resolve) => { setTimeout(() => resolve(MOCK_ASSETS), MOCK_CONFIG.RESPONSE_DELAY); }); } const url = buildApiUrl(API_ENDPOINTS.ASSETS.GET); logApiDebug('Get Assets URL', url); try { const response = await fetch(url, { method: 'GET', headers: getApiHeaders(token), }); logApiDebug('Get Assets Response Status', response.status); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || 'Failed to fetch assets'); } return await response.json(); } catch (error) { console.error('Get assets error:', error); throw error; } }, /** * Create a new asset * @param asset - Asset creation data * @param token - JWT token for authentication * @returns Created asset */ async createAsset(asset: AssetCreate, token: string): Promise { if (NO_BACKEND_MODE) { logApiDebug('Create Asset', 'Using mock mode'); return new Promise((resolve) => { setTimeout(() => { resolve({ id: Date.now(), title: asset.title, author_id: MOCK_CONFIG.USER.id, private_key_shard: asset.private_key_shard, content_outer_encrypted: asset.content_inner_encrypted, }); }, MOCK_CONFIG.RESPONSE_DELAY); }); } const url = buildApiUrl(API_ENDPOINTS.ASSETS.CREATE); logApiDebug('Create Asset URL', url); try { const response = await fetch(url, { method: 'POST', headers: getApiHeaders(token), body: JSON.stringify(asset), }); const responseStatus = response.status; logApiDebug('Create Asset Response Status', responseStatus); if (!response.ok) { const errorData = await response.json().catch(() => ({})); const detail = errorData.detail || 'Failed to create asset'; const message = responseStatus === 401 ? `Unauthorized (401): ${detail}` : detail; const err = new Error(message) as Error & { status?: number }; err.status = responseStatus; throw err; } return await response.json(); } catch (error) { console.error('Create asset error:', error); throw error; } }, /** * Claim an inherited asset * @param claim - Asset claim data * @param token - JWT token for authentication * @returns Claimed asset with decrypted content */ async claimAsset(claim: AssetClaim, token: string): Promise { if (NO_BACKEND_MODE) { logApiDebug('Claim Asset', 'Using mock mode'); return new Promise((resolve) => { setTimeout(() => { resolve({ asset_id: claim.asset_id, title: 'Mock Claimed Asset', decrypted_content: 'This is the decrypted content of the claimed asset.', server_shard_key: 'mock_server_shard', }); }, MOCK_CONFIG.RESPONSE_DELAY); }); } const url = buildApiUrl(API_ENDPOINTS.ASSETS.CLAIM); logApiDebug('Claim Asset URL', url); try { const response = await fetch(url, { method: 'POST', headers: getApiHeaders(token), body: JSON.stringify(claim), }); logApiDebug('Claim Asset Response Status', response.status); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || 'Failed to claim asset'); } return await response.json(); } catch (error) { console.error('Claim asset error:', error); throw error; } }, /** * Assign an asset to an heir * @param assignment - Asset assignment data * @param token - JWT token for authentication * @returns Success message */ async assignAsset(assignment: AssetAssign, token: string): Promise<{ message: string }> { if (NO_BACKEND_MODE) { logApiDebug('Assign Asset', 'Using mock mode'); return new Promise((resolve) => { setTimeout(() => { resolve({ message: `Asset assigned to ${assignment.heir_email}` }); }, MOCK_CONFIG.RESPONSE_DELAY); }); } const url = buildApiUrl(API_ENDPOINTS.ASSETS.ASSIGN); logApiDebug('Assign Asset URL', url); try { const response = await fetch(url, { method: 'POST', headers: getApiHeaders(token), body: JSON.stringify(assignment), }); logApiDebug('Assign Asset Response Status', response.status); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || 'Failed to assign asset'); } return await response.json(); } catch (error) { console.error('Assign asset error:', error); throw error; } }, /** * Delete an asset * @param assetId - ID of the asset to delete * @param token - JWT token for authentication * @returns Success message */ async deleteAsset(assetId: number, token: string): Promise<{ message: string }> { if (NO_BACKEND_MODE) { logApiDebug('Delete Asset', `Using mock mode for ID: ${assetId}`); return new Promise((resolve) => { setTimeout(() => { resolve({ message: 'Asset deleted successfully' }); }, MOCK_CONFIG.RESPONSE_DELAY); }); } const url = buildApiUrl(API_ENDPOINTS.ASSETS.DELETE); logApiDebug('Delete Asset URL', url); try { const response = await fetch(url, { method: 'POST', headers: getApiHeaders(token), body: JSON.stringify({ asset_id: assetId }), }); logApiDebug('Delete Asset Response Status', response.status); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || 'Failed to delete asset'); } return await response.json(); } catch (error) { console.error('Delete asset error:', error); throw error; } }, };