From e9d1c863e1a312f8c83974432b3b42585b85a2fe Mon Sep 17 00:00:00 2001 From: Sanju Sivalingam Date: Wed, 18 Feb 2026 23:08:10 +0530 Subject: [PATCH] fix: self-hosted useSend support + purchase-first activate UX - Pass USESEND_BASE_URL to UseSend SDK for self-hosted instances - Add debug logging for email sends - Redesign activate page: prominent Purchase Now button, collapsible license key input --- web/src/lib/server/auth.ts | 7 +- web/src/lib/server/email.ts | 12 +-- .../routes/dashboard/activate/+page.svelte | 88 ++++++++++++------- 3 files changed, 67 insertions(+), 40 deletions(-) diff --git a/web/src/lib/server/auth.ts b/web/src/lib/server/auth.ts index 883ac62..a7e97c7 100644 --- a/web/src/lib/server/auth.ts +++ b/web/src/lib/server/auth.ts @@ -8,6 +8,7 @@ import * as schema from './db/schema'; import { sendEmail } from './email'; export const auth = betterAuth({ + baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:5173', database: drizzleAdapter(db, { provider: 'pg', schema @@ -15,14 +16,16 @@ export const auth = betterAuth({ plugins: [sveltekitCookies(getRequestEvent), apiKey()], emailVerification: { sendVerificationEmail: async ({ user, url }) => { + console.log('[Email] sendVerificationEmail called for:', user.email, 'url:', url); try { - await sendEmail({ + const result = await sendEmail({ to: user.email, subject: 'Verify your DroidClaw email', text: `Hi ${user.name || 'there'},\n\nClick the link below to verify your email:\n\n${url}\n\nThis link expires in 1 hour.\n\n-- DroidClaw` }); + console.log('[Email] sendEmail result:', JSON.stringify(result)); } catch (err) { - console.error('Failed to send verification email:', err); + console.error('[Email] Failed to send verification email:', err); } }, sendOnSignUp: true, diff --git a/web/src/lib/server/email.ts b/web/src/lib/server/email.ts index 4c3da77..9d35003 100644 --- a/web/src/lib/server/email.ts +++ b/web/src/lib/server/email.ts @@ -1,12 +1,13 @@ import { env } from '$env/dynamic/private'; import { UseSend } from 'usesend-js'; -if (!env.USESEND_API_KEY) throw new Error('USESEND_API_KEY is not set'); - -const usesend = new UseSend(env.USESEND_API_KEY); - const EMAIL_FROM = 'noreply@app.droidclaw.ai'; +function getClient() { + if (!env.USESEND_API_KEY) throw new Error('USESEND_API_KEY is not set'); + return new UseSend(env.USESEND_API_KEY, env.USESEND_BASE_URL); +} + export async function sendEmail({ to, subject, @@ -16,7 +17,8 @@ export async function sendEmail({ subject: string; text: string; }) { - return usesend.emails.send({ + console.log('[Email] API key prefix:', env.USESEND_API_KEY?.slice(0, 15) + '...'); + return getClient().emails.send({ to, from: EMAIL_FROM, subject, diff --git a/web/src/routes/dashboard/activate/+page.svelte b/web/src/routes/dashboard/activate/+page.svelte index 5dea34d..7ed23cb 100644 --- a/web/src/routes/dashboard/activate/+page.svelte +++ b/web/src/routes/dashboard/activate/+page.svelte @@ -5,6 +5,8 @@ import { LICENSE_ACTIVATE_CHECKOUT, LICENSE_ACTIVATE_MANUAL, LICENSE_PURCHASE_CLICK } from '$lib/analytics/events'; const checkoutId = page.url.searchParams.get('checkout_id'); + + let showKeyInput = $state(false); {#if checkoutId} @@ -69,49 +71,69 @@ {:else} - +
-
- +
+
-

Activate your license

-

- Enter the license key you received after purchasing DroidClaw. +

Get started with DroidClaw

+

+ Unlock AI-powered Android device control.

-
- + + + Purchase Now + +
- -

- Don't have a key? - - Purchase here - -

+ {#if showKeyInput} +
+
+ + + +
+
+ {/if} +
{/if}