11import fs from "node:fs" ;
22import { join } from "node:path" ;
3- import { SQL } from "bun" ;
3+ import { SQL , sql } from "bun" ;
44
55fs . mkdirSync ( process . env . DATA_PATH || "./.data" , {
66 recursive : true ,
@@ -13,66 +13,82 @@ async function initDb() {
1313
1414 db = new SQL ( dbUrl ) ;
1515
16+ const isSqlite = db . options . adapter === "sqlite" ;
17+ const isPostgres = db . options . adapter === "postgres" ;
18+ const changeIntToBigInt = async ( tbl , col ) => {
19+ if ( isSqlite ) return ; // Irrelevant in SQLite.
20+ if ( isPostgres ) {
21+ await db `alter table ${ sql ( tbl ) } alter column ${ sql ( col ) } type bigint` . simple ( ) ;
22+ } else {
23+ await db `alter table ${ sql ( tbl ) } modify column ${ sql ( col ) } bigint` . simple ( ) ;
24+ }
25+ } ;
26+ // MySQL requires a prefix-length for indexing text. 4096 is an arbitrarily chosen number.
27+ const indexableTextColType = isPostgres || isSqlite ? sql `text` : sql `varchar(4096)` ;
28+
1629 await db `create table if not exists sessions (
17- token text primary key not null,
18- expires integer not null,
19- created integer not null
30+ token ${ indexableTextColType } primary key not null,
31+ expires bigint not null,
32+ created bigint not null
2033 )` . simple ( ) ;
34+ await changeIntToBigInt ( "sessions" , "expires" ) ;
35+ await changeIntToBigInt ( "sessions" , "created" ) ;
2136
2237 await db `create table if not exists keys (
23- siteKey text primary key not null,
38+ siteKey ${ indexableTextColType } primary key not null,
2439 name text not null,
2540 secretHash text not null,
2641 config text not null,
27- created integer not null
42+ created bigint not null
2843 )` . simple ( ) ;
44+ await changeIntToBigInt ( "keys" , "created" ) ;
2945
3046 await db `create table if not exists solutions (
31- siteKey text not null,
32- bucket integer not null,
47+ siteKey ${ indexableTextColType } not null,
48+ bucket bigint not null,
3349 count integer default 0,
3450 primary key (siteKey, bucket)
3551 )` . simple ( ) ;
52+ await changeIntToBigInt ( "solutions" , "bucket" ) ;
3653
3754 await db `create table if not exists challenges (
38- siteKey text not null,
39- token text not null,
55+ siteKey ${ indexableTextColType } not null,
56+ token ${ indexableTextColType } not null,
4057 data text not null,
41- expires integer not null,
58+ expires bigint not null,
4259 primary key (siteKey, token)
4360 )` . simple ( ) ;
61+ await changeIntToBigInt ( "challenges" , "expires" ) ;
4462
4563 await db `create table if not exists tokens (
46- siteKey text not null,
47- token text not null,
48- expires integer not null,
64+ siteKey ${ indexableTextColType } not null,
65+ token ${ indexableTextColType } not null,
66+ expires bigint not null,
4967 primary key (siteKey, token)
5068 )` . simple ( ) ;
69+ await changeIntToBigInt ( "tokens" , "expires" ) ;
5170
5271 await db `create table if not exists api_keys (
53- id text not null,
72+ id ${ indexableTextColType } not null,
5473 name text not null,
55- tokenHash text not null,
56- created integer not null,
74+ tokenHash ${ indexableTextColType } not null,
75+ created bigint not null,
5776 primary key (id, tokenHash)
5877 )` . simple ( ) ;
78+ await changeIntToBigInt ( "api_keys" , "created" ) ;
5979
60- setInterval ( async ( ) => {
61- const now = Date . now ( ) ;
62-
63- await db `delete from sessions where expires < ${ now } ` ;
64- await db `delete from tokens where expires < ${ now } ` ;
65- await db `delete from challenges where expires < ${ now } ` ;
66- } , 60 * 1000 ) ;
80+ setInterval ( periodicCleanup , 60 * 1000 ) ;
81+ await periodicCleanup ( ) ;
6782
83+ return db ;
84+ }
6885
86+ async function periodicCleanup ( ) {
6987 const now = Date . now ( ) ;
7088
7189 await db `delete from sessions where expires < ${ now } ` ;
7290 await db `delete from tokens where expires < ${ now } ` ;
7391 await db `delete from challenges where expires < ${ now } ` ;
74-
75- return db ;
7692}
7793
7894db = await initDb ( ) ;
0 commit comments