RadiantFrog
RadiantFrog
Explore posts from servers
BABetter Auth
Created by RadiantFrog on 4/16/2025 in #help
Stripe Better-Auth Plugin
I have an issue with the Stripe plugin (or maybe Stripe itself). Im implementing subscriptions and I'm getting conflicting events after a checkout in the Sandbox. First I get a OnSubscriptionComplete, I use the status to update the user's proStatus to "active". Secondly I get a onSubscriptionUpdate with "incomplete", so I use the status to update the user's proStatus to "incomplete". Why do I get a "onSubscriptionUpdate" with "incomplete" after a succesful checkout?
3 replies
CCConvex Community
Created by RadiantFrog on 4/6/2025 in #support-community
Local-first sync with Convex
Hello, I've read a bit about syncing mechanisms, but it seems there is no way to easily do this with Convex at this point in time?
5 replies
BABetter Auth
Created by RadiantFrog on 4/5/2025 in #help
Long delay after logging in with Apple (white screen)
It works but it causes quite a delay. What can I do to fix this? auth.ts
apple: {
clientId: import.meta.env.VITE_AUTH_APPLE_ID as string,
clientSecret: import.meta.env.VITE_AUTH_APPLE_SECRET as string,
scope: ["email", "name"],
mapProfileToUser: (profile) => {
return {
name: profile.email.split("@")[0],
providerId: "apple",
};
},
},
apple: {
clientId: import.meta.env.VITE_AUTH_APPLE_ID as string,
clientSecret: import.meta.env.VITE_AUTH_APPLE_SECRET as string,
scope: ["email", "name"],
mapProfileToUser: (profile) => {
return {
name: profile.email.split("@")[0],
providerId: "apple",
};
},
},
apple-auth-button.tsx
await signIn.social({
provider: "apple",
errorCallbackURL: PATHS.AUTH_ERROR, // url to redirect if an error occurs during the sign in process
newUserCallbackURL: `${PATHS.DASHBOARD}?isNewUser=true`,
callbackURL: PATHS.DASHBOARD,
});
await signIn.social({
provider: "apple",
errorCallbackURL: PATHS.AUTH_ERROR, // url to redirect if an error occurs during the sign in process
newUserCallbackURL: `${PATHS.DASHBOARD}?isNewUser=true`,
callbackURL: PATHS.DASHBOARD,
});
16 replies
BABetter Auth
Created by RadiantFrog on 4/4/2025 in #help
Stripe creating subscription: Unauthorized 401
Hello, I'm running into an issue with Stripe Subscriptions whereas I cannot generate a new subscription for an user. I'm using @better-auth/strip and receive a 401 Unauthorized when I'm creating a subscription on the client. The only weird thing AFAIK is that I use the convexAdapter, so I cannot run migrations for stripe myself (but this seems unrelated to the unauthorized). I've checked the .env.local keys a dozen times. I'm running a Tanstack Start app. auth.tsx
import { betterAuth } from "better-auth";
import { APP_NAME, DEFAULT_AVATAR, DEFAULT_LANGUAGE } from "@/config/constants";
import { ConvexHttpClient } from "convex/browser";
import { convexAdapter } from "@better-auth-kit/convex";
import { stripe } from "@better-auth/stripe";
import Stripe from "stripe";

const convexClient = new ConvexHttpClient(import.meta.env.VITE_CONVEX_URL);
const stripeClient = new Stripe(import.meta.env.VITE_STRIPE_SECRET_KEY);

export const AUTH_PROVIDERS = {
CREDENTIAL: "credential",
APPLE: "apple",
GOOGLE: "google",
} as const;

export const auth = betterAuth({
appName: APP_NAME,
secret: import.meta.env.VITE_BETTER_AUTH_SECRET,
baseURL: import.meta.env.VITE_BETTER_AUTH_URL,
database: convexAdapter(convexClient),
plugins: [
stripe({
stripeClient,
stripeWebhookSecret: import.meta.env.VITE_STRIPE_WEBHOOKS_ENDPOINT_SECRET,
createCustomerOnSignUp: true,
subscription: {
enabled: true,
plans: [
{
name: "monthly", // the name of the plan, it'll be automatically lower cased when stored in the database
priceId: import.meta.env.VITE_STRIPE_MONTHLY_PRICE_ID, // the price id from stripe
},
{
name: "yearly",
priceId: import.meta.env.VITE_STRIPE_YEARLY_PRICE_ID,
},
],
},
}),
],
import { betterAuth } from "better-auth";
import { APP_NAME, DEFAULT_AVATAR, DEFAULT_LANGUAGE } from "@/config/constants";
import { ConvexHttpClient } from "convex/browser";
import { convexAdapter } from "@better-auth-kit/convex";
import { stripe } from "@better-auth/stripe";
import Stripe from "stripe";

const convexClient = new ConvexHttpClient(import.meta.env.VITE_CONVEX_URL);
const stripeClient = new Stripe(import.meta.env.VITE_STRIPE_SECRET_KEY);

export const AUTH_PROVIDERS = {
CREDENTIAL: "credential",
APPLE: "apple",
GOOGLE: "google",
} as const;

export const auth = betterAuth({
appName: APP_NAME,
secret: import.meta.env.VITE_BETTER_AUTH_SECRET,
baseURL: import.meta.env.VITE_BETTER_AUTH_URL,
database: convexAdapter(convexClient),
plugins: [
stripe({
stripeClient,
stripeWebhookSecret: import.meta.env.VITE_STRIPE_WEBHOOKS_ENDPOINT_SECRET,
createCustomerOnSignUp: true,
subscription: {
enabled: true,
plans: [
{
name: "monthly", // the name of the plan, it'll be automatically lower cased when stored in the database
priceId: import.meta.env.VITE_STRIPE_MONTHLY_PRICE_ID, // the price id from stripe
},
{
name: "yearly",
priceId: import.meta.env.VITE_STRIPE_YEARLY_PRICE_ID,
},
],
},
}),
],
45 replies
CCConvex Community
Created by RadiantFrog on 4/4/2025 in #support-community
Tanstack: How to call a Convex mutation from createServerFn?
I'm lost on how I can use Convex from the serverFn in Tanstack. Here is my attempt
const convex = new ConvexHttpClient(import.meta.env.VITE_CONVEX_URL);

// Define the input schema using Zod
const suggestMilestonesInputSchema = z.object({
userId: z.string(),
goal: z.any(), // Allow any type for goal for now
language: z.string(),
});

export const suggestMilestones = createServerFn({
method: "POST",
})
.validator((person: unknown) => {
return suggestMilestonesInputSchema.parse(person);
})
.handler(async (ctx) => {
// Call mutation inside the handler
await convex.mutation(api.user.increaseAISuggestions, { userId: userId as Id<"user"> });

});
const convex = new ConvexHttpClient(import.meta.env.VITE_CONVEX_URL);

// Define the input schema using Zod
const suggestMilestonesInputSchema = z.object({
userId: z.string(),
goal: z.any(), // Allow any type for goal for now
language: z.string(),
});

export const suggestMilestones = createServerFn({
method: "POST",
})
.validator((person: unknown) => {
return suggestMilestonesInputSchema.parse(person);
})
.handler(async (ctx) => {
// Call mutation inside the handler
await convex.mutation(api.user.increaseAISuggestions, { userId: userId as Id<"user"> });

});
Here is my mutation
// Update user email
export const updateUserEmail = mutation({
args: {
userId: v.id("user"),
email: v.string(),
},
handler: async (ctx, { userId, email }) => {
await ctx.db.patch(userId, {
email,
updatedAt: new Date().toISOString(),
});

return { success: true };
},
});
// Update user email
export const updateUserEmail = mutation({
args: {
userId: v.id("user"),
email: v.string(),
},
handler: async (ctx, { userId, email }) => {
await ctx.db.patch(userId, {
email,
updatedAt: new Date().toISOString(),
});

return { success: true };
},
});
if there is any example boilerplate on how to call convex from the createServerFn handler that would be amazing. So I basically want to have some validations on the server side (does the user have enough credits) I can see there is:
import { fetchMutation, fetchQuery } from "convex/nextjs";
import { fetchMutation, fetchQuery } from "convex/nextjs";
but that requires met to set which I cannot do in a Vite project.
Error: Environment variable NEXT_PUBLIC_CONVEX_URL is not set.
Error: Environment variable NEXT_PUBLIC_CONVEX_URL is not set.
4 replies
BABetter Auth
Created by RadiantFrog on 4/3/2025 in #help
Cannot set additionalField when calling signUp.email
I'm trying to pass a referredBy field during user registration using signUp.email, but TypeScript is rejecting it with the following error: "Object literal may only specify known properties, and 'referredBy' does not exist in type " 1. I've properly configured referredBy in my auth.ts configuration:
user: {
additionalFields: {
referredBy: {
type: "string",
required: false,
},
// other fields...
}
}
user: {
additionalFields: {
referredBy: {
type: "string",
required: false,
},
// other fields...
}
}
2. In my RegisterForm.tsx, I'm trying to pass the field like this:
await signUp.email({
email: values.email,
password: values.password,
name: values.name,
referredBy: typeof window !== "undefined" ? localStorage.getItem("referredBy") : null,
});
await signUp.email({
email: values.email,
password: values.password,
name: values.name,
referredBy: typeof window !== "undefined" ? localStorage.getItem("referredBy") : null,
});
35 replies