fix(subscription-client): extend SubscriptionDoc with platform-service fields
This commit is contained in:
parent
87ae533b58
commit
d83641c5ee
@ -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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user