import type { Selectable } from 'kysely'
import type * as Db from '../Db.js'
import type * as db_Schema from '../Schema.js'
/** Columns of the `early_access` table, derived from `Schema.EarlyAccessEntry`. */
export type Table = db_Schema.EarlyAccessEntry
/** A stored early-access allowlist row. */
export type Record = Selectable
/**
* Inserts an allowlist entry (a domain or exact email, normalized lowercase).
* Returns the stored record, or `undefined` when the entry already exists.
*
* @param db - The database.
* @param input - The entry to insert.
* @returns The stored record, or `undefined` when already present.
*/
export function add(db: Db.Db, input: add.Input): Promise {
return db.kysely
.insertInto('early_access')
.values({
createdAt: new Date().toISOString(),
createdBy: input.createdBy,
entry: input.entry.trim().toLowerCase(),
})
.onConflict((oc) => oc.column('entry').doNothing())
.returningAll()
.executeTakeFirst()
}
export declare namespace add {
/** Fields accepted when inserting an allowlist entry. */
type Input = {
/** Admin email adding the entry, or `migration` for seeded rows. */
createdBy: string
/** Domain or exact email to grant early access; normalized lowercase. */
entry: string
}
}
/**
* Lists all allowlist entries, ordered by entry.
*
* @param db - The database.
* @returns The records.
*/
export function list(db: Db.Db): Promise {
return db.kysely.selectFrom('early_access').selectAll().orderBy('entry', 'asc').execute()
}
/**
* Removes an allowlist entry.
*
* @param db - The database.
* @param entry - The entry to remove (matched lowercase).
* @returns The removed record, or `undefined` when absent.
*/
export function remove(db: Db.Db, entry: string): Promise {
return db.kysely
.deleteFrom('early_access')
.where('entry', '=', entry.trim().toLowerCase())
.returningAll()
.executeTakeFirst()
}
/**
* Whether an allowlist entry matches `email`: the exact email or its domain.
* Two primary-key lookups via `IN`.
*
* @param db - The database.
* @param email - The email to match (case-insensitive).
* @returns Whether an entry matches.
*/
export async function matches(db: Db.Db, email: string): Promise {
const normalized = email.trim().toLowerCase()
const domain = normalized.slice(normalized.lastIndexOf('@') + 1)
const row = await db.kysely
.selectFrom('early_access')
.select('entry')
.where('entry', 'in', [normalized, domain])
.limit(1)
.executeTakeFirst()
return row !== undefined
}