Files
veridian/server/api/setup/index.post.ts
T
2026-10-15 10:22:06 -05:00

98 lines
3.0 KiB
TypeScript

import { sql } from 'drizzle-orm';
import * as z from 'zod';
import { INSTANCE_SETTINGS_ID, instanceSettings, users } from '~~/drizzle/schema';
import { auth } from '~~/lib/auth';
import { authTransaction } from '~~/server/lib/auth-transaction';
// any fixed number works, it only has to be the same for every request
const SETUP_LOCK_ID = 7_261_008;
/**
* Creates the first account of the instance as its admin.
*
* Public, because nobody can be signed in yet, and only works while there are
* no accounts at all. It does not go through sign up, so it also works when
* registration is turned off.
*/
export default defineEventHandler(async (event) => {
const result = await readValidatedBody(event, (body) =>
z
.object({
name: z.string().trim().min(1).max(128),
email: z.email(),
password: z.string().min(8).max(128),
})
.safeParse(body),
);
if (!result.success) {
throw createError({
statusCode: 400,
message: result.error.issues[0]!.message,
data: {
code: 'INVALID_BODY',
},
});
}
const { name, email, password } = result.data;
let alreadyDone = false;
try {
await authTransaction(async (tx) => {
// two people submitting the form at the same moment wait here, and
// the second one then finds the first one's account
await tx.execute(sql`select pg_advisory_xact_lock(${SETUP_LOCK_ID})`);
const existing = await tx.select({ id: users.id }).from(users).limit(1);
if (existing.length > 0) {
alreadyDone = true;
return;
}
await auth.api.createUser({
body: {
name,
email,
password,
role: 'admin',
},
});
// A new instance starts invite only. The next setup step lets the
// admin pick, and if they never get there it is not left open.
await tx.insert(instanceSettings)
.values({ id: INSTANCE_SETTINGS_ID, registration: 'invite' })
.onConflictDoNothing();
});
} catch (error: any) {
const code = error?.body?.code as string | undefined;
if (code === undefined) {
console.error('Failed to create the admin account:', error);
}
throw createError({
statusCode: code === undefined ? 500 : 400,
statusMessage: 'Failed to set up the instance',
message: error?.body?.message ?? 'Failed to set up the instance',
data: {
code: code ?? 'INTERNAL_ERROR',
},
});
}
if (alreadyDone) {
throw createError({
statusCode: 409,
statusMessage: 'This instance is already set up',
data: {
code: 'SETUP_ALREADY_DONE',
},
});
}
return { ok: true };
});