A decentralized music tracking and discovery platform built on AT Protocol 馃幍
rocksky.app
spotify
atproto
lastfm
musicbrainz
scrobbling
listenbrainz
1import SqliteDb from "better-sqlite3";
2import {
3 Kysely,
4 type Migration,
5 type MigrationProvider,
6 Migrator,
7 SqliteDialect,
8} from "kysely";
9
10// Types
11
12export type DatabaseSchema = {
13 status: Status;
14 auth_session: AuthSession;
15 auth_state: AuthState;
16};
17
18export type Status = {
19 uri: string;
20 authorDid: string;
21 status: string;
22 createdAt: string;
23 indexedAt: string;
24};
25
26export type AuthSession = {
27 key: string;
28 session: AuthSessionJson;
29};
30
31export type AuthState = {
32 key: string;
33 state: AuthStateJson;
34};
35
36type AuthStateJson = string;
37
38type AuthSessionJson = string;
39
40// Migrations
41
42const migrations: Record<string, Migration> = {};
43
44const migrationProvider: MigrationProvider = {
45 async getMigrations() {
46 return migrations;
47 },
48};
49
50migrations["001"] = {
51 async up(db: Kysely<unknown>) {
52 await db.schema
53 .createTable("status")
54 .addColumn("uri", "varchar", (col) => col.primaryKey())
55 .addColumn("authorDid", "varchar", (col) => col.notNull())
56 .addColumn("status", "varchar", (col) => col.notNull())
57 .addColumn("createdAt", "varchar", (col) => col.notNull())
58 .addColumn("indexedAt", "varchar", (col) => col.notNull())
59 .execute();
60 await db.schema
61 .createTable("auth_session")
62 .addColumn("key", "varchar", (col) => col.primaryKey())
63 .addColumn("session", "varchar", (col) => col.notNull())
64 .execute();
65 await db.schema
66 .createTable("auth_state")
67 .addColumn("key", "varchar", (col) => col.primaryKey())
68 .addColumn("state", "varchar", (col) => col.notNull())
69 .execute();
70 },
71 async down(db: Kysely<unknown>) {
72 await db.schema.dropTable("auth_state").execute();
73 await db.schema.dropTable("auth_session").execute();
74 await db.schema.dropTable("status").execute();
75 },
76};
77
78// APIs
79
80export const createDb = (location: string): Database => {
81 return new Kysely<DatabaseSchema>({
82 dialect: new SqliteDialect({
83 database: new SqliteDb(location),
84 }),
85 });
86};
87
88export const migrateToLatest = async (db: Database) => {
89 const migrator = new Migrator({ db, provider: migrationProvider });
90 const { error } = await migrator.migrateToLatest();
91 if (error) throw error;
92};
93
94export type Database = Kysely<DatabaseSchema>;