authrix
Version:
Lightweight, flexible authentication library for Node.js and TypeScript.
56 lines • 9.46 kB
JavaScript
require('../chunk-D6WM53FN.cjs');var w=null;async function g(){if(!w)try{w=(await import('pg')).Pool;}catch{throw new Error("PostgreSQL adapter requires 'pg' package. Install it with: npm install pg @types/pg")}return w}var E=null;function U(){E&&(E.end(),E=null);}async function a(){if(!E){let r=await g(),e=process.env.DATABASE_URL||process.env.POSTGRESQL_URL;if(e)E=new r({connectionString:e,ssl:process.env.NODE_ENV==="production"?{rejectUnauthorized:false}:false});else {let t={host:process.env.POSTGRESQL_HOST||process.env.PGHOST||"localhost",port:parseInt(process.env.POSTGRESQL_PORT||process.env.PGPORT||"5432"),database:process.env.POSTGRESQL_DATABASE||process.env.PGDATABASE,user:process.env.POSTGRESQL_USER||process.env.PGUSER,password:process.env.POSTGRESQL_PASSWORD||process.env.PGPASSWORD,ssl:process.env.NODE_ENV==="production"?{rejectUnauthorized:false}:false};if(!t.database||!t.user||!t.password)throw new Error("PostgreSQL configuration missing. Either set DATABASE_URL/POSTGRESQL_URL or provide individual environment variables: POSTGRESQL_HOST, POSTGRESQL_PORT, POSTGRESQL_DATABASE, POSTGRESQL_USER, POSTGRESQL_PASSWORD");E=new r(t);}E.on("error",t=>{});}return E}function T(){return process.env.POSTGRESQL_USER_TABLE||process.env.AUTH_USER_TABLE||"auth_users"}function f(){return process.env.POSTGRESQL_2FA_TABLE||process.env.AUTH_2FA_TABLE||"auth_two_factor_codes"}async function O(){let r=await a(),e=T(),t=f();try{await r.query(`
CREATE TABLE IF NOT EXISTS ${e} (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) UNIQUE,
first_name VARCHAR(100),
last_name VARCHAR(100),
full_name TEXT,
profile_picture TEXT,
auth_method VARCHAR(20),
auth_provider VARCHAR(100),
password TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
email_verified BOOLEAN DEFAULT FALSE,
email_verified_at TIMESTAMP WITH TIME ZONE,
two_factor_enabled BOOLEAN DEFAULT FALSE,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
`),await r.query(`
CREATE INDEX IF NOT EXISTS idx_${e}_email ON ${e}(email);
CREATE INDEX IF NOT EXISTS idx_${e}_username ON ${e}(username);
CREATE INDEX IF NOT EXISTS idx_${e}_created_at ON ${e}(created_at);
`),await r.query(`
CREATE TABLE IF NOT EXISTS ${t} (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES ${e}(id) ON DELETE CASCADE,
code TEXT NOT NULL,
hashed_code TEXT NOT NULL,
type VARCHAR(50) NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
attempts INTEGER DEFAULT 0,
is_used BOOLEAN DEFAULT FALSE,
metadata JSONB DEFAULT '{}'::jsonb
);
`),await r.query(`
CREATE INDEX IF NOT EXISTS idx_${t}_id ON ${t}(id);
CREATE INDEX IF NOT EXISTS idx_${t}_user_id ON ${t}(user_id);
CREATE INDEX IF NOT EXISTS idx_${t}_type ON ${t}(type);
CREATE INDEX IF NOT EXISTS idx_${t}_expires_at ON ${t}(expires_at);
CREATE INDEX IF NOT EXISTS idx_${t}_created_at ON ${t}(created_at);
`);}catch(n){throw n}}function $(r,e){if(!r||typeof r.message!="string")return false;let t=r.message.toLowerCase(),n=e.toLowerCase();return t.includes("duplicate key")&&(t.includes(`${n}_idx`)||t.includes(`${n}_key`)||t.includes("unique constraint")&&t.includes(n))}function _(r){return r?{id:r.id,email:r.email,password:r.password,username:r.username,firstName:r.first_name,lastName:r.last_name,fullName:r.full_name,profilePicture:r.profile_picture,createdAt:r.created_at,emailVerified:r.email_verified,emailVerifiedAt:r.email_verified_at,twoFactorEnabled:r.two_factor_enabled,authMethod:r.auth_method,authProvider:r.auth_provider}:null}function S(r){return {id:r.id,userId:r.user_id,code:r.code,hashedCode:r.hashed_code,type:r.type,expiresAt:r.expires_at,createdAt:r.created_at,attempts:r.attempts,isUsed:r.is_used,metadata:r.metadata||{}}}var I={async findUserByEmail(r){try{let e=await a(),t=T(),n=r.toLowerCase().trim(),s=await e.query(`SELECT * FROM ${t} WHERE email = $1 LIMIT 1`,[n]);return s.rows.length===0?null:_(s.rows[0])}catch(e){if(e instanceof Error&&e.message.includes("PostgreSQL configuration missing"))throw e;return null}},async getUserByEmail(r){return this.findUserByEmail(r)},async findUserById(r){try{let e=await a(),t=T(),n=await e.query(`SELECT * FROM ${t} WHERE id = $1 LIMIT 1`,[r]);return n.rows.length===0?null:_(n.rows[0])}catch{return null}},async findUserByUsername(r){try{let e=await a(),t=T(),n=r.toLowerCase().trim(),s=await e.query(`SELECT * FROM ${t} WHERE LOWER(username) = $1 LIMIT 1`,[n]);return s.rows.length===0?null:_(s.rows[0])}catch{return null}},async createUser({email:r,password:e,username:t,firstName:n,lastName:s,fullName:o,profilePicture:i,authMethod:p,authProvider:h}){try{let m=await a(),N=T(),y=r.toLowerCase().trim(),A=t?t.toLowerCase().trim():null,u=["email","password"],l=[y,e],c=["$1","$2"],d=3;A&&(u.push("username"),l.push(A),c.push(`$${d++}`)),n&&(u.push("first_name"),l.push(n.trim()),c.push(`$${d++}`)),s&&(u.push("last_name"),l.push(s.trim()),c.push(`$${d++}`)),typeof o=="string"&&o.trim()&&(u.push("full_name"),l.push(o.trim()),c.push(`$${d++}`)),typeof i=="string"&&i.trim()&&(u.push("profile_picture"),l.push(i.trim()),c.push(`$${d++}`)),p&&(u.push("auth_method"),l.push(p),c.push(`$${d++}`)),h&&(u.push("auth_provider"),l.push(h),c.push(`$${d++}`));let L=`
INSERT INTO ${N} (${u.join(", ")})
VALUES (${c.join(", ")})
RETURNING *
`,R=await m.query(L,l);return _(R.rows[0])}catch(m){throw $(m,"email")?new Error(`User with email ${r} already exists`):$(m,"username")?new Error(`Username ${t} is already taken`):new Error(`Failed to create user: ${m instanceof Error?m.message:"Unknown error"}`)}},async updateUser(r,e){try{let t=await a(),n=T(),s=[],o=[],i=1;if(e.email!==void 0&&(s.push(`email = $${i++}`),o.push(e.email.toLowerCase().trim())),e.password!==void 0&&(s.push(`password = $${i++}`),o.push(e.password)),e.emailVerified!==void 0&&(s.push(`email_verified = $${i++}`),o.push(e.emailVerified)),e.emailVerifiedAt!==void 0&&(s.push(`email_verified_at = $${i++}`),o.push(e.emailVerifiedAt)),e.twoFactorEnabled!==void 0&&(s.push(`two_factor_enabled = $${i++}`),o.push(e.twoFactorEnabled)),e.username!==void 0&&(s.push(`username = $${i++}`),o.push(e.username?e.username.toLowerCase().trim():null)),e.firstName!==void 0&&(s.push(`first_name = $${i++}`),o.push(e.firstName?e.firstName.trim():null)),e.lastName!==void 0&&(s.push(`last_name = $${i++}`),o.push(e.lastName?e.lastName.trim():null)),e.fullName!==void 0&&(s.push(`full_name = $${i++}`),o.push(e.fullName?e.fullName.trim():null)),e.profilePicture!==void 0&&(s.push(`profile_picture = $${i++}`),o.push(e.profilePicture?e.profilePicture.trim():null)),e.authMethod!==void 0&&(s.push(`auth_method = $${i++}`),o.push(e.authMethod||null)),e.authProvider!==void 0&&(s.push(`auth_provider = $${i++}`),o.push(e.authProvider||null)),s.length===0)throw new Error("No valid fields to update");s.push("updated_at = NOW()"),o.push(r);let p=`
UPDATE ${n}
SET ${s.join(", ")}
WHERE id = $${i}
RETURNING *
`,h=await t.query(p,o);if(h.rows.length===0)throw new Error("User not found");return _(h.rows[0])}catch(t){throw $(t,"email")?new Error(`Email ${e.email||"unknown"} is already in use`):$(t,"username")?new Error(`Username ${e.username||"unknown"} is already taken`):t instanceof Error&&t.message==="User not found"||t instanceof Error&&t.message==="No valid fields to update"?t:new Error(`Failed to update user: ${t instanceof Error?t.message:"Unknown error"}`)}},async storeTwoFactorCode(r){try{let e=await a(),t=f();await e.query(`INSERT INTO ${t} (id, user_id, code, hashed_code, type, expires_at, attempts, is_used, metadata)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,[r.id,r.userId,r.code,r.hashedCode,r.type,r.expiresAt,r.attempts,r.isUsed,JSON.stringify(r.metadata||{})]);}catch(e){throw new Error(`Failed to store two-factor code: ${e instanceof Error?e.message:"Unknown error"}`)}},async getTwoFactorCode(r){try{let e=await a(),t=f(),n=await e.query(`SELECT * FROM ${t} WHERE id = $1 LIMIT 1`,[r]);return n.rows.length===0?null:S(n.rows[0])}catch{return null}},async updateTwoFactorCode(r,e){try{let t=await a(),n=f(),s=[],o=[],i=1;if(e.attempts!==void 0&&(s.push(`attempts = $${i++}`),o.push(e.attempts)),e.isUsed!==void 0&&(s.push(`is_used = $${i++}`),o.push(e.isUsed)),e.metadata!==void 0&&(s.push(`metadata = $${i++}`),o.push(JSON.stringify(e.metadata))),s.length===0)return;o.push(r);let p=`
UPDATE ${n}
SET ${s.join(", ")}
WHERE id = $${i}
`;await t.query(p,o);}catch(t){throw new Error(`Failed to update two-factor code: ${t instanceof Error?t.message:"Unknown error"}`)}},async getUserTwoFactorCodes(r,e){try{let t=await a(),s=`SELECT * FROM ${f()} WHERE user_id = $1`,o=[r];return e&&(s+=" AND type = $2",o.push(e)),s+=" ORDER BY created_at DESC",(await t.query(s,o)).rows.map(S)}catch{return []}},async cleanupExpiredTwoFactorCodes(){try{let r=await a(),e=f();return (await r.query(`DELETE FROM ${e} WHERE expires_at < NOW()`)).rowCount||0}catch{return 0}}};exports.initializePostgreSQLTables=O;exports.postgresqlAdapter=I;exports.resetPostgreSQLConnection=U;
;