mirror of
https://github.com/LukeHagar/polar.git
synced 2025-12-09 20:57:43 +00:00
use standalone functions to reduce bundle size
This commit is contained in:
1
example/convex/_generated/api.d.ts
vendored
1
example/convex/_generated/api.d.ts
vendored
@@ -17,6 +17,7 @@ import type {
|
|||||||
FilterApi,
|
FilterApi,
|
||||||
FunctionReference,
|
FunctionReference,
|
||||||
} from "convex/server";
|
} from "convex/server";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility for referencing Convex functions in your app's API.
|
* A utility for referencing Convex functions in your app's API.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { Polar } from "@polar-sh/sdk";
|
import { PolarCore } from "@polar-sh/sdk/core.js";
|
||||||
|
import { productsCreate } from "@polar-sh/sdk/funcs/productsCreate.js";
|
||||||
|
import { productsList } from "@polar-sh/sdk/funcs/productsList.js";
|
||||||
import { internalAction, internalMutation } from "./_generated/server";
|
import { internalAction, internalMutation } from "./_generated/server";
|
||||||
import { internal } from "./_generated/api";
|
import { internal } from "./_generated/api";
|
||||||
|
|
||||||
const accessToken = process.env.POLAR_ORGANIZATION_TOKEN;
|
const accessToken = process.env.POLAR_ORGANIZATION_TOKEN;
|
||||||
|
|
||||||
const polar = new Polar({
|
const polar = new PolarCore({
|
||||||
accessToken,
|
accessToken,
|
||||||
server: "sandbox",
|
server: "sandbox",
|
||||||
});
|
});
|
||||||
@@ -36,7 +38,7 @@ const seed = internalAction({
|
|||||||
return items.length > 0;
|
return items.length > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const result = await polar.products.list({
|
const result = await productsList(polar, {
|
||||||
isArchived: false,
|
isArchived: false,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
});
|
});
|
||||||
@@ -52,7 +54,7 @@ const seed = internalAction({
|
|||||||
// Create example products. In a real app you would likely create your
|
// Create example products. In a real app you would likely create your
|
||||||
// products in the Polar dashboard and reference them by id in your application.
|
// products in the Polar dashboard and reference them by id in your application.
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
polar.products.create({
|
productsCreate(polar, {
|
||||||
name: PREMIUM_PLAN_NAME,
|
name: PREMIUM_PLAN_NAME,
|
||||||
description: "All the things for one low monthly price.",
|
description: "All the things for one low monthly price.",
|
||||||
recurringInterval: "month",
|
recurringInterval: "month",
|
||||||
@@ -63,7 +65,7 @@ const seed = internalAction({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
polar.products.create({
|
productsCreate(polar, {
|
||||||
name: PREMIUM_PLAN_NAME,
|
name: PREMIUM_PLAN_NAME,
|
||||||
description: "All the things for one low annual price.",
|
description: "All the things for one low annual price.",
|
||||||
recurringInterval: "year",
|
recurringInterval: "year",
|
||||||
@@ -74,7 +76,7 @@ const seed = internalAction({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
polar.products.create({
|
productsCreate(polar, {
|
||||||
name: PREMIUM_PLUS_PLAN_NAME,
|
name: PREMIUM_PLUS_PLAN_NAME,
|
||||||
description: "All the things for one low monthly price.",
|
description: "All the things for one low monthly price.",
|
||||||
recurringInterval: "month",
|
recurringInterval: "month",
|
||||||
@@ -85,7 +87,7 @@ const seed = internalAction({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
polar.products.create({
|
productsCreate(polar, {
|
||||||
name: PREMIUM_PLUS_PLAN_NAME,
|
name: PREMIUM_PLUS_PLAN_NAME,
|
||||||
description: "All the things for one low annual price.",
|
description: "All the things for one low annual price.",
|
||||||
recurringInterval: "year",
|
recurringInterval: "year",
|
||||||
|
|||||||
10
example/package-lock.json
generated
10
example/package-lock.json
generated
@@ -48,11 +48,9 @@
|
|||||||
},
|
},
|
||||||
"..": {
|
"..": {
|
||||||
"name": "@convex-dev/polar",
|
"name": "@convex-dev/polar",
|
||||||
"version": "0.4.4",
|
"version": "0.5.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@polar-sh/checkout": "0.1.10",
|
|
||||||
"@polar-sh/sdk": "0.32.11",
|
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"convex-helpers": "^0.1.63",
|
"convex-helpers": "^0.1.63",
|
||||||
"remeda": "^2.20.2",
|
"remeda": "^2.20.2",
|
||||||
@@ -66,12 +64,14 @@
|
|||||||
"eslint": "^9.9.1",
|
"eslint": "^9.9.1",
|
||||||
"globals": "^15.9.0",
|
"globals": "^15.9.0",
|
||||||
"prettier": "3.2.5",
|
"prettier": "3.2.5",
|
||||||
"typescript": "~5.0.3",
|
"typescript": "^5.5.0",
|
||||||
"typescript-eslint": "^8.4.0",
|
"typescript-eslint": "^8.4.0",
|
||||||
"vitest": "^2.1.4"
|
"vitest": "^2.1.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"convex": "^1.19.2 || >=1.17.0 <1.25.0",
|
"@polar-sh/checkout": ">=0.1.10",
|
||||||
|
"@polar-sh/sdk": ">=0.32.11",
|
||||||
|
"convex": "^1.25.4",
|
||||||
"react": "^18 || ^19",
|
"react": "^18 || ^19",
|
||||||
"react-dom": "^18 || ^19"
|
"react-dom": "^18 || ^19"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,14 +41,16 @@ export default function TodoList() {
|
|||||||
|
|
||||||
const getButtonText = (targetProductId: string) => {
|
const getButtonText = (targetProductId: string) => {
|
||||||
if (!user?.subscription) return "Upgrade";
|
if (!user?.subscription) return "Upgrade";
|
||||||
const currentAmount = user.subscription.amount ?? 0;
|
const isPremium =
|
||||||
const targetProduct = Object.values(products ?? {}).find(
|
user.subscription.productId === premiumMonthly?.id ||
|
||||||
(p) => p?.id === targetProductId
|
user.subscription.productId === premiumYearly?.id;
|
||||||
);
|
const targetIsPremiumPlus =
|
||||||
const targetAmount = targetProduct?.prices[0].priceAmount ?? 0;
|
targetProductId === premiumPlusMonthly?.id ||
|
||||||
if (targetAmount > currentAmount) return "Upgrade";
|
targetProductId === premiumPlusYearly?.id;
|
||||||
if (targetAmount < currentAmount) return "Downgrade";
|
if (isPremium && targetIsPremiumPlus) {
|
||||||
return "Switch";
|
return "Upgrade";
|
||||||
|
}
|
||||||
|
return "Downgrade";
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePlanChange = async (productId: string) => {
|
const handlePlanChange = async (productId: string) => {
|
||||||
|
|||||||
@@ -73,7 +73,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"convex": "^1.19.2 || >=1.17.0 <1.35.0",
|
"@polar-sh/checkout": ">=0.1.10",
|
||||||
|
"@polar-sh/sdk": ">=0.32.11",
|
||||||
|
"convex": "^1.25.4",
|
||||||
"react": "^18 || ^19",
|
"react": "^18 || ^19",
|
||||||
"react-dom": "^18 || ^19"
|
"react-dom": "^18 || ^19"
|
||||||
},
|
},
|
||||||
@@ -93,8 +95,6 @@
|
|||||||
"types": "./dist/commonjs/client/index.d.ts",
|
"types": "./dist/commonjs/client/index.d.ts",
|
||||||
"module": "./dist/esm/client/index.js",
|
"module": "./dist/esm/client/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@polar-sh/checkout": "0.1.10",
|
|
||||||
"@polar-sh/sdk": "0.32.11",
|
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"convex-helpers": "^0.1.63",
|
"convex-helpers": "^0.1.63",
|
||||||
"remeda": "^2.20.2",
|
"remeda": "^2.20.2",
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import "./polyfill";
|
import "./polyfill";
|
||||||
import { Polar as PolarSdk } from "@polar-sh/sdk";
|
import { PolarCore } from "@polar-sh/sdk/core.js";
|
||||||
|
import { customersCreate } from "@polar-sh/sdk/funcs/customersCreate.js";
|
||||||
|
import { checkoutsCreate } from "@polar-sh/sdk/funcs/checkoutsCreate.js";
|
||||||
|
import { customerSessionsCreate } from "@polar-sh/sdk/funcs/customerSessionsCreate.js";
|
||||||
|
import { subscriptionsUpdate } from "@polar-sh/sdk/funcs/subscriptionsUpdate.js";
|
||||||
|
|
||||||
import type { Checkout } from "@polar-sh/sdk/models/components/checkout.js";
|
import type { Checkout } from "@polar-sh/sdk/models/components/checkout.js";
|
||||||
import type { WebhookProductCreatedPayload } from "@polar-sh/sdk/models/components/webhookproductcreatedpayload.js";
|
import type { WebhookProductCreatedPayload } from "@polar-sh/sdk/models/components/webhookproductcreatedpayload.js";
|
||||||
import type { WebhookProductUpdatedPayload } from "@polar-sh/sdk/models/components/webhookproductupdatedpayload.js";
|
import type { WebhookProductUpdatedPayload } from "@polar-sh/sdk/models/components/webhookproductupdatedpayload.js";
|
||||||
@@ -48,7 +53,7 @@ export class Polar<
|
|||||||
DataModel extends GenericDataModel = GenericDataModel,
|
DataModel extends GenericDataModel = GenericDataModel,
|
||||||
Products extends Record<string, string> = Record<string, string>,
|
Products extends Record<string, string> = Record<string, string>,
|
||||||
> {
|
> {
|
||||||
public sdk: PolarSdk;
|
public polar: PolarCore;
|
||||||
public products: Products;
|
public products: Products;
|
||||||
private organizationToken: string;
|
private organizationToken: string;
|
||||||
private webhookSecret: string;
|
private webhookSecret: string;
|
||||||
@@ -77,7 +82,7 @@ export class Polar<
|
|||||||
(process.env["POLAR_SERVER"] as "sandbox" | "production") ??
|
(process.env["POLAR_SERVER"] as "sandbox" | "production") ??
|
||||||
"sandbox";
|
"sandbox";
|
||||||
|
|
||||||
this.sdk = new PolarSdk({
|
this.polar = new PolarCore({
|
||||||
accessToken: this.organizationToken,
|
accessToken: this.organizationToken,
|
||||||
server: this.server,
|
server: this.server,
|
||||||
});
|
});
|
||||||
@@ -116,20 +121,23 @@ export class Polar<
|
|||||||
const customerId =
|
const customerId =
|
||||||
dbCustomer?.id ||
|
dbCustomer?.id ||
|
||||||
(
|
(
|
||||||
await this.sdk.customers.create({
|
await customersCreate(this.polar, {
|
||||||
email,
|
email,
|
||||||
metadata: {
|
metadata: {
|
||||||
userId,
|
userId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
).id;
|
).value?.id;
|
||||||
|
if (!customerId) {
|
||||||
|
throw new Error("Customer not created");
|
||||||
|
}
|
||||||
if (!dbCustomer) {
|
if (!dbCustomer) {
|
||||||
await ctx.runMutation(this.component.lib.insertCustomer, {
|
await ctx.runMutation(this.component.lib.insertCustomer, {
|
||||||
id: customerId,
|
id: customerId,
|
||||||
userId,
|
userId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.sdk.checkouts.create({
|
const checkout = await checkoutsCreate(this.polar, {
|
||||||
allowDiscountCodes: true,
|
allowDiscountCodes: true,
|
||||||
customerId,
|
customerId,
|
||||||
embedOrigin: origin,
|
embedOrigin: origin,
|
||||||
@@ -138,6 +146,10 @@ export class Polar<
|
|||||||
? { products: productIds }
|
? { products: productIds }
|
||||||
: { products: productIds }),
|
: { products: productIds }),
|
||||||
});
|
});
|
||||||
|
if (!checkout.value) {
|
||||||
|
throw new Error("Checkout not created");
|
||||||
|
}
|
||||||
|
return checkout.value;
|
||||||
}
|
}
|
||||||
async createCustomerPortalSession(
|
async createCustomerPortalSession(
|
||||||
ctx: GenericActionCtx<DataModel>,
|
ctx: GenericActionCtx<DataModel>,
|
||||||
@@ -152,11 +164,14 @@ export class Polar<
|
|||||||
throw new Error("Customer not found");
|
throw new Error("Customer not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await this.sdk.customerSessions.create({
|
const session = await customerSessionsCreate(this.polar, {
|
||||||
customerId: customer.id,
|
customerId: customer.id,
|
||||||
});
|
});
|
||||||
|
if (!session.value) {
|
||||||
|
throw new Error("Customer session not created");
|
||||||
|
}
|
||||||
|
|
||||||
return { url: session.customerPortalUrl };
|
return { url: session.value.customerPortalUrl };
|
||||||
}
|
}
|
||||||
listProducts(
|
listProducts(
|
||||||
ctx: RunQueryCtx,
|
ctx: RunQueryCtx,
|
||||||
@@ -209,12 +224,16 @@ export class Polar<
|
|||||||
if (subscription.productId === productId) {
|
if (subscription.productId === productId) {
|
||||||
throw new Error("Subscription already on this product");
|
throw new Error("Subscription already on this product");
|
||||||
}
|
}
|
||||||
await this.sdk.subscriptions.update({
|
const updatedSubscription = await subscriptionsUpdate(this.polar, {
|
||||||
id: subscription.id,
|
id: subscription.id,
|
||||||
subscriptionUpdate: {
|
subscriptionUpdate: {
|
||||||
productId,
|
productId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
if (!updatedSubscription.value) {
|
||||||
|
throw new Error("Subscription not updated");
|
||||||
|
}
|
||||||
|
return updatedSubscription.value;
|
||||||
}
|
}
|
||||||
async cancelSubscription(
|
async cancelSubscription(
|
||||||
ctx: RunActionCtx,
|
ctx: RunActionCtx,
|
||||||
@@ -228,13 +247,17 @@ export class Polar<
|
|||||||
if (subscription.status !== "active") {
|
if (subscription.status !== "active") {
|
||||||
throw new Error("Subscription is not active");
|
throw new Error("Subscription is not active");
|
||||||
}
|
}
|
||||||
await this.sdk.subscriptions.update({
|
const updatedSubscription = await subscriptionsUpdate(this.polar, {
|
||||||
id: subscription.id,
|
id: subscription.id,
|
||||||
subscriptionUpdate: {
|
subscriptionUpdate: {
|
||||||
cancelAtPeriodEnd: revokeImmediately ? undefined : true,
|
cancelAtPeriodEnd: revokeImmediately ? undefined : true,
|
||||||
revoke: revokeImmediately ? true : undefined,
|
revoke: revokeImmediately ? true : undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
if (!updatedSubscription.value) {
|
||||||
|
throw new Error("Subscription not updated");
|
||||||
|
}
|
||||||
|
return updatedSubscription.value;
|
||||||
}
|
}
|
||||||
api() {
|
api() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
1
src/component/_generated/api.d.ts
vendored
1
src/component/_generated/api.d.ts
vendored
@@ -16,6 +16,7 @@ import type {
|
|||||||
FilterApi,
|
FilterApi,
|
||||||
FunctionReference,
|
FunctionReference,
|
||||||
} from "convex/server";
|
} from "convex/server";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility for referencing Convex functions in your app's API.
|
* A utility for referencing Convex functions in your app's API.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Polar as PolarSdk } from "@polar-sh/sdk";
|
import { PolarCore } from "@polar-sh/sdk/core";
|
||||||
|
import { productsList } from "@polar-sh/sdk/funcs/productsList.js";
|
||||||
|
|
||||||
import { v } from "convex/values";
|
import { v } from "convex/values";
|
||||||
import { action, mutation, query } from "./_generated/server";
|
import { action, mutation, query } from "./_generated/server";
|
||||||
import schema from "./schema";
|
import schema from "./schema";
|
||||||
@@ -278,22 +280,25 @@ export const syncProducts = action({
|
|||||||
server: v.union(v.literal("sandbox"), v.literal("production")),
|
server: v.union(v.literal("sandbox"), v.literal("production")),
|
||||||
},
|
},
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const sdk = new PolarSdk({
|
const polar = new PolarCore({
|
||||||
accessToken: args.polarAccessToken,
|
accessToken: args.polarAccessToken,
|
||||||
server: args.server,
|
server: args.server,
|
||||||
});
|
});
|
||||||
let page = 1;
|
let page = 1;
|
||||||
let maxPage;
|
let maxPage;
|
||||||
do {
|
do {
|
||||||
const products = await sdk.products.list({
|
const products = await productsList(polar, {
|
||||||
page,
|
page,
|
||||||
limit: 100,
|
limit: 100,
|
||||||
});
|
});
|
||||||
|
if (!products.value) {
|
||||||
|
throw new Error("Failed to get products");
|
||||||
|
}
|
||||||
page = page + 1;
|
page = page + 1;
|
||||||
maxPage = products.result.pagination.maxPage;
|
maxPage = products.value.result.pagination.maxPage;
|
||||||
await ctx.runMutation(api.lib.updateProducts, {
|
await ctx.runMutation(api.lib.updateProducts, {
|
||||||
polarAccessToken: args.polarAccessToken,
|
polarAccessToken: args.polarAccessToken,
|
||||||
products: products.result.items.map(convertToDatabaseProduct),
|
products: products.value.result.items.map(convertToDatabaseProduct),
|
||||||
});
|
});
|
||||||
} while (maxPage >= page);
|
} while (maxPage >= page);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import type {
|
|||||||
import { GenericId } from "convex/values";
|
import { GenericId } from "convex/values";
|
||||||
import type { api } from "./_generated/api";
|
import type { api } from "./_generated/api";
|
||||||
import type { Doc } from "./_generated/dataModel";
|
import type { Doc } from "./_generated/dataModel";
|
||||||
import { Subscription } from "@polar-sh/sdk/models/components/subscription.js";
|
import type { Subscription } from "@polar-sh/sdk/models/components/subscription.js";
|
||||||
import { Product } from "@polar-sh/sdk/models/components/product.js";
|
import type { Product } from "@polar-sh/sdk/models/components/product.js";
|
||||||
|
|
||||||
export const omitSystemFields = <
|
export const omitSystemFields = <
|
||||||
T extends { _id: string; _creationTime: number } | null | undefined,
|
T extends { _id: string; _creationTime: number } | null | undefined,
|
||||||
|
|||||||
Reference in New Issue
Block a user