/** * Billing Service API client for the admin dashboard. * Uses @bytelyst/api-client shared package. * * Replaces direct Cosmos DB calls for usage tracking. */ import { createApiClient } from '@bytelyst/api-client'; const billingApi = createApiClient({ baseUrl: `${process.env.PLATFORM_SERVICE_URL || 'http://localhost:4003'}/api`, defaultHeaders: { 'x-product-id': process.env.PRODUCT_ID || 'lysnrai', }, }); // ── Subscriptions (Admin) ──────────────────────────────────── export interface SubscriptionDoc { id: string; productId: string; userId: string; plan: 'free' | 'pro' | 'enterprise'; status: 'active' | 'cancelled' | 'past_due' | 'trialing'; currentPeriodStart: string; currentPeriodEnd: string; cancelAtPeriodEnd: boolean; monthlyPrice: number; tokensIncluded: number; tokensUsed: number; stripeCustomerId?: string; stripeSubscriptionId?: string; createdAt: string; updatedAt: string; } export async function getSubscription(userId: string): Promise { try { return await billingApi.fetch(`/subscriptions/${userId}`); } catch { return null; } } export async function updateSubscription( userId: string, updates: Record ): Promise { try { return await billingApi.fetch(`/subscriptions/${userId}`, { method: 'PUT', body: JSON.stringify(updates), }); } catch { return null; } } // ── Usage ─────────────────────────────────────────────────────── export async function listUsage(options: { userId?: string; days?: number; limit?: number; productId?: string } = {}) { const params = new URLSearchParams(); if (options.userId) params.set('userId', options.userId); if (options.days) params.set('days', String(options.days)); if (options.limit) params.set('limit', String(options.limit)); if (options.productId) params.set('productId', options.productId); const qs = params.toString(); return billingApi.fetch<{ records: unknown[] }>(`/usage${qs ? `?${qs}` : ''}`); } export async function getUsageSummary(days = 30, userId?: string, productId?: string) { const params = new URLSearchParams({ days: String(days) }); if (userId) params.set('userId', userId); if (productId) params.set('productId', productId); return billingApi.fetch<{ totalWords: number; totalDictations: number; totalTokens: number; totalCost: number; records: unknown[]; modelBreakdown: { model: string; tokens: number; requests: number; cost: number }[]; sourceBreakdown?: { source: string; tokens: number; requests: number; cost: number }[]; productBreakdown?: { productId: string; tokens: number; requests: number; cost: number }[]; }>(`/usage/summary?${params}`); } // ── Licenses (Admin) ──────────────────────────────────────── export interface LicenseDoc { id: string; productId: string; key: string; userId: string; plan: 'free' | 'pro' | 'enterprise'; status: 'active' | 'revoked' | 'expired'; activatedAt: string | null; expiresAt: string | null; deviceIds: string[]; maxDevices: number; createdAt: string; updatedAt: string; } export async function generateLicense(input: { userId: string; plan: 'free' | 'pro' | 'enterprise'; maxDevices?: number; expiresAt?: string | null; }): Promise { return billingApi.fetch('/licenses/generate', { method: 'POST', body: JSON.stringify(input), }); } export async function getLicenseStatus(key: string) { return billingApi.fetch<{ key: string; plan: string; status: string; devicesUsed: number; maxDevices: number; expiresAt: string | null; }>(`/licenses/status/${encodeURIComponent(key)}`); } export async function getUserLicenses(userId: string): Promise<{ licenses: LicenseDoc[] }> { return billingApi.fetch<{ licenses: LicenseDoc[] }>(`/licenses/user/${userId}`); } export async function revokeLicense(key: string) { return billingApi.fetch('/licenses/revoke', { method: 'POST', body: JSON.stringify({ key }), }); } export async function deactivateLicenseDevice(key: string, deviceId: string) { return billingApi.fetch('/licenses/deactivate', { method: 'POST', body: JSON.stringify({ key, deviceId }), }); }