@korajs/auth 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -1631,6 +1631,383 @@ function generateSecureToken2() {
1631
1631
  return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1632
1632
  }
1633
1633
 
1634
+ // src/provider/built-in/sqlite-user-store.ts
1635
+ import { randomUUID as randomUUID3 } from "crypto";
1636
+ var SqliteUserStore = class {
1637
+ db;
1638
+ constructor(db) {
1639
+ this.db = db;
1640
+ this.db.pragma("journal_mode = WAL");
1641
+ this.ensureTables();
1642
+ }
1643
+ ensureTables() {
1644
+ this.db.exec(`
1645
+ CREATE TABLE IF NOT EXISTS auth_users (
1646
+ id TEXT PRIMARY KEY,
1647
+ email TEXT NOT NULL UNIQUE COLLATE NOCASE,
1648
+ name TEXT NOT NULL,
1649
+ email_verified INTEGER NOT NULL DEFAULT 0,
1650
+ created_at INTEGER NOT NULL,
1651
+ password_hash TEXT NOT NULL,
1652
+ salt TEXT NOT NULL
1653
+ );
1654
+
1655
+ CREATE TABLE IF NOT EXISTS auth_devices (
1656
+ id TEXT PRIMARY KEY,
1657
+ user_id TEXT NOT NULL,
1658
+ public_key TEXT NOT NULL,
1659
+ name TEXT NOT NULL,
1660
+ revoked INTEGER NOT NULL DEFAULT 0,
1661
+ created_at INTEGER NOT NULL,
1662
+ last_seen_at INTEGER NOT NULL,
1663
+ FOREIGN KEY (user_id) REFERENCES auth_users(id) ON DELETE CASCADE
1664
+ );
1665
+
1666
+ CREATE INDEX IF NOT EXISTS idx_auth_devices_user_id ON auth_devices(user_id);
1667
+ `);
1668
+ }
1669
+ async createUser(params) {
1670
+ const normalizedEmail = params.email.toLowerCase();
1671
+ const now = Date.now();
1672
+ const id = randomUUID3();
1673
+ try {
1674
+ this.db.prepare(`
1675
+ INSERT INTO auth_users (id, email, name, email_verified, created_at, password_hash, salt)
1676
+ VALUES (?, ?, ?, 0, ?, ?, ?)
1677
+ `).run(id, normalizedEmail, params.name, now, params.passwordHash, params.salt);
1678
+ } catch (err) {
1679
+ if (err instanceof Error && err.message.includes("UNIQUE constraint failed")) {
1680
+ throw new DuplicateEmailError();
1681
+ }
1682
+ throw err;
1683
+ }
1684
+ return { id, email: normalizedEmail, name: params.name, emailVerified: false, createdAt: now };
1685
+ }
1686
+ async findByEmail(email) {
1687
+ const row = this.db.prepare(
1688
+ "SELECT * FROM auth_users WHERE email = ?"
1689
+ ).get(email.toLowerCase());
1690
+ return row ? rowToStoredUser(row) : null;
1691
+ }
1692
+ async findById(id) {
1693
+ const row = this.db.prepare(
1694
+ "SELECT * FROM auth_users WHERE id = ?"
1695
+ ).get(id);
1696
+ return row ? rowToStoredUser(row) : null;
1697
+ }
1698
+ async registerDevice(params) {
1699
+ const existing = this.db.prepare(
1700
+ "SELECT * FROM auth_devices WHERE id = ?"
1701
+ ).get(params.id);
1702
+ if (existing && !existing.revoked) {
1703
+ return rowToDevice(existing);
1704
+ }
1705
+ const now = Date.now();
1706
+ if (existing) {
1707
+ this.db.prepare(`
1708
+ UPDATE auth_devices SET revoked = 0, public_key = ?, name = ?, last_seen_at = ?
1709
+ WHERE id = ?
1710
+ `).run(params.publicKey, params.name, now, params.id);
1711
+ } else {
1712
+ this.db.prepare(`
1713
+ INSERT INTO auth_devices (id, user_id, public_key, name, revoked, created_at, last_seen_at)
1714
+ VALUES (?, ?, ?, ?, 0, ?, ?)
1715
+ `).run(params.id, params.userId, params.publicKey, params.name, now, now);
1716
+ }
1717
+ return {
1718
+ id: params.id,
1719
+ userId: params.userId,
1720
+ publicKey: params.publicKey,
1721
+ name: params.name,
1722
+ revoked: false,
1723
+ createdAt: existing ? existing.created_at : now,
1724
+ lastSeenAt: now
1725
+ };
1726
+ }
1727
+ async findDevice(deviceId) {
1728
+ const row = this.db.prepare(
1729
+ "SELECT * FROM auth_devices WHERE id = ?"
1730
+ ).get(deviceId);
1731
+ return row ? rowToDevice(row) : null;
1732
+ }
1733
+ async listDevices(userId) {
1734
+ const rows = this.db.prepare(
1735
+ "SELECT * FROM auth_devices WHERE user_id = ?"
1736
+ ).all(userId);
1737
+ return rows.map(rowToDevice);
1738
+ }
1739
+ async revokeDevice(deviceId) {
1740
+ this.db.prepare("UPDATE auth_devices SET revoked = 1 WHERE id = ?").run(deviceId);
1741
+ }
1742
+ async setEmailVerified(userId, verified) {
1743
+ this.db.prepare(
1744
+ "UPDATE auth_users SET email_verified = ? WHERE id = ?"
1745
+ ).run(verified ? 1 : 0, userId);
1746
+ }
1747
+ async updatePassword(userId, passwordHash, salt) {
1748
+ this.db.prepare(
1749
+ "UPDATE auth_users SET password_hash = ?, salt = ? WHERE id = ?"
1750
+ ).run(passwordHash, salt, userId);
1751
+ }
1752
+ async listAll() {
1753
+ const rows = this.db.prepare("SELECT * FROM auth_users").all();
1754
+ return rows.map(rowToStoredUser);
1755
+ }
1756
+ async update(user) {
1757
+ this.db.prepare(`
1758
+ UPDATE auth_users
1759
+ SET email = ?, name = ?, email_verified = ?, password_hash = ?, salt = ?
1760
+ WHERE id = ?
1761
+ `).run(user.email, user.name, user.emailVerified ? 1 : 0, user.passwordHash, user.salt, user.id);
1762
+ }
1763
+ async delete(userId) {
1764
+ const deleteInTransaction = this.db.transaction(() => {
1765
+ this.db.prepare("DELETE FROM auth_devices WHERE user_id = ?").run(userId);
1766
+ this.db.prepare("DELETE FROM auth_users WHERE id = ?").run(userId);
1767
+ });
1768
+ deleteInTransaction();
1769
+ }
1770
+ async touchDevice(deviceId) {
1771
+ this.db.prepare(
1772
+ "UPDATE auth_devices SET last_seen_at = ? WHERE id = ?"
1773
+ ).run(Date.now(), deviceId);
1774
+ }
1775
+ };
1776
+ async function createSqliteUserStore(options) {
1777
+ const Database = await loadBetterSqlite3();
1778
+ const db = new Database(options.filename);
1779
+ return new SqliteUserStore(db);
1780
+ }
1781
+ async function loadBetterSqlite3() {
1782
+ try {
1783
+ const { createRequire } = await import("module");
1784
+ const require2 = createRequire(import.meta.url);
1785
+ return require2("better-sqlite3");
1786
+ } catch {
1787
+ throw new Error(
1788
+ 'SQLite backend requires the "better-sqlite3" package. Install it in your project dependencies.'
1789
+ );
1790
+ }
1791
+ }
1792
+ function rowToStoredUser(row) {
1793
+ return {
1794
+ id: row.id,
1795
+ email: row.email,
1796
+ name: row.name,
1797
+ emailVerified: Boolean(row.email_verified),
1798
+ createdAt: row.created_at,
1799
+ passwordHash: row.password_hash,
1800
+ salt: row.salt
1801
+ };
1802
+ }
1803
+ function rowToDevice(row) {
1804
+ return {
1805
+ id: row.id,
1806
+ userId: row.user_id,
1807
+ publicKey: row.public_key,
1808
+ name: row.name,
1809
+ revoked: Boolean(row.revoked),
1810
+ createdAt: row.created_at,
1811
+ lastSeenAt: row.last_seen_at
1812
+ };
1813
+ }
1814
+
1815
+ // src/provider/built-in/postgres-user-store.ts
1816
+ import { randomUUID as randomUUID4 } from "crypto";
1817
+ var PostgresUserStore = class {
1818
+ sql;
1819
+ ready;
1820
+ constructor(sql) {
1821
+ this.sql = sql;
1822
+ this.ready = this.ensureTables();
1823
+ }
1824
+ async ensureTables() {
1825
+ await this.sql`
1826
+ CREATE TABLE IF NOT EXISTS auth_users (
1827
+ id TEXT PRIMARY KEY,
1828
+ email TEXT NOT NULL UNIQUE,
1829
+ name TEXT NOT NULL,
1830
+ email_verified BOOLEAN NOT NULL DEFAULT FALSE,
1831
+ created_at BIGINT NOT NULL,
1832
+ password_hash TEXT NOT NULL,
1833
+ salt TEXT NOT NULL
1834
+ )
1835
+ `;
1836
+ await this.sql`
1837
+ CREATE TABLE IF NOT EXISTS auth_devices (
1838
+ id TEXT PRIMARY KEY,
1839
+ user_id TEXT NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
1840
+ public_key TEXT NOT NULL,
1841
+ name TEXT NOT NULL,
1842
+ revoked BOOLEAN NOT NULL DEFAULT FALSE,
1843
+ created_at BIGINT NOT NULL,
1844
+ last_seen_at BIGINT NOT NULL
1845
+ )
1846
+ `;
1847
+ await this.sql`
1848
+ CREATE INDEX IF NOT EXISTS idx_auth_devices_user_id ON auth_devices(user_id)
1849
+ `;
1850
+ await this.sql`
1851
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_auth_users_email_lower ON auth_users(LOWER(email))
1852
+ `;
1853
+ }
1854
+ async createUser(params) {
1855
+ await this.ready;
1856
+ const normalizedEmail = params.email.toLowerCase();
1857
+ const now = Date.now();
1858
+ const id = randomUUID4();
1859
+ try {
1860
+ await this.sql`
1861
+ INSERT INTO auth_users (id, email, name, email_verified, created_at, password_hash, salt)
1862
+ VALUES (${id}, ${normalizedEmail}, ${params.name}, FALSE, ${now}, ${params.passwordHash}, ${params.salt})
1863
+ `;
1864
+ } catch (err) {
1865
+ if (err instanceof Error && (err.message.includes("unique constraint") || err.message.includes("duplicate key"))) {
1866
+ throw new DuplicateEmailError();
1867
+ }
1868
+ throw err;
1869
+ }
1870
+ return { id, email: normalizedEmail, name: params.name, emailVerified: false, createdAt: now };
1871
+ }
1872
+ async findByEmail(email) {
1873
+ await this.ready;
1874
+ const rows = await this.sql`
1875
+ SELECT * FROM auth_users WHERE LOWER(email) = ${email.toLowerCase()}
1876
+ `;
1877
+ return rows.length > 0 ? rowToStoredUser2(rows[0]) : null;
1878
+ }
1879
+ async findById(id) {
1880
+ await this.ready;
1881
+ const rows = await this.sql`
1882
+ SELECT * FROM auth_users WHERE id = ${id}
1883
+ `;
1884
+ return rows.length > 0 ? rowToStoredUser2(rows[0]) : null;
1885
+ }
1886
+ async registerDevice(params) {
1887
+ await this.ready;
1888
+ const existingRows = await this.sql`
1889
+ SELECT * FROM auth_devices WHERE id = ${params.id}
1890
+ `;
1891
+ if (existingRows.length > 0 && !existingRows[0].revoked) {
1892
+ return rowToDevice2(existingRows[0]);
1893
+ }
1894
+ const now = Date.now();
1895
+ if (existingRows.length > 0) {
1896
+ await this.sql`
1897
+ UPDATE auth_devices SET revoked = FALSE, public_key = ${params.publicKey}, name = ${params.name}, last_seen_at = ${now}
1898
+ WHERE id = ${params.id}
1899
+ `;
1900
+ } else {
1901
+ await this.sql`
1902
+ INSERT INTO auth_devices (id, user_id, public_key, name, revoked, created_at, last_seen_at)
1903
+ VALUES (${params.id}, ${params.userId}, ${params.publicKey}, ${params.name}, FALSE, ${now}, ${now})
1904
+ `;
1905
+ }
1906
+ return {
1907
+ id: params.id,
1908
+ userId: params.userId,
1909
+ publicKey: params.publicKey,
1910
+ name: params.name,
1911
+ revoked: false,
1912
+ createdAt: existingRows.length > 0 ? Number(existingRows[0].created_at) : now,
1913
+ lastSeenAt: now
1914
+ };
1915
+ }
1916
+ async findDevice(deviceId) {
1917
+ await this.ready;
1918
+ const rows = await this.sql`
1919
+ SELECT * FROM auth_devices WHERE id = ${deviceId}
1920
+ `;
1921
+ return rows.length > 0 ? rowToDevice2(rows[0]) : null;
1922
+ }
1923
+ async listDevices(userId) {
1924
+ await this.ready;
1925
+ const rows = await this.sql`
1926
+ SELECT * FROM auth_devices WHERE user_id = ${userId}
1927
+ `;
1928
+ return rows.map(rowToDevice2);
1929
+ }
1930
+ async revokeDevice(deviceId) {
1931
+ await this.ready;
1932
+ await this.sql`UPDATE auth_devices SET revoked = TRUE WHERE id = ${deviceId}`;
1933
+ }
1934
+ async setEmailVerified(userId, verified) {
1935
+ await this.ready;
1936
+ await this.sql`UPDATE auth_users SET email_verified = ${verified} WHERE id = ${userId}`;
1937
+ }
1938
+ async updatePassword(userId, passwordHash, salt) {
1939
+ await this.ready;
1940
+ await this.sql`
1941
+ UPDATE auth_users SET password_hash = ${passwordHash}, salt = ${salt}
1942
+ WHERE id = ${userId}
1943
+ `;
1944
+ }
1945
+ async listAll() {
1946
+ await this.ready;
1947
+ const rows = await this.sql`SELECT * FROM auth_users`;
1948
+ return rows.map(rowToStoredUser2);
1949
+ }
1950
+ async update(user) {
1951
+ await this.ready;
1952
+ await this.sql`
1953
+ UPDATE auth_users
1954
+ SET email = ${user.email}, name = ${user.name}, email_verified = ${user.emailVerified},
1955
+ password_hash = ${user.passwordHash}, salt = ${user.salt}
1956
+ WHERE id = ${user.id}
1957
+ `;
1958
+ }
1959
+ async delete(userId) {
1960
+ await this.ready;
1961
+ await this.sql.begin(async (tx) => {
1962
+ await tx`DELETE FROM auth_devices WHERE user_id = ${userId}`;
1963
+ await tx`DELETE FROM auth_users WHERE id = ${userId}`;
1964
+ });
1965
+ }
1966
+ async touchDevice(deviceId) {
1967
+ await this.ready;
1968
+ const now = Date.now();
1969
+ await this.sql`UPDATE auth_devices SET last_seen_at = ${now} WHERE id = ${deviceId}`;
1970
+ }
1971
+ };
1972
+ async function createPostgresUserStore(options) {
1973
+ const postgresClient = await loadPostgresDeps();
1974
+ const sql = postgresClient(options.connectionString);
1975
+ return new PostgresUserStore(sql);
1976
+ }
1977
+ async function loadPostgresDeps() {
1978
+ try {
1979
+ const dynamicImport = new Function("specifier", "return import(specifier)");
1980
+ const postgresMod = await dynamicImport("postgres");
1981
+ return postgresMod.default;
1982
+ } catch {
1983
+ throw new Error(
1984
+ 'PostgreSQL backend requires the "postgres" package. Install it in your project dependencies.'
1985
+ );
1986
+ }
1987
+ }
1988
+ function rowToStoredUser2(row) {
1989
+ return {
1990
+ id: row.id,
1991
+ email: row.email,
1992
+ name: row.name,
1993
+ emailVerified: Boolean(row.email_verified),
1994
+ createdAt: Number(row.created_at),
1995
+ passwordHash: row.password_hash,
1996
+ salt: row.salt
1997
+ };
1998
+ }
1999
+ function rowToDevice2(row) {
2000
+ return {
2001
+ id: row.id,
2002
+ userId: row.user_id,
2003
+ publicKey: row.public_key,
2004
+ name: row.name,
2005
+ revoked: Boolean(row.revoked),
2006
+ createdAt: Number(row.created_at),
2007
+ lastSeenAt: Number(row.last_seen_at)
2008
+ };
2009
+ }
2010
+
1634
2011
  // src/provider/adapter.ts
1635
2012
  var AuthProviderError = class extends Error {
1636
2013
  /** HTTP-style status code */
@@ -5015,6 +5392,7 @@ export {
5015
5392
  PasskeyVerificationError,
5016
5393
  PasswordResetError,
5017
5394
  PasswordResetManager,
5395
+ PostgresUserStore,
5018
5396
  ROLE_HIERARCHY,
5019
5397
  RbacEngine,
5020
5398
  RbacError,
@@ -5028,6 +5406,7 @@ export {
5028
5406
  SessionManager,
5029
5407
  SessionMfaRequiredError,
5030
5408
  SessionNotFoundError,
5409
+ SqliteUserStore,
5031
5410
  TokenManager,
5032
5411
  TotpAlreadyEnabledError,
5033
5412
  TotpError,
@@ -5045,6 +5424,8 @@ export {
5045
5424
  base32Encode,
5046
5425
  computePublicKeyThumbprint,
5047
5426
  createClerkAdapter,
5427
+ createPostgresUserStore,
5428
+ createSqliteUserStore,
5048
5429
  createSupabaseAdapter,
5049
5430
  decodeJwt,
5050
5431
  defineRoles,