2026-06-11 14:26:42 +01:00
|
|
|
import { Polar } from '@polar-sh/sdk';
|
|
|
|
|
import { PLANS } from '@cio/utils/plans';
|
2025-01-09 01:30:01 +01:00
|
|
|
import { dev } from '$app/environment';
|
2025-01-06 03:36:00 +01:00
|
|
|
import { env } from '$env/dynamic/private';
|
2026-06-11 14:26:42 +01:00
|
|
|
import type { RequestEvent } from './$types';
|
2026-06-13 09:55:34 +01:00
|
|
|
import { classroomio, getApiHeaders } from '$lib/utils/services/api';
|
2025-01-06 03:36:00 +01:00
|
|
|
|
2026-06-11 14:26:42 +01:00
|
|
|
const SUBSCRIPTION_PRODUCT_IDS = new Set(
|
|
|
|
|
Object.values(PLANS)
|
|
|
|
|
.flatMap((plan) => {
|
|
|
|
|
const cta = plan.CTA as { PRODUCT_ID?: string; PRODUCT_ID_YEARLY?: string };
|
|
|
|
|
return [cta.PRODUCT_ID, cta.PRODUCT_ID_YEARLY];
|
|
|
|
|
})
|
|
|
|
|
.filter((id): id is string => Boolean(id))
|
|
|
|
|
);
|
2025-01-06 03:36:00 +01:00
|
|
|
|
2026-06-13 09:55:34 +01:00
|
|
|
export const GET = async ({ url, locals, cookies }: RequestEvent) => {
|
|
|
|
|
const { user } = locals;
|
2026-06-11 14:26:42 +01:00
|
|
|
|
2026-06-13 09:55:34 +01:00
|
|
|
if (!user) {
|
2026-06-11 14:26:42 +01:00
|
|
|
return new Response('Unauthorized', { status: 401 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const orgId = url.searchParams.get('orgId');
|
|
|
|
|
|
2026-06-13 09:55:34 +01:00
|
|
|
if (!orgId) {
|
|
|
|
|
return new Response('Missing orgId', { status: 400 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const accountResponse = await classroomio.account.$get(undefined, getApiHeaders(cookies));
|
|
|
|
|
|
|
|
|
|
if (!accountResponse.ok) {
|
|
|
|
|
return new Response('Failed to fetch account data', { status: 500 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const accountData = await accountResponse.json();
|
|
|
|
|
|
|
|
|
|
if (!accountData.success) {
|
|
|
|
|
return new Response('Failed to fetch account data', { status: 500 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const org = accountData.organizations?.find((candidate) => candidate.id === orgId);
|
|
|
|
|
|
|
|
|
|
if (!org?.siteName || !org.memberId) {
|
2026-06-11 14:26:42 +01:00
|
|
|
return new Response('You are not a member of this organization', { status: 403 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const productId = url.searchParams.get('products');
|
|
|
|
|
|
|
|
|
|
if (!productId || !SUBSCRIPTION_PRODUCT_IDS.has(productId)) {
|
|
|
|
|
return new Response('Unknown product', { status: 400 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!env.POLAR_ACCESS_TOKEN) {
|
|
|
|
|
return new Response('POLAR_ACCESS_TOKEN is not configured', { status: 500 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const polar = new Polar({
|
2025-01-06 03:36:00 +01:00
|
|
|
accessToken: env.POLAR_ACCESS_TOKEN,
|
2025-01-09 01:30:01 +01:00
|
|
|
server: dev ? 'sandbox' : 'production'
|
2025-01-06 03:36:00 +01:00
|
|
|
});
|
|
|
|
|
|
2026-06-11 14:26:42 +01:00
|
|
|
const checkout = await polar.checkouts.create({
|
|
|
|
|
products: [productId],
|
2026-06-13 09:55:34 +01:00
|
|
|
customerEmail: accountData.profile?.email ?? user.email,
|
|
|
|
|
customerName: accountData.profile?.fullname || undefined,
|
2026-06-11 14:26:42 +01:00
|
|
|
successUrl: `${url.origin}/org/${org.siteName}?upgrade=true&confirmation=true`,
|
|
|
|
|
metadata: {
|
|
|
|
|
orgId: org.id,
|
|
|
|
|
orgSlug: org.siteName,
|
2026-06-13 09:55:34 +01:00
|
|
|
triggeredBy: String(org.memberId)
|
2026-06-11 14:26:42 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Response.redirect(checkout.url, 303);
|
2025-01-06 03:36:00 +01:00
|
|
|
};
|