fix: handle Polar activation limit gracefully + switch checkout to command pattern
- Server: wrap licenseKeys.activate() in try/catch — if activation limit reached, treat as already-activated and proceed to store the key - Web: switch activateFromCheckout from form() to command() pattern for programmatic invocation with proper error handling - Activate page: auto-fires on mount, shows spinner/error states, retry button
This commit is contained in:
@@ -1,69 +1,44 @@
|
||||
import { form, query, getRequestEvent } from '$app/server';
|
||||
import { form, command, getRequestEvent } from '$app/server';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { db } from '$lib/server/db';
|
||||
import { user } from '$lib/server/db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { env } from '$env/dynamic/private';
|
||||
import * as v from 'valibot';
|
||||
import { activateLicenseSchema, activateCheckoutSchema } from '$lib/schema/license';
|
||||
|
||||
export const getLicenseStatus = query(async () => {
|
||||
/** Forward a request to the DroidClaw server with internal auth */
|
||||
async function serverFetch(path: string, body: Record<string, unknown>) {
|
||||
const { locals } = getRequestEvent();
|
||||
if (!locals.user) return null;
|
||||
if (!locals.user) throw new Error('Not authenticated');
|
||||
|
||||
const rows = await db
|
||||
.select({ plan: user.plan, polarLicenseKey: user.polarLicenseKey })
|
||||
.from(user)
|
||||
.where(eq(user.id, locals.user.id))
|
||||
.limit(1);
|
||||
const serverUrl = env.SERVER_URL || 'http://localhost:8080';
|
||||
const internalSecret = env.INTERNAL_SECRET || '';
|
||||
|
||||
const row = rows[0];
|
||||
return {
|
||||
activated: !!row?.plan,
|
||||
plan: row?.plan ?? null,
|
||||
licenseKey: row?.polarLicenseKey ?? null
|
||||
};
|
||||
});
|
||||
const res = await fetch(`${serverUrl}${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-internal-secret': internalSecret,
|
||||
'x-internal-user-id': locals.user.id
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
const data = await res.json().catch(() => ({ error: 'Unknown error' }));
|
||||
if (!res.ok) throw new Error(data.error ?? `Error ${res.status}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export const activateLicense = form(activateLicenseSchema, async (data) => {
|
||||
const { locals } = getRequestEvent();
|
||||
if (!locals.user) return;
|
||||
|
||||
const serverUrl = env.SERVER_URL || 'http://localhost:8080';
|
||||
const internalSecret = env.INTERNAL_SECRET || '';
|
||||
|
||||
const res = await fetch(`${serverUrl}/license/activate`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-internal-secret': internalSecret,
|
||||
'x-internal-user-id': locals.user.id
|
||||
},
|
||||
body: JSON.stringify({ key: data.key })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
redirect(303, '/dashboard');
|
||||
}
|
||||
await serverFetch('/license/activate', { key: data.key });
|
||||
redirect(303, '/dashboard');
|
||||
});
|
||||
|
||||
export const activateFromCheckout = form(activateCheckoutSchema, async (data) => {
|
||||
const { locals } = getRequestEvent();
|
||||
if (!locals.user) return;
|
||||
|
||||
const serverUrl = env.SERVER_URL || 'http://localhost:8080';
|
||||
const internalSecret = env.INTERNAL_SECRET || '';
|
||||
|
||||
const res = await fetch(`${serverUrl}/license/activate-checkout`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-internal-secret': internalSecret,
|
||||
'x-internal-user-id': locals.user.id
|
||||
},
|
||||
body: JSON.stringify({ checkoutId: data.checkoutId })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
redirect(303, '/dashboard');
|
||||
export const activateFromCheckout = command(
|
||||
v.object({ checkoutId: v.string() }),
|
||||
async ({ checkoutId }) => {
|
||||
const result = await serverFetch('/license/activate-checkout', { checkoutId });
|
||||
return result;
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user