Files
myeasycms-v2/packages/features/accounts/src/server/personal-accounts-server-actions.ts
2026-03-11 14:47:47 +08:00

107 lines
2.8 KiB
TypeScript

'use server';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { enhanceAction } from '@kit/next/actions';
import { createOtpApi } from '@kit/otp';
import { getLogger } from '@kit/shared/logger';
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { DeletePersonalAccountSchema } from '../schema/delete-personal-account.schema';
import { createDeletePersonalAccountService } from './services/delete-personal-account.service';
const enableAccountDeletion =
process.env.NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETION === 'true';
export async function refreshAuthSession() {
const client = getSupabaseServerClient();
await client.auth.refreshSession();
return {};
}
export const deletePersonalAccountAction = enhanceAction(
async (formData: FormData, user) => {
const logger = await getLogger();
// validate the form data
const { success } = DeletePersonalAccountSchema.safeParse(
Object.fromEntries(formData.entries()),
);
if (!success) {
throw new Error('Invalid form data');
}
const ctx = {
name: 'account.delete',
userId: user.id,
};
const otp = formData.get('otp') as string;
if (!otp) {
throw new Error('OTP is required');
}
if (!enableAccountDeletion) {
logger.warn(ctx, `Account deletion is not enabled`);
throw new Error('Account deletion is not enabled');
}
logger.info(ctx, `Deleting account...`);
// verify the OTP
const client = getSupabaseServerClient();
const otpApi = createOtpApi(client);
const otpResult = await otpApi.verifyToken({
token: otp,
userId: user.id,
purpose: 'delete-personal-account',
});
if (!otpResult.valid) {
throw new Error('Invalid OTP');
}
// validate the user ID matches the nonce's user ID
if (otpResult.user_id !== user.id) {
logger.error(
ctx,
`This token was meant to be used by a different user. Exiting.`,
);
throw new Error('Nonce mismatch');
}
// create a new instance of the personal accounts service
const service = createDeletePersonalAccountService();
// delete the user's account and cancel all subscriptions
await service.deletePersonalAccount({
adminClient: getSupabaseServerAdminClient(),
account: {
id: user.id,
email: user.email ?? null,
},
});
// sign out the user after deleting their account
await client.auth.signOut();
logger.info(ctx, `Account request successfully sent`);
// clear the cache for all pages
revalidatePath('/', 'layout');
// redirect to the home page
redirect('/');
},
{},
);