Compare commits

..

No commits in common. '5400c123bd78097024449b55d381d8364dd42eba' and '186a06b3a928205f40aac4dee40cc510cfbf2d64' have entirely different histories.

@ -1,20 +0,0 @@
on:
push:
branches:
- main
name: migrate-db
jobs:
migrate-db:
name: migrate-db
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- name: bun install
working-directory: ./frontend
run: bun install
- name: migrate-db
working-directory: ./frontend
env: # Or as an environment variable
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: bun run db:migrate

@ -61,12 +61,6 @@ go build
## Breaking Changes (For builds before this date)
### 9 February 2025
Migrate using polar.sh, if you want to keep using stripe you must add `PAYMENT_PROVIDER=stripe` to .env
All stripe related features will be removed soon
### 24 December 2024
New file upload feature requires a tigris/s3 bucket with webhook setup in order to work properly

@ -1,17 +1,24 @@
FROM oven/bun
FROM node:22
WORKDIR /app
RUN npm install -g bun
COPY ./package.json ./
COPY ./bun.lock ./
COPY ./bun.lockb ./
RUN bun install
COPY . .
# COPY ./.env.example ./.env
RUN bun run build
ARG DATABASE_URL
RUN DATABASE_URL=$DATABASE_URL npm run db:migrate
RUN npm run build
EXPOSE 3000
ENTRYPOINT ["bun", "build/index.js"]
ENTRYPOINT ["node", "build"]

File diff suppressed because it is too large Load Diff

Binary file not shown.

@ -1 +0,0 @@
ALTER TABLE "user" ADD COLUMN "polar_customer_id" varchar(255);

@ -1,548 +0,0 @@
{
"id": "f7c94100-ab5e-40a0-82b6-b4f93b459a6c",
"prevId": "ce042384-c48f-4a7b-b067-8808e73834d6",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.email_verification_token": {
"name": "email_verification_token",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(255)",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.file": {
"name": "file",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"project_id": {
"name": "project_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"size": {
"name": "size",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"default": 0
},
"etag": {
"name": "etag",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at_epoch": {
"name": "created_at_epoch",
"type": "bigint",
"primaryKey": false,
"notNull": true
},
"updated_at_epoch": {
"name": "updated_at_epoch",
"type": "bigint",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.project": {
"name": "project",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"uuid": {
"name": "uuid",
"type": "uuid",
"primaryKey": false,
"notNull": false,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"qr_background": {
"name": "qr_background",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"default": "'#ffffff'"
},
"qr_foreground": {
"name": "qr_foreground",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"default": "'#000000'"
},
"domain_status": {
"name": "domain_status",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"default": "'verified'"
},
"enable_custom_domain": {
"name": "enable_custom_domain",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"custom_ip": {
"name": "custom_ip",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"custom_domain_id": {
"name": "custom_domain_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"custom_domain": {
"name": "custom_domain",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"qr_corner_square_style": {
"name": "qr_corner_square_style",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'square'"
},
"qr_dot_style": {
"name": "qr_dot_style",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'square'"
},
"qr_image_base64": {
"name": "qr_image_base64",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.session": {
"name": "session",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(255)",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.shortener": {
"name": "shortener",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"link": {
"name": "link",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"ios": {
"name": "ios",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"ios_link": {
"name": "ios_link",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"android": {
"name": "android",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"android_link": {
"name": "android_link",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"code": {
"name": "code",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"active": {
"name": "active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"project_id": {
"name": "project_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"is_file_upload": {
"name": "is_file_upload",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"file_path": {
"name": "file_path",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.user": {
"name": "user",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"uuid": {
"name": "uuid",
"type": "uuid",
"primaryKey": false,
"notNull": false,
"default": "gen_random_uuid()"
},
"email_verified": {
"name": "email_verified",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"google_id": {
"name": "google_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"username": {
"name": "username",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"password": {
"name": "password",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"plan": {
"name": "plan",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"default": "'free'"
},
"stripe_customer_id": {
"name": "stripe_customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"polar_customer_id": {
"name": "polar_customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"qr_background": {
"name": "qr_background",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"default": "'#fff'"
},
"qr_foreground": {
"name": "qr_foreground",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"default": "'#000'"
},
"qr_corner_square_style": {
"name": "qr_corner_square_style",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'square'"
},
"qr_dot_style": {
"name": "qr_dot_style",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'square'"
},
"qr_image_base64": {
"name": "qr_image_base64",
"type": "text",
"primaryKey": false,
"notNull": false
},
"file_storage_usage_in_byte": {
"name": "file_storage_usage_in_byte",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"default": 0
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"user_email_unique": {
"name": "user_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
}
}
},
"public.visitor": {
"name": "visitor",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"shortener_id": {
"name": "shortener_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"country_code": {
"name": "country_code",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"country": {
"name": "country",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"city": {
"name": "city",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"device_type": {
"name": "device_type",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"default": "''"
},
"device_vendor": {
"name": "device_vendor",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"default": "''"
},
"os": {
"name": "os",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"default": "''"
},
"browser": {
"name": "browser",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"default": "''"
},
"referer": {
"name": "referer",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"default": "''"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

@ -204,13 +204,6 @@
"when": 1734847628427,
"tag": "0028_hard_red_shift",
"breakpoints": true
},
{
"idx": 29,
"version": "7",
"when": 1739092508279,
"tag": "0029_chemical_wiccan",
"breakpoints": true
}
]
}

@ -17,7 +17,7 @@
},
"devDependencies": {
"@sveltejs/adapter-node": "^2.0.0",
"@sveltejs/kit": "^2.17.1",
"@sveltejs/kit": "^2.5.27",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"@types/pg": "^8.11.6",
"autoprefixer": "^10.4.14",
@ -29,7 +29,7 @@
"prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.2.6",
"prettier-plugin-tailwindcss": "^0.5.7",
"svelte": "^5.19.9",
"svelte": "^5.0.0",
"svelte-adapter-bun": "^0.5.1",
"svelte-check": "^4.0.0",
"tailwindcss": "^3.4.14",
@ -43,8 +43,6 @@
"@aws-sdk/client-s3": "^3.705.0",
"@aws-sdk/s3-request-presigner": "^3.705.0",
"@lucia-auth/adapter-drizzle": "^1.0.7",
"@polar-sh/sdk": "^0.25.0",
"@polar-sh/sveltekit": "^0.3.17",
"@prgm/sveltekit-progress-bar": "^2.0.0",
"@stripe/stripe-js": "^4.3.0",
"@types/he": "^1.2.3",

@ -87,9 +87,7 @@
<DropdownMenu.Separator />
{#if !user.isPro}
<DropdownMenu.Group>
<a
href="/dashboard/billing/plan/pro"
data-sveltekit-reload>
<a href="/dashboard/billing/plan/pro">
<DropdownMenu.Item>
<Sparkles />
Upgrade to Pro

@ -28,7 +28,6 @@ export const user = pgTable('user', {
.$type<'free' | 'pro' | 'owner'>()
.default('free'),
stripeCustomerId: varchar('stripe_customer_id', { length: 255 }),
polarCustomerId: varchar('polar_customer_id', { length: 255 }),
qrBackground: varchar('qr_background', { length: 7 })
.notNull()
.default('#fff'),

@ -4,20 +4,16 @@ import { env } from '$env/dynamic/private'
import { fail, setMessage, superValidate } from 'sveltekit-superforms'
import { zod } from 'sveltekit-superforms/adapters'
import { cancelSubscriptionSchema } from './schema'
import { Polar } from '@polar-sh/sdk'
import { redirect } from '@sveltejs/kit'
export const load = (async () => {
const breadcrumbs = [
{ name: 'Billing', path: '/dashboard/billing' },
]
return {
breadcrumbs,
cancel_subscription_form: await superValidate(
zod(cancelSubscriptionSchema),
),
isPolar: env.PAYMENT_PROVIDER !== 'stripe',
}
}) satisfies PageServerLoad
@ -32,25 +28,22 @@ export const actions = {
form,
})
}
if (env.PAYMENT_PROVIDER === 'stripe') {
const stripe = new Stripe(env.PRIVATE_STRIPE_SECRET_KEY)
const stripe = new Stripe(env.PRIVATE_STRIPE_SECRET_KEY)
const user = event.locals.user
const user = event.locals.user
if (!user.stripeCustomerId) return { form }
if (!user.stripeCustomerId) return { form }
const subscription = await stripe.subscriptions.list({
customer: user.stripeCustomerId,
price: env.PRIVATE_PRO_PLAN_PRICE_ID,
limit: 1,
})
const subscription = await stripe.subscriptions.list({
customer: user.stripeCustomerId,
price: env.PRIVATE_PRO_PLAN_PRICE_ID,
limit: 1,
})
const cancelSubscription = await stripe.subscriptions.update(
subscription.data[0].id,
{ cancel_at_period_end: true },
)
} else {
}
const cancelSubscription = await stripe.subscriptions.update(
subscription.data[0].id,
{ cancel_at_period_end: true },
)
setMessage(form, 'Successfully cancelled subsciption')
return { form }

@ -1,4 +1,5 @@
<script lang="ts">
import * as Tooltip from '$lib/components/ui/tooltip/index.js'
import * as Form from '$lib/components/ui/form'
import { Button, buttonVariants } from '$lib/components/ui/button'
import { Separator } from '$lib/components/ui/separator'
@ -140,60 +141,47 @@
{#if data.user.plan === 'owner'}
<Button variant={'brand'} disabled>Owner</Button>
{:else if data.user.plan === 'pro'}
{#if data.isPolar}
<a
href="/api/polar/portal"
data-sveltekit-reload
<Dialog.Root bind:open={cancelPlanDialogOpen}>
<Dialog.Trigger
class={buttonVariants({ variant: 'destructive' })}>
Cancel Plan
</a>
{:else}
<Dialog.Root bind:open={cancelPlanDialogOpen}>
<Dialog.Trigger
class={buttonVariants({
variant: 'destructive',
})}>
Cancel Plan
</Dialog.Trigger>
<Dialog.Content class="sm:max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Cancel plan?</Dialog.Title>
<Dialog.Description>
Your subscription will still be valid until
the next billing
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Button
variant={'outline'}
onclick={() =>
(cancelPlanDialogOpen = false)}>
Cancel
</Button>
<form
method="POST"
use:enhanceCancelSubscription
class="flex flex-col gap-6"
action="?/cancel_subscription">
<Form.Button
class="w-fit"
variant="destructive"
disabled={$submittingCancelSubscription ||
!data.user.plan}>
{#if $submittingCancelSubscription}
<LoaderCircleIcon class="animate-spin" />
{/if}
Proceed
</Form.Button>
</form>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
{/if}
</Dialog.Trigger>
<Dialog.Content class="sm:max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Cancel plan?</Dialog.Title>
<Dialog.Description>
Your subscription will still be valid until the
next billing
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Button
variant={'outline'}
onclick={() => (cancelPlanDialogOpen = false)}>
Cancel
</Button>
<form
method="POST"
use:enhanceCancelSubscription
class="flex flex-col gap-6"
action="?/cancel_subscription">
<Form.Button
class="w-fit"
variant="destructive"
disabled={$submittingCancelSubscription ||
!data.user.plan}>
{#if $submittingCancelSubscription}
<LoaderCircleIcon class="animate-spin" />
{/if}
Proceed
</Form.Button>
</form>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
{:else}
<Button
href={'/dashboard/billing/plan/pro'}
data-sveltekit-reload
variant={'brand'}>
Select Plan
</Button>

@ -5,7 +5,6 @@ import { db } from '$lib/db'
import { env } from '$env/dynamic/private'
import { user as userTable } from '$lib/db/schema'
import { eq } from 'drizzle-orm'
import { Polar } from '@polar-sh/sdk'
export const load = (async (events) => {
if (events.locals.user.plan !== 'free') {
@ -15,71 +14,41 @@ export const load = (async (events) => {
redirect(302, '/dashboard/billing')
}
if (env.PAYMENT_PROVIDER === 'stripe') {
const user = events.locals.user
const user = events.locals.user
const stripe = new Stripe(env.PRIVATE_STRIPE_SECRET_KEY)
const stripe = new Stripe(env.PRIVATE_STRIPE_SECRET_KEY)
let stripeCustomerId = events.locals.user.stripeCustomerId
let stripeCustomerId = events.locals.user.stripeCustomerId
if (!stripeCustomerId) {
const customer = await stripe.customers.create({
email: user.email,
})
stripeCustomerId = customer.id
await db
.update(userTable)
.set({
stripeCustomerId: customer.id,
})
.where(eq(userTable.id, user.id))
}
const session = await stripe.checkout.sessions.create({
customer: stripeCustomerId,
line_items: [
{ price: env.PRIVATE_PRO_PLAN_PRICE_ID, quantity: 1 },
],
mode: 'subscription',
ui_mode: 'hosted',
success_url:
env.ORIGIN +
'/dashboard/billing/plan/pro/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: env.ORIGIN + '/dashboard/billing',
})
if (!session.url) {
redirect(302, '/dashboard/billing')
}
redirect(302, session.url)
} else {
const polar = new Polar({
accessToken: env.PRIVATE_POLAR_ACCESS_KEY,
server: env.APP_ENV === 'prod' ? 'production' : 'sandbox',
if (!stripeCustomerId) {
const customer = await stripe.customers.create({
email: user.email,
})
const user = events.locals.user
let polarCustomerId = events.locals.user.polarCustomerId
if (!polarCustomerId) {
const result = await polar.customers.create({
email: user.email,
stripeCustomerId = customer.id
await db
.update(userTable)
.set({
stripeCustomerId: customer.id,
})
.where(eq(userTable.id, user.id))
}
await db
.update(userTable)
.set({
polarCustomerId: result.id,
})
.where(eq(userTable.id, user.id))
polarCustomerId = result.id
}
redirect(
302,
`/api/polar/checkout?productPriceId=${env.PRIVATE_POLAR_PRO_PLAN_PRICE_ID}&customerId=${polarCustomerId}`,
)
const session = await stripe.checkout.sessions.create({
customer: stripeCustomerId,
line_items: [
{ price: env.PRIVATE_PRO_PLAN_PRICE_ID, quantity: 1 },
],
mode: 'subscription',
ui_mode: 'hosted',
success_url:
env.ORIGIN +
'/dashboard/billing/plan/pro/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: env.ORIGIN + '/dashboard/billing',
})
if (!session.url) {
redirect(302, '/dashboard/billing')
}
redirect(302, session.url)
}) satisfies PageServerLoad

@ -141,7 +141,7 @@
</p>
</div>
<div class="flex flex-row items-end gap-2">
<span class="text-4xl font-bold">$5</span>
<span class="text-4xl font-bold">$9</span>
<span>/ month</span>
</div>
<Button

@ -5,7 +5,6 @@
ReceiptText,
CodeXml,
Check,
StarsIcon,
} from 'lucide-svelte'
import { Button } from '$lib/components/ui/button/index.js'
@ -68,7 +67,7 @@
</p>
</div>
<div class="flex flex-row items-end gap-2">
<span class="text-4xl font-bold">$5</span>
<span class="text-4xl font-bold">$9</span>
<span>/ month</span>
</div>
<Button
@ -88,10 +87,6 @@
<Check class="text-brand" />
<span class="flex">5 custom domains</span>
</li>
<li class="flex items-center gap-3">
<StarsIcon class="text-brand" />
<span class="flex">File Upload (100 GB)</span>
</li>
<li class="flex items-center gap-3">
<Check class="text-brand" />
<span class="flex">2 years click history</span>

@ -1,8 +0,0 @@
import { env } from '$env/dynamic/private'
import { Checkout } from '@polar-sh/sveltekit'
export const GET = Checkout({
accessToken: env.PRIVATE_POLAR_ACCESS_KEY,
successUrl: env.APP_URL + '/dashboard/',
server: env.APP_ENV === 'prod' ? 'production' : 'sandbox',
})

@ -1,9 +0,0 @@
import { env } from '$env/dynamic/private'
import { CustomerPortal } from '@polar-sh/sveltekit'
export const GET = CustomerPortal({
accessToken: env.PRIVATE_POLAR_ACCESS_KEY,
getCustomerId: async (event) =>
event.locals.user.polarCustomerId || '', // Fuction to resolve a Polar Customer ID
server: env.APP_ENV === 'prod' ? 'production' : 'sandbox',
})

@ -1,45 +0,0 @@
import { env } from '$env/dynamic/private'
import { db } from '$lib/db'
import { user } from '$lib/db/schema'
import { Webhooks } from '@polar-sh/sveltekit'
import { eq } from 'drizzle-orm'
export const POST = Webhooks({
webhookSecret: env.PRIVATE_POLAR_WEBHOOK_SECRET,
onSubscriptionRevoked: async (payload) => {
if (
payload.data.priceId === env.PRIVATE_POLAR_PRO_PLAN_PRICE_ID
) {
const customerId = payload.data.customerId
if (!customerId) return
await db
.update(user)
.set({
plan: 'free',
})
.where(eq(user.polarCustomerId, customerId))
}
},
onOrderCreated: async (payload) => {
if (
payload.data.billingReason === 'subscription_cycle' ||
payload.data.billingReason === 'subscription_create'
) {
const priceId = payload.data.productPriceId
if (priceId === env.PRIVATE_POLAR_PRO_PLAN_PRICE_ID) {
const customerId = payload.data.customerId
if (!customerId) return
await db
.update(user)
.set({
plan: 'pro',
})
.where(eq(user.polarCustomerId, customerId))
}
}
},
})
Loading…
Cancel
Save