144 lines
4.5 KiB
TypeScript
144 lines
4.5 KiB
TypeScript
/**
|
|
* 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<SubscriptionDoc | null> {
|
|
try {
|
|
return await billingApi.fetch<SubscriptionDoc>(`/subscriptions/${userId}`);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function updateSubscription(
|
|
userId: string,
|
|
updates: Record<string, unknown>
|
|
): Promise<SubscriptionDoc | null> {
|
|
try {
|
|
return await billingApi.fetch<SubscriptionDoc>(`/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<LicenseDoc> {
|
|
return billingApi.fetch<LicenseDoc>('/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<LicenseDoc>('/licenses/revoke', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ key }),
|
|
});
|
|
}
|
|
|
|
export async function deactivateLicenseDevice(key: string, deviceId: string) {
|
|
return billingApi.fetch<LicenseDoc>('/licenses/deactivate', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ key, deviceId }),
|
|
});
|
|
}
|