Why am I so anal about my types

This commit is contained in:
Eclypsed
2024-02-22 00:36:44 -05:00
parent b7d7c0c116
commit 25260ca3cd
2 changed files with 35 additions and 24 deletions

43
src/app.d.ts vendored
View File

@@ -26,12 +26,21 @@ declare global {
type serviceType = 'jellyfin' | 'youtube-music' type serviceType = 'jellyfin' | 'youtube-music'
interface BaseConnection { type Service = Jellyfin.Service | YouTubeMusic.Service
type Tokens<T> = T extends Jellyfin.Service ? Jellyfin.Tokens : T extends YouTubeMusic.Service ? YouTubeMusic.Tokens : {}
// type ServiceTokenPair = [Jellyfin.Service, Jellyfin.Tokens] | [YouTubeMusic.Service, YouTubeMusic.Tokens]
interface BaseConnection<T> {
id: string id: string
userId: string userId: string
type: serviceType type: T extends Jellyfin.Service ? 'jellyfin' : T extends YouTubeMusic.Service ? 'youtube-music' : serviceType
service: T extends undefined ? Service : T
} }
type Connection<T extends Service = undefined> = BaseConnection<T> & Tokens<T>
// These Schemas should only contain general info data that is necessary for data fetching purposes. // These Schemas should only contain general info data that is necessary for data fetching purposes.
// They are NOT meant to be stores for large amounts of data, i.e. Don't include the data for every single song the Playlist type. // They are NOT meant to be stores for large amounts of data, i.e. Don't include the data for every single song the Playlist type.
// Big data should be fetched as needed in the app, these exist to ensure that the info necessary to fetch that data is there. // Big data should be fetched as needed in the app, these exist to ensure that the info necessary to fetch that data is there.
@@ -85,19 +94,17 @@ declare global {
// The jellyfin API will not always return the data it says it will, for example /Users/AuthenticateByName says it will // The jellyfin API will not always return the data it says it will, for example /Users/AuthenticateByName says it will
// retrun the ServerName, it wont. This must be fetched from /System/Info. // retrun the ServerName, it wont. This must be fetched from /System/Info.
// So, ONLY DEFINE THE INTERFACES FOR DATA THAT IS GARUNTEED TO BE RETURNED (unless the data value itself is inherently optional) // So, ONLY DEFINE THE INTERFACES FOR DATA THAT IS GARUNTEED TO BE RETURNED (unless the data value itself is inherently optional)
interface Connection<T = undefined> extends BaseConnection { interface Service {
type: 'jellyfin' userId: string
jellyfinUserId: string
urlOrigin: string urlOrigin: string
accessToken: string
info?: T
}
interface ConnectionInfo {
username?: string username?: string
serverName?: string serverName?: string
} }
interface Tokens {
accessToken: string
}
interface User { interface User {
Name: string Name: string
Id: string Id: string
@@ -164,17 +171,17 @@ declare global {
} }
namespace YouTubeMusic { namespace YouTubeMusic {
interface Connection<T = undefined> extends BaseConnection { interface Service {
type: 'youtube-music' userId: string
youtubeUserId: string
accessToken: string
info?: T
}
interface ConnectionInfo {
username?: string username?: string
profilePicture?: string profilePicture?: string
} }
interface Tokens {
accessToken: string
refreshToken: string
expiry: number
}
} }
} }

View File

@@ -12,6 +12,7 @@ const initUsersTable = `CREATE TABLE IF NOT EXISTS Users(
const initConnectionsTable = `CREATE TABLE IF NOT EXISTS Connections( const initConnectionsTable = `CREATE TABLE IF NOT EXISTS Connections(
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
userId VARCHAR(36) NOT NULL, userId VARCHAR(36) NOT NULL,
type VARCHAR(36) NOT NULL,
service TEXT NOT NULL, service TEXT NOT NULL,
accessToken TEXT NOT NULL, accessToken TEXT NOT NULL,
refreshToken TEXT, refreshToken TEXT,
@@ -23,6 +24,7 @@ db.exec(initUsersTable), db.exec(initConnectionsTable)
interface ConnectionsTableSchema { interface ConnectionsTableSchema {
id: string id: string
userId: string userId: string
type: string
service: string service: string
accessToken: string accessToken: string
refreshToken?: string refreshToken?: string
@@ -71,17 +73,19 @@ export class Connections {
return connections return connections
} }
static addConnection = (userId: string, service: Service, accessToken: string, refreshToken?: string, expiry?: number): Connection => { static addConnection = (userId: string, service: Service, accessToken?: string, refreshToken?: string, expiry?: number): Connection => {
const connectionId = generateUUID() const connectionId = generateUUID()
const ytConnection: YouTubeMusic.Connection = { const test: Connection = {
id: 'test', id: 'test',
userId: 'test', userId: 'test',
youtubeUserId: 'test', type: 'jellyfin',
type: 'youtube-music', service: {
userId: 'test',
urlOrigin: 'test',
},
accessToken: 'test', accessToken: 'test',
} }
const test = this.insertConnection(ytConnection) // if (!isValidURL(service.urlOrigin)) throw new Error('Service does not have valid url')
if (!isValidURL(service.urlOrigin)) throw new Error('Service does not have valid url')
db.prepare('INSERT INTO Connections(id, userId, service, accessToken, refreshToken, expiry) VALUES(?, ?, ?, ?, ?, ?)').run(connectionId, userId, JSON.stringify(service), accessToken, refreshToken, expiry) db.prepare('INSERT INTO Connections(id, userId, service, accessToken, refreshToken, expiry) VALUES(?, ?, ?, ?, ?, ?)').run(connectionId, userId, JSON.stringify(service), accessToken, refreshToken, expiry)
return this.getConnection(connectionId) return this.getConnection(connectionId)
} }