···11+CREATE TABLE `album_tracks` (
22+ `id` text PRIMARY KEY NOT NULL,
33+ `album_id` text NOT NULL,
44+ `track_id` text NOT NULL,
55+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
66+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
77+ FOREIGN KEY (`album_id`) REFERENCES `albums`(`id`) ON UPDATE no action ON DELETE no action,
88+ FOREIGN KEY (`track_id`) REFERENCES `tracks`(`id`) ON UPDATE no action ON DELETE no action
99+);
1010+--> statement-breakpoint
1111+CREATE TABLE `albums` (
1212+ `id` text PRIMARY KEY NOT NULL,
1313+ `title` text NOT NULL,
1414+ `artist` text NOT NULL,
1515+ `release_date` text,
1616+ `year` integer,
1717+ `album_art` text,
1818+ `uri` text,
1919+ `artist_uri` text,
2020+ `apple_music_link` text,
2121+ `spotify_link` text,
2222+ `tidal_link` text,
2323+ `youtube_link` text,
2424+ `sha256` text NOT NULL,
2525+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
2626+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL
2727+);
2828+--> statement-breakpoint
2929+CREATE UNIQUE INDEX `albums_uri_unique` ON `albums` (`uri`);--> statement-breakpoint
3030+CREATE UNIQUE INDEX `albums_apple_music_link_unique` ON `albums` (`apple_music_link`);--> statement-breakpoint
3131+CREATE UNIQUE INDEX `albums_spotify_link_unique` ON `albums` (`spotify_link`);--> statement-breakpoint
3232+CREATE UNIQUE INDEX `albums_tidal_link_unique` ON `albums` (`tidal_link`);--> statement-breakpoint
3333+CREATE UNIQUE INDEX `albums_youtube_link_unique` ON `albums` (`youtube_link`);--> statement-breakpoint
3434+CREATE UNIQUE INDEX `albums_sha256_unique` ON `albums` (`sha256`);--> statement-breakpoint
3535+CREATE TABLE `artist_albums` (
3636+ `id` text PRIMARY KEY NOT NULL,
3737+ `artist_id` text NOT NULL,
3838+ `album_id` text NOT NULL,
3939+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
4040+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
4141+ FOREIGN KEY (`artist_id`) REFERENCES `artists`(`id`) ON UPDATE no action ON DELETE no action,
4242+ FOREIGN KEY (`album_id`) REFERENCES `albums`(`id`) ON UPDATE no action ON DELETE no action
4343+);
4444+--> statement-breakpoint
4545+CREATE TABLE `artist_tracks` (
4646+ `id` text PRIMARY KEY NOT NULL,
4747+ `artist_id` text NOT NULL,
4848+ `track_id` text NOT NULL,
4949+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
5050+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
5151+ FOREIGN KEY (`artist_id`) REFERENCES `artists`(`id`) ON UPDATE no action ON DELETE no action,
5252+ FOREIGN KEY (`track_id`) REFERENCES `tracks`(`id`) ON UPDATE no action ON DELETE no action
5353+);
5454+--> statement-breakpoint
5555+CREATE TABLE `artists` (
5656+ `id` text PRIMARY KEY NOT NULL,
5757+ `name` text NOT NULL,
5858+ `biography` text,
5959+ `born` integer,
6060+ `born_in` text,
6161+ `died` integer,
6262+ `picture` text,
6363+ `sha256` text NOT NULL,
6464+ `uri` text,
6565+ `apple_music_link` text,
6666+ `spotify_link` text,
6767+ `tidal_link` text,
6868+ `youtube_link` text,
6969+ `genres` text,
7070+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
7171+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL
7272+);
7373+--> statement-breakpoint
7474+CREATE UNIQUE INDEX `artists_sha256_unique` ON `artists` (`sha256`);--> statement-breakpoint
7575+CREATE UNIQUE INDEX `artists_uri_unique` ON `artists` (`uri`);--> statement-breakpoint
7676+CREATE TABLE `loved_tracks` (
7777+ `id` text PRIMARY KEY NOT NULL,
7878+ `user_id` text NOT NULL,
7979+ `track_id` text NOT NULL,
8080+ `uri` text,
8181+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
8282+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
8383+ FOREIGN KEY (`track_id`) REFERENCES `tracks`(`id`) ON UPDATE no action ON DELETE no action
8484+);
8585+--> statement-breakpoint
8686+CREATE UNIQUE INDEX `loved_tracks_uri_unique` ON `loved_tracks` (`uri`);--> statement-breakpoint
8787+CREATE TABLE `tracks` (
8888+ `id` text PRIMARY KEY NOT NULL,
8989+ `title` text NOT NULL,
9090+ `artist` text NOT NULL,
9191+ `album_artist` text NOT NULL,
9292+ `album_art` text,
9393+ `album` text NOT NULL,
9494+ `track_number` integer,
9595+ `duration` integer NOT NULL,
9696+ `mb_id` text,
9797+ `youtube_link` text,
9898+ `spotify_link` text,
9999+ `apple_music_link` text,
100100+ `tidal_link` text,
101101+ `sha256` text NOT NULL,
102102+ `disc_number` integer,
103103+ `lyrics` text,
104104+ `composer` text,
105105+ `genre` text,
106106+ `label` text,
107107+ `copyright_message` text,
108108+ `uri` text,
109109+ `album_uri` text,
110110+ `artist_uri` text,
111111+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
112112+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL
113113+);
114114+--> statement-breakpoint
115115+CREATE UNIQUE INDEX `tracks_mb_id_unique` ON `tracks` (`mb_id`);--> statement-breakpoint
116116+CREATE UNIQUE INDEX `tracks_youtube_link_unique` ON `tracks` (`youtube_link`);--> statement-breakpoint
117117+CREATE UNIQUE INDEX `tracks_spotify_link_unique` ON `tracks` (`spotify_link`);--> statement-breakpoint
118118+CREATE UNIQUE INDEX `tracks_apple_music_link_unique` ON `tracks` (`apple_music_link`);--> statement-breakpoint
119119+CREATE UNIQUE INDEX `tracks_tidal_link_unique` ON `tracks` (`tidal_link`);--> statement-breakpoint
120120+CREATE UNIQUE INDEX `tracks_sha256_unique` ON `tracks` (`sha256`);--> statement-breakpoint
121121+CREATE UNIQUE INDEX `tracks_uri_unique` ON `tracks` (`uri`);--> statement-breakpoint
122122+CREATE TABLE `user_albums` (
123123+ `id` text PRIMARY KEY NOT NULL,
124124+ `user_id` text NOT NULL,
125125+ `artist_id` text NOT NULL,
126126+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
127127+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
128128+ `scrobbles` integer,
129129+ `uri` text NOT NULL,
130130+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
131131+ FOREIGN KEY (`artist_id`) REFERENCES `artists`(`id`) ON UPDATE no action ON DELETE no action
132132+);
133133+--> statement-breakpoint
134134+CREATE UNIQUE INDEX `user_albums_uri_unique` ON `user_albums` (`uri`);--> statement-breakpoint
135135+CREATE TABLE `user_tracks` (
136136+ `id` text PRIMARY KEY NOT NULL,
137137+ `user_id` text NOT NULL,
138138+ `track_id` text NOT NULL,
139139+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
140140+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
141141+ `scrobbles` integer,
142142+ `uri` text NOT NULL,
143143+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
144144+ FOREIGN KEY (`track_id`) REFERENCES `tracks`(`id`) ON UPDATE no action ON DELETE no action
145145+);
146146+--> statement-breakpoint
147147+CREATE UNIQUE INDEX `user_tracks_uri_unique` ON `user_tracks` (`uri`);--> statement-breakpoint
148148+CREATE TABLE `users` (
149149+ `id` text PRIMARY KEY NOT NULL,
150150+ `did` text NOT NULL,
151151+ `display_name` text,
152152+ `handle` text NOT NULL,
153153+ `avatar` text NOT NULL,
154154+ `created_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL,
155155+ `updated_at` integer DEFAULT CURRENT_TIMESTAMP NOT NULL
156156+);
157157+--> statement-breakpoint
158158+CREATE UNIQUE INDEX `users_did_unique` ON `users` (`did`);--> statement-breakpoint
159159+CREATE UNIQUE INDEX `users_handle_unique` ON `users` (`handle`);
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+import * as AppRockskyArtistDefs from '../artist/defs'
99+1010+export interface ProfileViewDetailed {
1111+ /** The unique identifier of the actor. */
1212+ id?: string
1313+ /** The DID of the actor. */
1414+ did?: string
1515+ /** The handle of the actor. */
1616+ handle?: string
1717+ /** The display name of the actor. */
1818+ displayName?: string
1919+ /** The URL of the actor's avatar image. */
2020+ avatar?: string
2121+ /** The date and time when the actor was created. */
2222+ createdAt?: string
2323+ /** The date and time when the actor was last updated. */
2424+ updatedAt?: string
2525+ [k: string]: unknown
2626+}
2727+2828+export function isProfileViewDetailed(v: unknown): v is ProfileViewDetailed {
2929+ return (
3030+ isObj(v) &&
3131+ hasProp(v, '$type') &&
3232+ v.$type === 'app.rocksky.actor.defs#profileViewDetailed'
3333+ )
3434+}
3535+3636+export function validateProfileViewDetailed(v: unknown): ValidationResult {
3737+ return lexicons.validate('app.rocksky.actor.defs#profileViewDetailed', v)
3838+}
3939+4040+export interface ProfileViewBasic {
4141+ /** The unique identifier of the actor. */
4242+ id?: string
4343+ /** The DID of the actor. */
4444+ did?: string
4545+ /** The handle of the actor. */
4646+ handle?: string
4747+ /** The display name of the actor. */
4848+ displayName?: string
4949+ /** The URL of the actor's avatar image. */
5050+ avatar?: string
5151+ /** The date and time when the actor was created. */
5252+ createdAt?: string
5353+ /** The date and time when the actor was last updated. */
5454+ updatedAt?: string
5555+ [k: string]: unknown
5656+}
5757+5858+export function isProfileViewBasic(v: unknown): v is ProfileViewBasic {
5959+ return (
6060+ isObj(v) &&
6161+ hasProp(v, '$type') &&
6262+ v.$type === 'app.rocksky.actor.defs#profileViewBasic'
6363+ )
6464+}
6565+6666+export function validateProfileViewBasic(v: unknown): ValidationResult {
6767+ return lexicons.validate('app.rocksky.actor.defs#profileViewBasic', v)
6868+}
6969+7070+export interface NeighbourViewBasic {
7171+ userId?: string
7272+ did?: string
7373+ handle?: string
7474+ displayName?: string
7575+ /** The URL of the actor's avatar image. */
7676+ avatar?: string
7777+ /** The number of artists shared with the actor. */
7878+ sharedArtistsCount?: number
7979+ /** The similarity score with the actor. */
8080+ similarityScore?: number
8181+ /** The top shared artist names with the actor. */
8282+ topSharedArtistNames?: string[]
8383+ /** The top shared artist details with the actor. */
8484+ topSharedArtistsDetails?: AppRockskyArtistDefs.ArtistViewBasic[]
8585+ [k: string]: unknown
8686+}
8787+8888+export function isNeighbourViewBasic(v: unknown): v is NeighbourViewBasic {
8989+ return (
9090+ isObj(v) &&
9191+ hasProp(v, '$type') &&
9292+ v.$type === 'app.rocksky.actor.defs#neighbourViewBasic'
9393+ )
9494+}
9595+9696+export function validateNeighbourViewBasic(v: unknown): ValidationResult {
9797+ return lexicons.validate('app.rocksky.actor.defs#neighbourViewBasic', v)
9898+}
9999+100100+export interface CompatibilityViewBasic {
101101+ compatibilityLevel?: number
102102+ compatibilityPercentage?: number
103103+ sharedArtists?: number
104104+ topSharedArtistNames?: string[]
105105+ topSharedDetailedArtists?: ArtistViewBasic[]
106106+ user1ArtistCount?: number
107107+ user2ArtistCount?: number
108108+ [k: string]: unknown
109109+}
110110+111111+export function isCompatibilityViewBasic(
112112+ v: unknown,
113113+): v is CompatibilityViewBasic {
114114+ return (
115115+ isObj(v) &&
116116+ hasProp(v, '$type') &&
117117+ v.$type === 'app.rocksky.actor.defs#compatibilityViewBasic'
118118+ )
119119+}
120120+121121+export function validateCompatibilityViewBasic(v: unknown): ValidationResult {
122122+ return lexicons.validate('app.rocksky.actor.defs#compatibilityViewBasic', v)
123123+}
124124+125125+export interface ArtistViewBasic {
126126+ id?: string
127127+ name?: string
128128+ picture?: string
129129+ uri?: string
130130+ user1Rank?: number
131131+ user2Rank?: number
132132+ weight?: number
133133+ [k: string]: unknown
134134+}
135135+136136+export function isArtistViewBasic(v: unknown): v is ArtistViewBasic {
137137+ return (
138138+ isObj(v) &&
139139+ hasProp(v, '$type') &&
140140+ v.$type === 'app.rocksky.actor.defs#artistViewBasic'
141141+ )
142142+}
143143+144144+export function validateArtistViewBasic(v: unknown): ValidationResult {
145145+ return lexicons.validate('app.rocksky.actor.defs#artistViewBasic', v)
146146+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import express from 'express'
55+import { ValidationResult, BlobRef } from '@atproto/lexicon'
66+import { lexicons } from '../../../../lexicons'
77+import { isObj, hasProp } from '../../../../util'
88+import { CID } from 'multiformats/cid'
99+import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
1010+import * as AppRockskyActorDefs from './defs'
1111+1212+export interface QueryParams {
1313+ /** The DID or handle of the actor */
1414+ did?: string
1515+}
1616+1717+export type InputSchema = undefined
1818+export type OutputSchema = AppRockskyActorDefs.ProfileViewDetailed
1919+export type HandlerInput = undefined
2020+2121+export interface HandlerSuccess {
2222+ encoding: 'application/json'
2323+ body: OutputSchema
2424+ headers?: { [key: string]: string }
2525+}
2626+2727+export interface HandlerError {
2828+ status: number
2929+ message?: string
3030+}
3131+3232+export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
3333+export type HandlerReqCtx<HA extends HandlerAuth = never> = {
3434+ auth: HA
3535+ params: QueryParams
3636+ input: HandlerInput
3737+ req: express.Request
3838+ res: express.Response
3939+ resetRouteRateLimits: () => Promise<void>
4040+}
4141+export type Handler<HA extends HandlerAuth = never> = (
4242+ ctx: HandlerReqCtx<HA>,
4343+) => Promise<HandlerOutput> | HandlerOutput
+51
apps/cli/src/lexicon/types/app/rocksky/album.ts
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../lexicons'
66+import { isObj, hasProp } from '../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface Record {
1010+ /** The title of the album. */
1111+ title: string
1212+ /** The artist of the album. */
1313+ artist: string
1414+ /** The duration of the album in seconds. */
1515+ duration?: number
1616+ /** The release date of the album. */
1717+ releaseDate?: string
1818+ /** The year the album was released. */
1919+ year?: number
2020+ /** The genre of the album. */
2121+ genre?: string
2222+ /** The album art of the album. */
2323+ albumArt?: BlobRef
2424+ /** The URL of the album art of the album. */
2525+ albumArtUrl?: string
2626+ /** The tags of the album. */
2727+ tags?: string[]
2828+ /** The YouTube link of the album. */
2929+ youtubeLink?: string
3030+ /** The Spotify link of the album. */
3131+ spotifyLink?: string
3232+ /** The tidal link of the album. */
3333+ tidalLink?: string
3434+ /** The Apple Music link of the album. */
3535+ appleMusicLink?: string
3636+ /** The date and time when the album was created. */
3737+ createdAt: string
3838+ [k: string]: unknown
3939+}
4040+4141+export function isRecord(v: unknown): v is Record {
4242+ return (
4343+ isObj(v) &&
4444+ hasProp(v, '$type') &&
4545+ (v.$type === 'app.rocksky.album#main' || v.$type === 'app.rocksky.album')
4646+ )
4747+}
4848+4949+export function validateRecord(v: unknown): ValidationResult {
5050+ return lexicons.validate('app.rocksky.album#main', v)
5151+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+import * as AppRockskySongDefsSongViewBasic from '../song/defs/songViewBasic'
99+1010+export interface AlbumViewBasic {
1111+ /** The unique identifier of the album. */
1212+ id?: string
1313+ /** The URI of the album. */
1414+ uri?: string
1515+ /** The title of the album. */
1616+ title?: string
1717+ /** The artist of the album. */
1818+ artist?: string
1919+ /** The URI of the album's artist. */
2020+ artistUri?: string
2121+ /** The year the album was released. */
2222+ year?: number
2323+ /** The URL of the album art image. */
2424+ albumArt?: string
2525+ /** The release date of the album. */
2626+ releaseDate?: string
2727+ /** The SHA256 hash of the album. */
2828+ sha256?: string
2929+ /** The number of times the album has been played. */
3030+ playCount?: number
3131+ /** The number of unique listeners who have played the album. */
3232+ uniqueListeners?: number
3333+ [k: string]: unknown
3434+}
3535+3636+export function isAlbumViewBasic(v: unknown): v is AlbumViewBasic {
3737+ return (
3838+ isObj(v) &&
3939+ hasProp(v, '$type') &&
4040+ v.$type === 'app.rocksky.album.defs#albumViewBasic'
4141+ )
4242+}
4343+4444+export function validateAlbumViewBasic(v: unknown): ValidationResult {
4545+ return lexicons.validate('app.rocksky.album.defs#albumViewBasic', v)
4646+}
4747+4848+export interface AlbumViewDetailed {
4949+ /** The unique identifier of the album. */
5050+ id?: string
5151+ /** The URI of the album. */
5252+ uri?: string
5353+ /** The title of the album. */
5454+ title?: string
5555+ /** The artist of the album. */
5656+ artist?: string
5757+ /** The URI of the album's artist. */
5858+ artistUri?: string
5959+ /** The year the album was released. */
6060+ year?: number
6161+ /** The URL of the album art image. */
6262+ albumArt?: string
6363+ /** The release date of the album. */
6464+ releaseDate?: string
6565+ /** The SHA256 hash of the album. */
6666+ sha256?: string
6767+ /** The number of times the album has been played. */
6868+ playCount?: number
6969+ /** The number of unique listeners who have played the album. */
7070+ uniqueListeners?: number
7171+ tracks?: AppRockskySongDefsSongViewBasic.Main[]
7272+ [k: string]: unknown
7373+}
7474+7575+export function isAlbumViewDetailed(v: unknown): v is AlbumViewDetailed {
7676+ return (
7777+ isObj(v) &&
7878+ hasProp(v, '$type') &&
7979+ v.$type === 'app.rocksky.album.defs#albumViewDetailed'
8080+ )
8181+}
8282+8383+export function validateAlbumViewDetailed(v: unknown): ValidationResult {
8484+ return lexicons.validate('app.rocksky.album.defs#albumViewDetailed', v)
8585+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface ApiKeyView {
1010+ /** The unique identifier of the API key. */
1111+ id?: string
1212+ /** The name of the API key. */
1313+ name?: string
1414+ /** A description for the API key. */
1515+ description?: string
1616+ /** The date and time when the API key was created. */
1717+ createdAt?: string
1818+ [k: string]: unknown
1919+}
2020+2121+export function isApiKeyView(v: unknown): v is ApiKeyView {
2222+ return (
2323+ isObj(v) &&
2424+ hasProp(v, '$type') &&
2525+ v.$type === 'app.rocksky.apikey.defs#apiKeyView'
2626+ )
2727+}
2828+2929+export function validateApiKeyView(v: unknown): ValidationResult {
3030+ return lexicons.validate('app.rocksky.apikey.defs#apiKeyView', v)
3131+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
+41
apps/cli/src/lexicon/types/app/rocksky/artist.ts
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../lexicons'
66+import { isObj, hasProp } from '../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface Record {
1010+ /** The name of the artist. */
1111+ name: string
1212+ /** The biography of the artist. */
1313+ bio?: string
1414+ /** The picture of the artist. */
1515+ picture?: BlobRef
1616+ /** The URL of the picture of the artist. */
1717+ pictureUrl?: string
1818+ /** The tags of the artist. */
1919+ tags?: string[]
2020+ /** The birth date of the artist. */
2121+ born?: string
2222+ /** The death date of the artist. */
2323+ died?: string
2424+ /** The birth place of the artist. */
2525+ bornIn?: string
2626+ /** The date when the artist was created. */
2727+ createdAt: string
2828+ [k: string]: unknown
2929+}
3030+3131+export function isRecord(v: unknown): v is Record {
3232+ return (
3333+ isObj(v) &&
3434+ hasProp(v, '$type') &&
3535+ (v.$type === 'app.rocksky.artist#main' || v.$type === 'app.rocksky.artist')
3636+ )
3737+}
3838+3939+export function validateRecord(v: unknown): ValidationResult {
4040+ return lexicons.validate('app.rocksky.artist#main', v)
4141+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface ArtistViewBasic {
1010+ /** The unique identifier of the artist. */
1111+ id?: string
1212+ /** The URI of the artist. */
1313+ uri?: string
1414+ /** The name of the artist. */
1515+ name?: string
1616+ /** The picture of the artist. */
1717+ picture?: string
1818+ /** The SHA256 hash of the artist. */
1919+ sha256?: string
2020+ /** The number of times the artist has been played. */
2121+ playCount?: number
2222+ /** The number of unique listeners who have played the artist. */
2323+ uniqueListeners?: number
2424+ [k: string]: unknown
2525+}
2626+2727+export function isArtistViewBasic(v: unknown): v is ArtistViewBasic {
2828+ return (
2929+ isObj(v) &&
3030+ hasProp(v, '$type') &&
3131+ v.$type === 'app.rocksky.artist.defs#artistViewBasic'
3232+ )
3333+}
3434+3535+export function validateArtistViewBasic(v: unknown): ValidationResult {
3636+ return lexicons.validate('app.rocksky.artist.defs#artistViewBasic', v)
3737+}
3838+3939+export interface ArtistViewDetailed {
4040+ /** The unique identifier of the artist. */
4141+ id?: string
4242+ /** The URI of the artist. */
4343+ uri?: string
4444+ /** The name of the artist. */
4545+ name?: string
4646+ /** The picture of the artist. */
4747+ picture?: string
4848+ /** The SHA256 hash of the artist. */
4949+ sha256?: string
5050+ /** The number of times the artist has been played. */
5151+ playCount?: number
5252+ /** The number of unique listeners who have played the artist. */
5353+ uniqueListeners?: number
5454+ [k: string]: unknown
5555+}
5656+5757+export function isArtistViewDetailed(v: unknown): v is ArtistViewDetailed {
5858+ return (
5959+ isObj(v) &&
6060+ hasProp(v, '$type') &&
6161+ v.$type === 'app.rocksky.artist.defs#artistViewDetailed'
6262+ )
6363+}
6464+6565+export function validateArtistViewDetailed(v: unknown): ValidationResult {
6666+ return lexicons.validate('app.rocksky.artist.defs#artistViewDetailed', v)
6767+}
6868+6969+export interface SongViewBasic {
7070+ /** The URI of the song. */
7171+ uri?: string
7272+ /** The title of the song. */
7373+ title?: string
7474+ /** The number of times the song has been played. */
7575+ playCount?: number
7676+ [k: string]: unknown
7777+}
7878+7979+export function isSongViewBasic(v: unknown): v is SongViewBasic {
8080+ return (
8181+ isObj(v) &&
8282+ hasProp(v, '$type') &&
8383+ v.$type === 'app.rocksky.artist.defs#songViewBasic'
8484+ )
8585+}
8686+8787+export function validateSongViewBasic(v: unknown): ValidationResult {
8888+ return lexicons.validate('app.rocksky.artist.defs#songViewBasic', v)
8989+}
9090+9191+export interface ListenerViewBasic {
9292+ /** The unique identifier of the actor. */
9393+ id?: string
9494+ /** The DID of the listener. */
9595+ did?: string
9696+ /** The handle of the listener. */
9797+ handle?: string
9898+ /** The display name of the listener. */
9999+ displayName?: string
100100+ /** The URL of the listener's avatar image. */
101101+ avatar?: string
102102+ mostListenedSong?: SongViewBasic
103103+ /** The total number of plays by the listener. */
104104+ totalPlays?: number
105105+ /** The rank of the listener among all listeners of the artist. */
106106+ rank?: number
107107+ [k: string]: unknown
108108+}
109109+110110+export function isListenerViewBasic(v: unknown): v is ListenerViewBasic {
111111+ return (
112112+ isObj(v) &&
113113+ hasProp(v, '$type') &&
114114+ v.$type === 'app.rocksky.artist.defs#listenerViewBasic'
115115+ )
116116+}
117117+118118+export function validateListenerViewBasic(v: unknown): ValidationResult {
119119+ return lexicons.validate('app.rocksky.artist.defs#listenerViewBasic', v)
120120+}
121121+122122+export interface ArtistMbid {
123123+ /** The MusicBrainz Identifier (MBID) of the artist. */
124124+ mbid?: string
125125+ /** The name of the artist. */
126126+ name?: string
127127+ [k: string]: unknown
128128+}
129129+130130+export function isArtistMbid(v: unknown): v is ArtistMbid {
131131+ return (
132132+ isObj(v) &&
133133+ hasProp(v, '$type') &&
134134+ v.$type === 'app.rocksky.artist.defs#artistMbid'
135135+ )
136136+}
137137+138138+export function validateArtistMbid(v: unknown): ValidationResult {
139139+ return lexicons.validate('app.rocksky.artist.defs#artistMbid', v)
140140+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import express from 'express'
55+import { ValidationResult, BlobRef } from '@atproto/lexicon'
66+import { lexicons } from '../../../../lexicons'
77+import { isObj, hasProp } from '../../../../util'
88+import { CID } from 'multiformats/cid'
99+import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
1010+import * as AppRockskyChartsDefs from './defs'
1111+1212+export interface QueryParams {
1313+ /** The DID or handle of the actor */
1414+ did?: string
1515+ /** The URI of the artist to filter by */
1616+ artisturi?: string
1717+ /** The URI of the album to filter by */
1818+ albumuri?: string
1919+ /** The URI of the track to filter by */
2020+ songuri?: string
2121+}
2222+2323+export type InputSchema = undefined
2424+export type OutputSchema = AppRockskyChartsDefs.ChartsView
2525+export type HandlerInput = undefined
2626+2727+export interface HandlerSuccess {
2828+ encoding: 'application/json'
2929+ body: OutputSchema
3030+ headers?: { [key: string]: string }
3131+}
3232+3333+export interface HandlerError {
3434+ status: number
3535+ message?: string
3636+}
3737+3838+export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
3939+export type HandlerReqCtx<HA extends HandlerAuth = never> = {
4040+ auth: HA
4141+ params: QueryParams
4242+ input: HandlerInput
4343+ req: express.Request
4444+ res: express.Response
4545+ resetRouteRateLimits: () => Promise<void>
4646+}
4747+export type Handler<HA extends HandlerAuth = never> = (
4848+ ctx: HandlerReqCtx<HA>,
4949+) => Promise<HandlerOutput> | HandlerOutput
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface FileView {
1010+ /** The unique identifier of the file. */
1111+ id?: string
1212+ /** The name of the file. */
1313+ name?: string
1414+ /** The lowercased path of the file. */
1515+ pathLower?: string
1616+ /** The display path of the file. */
1717+ pathDisplay?: string
1818+ /** The last modified date and time of the file on the client. */
1919+ clientModified?: string
2020+ /** The last modified date and time of the file on the server. */
2121+ serverModified?: string
2222+ [k: string]: unknown
2323+}
2424+2525+export function isFileView(v: unknown): v is FileView {
2626+ return (
2727+ isObj(v) &&
2828+ hasProp(v, '$type') &&
2929+ v.$type === 'app.rocksky.dropbox.defs#fileView'
3030+ )
3131+}
3232+3333+export function validateFileView(v: unknown): ValidationResult {
3434+ return lexicons.validate('app.rocksky.dropbox.defs#fileView', v)
3535+}
3636+3737+export interface FileListView {
3838+ /** A list of files in the Dropbox. */
3939+ files?: FileView[]
4040+ [k: string]: unknown
4141+}
4242+4343+export function isFileListView(v: unknown): v is FileListView {
4444+ return (
4545+ isObj(v) &&
4646+ hasProp(v, '$type') &&
4747+ v.$type === 'app.rocksky.dropbox.defs#fileListView'
4848+ )
4949+}
5050+5151+export function validateFileListView(v: unknown): ValidationResult {
5252+ return lexicons.validate('app.rocksky.dropbox.defs#fileListView', v)
5353+}
5454+5555+export interface TemporaryLinkView {
5656+ /** The temporary link to access the file. */
5757+ link?: string
5858+ [k: string]: unknown
5959+}
6060+6161+export function isTemporaryLinkView(v: unknown): v is TemporaryLinkView {
6262+ return (
6363+ isObj(v) &&
6464+ hasProp(v, '$type') &&
6565+ v.$type === 'app.rocksky.dropbox.defs#temporaryLinkView'
6666+ )
6767+}
6868+6969+export function validateTemporaryLinkView(v: unknown): ValidationResult {
7070+ return lexicons.validate('app.rocksky.dropbox.defs#temporaryLinkView', v)
7171+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+/** indicates that a handle or DID could not be resolved */
1010+export interface NotFoundActor {
1111+ actor: string
1212+ notFound: boolean
1313+ [k: string]: unknown
1414+}
1515+1616+export function isNotFoundActor(v: unknown): v is NotFoundActor {
1717+ return (
1818+ isObj(v) &&
1919+ hasProp(v, '$type') &&
2020+ v.$type === 'app.rocksky.graph.defs#notFoundActor'
2121+ )
2222+}
2323+2424+export function validateNotFoundActor(v: unknown): ValidationResult {
2525+ return lexicons.validate('app.rocksky.graph.defs#notFoundActor', v)
2626+}
2727+2828+export interface Relationship {
2929+ did: string
3030+ /** if the actor follows this DID, this is the AT-URI of the follow record */
3131+ following?: string
3232+ /** if the actor is followed by this DID, contains the AT-URI of the follow record */
3333+ followedBy?: string
3434+ [k: string]: unknown
3535+}
3636+3737+export function isRelationship(v: unknown): v is Relationship {
3838+ return (
3939+ isObj(v) &&
4040+ hasProp(v, '$type') &&
4141+ v.$type === 'app.rocksky.graph.defs#relationship'
4242+ )
4343+}
4444+4545+export function validateRelationship(v: unknown): ValidationResult {
4646+ return lexicons.validate('app.rocksky.graph.defs#relationship', v)
4747+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../lexicons'
66+import { isObj, hasProp } from '../../../util'
77+import { CID } from 'multiformats/cid'
88+import * as AppRockskySong from './song'
99+1010+export interface Record {
1111+ /** The name of the playlist. */
1212+ name: string
1313+ /** The playlist description. */
1414+ description?: string
1515+ /** The picture of the playlist. */
1616+ picture?: BlobRef
1717+ /** The tracks in the playlist. */
1818+ tracks?: AppRockskySong.Record[]
1919+ /** The date the playlist was created. */
2020+ createdAt: string
2121+ /** The Spotify link of the playlist. */
2222+ spotifyLink?: string
2323+ /** The Tidal link of the playlist. */
2424+ tidalLink?: string
2525+ /** The YouTube link of the playlist. */
2626+ youtubeLink?: string
2727+ /** The Apple Music link of the playlist. */
2828+ appleMusicLink?: string
2929+ [k: string]: unknown
3030+}
3131+3232+export function isRecord(v: unknown): v is Record {
3333+ return (
3434+ isObj(v) &&
3535+ hasProp(v, '$type') &&
3636+ (v.$type === 'app.rocksky.playlist#main' ||
3737+ v.$type === 'app.rocksky.playlist')
3838+ )
3939+}
4040+4141+export function validateRecord(v: unknown): ValidationResult {
4242+ return lexicons.validate('app.rocksky.playlist#main', v)
4343+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+import * as AppRockskySongDefs from '../song/defs'
99+1010+/** Detailed view of a playlist, including its tracks and metadata */
1111+export interface PlaylistViewDetailed {
1212+ /** The unique identifier of the playlist. */
1313+ id?: string
1414+ /** The title of the playlist. */
1515+ title?: string
1616+ /** The URI of the playlist. */
1717+ uri?: string
1818+ /** The DID of the curator of the playlist. */
1919+ curatorDid?: string
2020+ /** The handle of the curator of the playlist. */
2121+ curatorHandle?: string
2222+ /** The name of the curator of the playlist. */
2323+ curatorName?: string
2424+ /** The URL of the avatar image of the curator. */
2525+ curatorAvatarUrl?: string
2626+ /** A description of the playlist. */
2727+ description?: string
2828+ /** The URL of the cover image for the playlist. */
2929+ coverImageUrl?: string
3030+ /** The date and time when the playlist was created. */
3131+ createdAt?: string
3232+ /** A list of tracks in the playlist. */
3333+ tracks?: AppRockskySongDefs.SongViewBasic[]
3434+ [k: string]: unknown
3535+}
3636+3737+export function isPlaylistViewDetailed(v: unknown): v is PlaylistViewDetailed {
3838+ return (
3939+ isObj(v) &&
4040+ hasProp(v, '$type') &&
4141+ v.$type === 'app.rocksky.playlist.defs#playlistViewDetailed'
4242+ )
4343+}
4444+4545+export function validatePlaylistViewDetailed(v: unknown): ValidationResult {
4646+ return lexicons.validate('app.rocksky.playlist.defs#playlistViewDetailed', v)
4747+}
4848+4949+/** Basic view of a playlist, including its metadata */
5050+export interface PlaylistViewBasic {
5151+ /** The unique identifier of the playlist. */
5252+ id?: string
5353+ /** The title of the playlist. */
5454+ title?: string
5555+ /** The URI of the playlist. */
5656+ uri?: string
5757+ /** The DID of the curator of the playlist. */
5858+ curatorDid?: string
5959+ /** The handle of the curator of the playlist. */
6060+ curatorHandle?: string
6161+ /** The name of the curator of the playlist. */
6262+ curatorName?: string
6363+ /** The URL of the avatar image of the curator. */
6464+ curatorAvatarUrl?: string
6565+ /** A description of the playlist. */
6666+ description?: string
6767+ /** The URL of the cover image for the playlist. */
6868+ coverImageUrl?: string
6969+ /** The date and time when the playlist was created. */
7070+ createdAt?: string
7171+ /** The number of tracks in the playlist. */
7272+ trackCount?: number
7373+ [k: string]: unknown
7474+}
7575+7676+export function isPlaylistViewBasic(v: unknown): v is PlaylistViewBasic {
7777+ return (
7878+ isObj(v) &&
7979+ hasProp(v, '$type') &&
8080+ v.$type === 'app.rocksky.playlist.defs#playlistViewBasic'
8181+ )
8282+}
8383+8484+export function validatePlaylistViewBasic(v: unknown): ValidationResult {
8585+ return lexicons.validate('app.rocksky.playlist.defs#playlistViewBasic', v)
8686+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import express from 'express'
55+import { ValidationResult, BlobRef } from '@atproto/lexicon'
66+import { lexicons } from '../../../../lexicons'
77+import { isObj, hasProp } from '../../../../util'
88+import { CID } from 'multiformats/cid'
99+import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
1010+1111+export interface QueryParams {
1212+ /** The URI of the playlist to start */
1313+ uri: string
1414+ /** The directory (id) to insert into the playlist */
1515+ directory: string
1616+ /** The position in the playlist to insert the directory at, if not specified, the directory will be appended */
1717+ position?: number
1818+}
1919+2020+export type InputSchema = undefined
2121+export type HandlerInput = undefined
2222+2323+export interface HandlerError {
2424+ status: number
2525+ message?: string
2626+}
2727+2828+export type HandlerOutput = HandlerError | void
2929+export type HandlerReqCtx<HA extends HandlerAuth = never> = {
3030+ auth: HA
3131+ params: QueryParams
3232+ input: HandlerInput
3333+ req: express.Request
3434+ res: express.Response
3535+ resetRouteRateLimits: () => Promise<void>
3636+}
3737+export type Handler<HA extends HandlerAuth = never> = (
3838+ ctx: HandlerReqCtx<HA>,
3939+) => Promise<HandlerOutput> | HandlerOutput
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import express from 'express'
55+import { ValidationResult, BlobRef } from '@atproto/lexicon'
66+import { lexicons } from '../../../../lexicons'
77+import { isObj, hasProp } from '../../../../util'
88+import { CID } from 'multiformats/cid'
99+import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
1010+1111+export interface QueryParams {
1212+ /** The URI of the playlist to start */
1313+ uri: string
1414+ /** Whether to shuffle the playlist when starting it */
1515+ shuffle?: boolean
1616+ /** The position in the playlist to start from, if not specified, starts from the beginning */
1717+ position?: number
1818+}
1919+2020+export type InputSchema = undefined
2121+export type HandlerInput = undefined
2222+2323+export interface HandlerError {
2424+ status: number
2525+ message?: string
2626+}
2727+2828+export type HandlerOutput = HandlerError | void
2929+export type HandlerReqCtx<HA extends HandlerAuth = never> = {
3030+ auth: HA
3131+ params: QueryParams
3232+ input: HandlerInput
3333+ req: express.Request
3434+ res: express.Response
3535+ resetRouteRateLimits: () => Promise<void>
3636+}
3737+export type Handler<HA extends HandlerAuth = never> = (
3838+ ctx: HandlerReqCtx<HA>,
3939+) => Promise<HandlerOutput> | HandlerOutput
+37
apps/cli/src/lexicon/types/app/rocksky/radio.ts
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../lexicons'
66+import { isObj, hasProp } from '../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface Record {
1010+ /** The name of the radio station. */
1111+ name: string
1212+ /** The URL of the radio station. */
1313+ url: string
1414+ /** A description of the radio station. */
1515+ description?: string
1616+ /** The genre of the radio station. */
1717+ genre?: string
1818+ /** The logo of the radio station. */
1919+ logo?: BlobRef
2020+ /** The website of the radio station. */
2121+ website?: string
2222+ /** The date when the radio station was created. */
2323+ createdAt: string
2424+ [k: string]: unknown
2525+}
2626+2727+export function isRecord(v: unknown): v is Record {
2828+ return (
2929+ isObj(v) &&
3030+ hasProp(v, '$type') &&
3131+ (v.$type === 'app.rocksky.radio#main' || v.$type === 'app.rocksky.radio')
3232+ )
3333+}
3434+3535+export function validateRecord(v: unknown): ValidationResult {
3636+ return lexicons.validate('app.rocksky.radio#main', v)
3737+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface RadioViewBasic {
1010+ /** The unique identifier of the radio. */
1111+ id?: string
1212+ /** The name of the radio. */
1313+ name?: string
1414+ /** A brief description of the radio. */
1515+ description?: string
1616+ /** The date and time when the radio was created. */
1717+ createdAt?: string
1818+ [k: string]: unknown
1919+}
2020+2121+export function isRadioViewBasic(v: unknown): v is RadioViewBasic {
2222+ return (
2323+ isObj(v) &&
2424+ hasProp(v, '$type') &&
2525+ v.$type === 'app.rocksky.radio.defs#radioViewBasic'
2626+ )
2727+}
2828+2929+export function validateRadioViewBasic(v: unknown): ValidationResult {
3030+ return lexicons.validate('app.rocksky.radio.defs#radioViewBasic', v)
3131+}
3232+3333+export interface RadioViewDetailed {
3434+ /** The unique identifier of the radio. */
3535+ id?: string
3636+ /** The name of the radio. */
3737+ name?: string
3838+ /** A brief description of the radio. */
3939+ description?: string
4040+ /** The website of the radio. */
4141+ website?: string
4242+ /** The streaming URL of the radio. */
4343+ url?: string
4444+ /** The genre of the radio. */
4545+ genre?: string
4646+ /** The logo of the radio station. */
4747+ logo?: string
4848+ /** The date and time when the radio was created. */
4949+ createdAt?: string
5050+ [k: string]: unknown
5151+}
5252+5353+export function isRadioViewDetailed(v: unknown): v is RadioViewDetailed {
5454+ return (
5555+ isObj(v) &&
5656+ hasProp(v, '$type') &&
5757+ v.$type === 'app.rocksky.radio.defs#radioViewDetailed'
5858+ )
5959+}
6060+6161+export function validateRadioViewDetailed(v: unknown): ValidationResult {
6262+ return lexicons.validate('app.rocksky.radio.defs#radioViewDetailed', v)
6363+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../lexicons'
66+import { isObj, hasProp } from '../../../util'
77+import { CID } from 'multiformats/cid'
88+import * as AppRockskyArtistDefs from './artist/defs'
99+1010+export interface Record {
1111+ /** The title of the song. */
1212+ title: string
1313+ /** The artist of the song. */
1414+ artist: string
1515+ /** The artists of the song with MusicBrainz IDs. */
1616+ artists?: AppRockskyArtistDefs.ArtistMbid[]
1717+ /** The album artist of the song. */
1818+ albumArtist: string
1919+ /** The album of the song. */
2020+ album: string
2121+ /** The duration of the song in seconds. */
2222+ duration: number
2323+ /** The track number of the song in the album. */
2424+ trackNumber?: number
2525+ /** The disc number of the song in the album. */
2626+ discNumber?: number
2727+ /** The release date of the song. */
2828+ releaseDate?: string
2929+ /** The year the song was released. */
3030+ year?: number
3131+ /** The genre of the song. */
3232+ genre?: string
3333+ /** The tags of the song. */
3434+ tags?: string[]
3535+ /** The composer of the song. */
3636+ composer?: string
3737+ /** The lyrics of the song. */
3838+ lyrics?: string
3939+ /** The copyright message of the song. */
4040+ copyrightMessage?: string
4141+ /** Informations about the song */
4242+ wiki?: string
4343+ /** The album art of the song. */
4444+ albumArt?: BlobRef
4545+ /** The URL of the album art of the song. */
4646+ albumArtUrl?: string
4747+ /** The YouTube link of the song. */
4848+ youtubeLink?: string
4949+ /** The Spotify link of the song. */
5050+ spotifyLink?: string
5151+ /** The Tidal link of the song. */
5252+ tidalLink?: string
5353+ /** The Apple Music link of the song. */
5454+ appleMusicLink?: string
5555+ /** The date when the song was created. */
5656+ createdAt: string
5757+ /** The MusicBrainz ID of the song. */
5858+ mbid?: string
5959+ /** The label of the song. */
6060+ label?: string
6161+ [k: string]: unknown
6262+}
6363+6464+export function isRecord(v: unknown): v is Record {
6565+ return (
6666+ isObj(v) &&
6767+ hasProp(v, '$type') &&
6868+ (v.$type === 'app.rocksky.scrobble#main' ||
6969+ v.$type === 'app.rocksky.scrobble')
7070+ )
7171+}
7272+7373+export function validateRecord(v: unknown): ValidationResult {
7474+ return lexicons.validate('app.rocksky.scrobble#main', v)
7575+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import express from 'express'
55+import { ValidationResult, BlobRef } from '@atproto/lexicon'
66+import { lexicons } from '../../../../lexicons'
77+import { isObj, hasProp } from '../../../../util'
88+import { CID } from 'multiformats/cid'
99+import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
1010+import * as AppRockskyScrobbleDefs from './defs'
1111+1212+export interface QueryParams {}
1313+1414+export interface InputSchema {
1515+ /** The title of the track being scrobbled */
1616+ title: string
1717+ /** The artist of the track being scrobbled */
1818+ artist: string
1919+ /** The album of the track being scrobbled */
2020+ album?: string
2121+ /** The duration of the track in seconds */
2222+ duration?: number
2323+ /** The MusicBrainz ID of the track, if available */
2424+ mbId?: string
2525+ /** The URL of the album art for the track */
2626+ albumArt?: string
2727+ /** The track number of the track in the album */
2828+ trackNumber?: number
2929+ /** The release date of the track, formatted as YYYY-MM-DD */
3030+ releaseDate?: string
3131+ /** The year the track was released */
3232+ year?: number
3333+ /** The disc number of the track in the album, if applicable */
3434+ discNumber?: number
3535+ /** The lyrics of the track, if available */
3636+ lyrics?: string
3737+ /** The composer of the track, if available */
3838+ composer?: string
3939+ /** The copyright message for the track, if available */
4040+ copyrightMessage?: string
4141+ /** The record label of the track, if available */
4242+ label?: string
4343+ /** The URL of the artist's picture, if available */
4444+ artistPicture?: string
4545+ /** The Spotify link for the track, if available */
4646+ spotifyLink?: string
4747+ /** The Last.fm link for the track, if available */
4848+ lastfmLink?: string
4949+ /** The Tidal link for the track, if available */
5050+ tidalLink?: string
5151+ /** The Apple Music link for the track, if available */
5252+ appleMusicLink?: string
5353+ /** The Youtube link for the track, if available */
5454+ youtubeLink?: string
5555+ /** The Deezer link for the track, if available */
5656+ deezerLink?: string
5757+ /** The timestamp of the scrobble in milliseconds since epoch */
5858+ timestamp?: number
5959+ [k: string]: unknown
6060+}
6161+6262+export type OutputSchema = AppRockskyScrobbleDefs.ScrobbleViewBasic
6363+6464+export interface HandlerInput {
6565+ encoding: 'application/json'
6666+ body: InputSchema
6767+}
6868+6969+export interface HandlerSuccess {
7070+ encoding: 'application/json'
7171+ body: OutputSchema
7272+ headers?: { [key: string]: string }
7373+}
7474+7575+export interface HandlerError {
7676+ status: number
7777+ message?: string
7878+}
7979+8080+export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
8181+export type HandlerReqCtx<HA extends HandlerAuth = never> = {
8282+ auth: HA
8383+ params: QueryParams
8484+ input: HandlerInput
8585+ req: express.Request
8686+ res: express.Response
8787+ resetRouteRateLimits: () => Promise<void>
8888+}
8989+export type Handler<HA extends HandlerAuth = never> = (
9090+ ctx: HandlerReqCtx<HA>,
9191+) => Promise<HandlerOutput> | HandlerOutput
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface ScrobbleViewBasic {
1010+ /** The unique identifier of the scrobble. */
1111+ id?: string
1212+ /** The handle of the user who created the scrobble. */
1313+ user?: string
1414+ /** The display name of the user who created the scrobble. */
1515+ userDisplayName?: string
1616+ /** The avatar URL of the user who created the scrobble. */
1717+ userAvatar?: string
1818+ /** The title of the scrobble. */
1919+ title?: string
2020+ /** The artist of the song. */
2121+ artist?: string
2222+ /** The URI of the artist. */
2323+ artistUri?: string
2424+ /** The album of the song. */
2525+ album?: string
2626+ /** The URI of the album. */
2727+ albumUri?: string
2828+ /** The album art URL of the song. */
2929+ cover?: string
3030+ /** The timestamp when the scrobble was created. */
3131+ date?: string
3232+ /** The URI of the scrobble. */
3333+ uri?: string
3434+ /** The SHA256 hash of the scrobble data. */
3535+ sha256?: string
3636+ liked?: boolean
3737+ likesCount?: number
3838+ [k: string]: unknown
3939+}
4040+4141+export function isScrobbleViewBasic(v: unknown): v is ScrobbleViewBasic {
4242+ return (
4343+ isObj(v) &&
4444+ hasProp(v, '$type') &&
4545+ v.$type === 'app.rocksky.scrobble.defs#scrobbleViewBasic'
4646+ )
4747+}
4848+4949+export function validateScrobbleViewBasic(v: unknown): ValidationResult {
5050+ return lexicons.validate('app.rocksky.scrobble.defs#scrobbleViewBasic', v)
5151+}
5252+5353+export interface ScrobbleViewDetailed {
5454+ /** The unique identifier of the scrobble. */
5555+ id?: string
5656+ /** The handle of the user who created the scrobble. */
5757+ user?: string
5858+ /** The title of the scrobble. */
5959+ title?: string
6060+ /** The artist of the song. */
6161+ artist?: string
6262+ /** The URI of the artist. */
6363+ artistUri?: string
6464+ /** The album of the song. */
6565+ album?: string
6666+ /** The URI of the album. */
6767+ albumUri?: string
6868+ /** The album art URL of the song. */
6969+ cover?: string
7070+ /** The timestamp when the scrobble was created. */
7171+ date?: string
7272+ /** The URI of the scrobble. */
7373+ uri?: string
7474+ /** The SHA256 hash of the scrobble data. */
7575+ sha256?: string
7676+ /** The number of listeners */
7777+ listeners?: number
7878+ /** The number of scrobbles for this song */
7979+ scrobbles?: number
8080+ [k: string]: unknown
8181+}
8282+8383+export function isScrobbleViewDetailed(v: unknown): v is ScrobbleViewDetailed {
8484+ return (
8585+ isObj(v) &&
8686+ hasProp(v, '$type') &&
8787+ v.$type === 'app.rocksky.scrobble.defs#scrobbleViewDetailed'
8888+ )
8989+}
9090+9191+export function validateScrobbleViewDetailed(v: unknown): ValidationResult {
9292+ return lexicons.validate('app.rocksky.scrobble.defs#scrobbleViewDetailed', v)
9393+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface Author {
1010+ /** The unique identifier of the author. */
1111+ id?: string
1212+ /** The decentralized identifier (DID) of the author. */
1313+ did?: string
1414+ /** The handle of the author. */
1515+ handle?: string
1616+ /** The display name of the author. */
1717+ displayName?: string
1818+ /** The URL of the author's avatar image. */
1919+ avatar?: string
2020+ [k: string]: unknown
2121+}
2222+2323+export function isAuthor(v: unknown): v is Author {
2424+ return (
2525+ isObj(v) &&
2626+ hasProp(v, '$type') &&
2727+ v.$type === 'app.rocksky.shout.defs#author'
2828+ )
2929+}
3030+3131+export function validateAuthor(v: unknown): ValidationResult {
3232+ return lexicons.validate('app.rocksky.shout.defs#author', v)
3333+}
3434+3535+export interface ShoutView {
3636+ /** The unique identifier of the shout. */
3737+ id?: string
3838+ /** The content of the shout. */
3939+ message?: string
4040+ /** The ID of the parent shout if this is a reply, otherwise null. */
4141+ parent?: string
4242+ /** The date and time when the shout was created. */
4343+ createdAt?: string
4444+ author?: Author
4545+ [k: string]: unknown
4646+}
4747+4848+export function isShoutView(v: unknown): v is ShoutView {
4949+ return (
5050+ isObj(v) &&
5151+ hasProp(v, '$type') &&
5252+ v.$type === 'app.rocksky.shout.defs#shoutView'
5353+ )
5454+}
5555+5656+export function validateShoutView(v: unknown): ValidationResult {
5757+ return lexicons.validate('app.rocksky.shout.defs#shoutView', v)
5858+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import express from 'express'
55+import { ValidationResult, BlobRef } from '@atproto/lexicon'
66+import { lexicons } from '../../../../lexicons'
77+import { isObj, hasProp } from '../../../../util'
88+import { CID } from 'multiformats/cid'
99+import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
1010+import * as AppRockskyShoutDefs from './defs'
1111+1212+export interface QueryParams {}
1313+1414+export interface InputSchema {
1515+ /** The unique identifier of the shout to report */
1616+ shoutId: string
1717+ /** The reason for reporting the shout */
1818+ reason?: string
1919+ [k: string]: unknown
2020+}
2121+2222+export type OutputSchema = AppRockskyShoutDefs.ShoutView
2323+2424+export interface HandlerInput {
2525+ encoding: 'application/json'
2626+ body: InputSchema
2727+}
2828+2929+export interface HandlerSuccess {
3030+ encoding: 'application/json'
3131+ body: OutputSchema
3232+ headers?: { [key: string]: string }
3333+}
3434+3535+export interface HandlerError {
3636+ status: number
3737+ message?: string
3838+}
3939+4040+export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
4141+export type HandlerReqCtx<HA extends HandlerAuth = never> = {
4242+ auth: HA
4343+ params: QueryParams
4444+ input: HandlerInput
4545+ req: express.Request
4646+ res: express.Response
4747+ resetRouteRateLimits: () => Promise<void>
4848+}
4949+export type Handler<HA extends HandlerAuth = never> = (
5050+ ctx: HandlerReqCtx<HA>,
5151+) => Promise<HandlerOutput> | HandlerOutput
+74
apps/cli/src/lexicon/types/app/rocksky/song.ts
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../lexicons'
66+import { isObj, hasProp } from '../../../util'
77+import { CID } from 'multiformats/cid'
88+import * as AppRockskyArtistDefs from './artist/defs'
99+1010+export interface Record {
1111+ /** The title of the song. */
1212+ title: string
1313+ /** The artist of the song. */
1414+ artist: string
1515+ /** The artists of the song with MusicBrainz IDs. */
1616+ artists?: AppRockskyArtistDefs.ArtistMbid[]
1717+ /** The album artist of the song. */
1818+ albumArtist: string
1919+ /** The album of the song. */
2020+ album: string
2121+ /** The duration of the song in seconds. */
2222+ duration: number
2323+ /** The track number of the song in the album. */
2424+ trackNumber?: number
2525+ /** The disc number of the song in the album. */
2626+ discNumber?: number
2727+ /** The release date of the song. */
2828+ releaseDate?: string
2929+ /** The year the song was released. */
3030+ year?: number
3131+ /** The genre of the song. */
3232+ genre?: string
3333+ /** The tags of the song. */
3434+ tags?: string[]
3535+ /** The composer of the song. */
3636+ composer?: string
3737+ /** The lyrics of the song. */
3838+ lyrics?: string
3939+ /** The copyright message of the song. */
4040+ copyrightMessage?: string
4141+ /** Informations about the song */
4242+ wiki?: string
4343+ /** The album art of the song. */
4444+ albumArt?: BlobRef
4545+ /** The URL of the album art of the song. */
4646+ albumArtUrl?: string
4747+ /** The YouTube link of the song. */
4848+ youtubeLink?: string
4949+ /** The Spotify link of the song. */
5050+ spotifyLink?: string
5151+ /** The Tidal link of the song. */
5252+ tidalLink?: string
5353+ /** The Apple Music link of the song. */
5454+ appleMusicLink?: string
5555+ /** The date when the song was created. */
5656+ createdAt: string
5757+ /** The MusicBrainz ID of the song. */
5858+ mbid?: string
5959+ /** The label of the song. */
6060+ label?: string
6161+ [k: string]: unknown
6262+}
6363+6464+export function isRecord(v: unknown): v is Record {
6565+ return (
6666+ isObj(v) &&
6767+ hasProp(v, '$type') &&
6868+ (v.$type === 'app.rocksky.song#main' || v.$type === 'app.rocksky.song')
6969+ )
7070+}
7171+7272+export function validateRecord(v: unknown): ValidationResult {
7373+ return lexicons.validate('app.rocksky.song#main', v)
7474+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import express from 'express'
55+import { ValidationResult, BlobRef } from '@atproto/lexicon'
66+import { lexicons } from '../../../../lexicons'
77+import { isObj, hasProp } from '../../../../util'
88+import { CID } from 'multiformats/cid'
99+import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
1010+import * as AppRockskySongDefs from './defs'
1111+1212+export interface QueryParams {}
1313+1414+export interface InputSchema {
1515+ /** The title of the song */
1616+ title: string
1717+ /** The artist of the song */
1818+ artist: string
1919+ /** The album artist of the song, if different from the main artist */
2020+ albumArtist: string
2121+ /** The album of the song, if applicable */
2222+ album: string
2323+ /** The duration of the song in seconds */
2424+ duration?: number
2525+ /** The MusicBrainz ID of the song, if available */
2626+ mbId?: string
2727+ /** The URL of the album art for the song */
2828+ albumArt?: string
2929+ /** The track number of the song in the album, if applicable */
3030+ trackNumber?: number
3131+ /** The release date of the song, formatted as YYYY-MM-DD */
3232+ releaseDate?: string
3333+ /** The year the song was released */
3434+ year?: number
3535+ /** The disc number of the song in the album, if applicable */
3636+ discNumber?: number
3737+ /** The lyrics of the song, if available */
3838+ lyrics?: string
3939+ [k: string]: unknown
4040+}
4141+4242+export type OutputSchema = AppRockskySongDefs.SongViewDetailed
4343+4444+export interface HandlerInput {
4545+ encoding: 'application/json'
4646+ body: InputSchema
4747+}
4848+4949+export interface HandlerSuccess {
5050+ encoding: 'application/json'
5151+ body: OutputSchema
5252+ headers?: { [key: string]: string }
5353+}
5454+5555+export interface HandlerError {
5656+ status: number
5757+ message?: string
5858+}
5959+6060+export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
6161+export type HandlerReqCtx<HA extends HandlerAuth = never> = {
6262+ auth: HA
6363+ params: QueryParams
6464+ input: HandlerInput
6565+ req: express.Request
6666+ res: express.Response
6767+ resetRouteRateLimits: () => Promise<void>
6868+}
6969+export type Handler<HA extends HandlerAuth = never> = (
7070+ ctx: HandlerReqCtx<HA>,
7171+) => Promise<HandlerOutput> | HandlerOutput
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface SongViewBasic {
1010+ /** The unique identifier of the song. */
1111+ id?: string
1212+ /** The title of the song. */
1313+ title?: string
1414+ /** The artist of the song. */
1515+ artist?: string
1616+ /** The artist of the album the song belongs to. */
1717+ albumArtist?: string
1818+ /** The URL of the album art image. */
1919+ albumArt?: string
2020+ /** The URI of the song. */
2121+ uri?: string
2222+ /** The album of the song. */
2323+ album?: string
2424+ /** The duration of the song in milliseconds. */
2525+ duration?: number
2626+ /** The track number of the song in the album. */
2727+ trackNumber?: number
2828+ /** The disc number of the song in the album. */
2929+ discNumber?: number
3030+ /** The number of times the song has been played. */
3131+ playCount?: number
3232+ /** The number of unique listeners who have played the song. */
3333+ uniqueListeners?: number
3434+ /** The URI of the album the song belongs to. */
3535+ albumUri?: string
3636+ /** The URI of the artist of the song. */
3737+ artistUri?: string
3838+ /** The SHA256 hash of the song. */
3939+ sha256?: string
4040+ /** The timestamp when the song was created. */
4141+ createdAt?: string
4242+ [k: string]: unknown
4343+}
4444+4545+export function isSongViewBasic(v: unknown): v is SongViewBasic {
4646+ return (
4747+ isObj(v) &&
4848+ hasProp(v, '$type') &&
4949+ v.$type === 'app.rocksky.song.defs#songViewBasic'
5050+ )
5151+}
5252+5353+export function validateSongViewBasic(v: unknown): ValidationResult {
5454+ return lexicons.validate('app.rocksky.song.defs#songViewBasic', v)
5555+}
5656+5757+export interface SongViewDetailed {
5858+ /** The unique identifier of the song. */
5959+ id?: string
6060+ /** The title of the song. */
6161+ title?: string
6262+ /** The artist of the song. */
6363+ artist?: string
6464+ /** The artist of the album the song belongs to. */
6565+ albumArtist?: string
6666+ /** The URL of the album art image. */
6767+ albumArt?: string
6868+ /** The URI of the song. */
6969+ uri?: string
7070+ /** The album of the song. */
7171+ album?: string
7272+ /** The duration of the song in milliseconds. */
7373+ duration?: number
7474+ /** The track number of the song in the album. */
7575+ trackNumber?: number
7676+ /** The disc number of the song in the album. */
7777+ discNumber?: number
7878+ /** The number of times the song has been played. */
7979+ playCount?: number
8080+ /** The number of unique listeners who have played the song. */
8181+ uniqueListeners?: number
8282+ /** The URI of the album the song belongs to. */
8383+ albumUri?: string
8484+ /** The URI of the artist of the song. */
8585+ artistUri?: string
8686+ /** The SHA256 hash of the song. */
8787+ sha256?: string
8888+ /** The timestamp when the song was created. */
8989+ createdAt?: string
9090+ [k: string]: unknown
9191+}
9292+9393+export function isSongViewDetailed(v: unknown): v is SongViewDetailed {
9494+ return (
9595+ isObj(v) &&
9696+ hasProp(v, '$type') &&
9797+ v.$type === 'app.rocksky.song.defs#songViewDetailed'
9898+ )
9999+}
100100+101101+export function validateSongViewDetailed(v: unknown): ValidationResult {
102102+ return lexicons.validate('app.rocksky.song.defs#songViewDetailed', v)
103103+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface SpotifyTrackView {
1010+ /** The unique identifier of the Spotify track. */
1111+ id?: string
1212+ /** The name of the track. */
1313+ name?: string
1414+ /** The name of the artist. */
1515+ artist?: string
1616+ /** The name of the album. */
1717+ album?: string
1818+ /** The duration of the track in milliseconds. */
1919+ duration?: number
2020+ /** A URL to a preview of the track. */
2121+ previewUrl?: string
2222+ [k: string]: unknown
2323+}
2424+2525+export function isSpotifyTrackView(v: unknown): v is SpotifyTrackView {
2626+ return (
2727+ isObj(v) &&
2828+ hasProp(v, '$type') &&
2929+ v.$type === 'app.rocksky.spotify.defs#spotifyTrackView'
3030+ )
3131+}
3232+3333+export function validateSpotifyTrackView(v: unknown): ValidationResult {
3434+ return lexicons.validate('app.rocksky.spotify.defs#spotifyTrackView', v)
3535+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface StatsView {
1010+ /** The total number of scrobbles. */
1111+ scrobbles?: number
1212+ /** The total number of unique artists scrobbled. */
1313+ artists?: number
1414+ /** The total number of tracks marked as loved. */
1515+ lovedTracks?: number
1616+ /** The total number of unique albums scrobbled. */
1717+ albums?: number
1818+ /** The total number of unique tracks scrobbled. */
1919+ tracks?: number
2020+ [k: string]: unknown
2121+}
2222+2323+export function isStatsView(v: unknown): v is StatsView {
2424+ return (
2525+ isObj(v) &&
2626+ hasProp(v, '$type') &&
2727+ v.$type === 'app.rocksky.stats.defs#statsView'
2828+ )
2929+}
3030+3131+export function validateStatsView(v: unknown): ValidationResult {
3232+ return lexicons.validate('app.rocksky.stats.defs#statsView', v)
3333+}
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+import { ValidationResult, BlobRef } from '@atproto/lexicon'
55+import { lexicons } from '../../../../lexicons'
66+import { isObj, hasProp } from '../../../../util'
77+import { CID } from 'multiformats/cid'
88+99+export interface Main {
1010+ uri: string
1111+ cid: string
1212+ [k: string]: unknown
1313+}
1414+1515+export function isMain(v: unknown): v is Main {
1616+ return (
1717+ isObj(v) &&
1818+ hasProp(v, '$type') &&
1919+ (v.$type === 'com.atproto.repo.strongRef#main' ||
2020+ v.$type === 'com.atproto.repo.strongRef')
2121+ )
2222+}
2323+2424+export function validateMain(v: unknown): ValidationResult {
2525+ return lexicons.validate('com.atproto.repo.strongRef#main', v)
2626+}
+13
apps/cli/src/lexicon/util.ts
···11+/**
22+ * GENERATED CODE - DO NOT MODIFY
33+ */
44+export function isObj(v: unknown): v is Record<string, unknown> {
55+ return typeof v === 'object' && v !== null
66+}
77+88+export function hasProp<K extends PropertyKey>(
99+ data: object,
1010+ prop: K,
1111+): data is Record<K, unknown> {
1212+ return prop in data
1313+}
+25
apps/cli/src/schema/album-tracks.ts
···11+import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm";
22+import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
33+import albums from "./albums";
44+import tracks from "./tracks";
55+66+const albumTracks = sqliteTable("album_tracks", {
77+ id: text("id").primaryKey().notNull(),
88+ albumId: text("album_id")
99+ .notNull()
1010+ .references(() => albums.id),
1111+ trackId: text("track_id")
1212+ .notNull()
1313+ .references(() => tracks.id),
1414+ createdAt: integer("created_at")
1515+ .notNull()
1616+ .default(sql`CURRENT_TIMESTAMP`),
1717+ updatedAt: integer("updated_at")
1818+ .notNull()
1919+ .default(sql`CURRENT_TIMESTAMP`),
2020+});
2121+2222+export type SelectAlbumTrack = InferSelectModel<typeof albumTracks>;
2323+export type InsertAlbumTrack = InferInsertModel<typeof albumTracks>;
2424+2525+export default albumTracks;
···11+import albumTracks from "./album-tracks";
22+import albums from "./albums";
33+import artists from "./artists";
44+import tracks from "./tracks";
55+import users from "./users";
66+77+export default {
88+ users,
99+ tracks,
1010+ artists,
1111+ albums,
1212+ albumTracks,
1313+};
+23
apps/cli/src/schema/loved-tracks.ts
···11+import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm";
22+import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
33+import tracks from "./tracks";
44+import users from "./users";
55+66+const lovedTracks = sqliteTable("loved_tracks", {
77+ id: text("id").primaryKey().notNull(),
88+ userId: text("user_id")
99+ .notNull()
1010+ .references(() => users.id),
1111+ trackId: text("track_id")
1212+ .notNull()
1313+ .references(() => tracks.id),
1414+ uri: text("uri").unique(),
1515+ createdAt: integer("created_at")
1616+ .notNull()
1717+ .default(sql`CURRENT_TIMESTAMP`),
1818+});
1919+2020+export type SelectLovedTrack = InferSelectModel<typeof lovedTracks>;
2121+export type InsertLovedTrack = InferInsertModel<typeof lovedTracks>;
2222+2323+export default lovedTracks;