fix(subscription-client): extend SubscriptionDoc with platform-service fields

This commit is contained in:
saravanakumardb1 2026-04-13 22:57:13 -07:00
parent 87ae533b58
commit d83641c5ee

View File

@ -1,11 +1,20 @@
export interface SubscriptionDoc { export interface SubscriptionDoc {
id: string; id: string;
userId: string; userId: string;
productId?: string;
plan: string; plan: string;
status: "active" | "trialing" | "past_due" | "cancelled" | "none"; status: 'active' | 'trialing' | 'past_due' | 'cancelled' | 'none';
currentPeriodStart?: string;
currentPeriodEnd: string; currentPeriodEnd: string;
cancelAtPeriodEnd: boolean; cancelAtPeriodEnd: boolean;
monthlyPrice?: number;
tokensIncluded?: number;
tokensUsed?: number;
stripeCustomerId?: string;
stripeSubscriptionId?: string;
features?: string[]; features?: string[];
createdAt?: string;
updatedAt?: string;
} }
export interface PlanConfig { export interface PlanConfig {
@ -34,25 +43,20 @@ export interface SubscriptionClient {
} }
function trimTrailingSlash(url: string): string { function trimTrailingSlash(url: string): string {
return url.replace(/\/+$/, ""); return url.replace(/\/+$/, '');
} }
export function createSubscriptionClient( export function createSubscriptionClient(opts: SubscriptionClientOptions): SubscriptionClient {
opts: SubscriptionClientOptions,
): SubscriptionClient {
const base = trimTrailingSlash(opts.baseUrl); const base = trimTrailingSlash(opts.baseUrl);
let cached: SubscriptionDoc | null | undefined; let cached: SubscriptionDoc | null | undefined;
async function request<T>( async function request<T>(path: string, init?: RequestInit): Promise<T> {
path: string,
init?: RequestInit,
): Promise<T> {
const token = opts.getAccessToken(); const token = opts.getAccessToken();
const headers = new Headers(init?.headers); const headers = new Headers(init?.headers);
headers.set("Authorization", `Bearer ${token}`); headers.set('Authorization', `Bearer ${token}`);
headers.set("X-Product-Id", opts.productId); headers.set('X-Product-Id', opts.productId);
if (!headers.has("Content-Type") && init?.body !== undefined) { if (!headers.has('Content-Type') && init?.body !== undefined) {
headers.set("Content-Type", "application/json"); headers.set('Content-Type', 'application/json');
} }
const res = await fetch(`${base}${path}`, { ...init, headers }); const res = await fetch(`${base}${path}`, { ...init, headers });
if (res.status === 404) { if (res.status === 404) {
@ -80,36 +84,31 @@ export function createSubscriptionClient(
return { return {
async getMySubscription(): Promise<SubscriptionDoc | null> { async getMySubscription(): Promise<SubscriptionDoc | null> {
const data = await request<SubscriptionDoc | null>( const data = await request<SubscriptionDoc | null>('/billing/subscriptions/me');
"/billing/subscriptions/me",
);
cached = data; cached = data;
return data; return data;
}, },
async getPlans(): Promise<PlanConfig[]> { async getPlans(): Promise<PlanConfig[]> {
const data = await request< const data = await request<PlanConfig[] | { plans?: PlanConfig[] } | null>('/billing/plans');
PlanConfig[] | { plans?: PlanConfig[] } | null
>("/billing/plans");
if (data == null) { if (data == null) {
return []; return [];
} }
if (Array.isArray(data)) { if (Array.isArray(data)) {
return data; return data;
} }
if (data && typeof data === "object" && "plans" in data && Array.isArray(data.plans)) { if (data && typeof data === 'object' && 'plans' in data && Array.isArray(data.plans)) {
return data.plans; return data.plans;
} }
return []; return [];
}, },
async cancelSubscription(): Promise<SubscriptionDoc> { async cancelSubscription(): Promise<SubscriptionDoc> {
const data = await request<SubscriptionDoc>( const data = await request<SubscriptionDoc>('/billing/subscriptions/cancel', {
"/billing/subscriptions/cancel", method: 'POST',
{ method: "POST" }, });
);
if (data === null) { if (data === null) {
throw new Error("Cancel subscription returned no body"); throw new Error('Cancel subscription returned no body');
} }
cached = data; cached = data;
return data; return data;
@ -120,15 +119,14 @@ export function createSubscriptionClient(
if (!sub) { if (!sub) {
return false; return false;
} }
const paid = const paid = sub.status === 'active' || sub.status === 'trialing';
sub.status === "active" || sub.status === "trialing";
const planLower = sub.plan.toLowerCase(); const planLower = sub.plan.toLowerCase();
const notFree = planLower !== "free" && planLower !== "none"; const notFree = planLower !== 'free' && planLower !== 'none';
return paid && notFree; return paid && notFree;
}, },
isTrialing(): boolean { isTrialing(): boolean {
return subscriptionFromCache()?.status === "trialing"; return subscriptionFromCache()?.status === 'trialing';
}, },
hasFeature(feature: string): boolean { hasFeature(feature: string): boolean {