@ -1,25 +1,86 @@
import './env' ;
import "./env" ;
import { seed } from "drizzle-seed ";
import { hash } from "bcryptjs ";
import { usersTable } from "./lib/schema/auth ";
import { eq , sql } from "drizzle-orm ";
import { dbGlobal } from "./lib/db" ;
import { dbGlobal } from "./lib/db" ;
import { users } from "./lib/schema/auth" ;
/** Match `server/service/auth/index.ts` */
const USERNAME_REGEX = /^[a-zA-Z0-9_]{3,20}$/ ;
const MIN_PASSWORD_LENGTH = 6 ;
/ * *
* Public slug is optional : use lowercased username only if it satisfies a URL - style slug
* ( lowercase alphanumeric only , 3 – 20 chars ) . Usernames with underscores or mixed rules
* that do not fit stay null ; the admin can set ` publicSlug ` later via profile APIs .
* /
const PUBLIC_SLUG_REGEX = /^[a-z0-9]{3,20}$/ ;
function derivePublicSlug ( username : string ) : string | null {
const lower = username . toLowerCase ( ) ;
return PUBLIC_SLUG_REGEX . test ( lower ) ? lower : null ;
}
async function getNextUserId() {
const [ row ] = await dbGlobal
. select ( {
maxId : sql < number > ` COALESCE(MAX( ${ users . id } ), 0) ` ,
} )
. from ( users ) ;
return ( row ? . maxId ? ? 0 ) + 1 ;
}
async function main() {
async function main() {
await seed ( dbGlobal , { usersTable } ) . refine ( ( f ) = > ( {
const [ existingAdmin ] = await dbGlobal
usersTable : {
. select ( { id : users.id } )
columns : {
. from ( users )
name : f.fullName ( ) ,
. where ( eq ( users . role , "admin" ) )
age : f.int ( { minValue : 18 , maxValue : 60 } ) ,
. limit ( 1 ) ;
email : f.email ( ) ,
} ,
if ( existingAdmin ) {
count : 10 ,
console . log ( "Bootstrap skipped: admin exists" ) ;
} ,
} ) ) ;
console . log ( 'Seed complete!' ) ;
process . exit ( 0 ) ;
process . exit ( 0 ) ;
}
const username = process . env . BOOTSTRAP_ADMIN_USERNAME ;
const password = process . env . BOOTSTRAP_ADMIN_PASSWORD ;
if ( ! username || ! password ) {
console . warn (
"Bootstrap skipped: set BOOTSTRAP_ADMIN_USERNAME and BOOTSTRAP_ADMIN_PASSWORD" ,
) ;
process . exit ( 0 ) ;
}
if ( ! USERNAME_REGEX . test ( username ) || password . length < MIN_PASSWORD_LENGTH ) {
console . warn (
"Bootstrap skipped: invalid BOOTSTRAP_ADMIN_USERNAME or BOOTSTRAP_ADMIN_PASSWORD" ,
) ;
process . exit ( 0 ) ;
}
const passwordHash = await hash ( password , 10 ) ;
const userId = await getNextUserId ( ) ;
const publicSlug = derivePublicSlug ( username ) ;
try {
await dbGlobal . insert ( users ) . values ( {
id : userId ,
username ,
password : passwordHash ,
role : "admin" ,
status : "active" ,
publicSlug ,
} ) ;
console . log ( "Bootstrap complete: admin user created" ) ;
} catch ( err ) {
console . warn ( "Bootstrap skipped: could not insert admin (unique conflict or DB error)" , err ) ;
process . exit ( 0 ) ;
}
process . exit ( 0 ) ;
}
}
main ( ) . catch ( e = > {
main ( ) . catch ( ( e ) = > {
console . error ( e ) ;
console . error ( e ) ;
process . exit ( 1 ) ;
process . exit ( 1 ) ;
} ) ;
} ) ;