diff --git a/apps/api/lexicons/feed/defs.json b/apps/api/lexicons/feed/defs.json index 540047b1..60c5f460 100644 --- a/apps/api/lexicons/feed/defs.json +++ b/apps/api/lexicons/feed/defs.json @@ -138,6 +138,16 @@ "ref": "app.rocksky.actor.defs#profileViewBasic" } } + }, + "feedUriView": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "The feed URI.", + "format": "at-uri" + } + } } } } diff --git a/apps/api/lexicons/feed/describeFeedGenerator.json b/apps/api/lexicons/feed/describeFeedGenerator.json new file mode 100644 index 00000000..acacbc9a --- /dev/null +++ b/apps/api/lexicons/feed/describeFeedGenerator.json @@ -0,0 +1,35 @@ +{ + "lexicon": 1, + "id": "app.rocksky.feed.describeFeedGenerator", + "defs": { + "main": { + "type": "query", + "description": "Get information about a feed generator", + "parameters": { + "type": "params", + "properties": {} + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "The DID of the feed generator.", + "format": "at-identifier" + }, + "feeds": { + "type": "array", + "description": "List of feed URIs generated by this feed generator.", + "items": { + "type": "ref", + "ref": "app.rocksky.feed.defs#feedUriView" + } + } + } + } + } + } + } +} diff --git a/apps/api/lexicons/feed/getFeed.json b/apps/api/lexicons/feed/getFeed.json new file mode 100644 index 00000000..7e9c1d1e --- /dev/null +++ b/apps/api/lexicons/feed/getFeed.json @@ -0,0 +1,48 @@ +{ + "lexicon": 1, + "id": "app.rocksky.feed.getFeed", + "defs": { + "main": { + "type": "query", + "description": "Get the feed by uri", + "parameters": { + "type": "params", + "required": [ + "feed" + ], + "properties": { + "feed": { + "type": "string", + "description": "The feed URI.", + "format": "at-uri" + }, + "limit": { + "type": "integer", + "description": "The maximum number of scrobbles to return", + "minimum": 1 + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "scrobbles": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.rocksky.scrobble.defs#scrobbleViewBasic" + } + } + } + } + } + } + } +} diff --git a/apps/api/lexicons/feed/getFeedGenerator.json b/apps/api/lexicons/feed/getFeedGenerator.json new file mode 100644 index 00000000..bab40c56 --- /dev/null +++ b/apps/api/lexicons/feed/getFeedGenerator.json @@ -0,0 +1,35 @@ +{ + "lexicon": 1, + "id": "app.rocksky.feed.getFeedGenerator", + "defs": { + "main": { + "type": "query", + "description": "Get information about a feed generator", + "parameters": { + "type": "params", + "required": [ + "feed" + ], + "properties": { + "feed": { + "type": "string", + "description": "AT-URI of the feed generator record.", + "format": "at-uri" + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "view": { + "type": "ref", + "ref": "app.rocksky.feed.defs#feedGeneratorView" + } + } + } + } + } + } +} diff --git a/apps/api/lexicons/feed/getFeedSkeleton.json b/apps/api/lexicons/feed/getFeedSkeleton.json new file mode 100644 index 00000000..cc9b2f42 --- /dev/null +++ b/apps/api/lexicons/feed/getFeedSkeleton.json @@ -0,0 +1,56 @@ +{ + "lexicon": 1, + "id": "app.rocksky.feed.getFeedSkeleton", + "defs": { + "main": { + "type": "query", + "description": "Get the feed by uri", + "parameters": { + "type": "params", + "required": [ + "feed" + ], + "properties": { + "feed": { + "type": "string", + "description": "The feed URI.", + "format": "at-uri" + }, + "limit": { + "type": "integer", + "description": "The maximum number of scrobbles to return", + "minimum": 1 + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0 + }, + "cursor": { + "type": "string", + "description": "The pagination cursor." + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "scrobbles": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.rocksky.scrobble.defs#scrobbleViewBasic" + } + }, + "cursor": { + "type": "string", + "description": "The pagination cursor for the next set of results." + } + } + } + } + } + } +} diff --git a/apps/api/pkl/defs/feed/defs.pkl b/apps/api/pkl/defs/feed/defs.pkl index 3a63a554..57088f38 100644 --- a/apps/api/pkl/defs/feed/defs.pkl +++ b/apps/api/pkl/defs/feed/defs.pkl @@ -141,4 +141,14 @@ defs = new Mapping { } } } -} \ No newline at end of file + ["feedUriView"] = new ObjectType { + type = "object" + properties { + ["uri"] = new StringType { + type = "string" + description = "The feed URI." + format = "at-uri" + } + } + } +} diff --git a/apps/api/pkl/defs/feed/describeFeedGenerator.pkl b/apps/api/pkl/defs/feed/describeFeedGenerator.pkl new file mode 100644 index 00000000..52eac240 --- /dev/null +++ b/apps/api/pkl/defs/feed/describeFeedGenerator.pkl @@ -0,0 +1,31 @@ +amends "../../schema/lexicon.pkl" + +lexicon = 1 +id = "app.rocksky.feed.describeFeedGenerator" +defs = new Mapping { + ["main"] { + type = "query" + description = "Get information about a feed generator" + output { + encoding = "application/json" + schema = new ObjectType { + type = "object" + properties { + ["did"] = new StringType { + type = "string" + description = "The DID of the feed generator." + format = "at-identifier" + } + ["feeds"] = new Array { + type = "array" + description = "List of feed URIs generated by this feed generator." + items = new Ref { + type = "ref" + ref = "app.rocksky.feed.defs#feedUriView" + } + } + } + } + } + } +} diff --git a/apps/api/pkl/defs/feed/getFeed.pkl b/apps/api/pkl/defs/feed/getFeed.pkl new file mode 100644 index 00000000..7fb54944 --- /dev/null +++ b/apps/api/pkl/defs/feed/getFeed.pkl @@ -0,0 +1,45 @@ +amends "../../schema/lexicon.pkl" + +lexicon = 1 +id = "app.rocksky.feed.getFeed" +defs = new Mapping { + ["main"] { + type = "query" + description = "Get the feed by uri" + parameters { + type = "params" + required = List("feed") + properties { + ["feed"] = new StringType { + type = "string" + description = "The feed URI." + format = "at-uri" + } + ["limit"] = new IntegerType { + type = "integer" + description = "The maximum number of scrobbles to return" + minimum = 1 + } + ["offset"] = new IntegerType { + type = "integer" + description = "The offset for pagination" + minimum = 0 + } + } + } + output { + encoding = "application/json" + schema = new ObjectType { + type = "object" + properties = new Mapping { + ["scrobbles"] = new Array { + type = "array" + items = new Ref { + ref = "app.rocksky.scrobble.defs#scrobbleViewBasic" + } + } + } + } + } + } +} diff --git a/apps/api/pkl/defs/feed/getFeedGenerator.pkl b/apps/api/pkl/defs/feed/getFeedGenerator.pkl new file mode 100644 index 00000000..a7da5f04 --- /dev/null +++ b/apps/api/pkl/defs/feed/getFeedGenerator.pkl @@ -0,0 +1,32 @@ +amends "../../schema/lexicon.pkl" + +lexicon = 1 +id = "app.rocksky.feed.getFeedGenerator" +defs = new Mapping { + ["main"] { + type = "query" + description = "Get information about a feed generator" + parameters { + type = "params" + required = List("feed") + properties { + ["feed"] = new StringType { + type = "string" + description = "AT-URI of the feed generator record." + format = "at-uri" + } + } + } + output { + encoding = "application/json" + schema = new ObjectType { + type = "object" + properties { + ["view"] = new Ref { + ref = "app.rocksky.feed.defs#feedGeneratorView" + } + } + } + } + } +} diff --git a/apps/api/pkl/defs/feed/getFeedGenerators.pkl b/apps/api/pkl/defs/feed/getFeedGenerators.pkl index 497861d2..6b32facb 100644 --- a/apps/api/pkl/defs/feed/getFeedGenerators.pkl +++ b/apps/api/pkl/defs/feed/getFeedGenerators.pkl @@ -1,4 +1,4 @@ -amends "../../schema/lexicon.pkl" +amends "../../schema/lexicon.pkl" lexicon = 1 id = "app.rocksky.feed.getFeedGenerators" @@ -24,4 +24,4 @@ defs = new Mapping { } } } -} \ No newline at end of file +} diff --git a/apps/api/pkl/defs/feed/getFeedSkeleton.pkl b/apps/api/pkl/defs/feed/getFeedSkeleton.pkl new file mode 100644 index 00000000..293e4019 --- /dev/null +++ b/apps/api/pkl/defs/feed/getFeedSkeleton.pkl @@ -0,0 +1,53 @@ +amends "../../schema/lexicon.pkl" + +lexicon = 1 +id = "app.rocksky.feed.getFeedSkeleton" +defs = new Mapping { + ["main"] { + type = "query" + description = "Get the feed by uri" + parameters { + type = "params" + required = List("feed") + properties { + ["feed"] = new StringType { + type = "string" + description = "The feed URI." + format = "at-uri" + } + ["limit"] = new IntegerType { + type = "integer" + description = "The maximum number of scrobbles to return" + minimum = 1 + } + ["offset"] = new IntegerType { + type = "integer" + description = "The offset for pagination" + minimum = 0 + } + ["cursor"] = new StringType { + type = "string" + description = "The pagination cursor." + } + } + } + output { + encoding = "application/json" + schema = new ObjectType { + type = "object" + properties { + ["scrobbles"] = new Array { + type = "array" + items = new Ref { + ref = "app.rocksky.scrobble.defs#scrobbleViewBasic" + } + } + ["cursor"] = new StringType { + type = "string" + description = "The pagination cursor for the next set of results." + } + } + } + } + } +} diff --git a/apps/api/pkl/schema/lexicon.pkl b/apps/api/pkl/schema/lexicon.pkl index 7e147c14..c8af9c51 100644 --- a/apps/api/pkl/schema/lexicon.pkl +++ b/apps/api/pkl/schema/lexicon.pkl @@ -1,4 +1,3 @@ - open class BaseType { type: String description: String? @@ -86,6 +85,10 @@ class Record extends BaseType { lexicon: Int = 1 id: String description: String? -defs: Mapping | Mapping | Mapping | Mapping | Mapping | Mapping | Null = null - - +defs: Mapping + | Mapping + | Mapping + | Mapping + | Mapping + | Mapping + | Null = null diff --git a/apps/api/src/lexicon/index.ts b/apps/api/src/lexicon/index.ts index 0422d766..b54be268 100644 --- a/apps/api/src/lexicon/index.ts +++ b/apps/api/src/lexicon/index.ts @@ -38,7 +38,11 @@ import type * as AppRockskyDropboxDownloadFile from "./types/app/rocksky/dropbox import type * as AppRockskyDropboxGetFiles from "./types/app/rocksky/dropbox/getFiles"; import type * as AppRockskyDropboxGetMetadata from "./types/app/rocksky/dropbox/getMetadata"; import type * as AppRockskyDropboxGetTemporaryLink from "./types/app/rocksky/dropbox/getTemporaryLink"; +import type * as AppRockskyFeedDescribeFeedGenerator from "./types/app/rocksky/feed/describeFeedGenerator"; +import type * as AppRockskyFeedGetFeed from "./types/app/rocksky/feed/getFeed"; +import type * as AppRockskyFeedGetFeedGenerator from "./types/app/rocksky/feed/getFeedGenerator"; import type * as AppRockskyFeedGetFeedGenerators from "./types/app/rocksky/feed/getFeedGenerators"; +import type * as AppRockskyFeedGetFeedSkeleton from "./types/app/rocksky/feed/getFeedSkeleton"; import type * as AppRockskyFeedGetNowPlayings from "./types/app/rocksky/feed/getNowPlayings"; import type * as AppRockskyFeedSearch from "./types/app/rocksky/feed/search"; import type * as AppRockskyGoogledriveDownloadFile from "./types/app/rocksky/googledrive/downloadFile"; @@ -582,6 +586,39 @@ export class AppRockskyFeedNS { this._server = server; } + describeFeedGenerator( + cfg: ConfigOf< + AV, + AppRockskyFeedDescribeFeedGenerator.Handler>, + AppRockskyFeedDescribeFeedGenerator.HandlerReqCtx> + >, + ) { + const nsid = "app.rocksky.feed.describeFeedGenerator"; // @ts-ignore + return this._server.xrpc.method(nsid, cfg); + } + + getFeed( + cfg: ConfigOf< + AV, + AppRockskyFeedGetFeed.Handler>, + AppRockskyFeedGetFeed.HandlerReqCtx> + >, + ) { + const nsid = "app.rocksky.feed.getFeed"; // @ts-ignore + return this._server.xrpc.method(nsid, cfg); + } + + getFeedGenerator( + cfg: ConfigOf< + AV, + AppRockskyFeedGetFeedGenerator.Handler>, + AppRockskyFeedGetFeedGenerator.HandlerReqCtx> + >, + ) { + const nsid = "app.rocksky.feed.getFeedGenerator"; // @ts-ignore + return this._server.xrpc.method(nsid, cfg); + } + getFeedGenerators( cfg: ConfigOf< AV, @@ -593,6 +630,17 @@ export class AppRockskyFeedNS { return this._server.xrpc.method(nsid, cfg); } + getFeedSkeleton( + cfg: ConfigOf< + AV, + AppRockskyFeedGetFeedSkeleton.Handler>, + AppRockskyFeedGetFeedSkeleton.HandlerReqCtx> + >, + ) { + const nsid = "app.rocksky.feed.getFeedSkeleton"; // @ts-ignore + return this._server.xrpc.method(nsid, cfg); + } + getNowPlayings( cfg: ConfigOf< AV, diff --git a/apps/api/src/lexicon/lexicons.ts b/apps/api/src/lexicon/lexicons.ts index c28e7a61..1e98d386 100644 --- a/apps/api/src/lexicon/lexicons.ts +++ b/apps/api/src/lexicon/lexicons.ts @@ -2314,6 +2314,52 @@ export const schemaDict = { }, }, }, + feedUriView: { + type: "object", + properties: { + uri: { + type: "string", + description: "The feed URI.", + format: "at-uri", + }, + }, + }, + }, + }, + AppRockskyFeedDescribeFeedGenerator: { + lexicon: 1, + id: "app.rocksky.feed.describeFeedGenerator", + defs: { + main: { + type: "query", + description: "Get information about a feed generator", + parameters: { + type: "params", + properties: {}, + }, + output: { + encoding: "application/json", + schema: { + type: "object", + properties: { + did: { + type: "string", + description: "The DID of the feed generator.", + format: "at-identifier", + }, + feeds: { + type: "array", + description: + "List of feed URIs generated by this feed generator.", + items: { + type: "ref", + ref: "lex:app.rocksky.feed.defs#feedUriView", + }, + }, + }, + }, + }, + }, }, }, AppRockskyFeedGenerator: { @@ -2357,6 +2403,85 @@ export const schemaDict = { }, }, }, + AppRockskyFeedGetFeed: { + lexicon: 1, + id: "app.rocksky.feed.getFeed", + defs: { + main: { + type: "query", + description: "Get the feed by uri", + parameters: { + type: "params", + required: ["feed"], + properties: { + feed: { + type: "string", + description: "The feed URI.", + format: "at-uri", + }, + limit: { + type: "integer", + description: "The maximum number of scrobbles to return", + minimum: 1, + }, + offset: { + type: "integer", + description: "The offset for pagination", + minimum: 0, + }, + }, + }, + output: { + encoding: "application/json", + schema: { + type: "object", + properties: { + scrobbles: { + type: "array", + items: { + type: "ref", + ref: "lex:app.rocksky.scrobble.defs#scrobbleViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + AppRockskyFeedGetFeedGenerator: { + lexicon: 1, + id: "app.rocksky.feed.getFeedGenerator", + defs: { + main: { + type: "query", + description: "Get information about a feed generator", + parameters: { + type: "params", + required: ["feed"], + properties: { + feed: { + type: "string", + description: "AT-URI of the feed generator record.", + format: "at-uri", + }, + }, + }, + output: { + encoding: "application/json", + schema: { + type: "object", + properties: { + view: { + type: "ref", + ref: "lex:app.rocksky.feed.defs#feedGeneratorView", + }, + }, + }, + }, + }, + }, + }, AppRockskyFeedGetFeedGenerators: { lexicon: 1, id: "app.rocksky.feed.getFeedGenerators", @@ -2384,6 +2509,61 @@ export const schemaDict = { }, }, }, + AppRockskyFeedGetFeedSkeleton: { + lexicon: 1, + id: "app.rocksky.feed.getFeedSkeleton", + defs: { + main: { + type: "query", + description: "Get the feed by uri", + parameters: { + type: "params", + required: ["feed"], + properties: { + feed: { + type: "string", + description: "The feed URI.", + format: "at-uri", + }, + limit: { + type: "integer", + description: "The maximum number of scrobbles to return", + minimum: 1, + }, + offset: { + type: "integer", + description: "The offset for pagination", + minimum: 0, + }, + cursor: { + type: "string", + description: "The pagination cursor.", + }, + }, + }, + output: { + encoding: "application/json", + schema: { + type: "object", + properties: { + scrobbles: { + type: "array", + items: { + type: "ref", + ref: "lex:app.rocksky.scrobble.defs#scrobbleViewBasic", + }, + }, + cursor: { + type: "string", + description: + "The pagination cursor for the next set of results.", + }, + }, + }, + }, + }, + }, + }, AppRockskyFeedGetNowPlayings: { lexicon: 1, id: "app.rocksky.feed.getNowPlayings", @@ -5191,8 +5371,12 @@ export const ids = { AppRockskyDropboxGetMetadata: "app.rocksky.dropbox.getMetadata", AppRockskyDropboxGetTemporaryLink: "app.rocksky.dropbox.getTemporaryLink", AppRockskyFeedDefs: "app.rocksky.feed.defs", + AppRockskyFeedDescribeFeedGenerator: "app.rocksky.feed.describeFeedGenerator", AppRockskyFeedGenerator: "app.rocksky.feed.generator", + AppRockskyFeedGetFeed: "app.rocksky.feed.getFeed", + AppRockskyFeedGetFeedGenerator: "app.rocksky.feed.getFeedGenerator", AppRockskyFeedGetFeedGenerators: "app.rocksky.feed.getFeedGenerators", + AppRockskyFeedGetFeedSkeleton: "app.rocksky.feed.getFeedSkeleton", AppRockskyFeedGetNowPlayings: "app.rocksky.feed.getNowPlayings", AppRockskyFeedSearch: "app.rocksky.feed.search", AppRockskyGoogledriveDefs: "app.rocksky.googledrive.defs", diff --git a/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts b/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts index 361b4902..5e12653e 100644 --- a/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts +++ b/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyApikeyDefs from "./defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The name of the API key. */ diff --git a/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts b/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts index 98edcefb..639a3d05 100644 --- a/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts +++ b/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyApikeyDefs from "./defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The ID of the API key to update. */ diff --git a/apps/api/src/lexicon/types/app/rocksky/feed/defs.ts b/apps/api/src/lexicon/types/app/rocksky/feed/defs.ts index 78efaeea..44d471af 100644 --- a/apps/api/src/lexicon/types/app/rocksky/feed/defs.ts +++ b/apps/api/src/lexicon/types/app/rocksky/feed/defs.ts @@ -125,3 +125,21 @@ export function isFeedGeneratorView(v: unknown): v is FeedGeneratorView { export function validateFeedGeneratorView(v: unknown): ValidationResult { return lexicons.validate("app.rocksky.feed.defs#feedGeneratorView", v); } + +export interface FeedUriView { + /** The feed URI. */ + uri?: string; + [k: string]: unknown; +} + +export function isFeedUriView(v: unknown): v is FeedUriView { + return ( + isObj(v) && + hasProp(v, "$type") && + v.$type === "app.rocksky.feed.defs#feedUriView" + ); +} + +export function validateFeedUriView(v: unknown): ValidationResult { + return lexicons.validate("app.rocksky.feed.defs#feedUriView", v); +} diff --git a/apps/api/src/lexicon/types/app/rocksky/feed/describeFeedGenerator.ts b/apps/api/src/lexicon/types/app/rocksky/feed/describeFeedGenerator.ts new file mode 100644 index 00000000..be17fd31 --- /dev/null +++ b/apps/api/src/lexicon/types/app/rocksky/feed/describeFeedGenerator.ts @@ -0,0 +1,48 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type express from "express"; +import { ValidationResult, BlobRef } from "@atproto/lexicon"; +import { lexicons } from "../../../../lexicons"; +import { isObj, hasProp } from "../../../../util"; +import { CID } from "multiformats/cid"; +import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; +import type * as AppRockskyFeedDefs from "./defs"; + +export type QueryParams = {}; + +export type InputSchema = undefined; + +export interface OutputSchema { + /** The DID of the feed generator. */ + did?: string; + /** List of feed URIs generated by this feed generator. */ + feeds?: AppRockskyFeedDefs.FeedUriView[]; + [k: string]: unknown; +} + +export type HandlerInput = undefined; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough; +export type HandlerReqCtx = { + auth: HA; + params: QueryParams; + input: HandlerInput; + req: express.Request; + res: express.Response; + resetRouteRateLimits: () => Promise; +}; +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput; diff --git a/apps/api/src/lexicon/types/app/rocksky/feed/getFeed.ts b/apps/api/src/lexicon/types/app/rocksky/feed/getFeed.ts new file mode 100644 index 00000000..d2f58451 --- /dev/null +++ b/apps/api/src/lexicon/types/app/rocksky/feed/getFeed.ts @@ -0,0 +1,52 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type express from "express"; +import { ValidationResult, BlobRef } from "@atproto/lexicon"; +import { lexicons } from "../../../../lexicons"; +import { isObj, hasProp } from "../../../../util"; +import { CID } from "multiformats/cid"; +import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; +import type * as AppRockskyScrobbleDefs from "../scrobble/defs"; + +export interface QueryParams { + /** The feed URI. */ + feed: string; + /** The maximum number of scrobbles to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +} + +export type InputSchema = undefined; + +export interface OutputSchema { + scrobbles?: AppRockskyScrobbleDefs.ScrobbleViewBasic[]; + [k: string]: unknown; +} + +export type HandlerInput = undefined; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough; +export type HandlerReqCtx = { + auth: HA; + params: QueryParams; + input: HandlerInput; + req: express.Request; + res: express.Response; + resetRouteRateLimits: () => Promise; +}; +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput; diff --git a/apps/api/src/lexicon/types/app/rocksky/feed/getFeedGenerator.ts b/apps/api/src/lexicon/types/app/rocksky/feed/getFeedGenerator.ts new file mode 100644 index 00000000..f389986c --- /dev/null +++ b/apps/api/src/lexicon/types/app/rocksky/feed/getFeedGenerator.ts @@ -0,0 +1,48 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type express from "express"; +import { ValidationResult, BlobRef } from "@atproto/lexicon"; +import { lexicons } from "../../../../lexicons"; +import { isObj, hasProp } from "../../../../util"; +import { CID } from "multiformats/cid"; +import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; +import type * as AppRockskyFeedDefs from "./defs"; + +export interface QueryParams { + /** AT-URI of the feed generator record. */ + feed: string; +} + +export type InputSchema = undefined; + +export interface OutputSchema { + view?: AppRockskyFeedDefs.FeedGeneratorView; + [k: string]: unknown; +} + +export type HandlerInput = undefined; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough; +export type HandlerReqCtx = { + auth: HA; + params: QueryParams; + input: HandlerInput; + req: express.Request; + res: express.Response; + resetRouteRateLimits: () => Promise; +}; +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput; diff --git a/apps/api/src/lexicon/types/app/rocksky/feed/getFeedSkeleton.ts b/apps/api/src/lexicon/types/app/rocksky/feed/getFeedSkeleton.ts new file mode 100644 index 00000000..8307cfa8 --- /dev/null +++ b/apps/api/src/lexicon/types/app/rocksky/feed/getFeedSkeleton.ts @@ -0,0 +1,56 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type express from "express"; +import { ValidationResult, BlobRef } from "@atproto/lexicon"; +import { lexicons } from "../../../../lexicons"; +import { isObj, hasProp } from "../../../../util"; +import { CID } from "multiformats/cid"; +import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; +import type * as AppRockskyScrobbleDefs from "../scrobble/defs"; + +export interface QueryParams { + /** The feed URI. */ + feed: string; + /** The maximum number of scrobbles to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; + /** The pagination cursor. */ + cursor?: string; +} + +export type InputSchema = undefined; + +export interface OutputSchema { + scrobbles?: AppRockskyScrobbleDefs.ScrobbleViewBasic[]; + /** The pagination cursor for the next set of results. */ + cursor?: string; + [k: string]: unknown; +} + +export type HandlerInput = undefined; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough; +export type HandlerReqCtx = { + auth: HA; + params: QueryParams; + input: HandlerInput; + req: express.Request; + res: express.Response; + resetRouteRateLimits: () => Promise; +}; +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput; diff --git a/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts b/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts index 666c305a..cce29e93 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "../shout/defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The unique identifier of the shout to dislike */ diff --git a/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts b/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts index 2e7efea3..ac21497a 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskySongDefs from "../song/defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The unique identifier of the song to dislike */ diff --git a/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts b/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts index 46307d1d..8d652876 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "../shout/defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The unique identifier of the shout to like */ diff --git a/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts b/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts index b0f4d600..3f36fdb9 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskySongDefs from "../song/defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The unique identifier of the song to like */ diff --git a/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts b/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts index b746c4ea..507ad0e3 100644 --- a/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts +++ b/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyScrobbleDefs from "./defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The title of the track being scrobbled */ diff --git a/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts b/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts index b51daaa3..8e4df585 100644 --- a/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "./defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The content of the shout */ diff --git a/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts b/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts index 83800a07..f4f5e9bb 100644 --- a/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "./defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The unique identifier of the shout to reply to */ diff --git a/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts b/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts index fb808117..b71fefbd 100644 --- a/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "./defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The unique identifier of the shout to report */ diff --git a/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts b/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts index f196c2e4..791c6966 100644 --- a/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts +++ b/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskySongDefs from "./defs"; -export type QueryParams = {} +export type QueryParams = {}; export interface InputSchema { /** The title of the song */ diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts index 66110356..c404dc11 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {} +export type QueryParams = {}; export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts index 66110356..c404dc11 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {} +export type QueryParams = {}; export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts index 66110356..c404dc11 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {} +export type QueryParams = {}; export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts index 66110356..c404dc11 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {} +export type QueryParams = {}; export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/xrpc/app/rocksky/feed/getFeed.ts b/apps/api/src/xrpc/app/rocksky/feed/getFeed.ts new file mode 100644 index 00000000..4e24f518 --- /dev/null +++ b/apps/api/src/xrpc/app/rocksky/feed/getFeed.ts @@ -0,0 +1,82 @@ +import type { Context } from "context"; +import { desc, eq } from "drizzle-orm"; +import { Effect, pipe } from "effect"; +import type { Server } from "lexicon"; +import type { ScrobbleViewBasic } from "lexicon/types/app/rocksky/scrobble/defs"; +import type { QueryParams } from "lexicon/types/app/rocksky/feed/getFeed"; +import * as R from "ramda"; +import tables from "schema"; +import type { SelectScrobble } from "schema/scrobbles"; +import type { SelectTrack } from "schema/tracks"; +import type { SelectUser } from "schema/users"; + +export default function (server: Server, ctx: Context) { + const getFeed = (params: QueryParams) => + pipe( + { params, ctx }, + retrieve, + Effect.flatMap(presentation), + Effect.retry({ times: 3 }), + Effect.timeout("10 seconds"), + Effect.catchAll((err) => { + console.error("Error retrieving scrobbles:", err); + return Effect.succeed({ scrobbles: [] }); + }), + ); + server.app.rocksky.feed.getFeed({ + handler: async ({ params }) => { + const result = await Effect.runPromise(getFeed(params)); + return { + encoding: "application/json", + body: result, + }; + }, + }); +} + +const retrieve = ({ + params, + ctx, +}: { + params: QueryParams; + ctx: Context; +}): Effect.Effect => { + return Effect.tryPromise({ + try: () => + ctx.db + .select() + .from(tables.scrobbles) + .leftJoin(tables.tracks, eq(tables.scrobbles.trackId, tables.tracks.id)) + .leftJoin(tables.users, eq(tables.scrobbles.userId, tables.users.id)) + .orderBy(desc(tables.scrobbles.timestamp)) + .offset(params.offset || 0) + .limit(params.limit || 20) + .execute(), + + catch: (error) => new Error(`Failed to retrieve scrobbles: ${error}`), + }); +}; + +const presentation = ( + data: Scrobbles, +): Effect.Effect<{ scrobbles: ScrobbleViewBasic[] }, never> => { + return Effect.sync(() => ({ + scrobbles: data.map(({ scrobbles, tracks, users }) => ({ + ...R.omit(["albumArt", "id", "lyrics"])(tracks), + cover: tracks.albumArt, + date: scrobbles.timestamp.toISOString(), + user: users.handle, + userDisplayName: users.displayName, + userAvatar: users.avatar, + uri: scrobbles.uri, + tags: [], + id: scrobbles.id, + })), + })); +}; + +type Scrobbles = { + scrobbles: SelectScrobble; + tracks: SelectTrack; + users: SelectUser; +}[]; diff --git a/apps/api/src/xrpc/app/rocksky/feed/getFeedGenerator.ts b/apps/api/src/xrpc/app/rocksky/feed/getFeedGenerator.ts new file mode 100644 index 00000000..76b9a53c --- /dev/null +++ b/apps/api/src/xrpc/app/rocksky/feed/getFeedGenerator.ts @@ -0,0 +1,58 @@ +import type { Server } from "lexicon"; +import type { Context } from "context"; +import { Effect, pipe } from "effect"; +import type { FeedGeneratorView } from "lexicon/types/app/rocksky/feed/defs"; +import type { QueryParams } from "lexicon/types/app/rocksky/feed/getFeedGenerator"; +import tables from "schema"; +import type { SelectFeed } from "schema/feeds"; +import { eq } from "drizzle-orm"; +import type { SelectUser } from "schema/users"; + +export default function (server: Server, ctx: Context) { + const getFeedGenerator = (params: QueryParams) => + pipe({ params, ctx }, retrieve, Effect.flatMap(presentation)); + server.app.rocksky.feed.getFeedGenerator({ + handler: async ({ params }) => { + const result = await Effect.runPromise(getFeedGenerator(params)); + return { + encoding: "application/json", + body: result, + }; + }, + }); +} + +const retrieve = ({ params, ctx }: { params: QueryParams; ctx: Context }) => { + return Effect.tryPromise({ + try: () => + ctx.db + .select() + .from(tables.feeds) + .leftJoin(tables.users, eq(tables.feeds.userId, tables.users.id)) + .where(eq(tables.feeds.uri, params.feed)) + .execute(), + catch: (error) => Effect.fail(error), + }); +}; + +const presentation = ( + data: { users: SelectUser; feeds: SelectFeed }[], +): Effect.Effect => { + return Effect.sync(() => ({ + view: data.map(({ users, feeds }) => ({ + id: feeds.id, + name: feeds.displayName, + description: feeds.description, + avatar: feeds.avatar, + did: feeds.did, + uri: feeds.uri, + creator: { + id: users.id, + did: users.did, + handle: users.handle, + displayName: users.displayName, + avatar: users.avatar, + }, + }))[0], + })); +}; diff --git a/apps/api/src/xrpc/app/rocksky/feed/getFeedGenerators.ts b/apps/api/src/xrpc/app/rocksky/feed/getFeedGenerators.ts index ab2b5f1b..1383a807 100644 --- a/apps/api/src/xrpc/app/rocksky/feed/getFeedGenerators.ts +++ b/apps/api/src/xrpc/app/rocksky/feed/getFeedGenerators.ts @@ -1,15 +1,15 @@ -import { Server } from "lexicon"; -import { Context } from "context"; +import type { Server } from "lexicon"; +import type { Context } from "context"; import { Effect, pipe } from "effect"; import type { FeedGeneratorsView } from "lexicon/types/app/rocksky/feed/defs"; import type { QueryParams } from "lexicon/types/app/rocksky/feed/getFeedGenerators"; import tables from "schema"; -import { SelectFeed } from "schema/feeds"; +import type { SelectFeed } from "schema/feeds"; import { eq } from "drizzle-orm"; -import { SelectUser } from "schema/users"; +import type { SelectUser } from "schema/users"; export default function (server: Server, ctx: Context) { - const getFeedGenerators = (params) => + const getFeedGenerators = (params: QueryParams) => pipe({ params, ctx }, retrieve, Effect.flatMap(presentation)); server.app.rocksky.feed.getFeedGenerators({ handler: async ({ params }) => { diff --git a/apps/api/src/xrpc/index.ts b/apps/api/src/xrpc/index.ts index 54371430..d68af7c1 100644 --- a/apps/api/src/xrpc/index.ts +++ b/apps/api/src/xrpc/index.ts @@ -73,6 +73,7 @@ import spotifyPrevious from "./app/rocksky/spotify/previous"; import spotifySeek from "./app/rocksky/spotify/seek"; import getStats from "./app/rocksky/stats/getStats"; import getFeedGenerators from "./app/rocksky/feed/getFeedGenerators"; +import getFeedGenerator from "./app/rocksky/feed/getFeedGenerator"; export default function (server: Server, ctx: Context) { // app.rocksky @@ -149,6 +150,7 @@ export default function (server: Server, ctx: Context) { removePlaylist(server, ctx); startPlaylist(server, ctx); getFeedGenerators(server, ctx); + getFeedGenerator(server, ctx); return server; } diff --git a/apps/feeds/.env.example b/apps/feeds/.env.example new file mode 100644 index 00000000..38bfc047 --- /dev/null +++ b/apps/feeds/.env.example @@ -0,0 +1,3 @@ +XATA_POSTGRES_URL="postgresql://postgres:mysecretpassword@localhost:5433/rocksky?sslmode=disable" +FEEDGEN_DOMAIN=discover.rocksky.app +NODE_ENV=development diff --git a/apps/feeds/.zed/settings.json b/apps/feeds/.zed/settings.json new file mode 100644 index 00000000..ae4f3e38 --- /dev/null +++ b/apps/feeds/.zed/settings.json @@ -0,0 +1,25 @@ +{ + "lsp": { + "deno": { + "settings": { + "deno": { + "enable": true, + "unstable": false, + "lint": true, + "cache": null + } + } + } + }, + "languages": { + "TypeScript": { + "language_servers": ["deno", "!typescript-language-server"] + }, + "TSX": { + "language_servers": ["deno", "!typescript-language-server"] + }, + "JavaScript": { + "language_servers": ["deno", "!typescript-language-server"] + } + } +} diff --git a/apps/feeds/deno.json b/apps/feeds/deno.json new file mode 100644 index 00000000..e5eb4201 --- /dev/null +++ b/apps/feeds/deno.json @@ -0,0 +1,25 @@ +{ + "tasks": { + "dev": "deno run -A --env-file=.env --watch main.ts", + "start": "deno run -A --env-file=.env main.ts", + "lexgen": "deno run -A jsr:@atp/lex-gen@0.1.0-alpha.5 server -o src/lex -i lexicons" + }, + "imports": { + "@atp/common": "jsr:@atp/common@^0.1.0-alpha.6", + "@atp/identity": "jsr:@atp/identity@^0.1.0-alpha.1", + "@atp/lexicon": "jsr:@atp/lexicon@^0.1.0-alpha.3", + "@atp/syntax": "jsr:@atp/syntax@^0.1.0-alpha.2", + "@atp/xrpc-server": "jsr:@atp/xrpc-server@^0.1.0-alpha.5", + "@hono/hono": "jsr:@hono/hono@^4.11.3", + "@logtape/logtape": "npm:@logtape/logtape@^1.3.5", + "@logtape/pretty": "npm:@logtape/pretty@^1.3.5", + "@std/assert": "jsr:@std/assert@1", + "drizzle-kit": "npm:drizzle-kit@^0.31.8", + "drizzle-orm": "npm:drizzle-orm@^0.45.1", + "effect": "npm:effect@^3.19.13", + "envalid": "npm:envalid@^8.1.1", + "lodash": "npm:lodash@^4.17.21", + "pg": "npm:pg@^8.16.3", + "ramda": "npm:ramda@^0.32.0" + } +} diff --git a/apps/feeds/deno.lock b/apps/feeds/deno.lock new file mode 100644 index 00000000..1bc9d7d8 --- /dev/null +++ b/apps/feeds/deno.lock @@ -0,0 +1,695 @@ +{ + "version": "5", + "specifiers": { + "jsr:@atp/bytes@~0.1.0-alpha.1": "0.1.0-alpha.1", + "jsr:@atp/common@~0.1.0-alpha.4": "0.1.0-alpha.6", + "jsr:@atp/common@~0.1.0-alpha.5": "0.1.0-alpha.6", + "jsr:@atp/common@~0.1.0-alpha.6": "0.1.0-alpha.6", + "jsr:@atp/crypto@~0.1.0-alpha.1": "0.1.0-alpha.2", + "jsr:@atp/crypto@~0.1.0-alpha.2": "0.1.0-alpha.2", + "jsr:@atp/identity@~0.1.0-alpha.1": "0.1.0-alpha.1", + "jsr:@atp/lexicon@~0.1.0-alpha.3": "0.1.0-alpha.3", + "jsr:@atp/syntax@~0.1.0-alpha.2": "0.1.0-alpha.2", + "jsr:@atp/xrpc-server@~0.1.0-alpha.5": "0.1.0-alpha.5", + "jsr:@atp/xrpc@~0.1.0-alpha.3": "0.1.0-alpha.3", + "jsr:@hono/hono@^4.10.8": "4.11.3", + "jsr:@hono/hono@^4.11.3": "4.11.3", + "jsr:@logtape/file@^1.2.2": "1.3.5", + "jsr:@logtape/logtape@^1.2.2": "1.3.5", + "jsr:@logtape/logtape@^1.3.5": "1.3.5", + "jsr:@noble/curves@^2.0.1": "2.0.1", + "jsr:@noble/hashes@2": "2.0.1", + "jsr:@noble/hashes@^2.0.1": "2.0.1", + "jsr:@std/assert@1": "1.0.16", + "jsr:@std/assert@^1.0.16": "1.0.16", + "jsr:@std/bytes@^1.0.6": "1.0.6", + "jsr:@std/cbor@~0.1.9": "0.1.9", + "jsr:@std/encoding@^1.0.10": "1.0.10", + "jsr:@std/fs@^1.0.20": "1.0.21", + "jsr:@std/internal@^1.0.12": "1.0.12", + "jsr:@std/streams@^1.0.14": "1.0.16", + "jsr:@zod/zod@^4.1.13": "4.2.1", + "npm:@ipld/dag-cbor@^9.2.5": "9.2.5", + "npm:@logtape/logtape@^1.3.5": "1.3.5", + "npm:@logtape/pretty@^1.3.5": "1.3.5_@logtape+logtape@1.3.5", + "npm:drizzle-kit@~0.31.8": "0.31.8_esbuild@0.25.12", + "npm:drizzle-orm@~0.45.1": "0.45.1_pg@8.16.3", + "npm:effect@^3.19.13": "3.19.13", + "npm:envalid@^8.1.1": "8.1.1", + "npm:lodash@^4.17.21": "4.17.21", + "npm:multiformats@^13.4.1": "13.4.2", + "npm:pg@^8.16.3": "8.16.3", + "npm:ramda@0.32": "0.32.0", + "npm:rate-limiter-flexible@9": "9.0.1" + }, + "jsr": { + "@atp/bytes@0.1.0-alpha.1": { + "integrity": "51ab3c11252f29265b9ac382b6b2f7023643fe74682114300f4efceee87cfd5c", + "dependencies": [ + "npm:multiformats" + ] + }, + "@atp/common@0.1.0-alpha.6": { + "integrity": "a27d967787c5036800a63c9b866ee5ee2ba839d5064ae038a9ed750a38d21685", + "dependencies": [ + "jsr:@atp/bytes", + "jsr:@logtape/file", + "jsr:@logtape/logtape@^1.2.2", + "jsr:@std/cbor", + "jsr:@std/encoding", + "jsr:@std/fs", + "jsr:@zod/zod", + "npm:@ipld/dag-cbor", + "npm:multiformats" + ] + }, + "@atp/crypto@0.1.0-alpha.2": { + "integrity": "594b0211ab82cc530bcd6f4a494ce192b0d5be60c01304d7096e030ef2baae11", + "dependencies": [ + "jsr:@atp/bytes", + "jsr:@noble/curves", + "jsr:@noble/hashes@^2.0.1" + ] + }, + "@atp/identity@0.1.0-alpha.1": { + "integrity": "a548f4715abeca8ed6f6f359cdaf277bf1a41cd455170d8e13a629bcf6351016", + "dependencies": [ + "jsr:@atp/common@~0.1.0-alpha.4", + "jsr:@atp/crypto@~0.1.0-alpha.1" + ] + }, + "@atp/lexicon@0.1.0-alpha.3": { + "integrity": "5caf556fde5e2b3df66de07fc28603631aeb4e2d1699b544ed34e368b49ba61f", + "dependencies": [ + "jsr:@atp/common@~0.1.0-alpha.5", + "jsr:@atp/syntax", + "jsr:@zod/zod", + "npm:multiformats" + ] + }, + "@atp/syntax@0.1.0-alpha.2": { + "integrity": "f7ab598b6b3c3b01dc446077b4c57acc1f1cb8a45f91bd3eb394997408a712a2" + }, + "@atp/xrpc@0.1.0-alpha.3": { + "integrity": "315fe6ff02a1e41975e8716df2a389ab117223430b112e009d07176bafe4ccfc", + "dependencies": [ + "jsr:@atp/lexicon", + "jsr:@zod/zod" + ] + }, + "@atp/xrpc-server@0.1.0-alpha.5": { + "integrity": "971d92b419dead72038cf3bceecbf19578d7a7eb0c05c17f0d7cc5a740d9ca39", + "dependencies": [ + "jsr:@atp/bytes", + "jsr:@atp/common@~0.1.0-alpha.6", + "jsr:@atp/crypto@~0.1.0-alpha.2", + "jsr:@atp/lexicon", + "jsr:@atp/xrpc", + "jsr:@hono/hono@^4.10.8", + "jsr:@std/assert@^1.0.16", + "jsr:@zod/zod", + "npm:rate-limiter-flexible" + ] + }, + "@hono/hono@4.11.3": { + "integrity": "de7f245516a970c60c6f4bf5b0f1585efbee38ee4e01171994c2b9d69d035d70" + }, + "@logtape/file@1.3.5": { + "integrity": "6e5248e873e260109267b79bd3fb19f307a664a2233c5ae6f699d697549db985", + "dependencies": [ + "jsr:@logtape/logtape@^1.3.5" + ] + }, + "@logtape/logtape@1.3.5": { + "integrity": "a5cdb130daf1a9d384006b0f850cc4443bfc2e163dadc6fa667875e79770beb3" + }, + "@noble/curves@2.0.1": { + "integrity": "21ef41d207a203f60ba37a4fdcbc4f4a545b10c5dab7f293889f18292f81ab23", + "dependencies": [ + "jsr:@noble/hashes@2" + ] + }, + "@noble/hashes@2.0.1": { + "integrity": "e0e908292a0bf91099cf8ba0720a1647cef82ab38b588815b5e9535b4ff4d7bb" + }, + "@std/assert@1.0.16": { + "integrity": "6a7272ed1eaa77defe76e5ff63ca705d9c495077e2d5fd0126d2b53fc5bd6532", + "dependencies": [ + "jsr:@std/internal" + ] + }, + "@std/bytes@1.0.6": { + "integrity": "f6ac6adbd8ccd99314045f5703e23af0a68d7f7e58364b47d2c7f408aeb5820a" + }, + "@std/cbor@0.1.9": { + "integrity": "fe1f61f445a34c8f97973b58fecbfb24e48fcc88df7b1253d9b6fe5d2ea16936", + "dependencies": [ + "jsr:@std/bytes", + "jsr:@std/streams" + ] + }, + "@std/encoding@1.0.10": { + "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" + }, + "@std/fs@1.0.21": { + "integrity": "d720fe1056d78d43065a4d6e0eeb2b19f34adb8a0bc7caf3a4dbf1d4178252cd" + }, + "@std/internal@1.0.12": { + "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027" + }, + "@std/streams@1.0.16": { + "integrity": "85030627befb1767c60d4f65cb30fa2f94af1d6ee6e5b2515b76157a542e89c4" + }, + "@zod/zod@4.2.1": { + "integrity": "693a557fccaf73bfcbcd132ca286929f3343cda9efb56e9780985aa41d229b38" + } + }, + "npm": { + "@drizzle-team/brocli@0.10.2": { + "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==" + }, + "@esbuild-kit/core-utils@3.3.2": { + "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "dependencies": [ + "esbuild@0.18.20", + "source-map-support" + ], + "deprecated": true + }, + "@esbuild-kit/esm-loader@2.6.5": { + "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "dependencies": [ + "@esbuild-kit/core-utils", + "get-tsconfig" + ], + "deprecated": true + }, + "@esbuild/aix-ppc64@0.25.12": { + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "os": ["aix"], + "cpu": ["ppc64"] + }, + "@esbuild/android-arm64@0.18.20": { + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@esbuild/android-arm64@0.25.12": { + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@esbuild/android-arm@0.18.20": { + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "os": ["android"], + "cpu": ["arm"] + }, + "@esbuild/android-arm@0.25.12": { + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "os": ["android"], + "cpu": ["arm"] + }, + "@esbuild/android-x64@0.18.20": { + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "os": ["android"], + "cpu": ["x64"] + }, + "@esbuild/android-x64@0.25.12": { + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "os": ["android"], + "cpu": ["x64"] + }, + "@esbuild/darwin-arm64@0.18.20": { + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@esbuild/darwin-arm64@0.25.12": { + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@esbuild/darwin-x64@0.18.20": { + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@esbuild/darwin-x64@0.25.12": { + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@esbuild/freebsd-arm64@0.18.20": { + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@esbuild/freebsd-arm64@0.25.12": { + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@esbuild/freebsd-x64@0.18.20": { + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@esbuild/freebsd-x64@0.25.12": { + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@esbuild/linux-arm64@0.18.20": { + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@esbuild/linux-arm64@0.25.12": { + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@esbuild/linux-arm@0.18.20": { + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@esbuild/linux-arm@0.25.12": { + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@esbuild/linux-ia32@0.18.20": { + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "os": ["linux"], + "cpu": ["ia32"] + }, + "@esbuild/linux-ia32@0.25.12": { + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "os": ["linux"], + "cpu": ["ia32"] + }, + "@esbuild/linux-loong64@0.18.20": { + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@esbuild/linux-loong64@0.25.12": { + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@esbuild/linux-mips64el@0.18.20": { + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@esbuild/linux-mips64el@0.25.12": { + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@esbuild/linux-ppc64@0.18.20": { + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@esbuild/linux-ppc64@0.25.12": { + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@esbuild/linux-riscv64@0.18.20": { + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@esbuild/linux-riscv64@0.25.12": { + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@esbuild/linux-s390x@0.18.20": { + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@esbuild/linux-s390x@0.25.12": { + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@esbuild/linux-x64@0.18.20": { + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/linux-x64@0.25.12": { + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-arm64@0.25.12": { + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, + "@esbuild/netbsd-x64@0.18.20": { + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-x64@0.25.12": { + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-arm64@0.25.12": { + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, + "@esbuild/openbsd-x64@0.18.20": { + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-x64@0.25.12": { + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/openharmony-arm64@0.25.12": { + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@esbuild/sunos-x64@0.18.20": { + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@esbuild/sunos-x64@0.25.12": { + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@esbuild/win32-arm64@0.18.20": { + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@esbuild/win32-arm64@0.25.12": { + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@esbuild/win32-ia32@0.18.20": { + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@esbuild/win32-ia32@0.25.12": { + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@esbuild/win32-x64@0.18.20": { + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@esbuild/win32-x64@0.25.12": { + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@ipld/dag-cbor@9.2.5": { + "integrity": "sha512-84wSr4jv30biui7endhobYhXBQzQE4c/wdoWlFrKcfiwH+ofaPg8fwsM8okX9cOzkkrsAsNdDyH3ou+kiLquwQ==", + "dependencies": [ + "cborg", + "multiformats" + ] + }, + "@logtape/logtape@1.3.5": { + "integrity": "sha512-G+MxWB7Tbv/2764519+Cp6rKXUdRbe/GiRwTvlm/Wv/sNsiquRnx9Hzr9eXaIpAYLT4PrBlkthjJ4gmqdSPrFg==" + }, + "@logtape/pretty@1.3.5_@logtape+logtape@1.3.5": { + "integrity": "sha512-b554wA36+jqMhorB2AVb7vmjhIryGUFtPlv0GBEig3eY8Jf0rSunVitReDXfO3s0iG4aqFdvAXQ1WfMllXMqaA==", + "dependencies": [ + "@logtape/logtape" + ] + }, + "@standard-schema/spec@1.1.0": { + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==" + }, + "buffer-from@1.1.2": { + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "cborg@4.3.2": { + "integrity": "sha512-l+QzebEAG0vb09YKkaOrMi2zmm80UNjmbvocMIeW5hO7JOXWdrQ/H49yOKfYX0MBgrj/KWgatBnEgRXyNyKD+A==", + "bin": true + }, + "debug@4.4.3": { + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dependencies": [ + "ms" + ] + }, + "drizzle-kit@0.31.8_esbuild@0.25.12": { + "integrity": "sha512-O9EC/miwdnRDY10qRxM8P3Pg8hXe3LyU4ZipReKOgTwn4OqANmftj8XJz1UPUAS6NMHf0E2htjsbQujUTkncCg==", + "dependencies": [ + "@drizzle-team/brocli", + "@esbuild-kit/esm-loader", + "esbuild@0.25.12", + "esbuild-register" + ], + "bin": true + }, + "drizzle-orm@0.45.1_pg@8.16.3": { + "integrity": "sha512-Te0FOdKIistGNPMq2jscdqngBRfBpC8uMFVwqjf6gtTVJHIQ/dosgV/CLBU2N4ZJBsXL5savCba9b0YJskKdcA==", + "dependencies": [ + "pg" + ], + "optionalPeers": [ + "pg" + ] + }, + "effect@3.19.13": { + "integrity": "sha512-8MZ783YuHRwHZX2Mmm+bpGxq+7XPd88sWwYAz2Ysry80sEKpftDZXs2Hg9ZyjESi1IBTNHF0oDKe0zJRkUlyew==", + "dependencies": [ + "@standard-schema/spec", + "fast-check" + ] + }, + "envalid@8.1.1": { + "integrity": "sha512-vOUfHxAFFvkBjbVQbBfgnCO9d3GcNfMMTtVfgqSU2rQGMFEVqWy9GBuoSfHnwGu7EqR0/GeukQcL3KjFBaga9w==", + "dependencies": [ + "tslib" + ] + }, + "esbuild-register@3.6.0_esbuild@0.25.12": { + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dependencies": [ + "debug", + "esbuild@0.25.12" + ] + }, + "esbuild@0.18.20": { + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "optionalDependencies": [ + "@esbuild/android-arm@0.18.20", + "@esbuild/android-arm64@0.18.20", + "@esbuild/android-x64@0.18.20", + "@esbuild/darwin-arm64@0.18.20", + "@esbuild/darwin-x64@0.18.20", + "@esbuild/freebsd-arm64@0.18.20", + "@esbuild/freebsd-x64@0.18.20", + "@esbuild/linux-arm@0.18.20", + "@esbuild/linux-arm64@0.18.20", + "@esbuild/linux-ia32@0.18.20", + "@esbuild/linux-loong64@0.18.20", + "@esbuild/linux-mips64el@0.18.20", + "@esbuild/linux-ppc64@0.18.20", + "@esbuild/linux-riscv64@0.18.20", + "@esbuild/linux-s390x@0.18.20", + "@esbuild/linux-x64@0.18.20", + "@esbuild/netbsd-x64@0.18.20", + "@esbuild/openbsd-x64@0.18.20", + "@esbuild/sunos-x64@0.18.20", + "@esbuild/win32-arm64@0.18.20", + "@esbuild/win32-ia32@0.18.20", + "@esbuild/win32-x64@0.18.20" + ], + "scripts": true, + "bin": true + }, + "esbuild@0.25.12": { + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "optionalDependencies": [ + "@esbuild/aix-ppc64", + "@esbuild/android-arm@0.25.12", + "@esbuild/android-arm64@0.25.12", + "@esbuild/android-x64@0.25.12", + "@esbuild/darwin-arm64@0.25.12", + "@esbuild/darwin-x64@0.25.12", + "@esbuild/freebsd-arm64@0.25.12", + "@esbuild/freebsd-x64@0.25.12", + "@esbuild/linux-arm@0.25.12", + "@esbuild/linux-arm64@0.25.12", + "@esbuild/linux-ia32@0.25.12", + "@esbuild/linux-loong64@0.25.12", + "@esbuild/linux-mips64el@0.25.12", + "@esbuild/linux-ppc64@0.25.12", + "@esbuild/linux-riscv64@0.25.12", + "@esbuild/linux-s390x@0.25.12", + "@esbuild/linux-x64@0.25.12", + "@esbuild/netbsd-arm64", + "@esbuild/netbsd-x64@0.25.12", + "@esbuild/openbsd-arm64", + "@esbuild/openbsd-x64@0.25.12", + "@esbuild/openharmony-arm64", + "@esbuild/sunos-x64@0.25.12", + "@esbuild/win32-arm64@0.25.12", + "@esbuild/win32-ia32@0.25.12", + "@esbuild/win32-x64@0.25.12" + ], + "scripts": true, + "bin": true + }, + "fast-check@3.23.2": { + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "dependencies": [ + "pure-rand" + ] + }, + "get-tsconfig@4.13.0": { + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dependencies": [ + "resolve-pkg-maps" + ] + }, + "lodash@4.17.21": { + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "ms@2.1.3": { + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "multiformats@13.4.2": { + "integrity": "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ==" + }, + "pg-cloudflare@1.2.7": { + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==" + }, + "pg-connection-string@2.9.1": { + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==" + }, + "pg-int8@1.0.1": { + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool@3.10.1_pg@8.16.3": { + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", + "dependencies": [ + "pg" + ] + }, + "pg-protocol@1.10.3": { + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==" + }, + "pg-types@2.2.0": { + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": [ + "pg-int8", + "postgres-array", + "postgres-bytea", + "postgres-date", + "postgres-interval" + ] + }, + "pg@8.16.3": { + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", + "dependencies": [ + "pg-connection-string", + "pg-pool", + "pg-protocol", + "pg-types", + "pgpass" + ], + "optionalDependencies": [ + "pg-cloudflare" + ] + }, + "pgpass@1.0.5": { + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": [ + "split2" + ] + }, + "postgres-array@2.0.0": { + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea@1.0.1": { + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==" + }, + "postgres-date@1.0.7": { + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval@1.2.0": { + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": [ + "xtend" + ] + }, + "pure-rand@6.1.0": { + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==" + }, + "ramda@0.32.0": { + "integrity": "sha512-GQWAHhxhxWBWA8oIBr1XahFVjQ9Fic6MK9ikijfd4TZHfE2+urfk+irVlR5VOn48uwMgM+loRRBJd6Yjsbc0zQ==" + }, + "rate-limiter-flexible@9.0.1": { + "integrity": "sha512-sO+QdoGPCxroi4VkO2FIVjfUGuexhRkBc9ROHqu5eVEEz+oPHzQqvCc25ajFfMUBosbNGb6qpNa8xmxH9YNZsg==" + }, + "resolve-pkg-maps@1.0.0": { + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" + }, + "source-map-support@0.5.21": { + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": [ + "buffer-from", + "source-map" + ] + }, + "source-map@0.6.1": { + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "split2@4.2.0": { + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, + "tslib@2.8.1": { + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "xtend@4.0.2": { + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + }, + "workspace": { + "dependencies": [ + "jsr:@atp/common@~0.1.0-alpha.6", + "jsr:@atp/identity@~0.1.0-alpha.1", + "jsr:@atp/lexicon@~0.1.0-alpha.3", + "jsr:@atp/syntax@~0.1.0-alpha.2", + "jsr:@atp/xrpc-server@~0.1.0-alpha.5", + "jsr:@hono/hono@^4.11.3", + "jsr:@std/assert@1", + "npm:@logtape/logtape@^1.3.5", + "npm:@logtape/pretty@^1.3.5", + "npm:drizzle-kit@~0.31.8", + "npm:drizzle-orm@~0.45.1", + "npm:effect@^3.19.13", + "npm:envalid@^8.1.1", + "npm:lodash@^4.17.21", + "npm:pg@^8.16.3", + "npm:ramda@0.32" + ] + } +} diff --git a/apps/feeds/drizzle.config.ts b/apps/feeds/drizzle.config.ts new file mode 100644 index 00000000..7e053900 --- /dev/null +++ b/apps/feeds/drizzle.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "postgresql", + schema: "./src/schema", + dbCredentials: { + url: Deno.env.get("XATA_POSTGRES_URL")!, + }, +}); diff --git a/apps/feeds/lexicons b/apps/feeds/lexicons new file mode 120000 index 00000000..4c1273b0 --- /dev/null +++ b/apps/feeds/lexicons @@ -0,0 +1 @@ +../api/lexicons \ No newline at end of file diff --git a/apps/feeds/main.ts b/apps/feeds/main.ts new file mode 100644 index 00000000..7cd30691 --- /dev/null +++ b/apps/feeds/main.ts @@ -0,0 +1,27 @@ +import { Hono } from "@hono/hono"; +import { ctx, type AppEnv } from "./src/context.ts"; +import { createServer } from "./src/lex/index.ts"; +import describeFeedGenerator from "./src/api/describeFeedGenerator.ts"; +import getFeedSkeleton from "./src/api/getFeedSkeleton.ts"; +import health from "./src/api/health.ts"; +import wellKnown from "./src/api/well-known.ts"; +import { env } from "./src/utils/env.ts"; + +const app = new Hono(); + +const server = createServer(); +describeFeedGenerator(server, ctx); +getFeedSkeleton(server, ctx); + +app.route("/", server.xrpc.app); + +app.get("/", (c) => { + return c.text( + "This is a Feed Generation service! Most endpoints are under /xrpc", + ); +}); + +app.route("/.well-known", wellKnown); +app.route("/", health); + +Deno.serve({ port: env.ROCKSKY_FEEDGEN_PORT }, app.fetch); diff --git a/apps/feeds/src/algos/afrobeat.ts b/apps/feeds/src/algos/afrobeat.ts new file mode 100644 index 00000000..7a03e6ea --- /dev/null +++ b/apps/feeds/src/algos/afrobeat.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["afrobeat"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "afrobeat"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/afrobeats.ts b/apps/feeds/src/algos/afrobeats.ts new file mode 100644 index 00000000..198ce169 --- /dev/null +++ b/apps/feeds/src/algos/afrobeats.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["afrobeats"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "afrobeats"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/alternative-metal.ts b/apps/feeds/src/algos/alternative-metal.ts new file mode 100644 index 00000000..659bce09 --- /dev/null +++ b/apps/feeds/src/algos/alternative-metal.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["alternative metal"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "alternative-metal"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/alternative-rnb.ts b/apps/feeds/src/algos/alternative-rnb.ts new file mode 100644 index 00000000..51fed40f --- /dev/null +++ b/apps/feeds/src/algos/alternative-rnb.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["alternative rnb"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "alternative-rnb"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/anime.ts b/apps/feeds/src/algos/anime.ts new file mode 100644 index 00000000..1c3b5f95 --- /dev/null +++ b/apps/feeds/src/algos/anime.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["anime"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "anime"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/art-pop.ts b/apps/feeds/src/algos/art-pop.ts new file mode 100644 index 00000000..1f31a35e --- /dev/null +++ b/apps/feeds/src/algos/art-pop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["art pop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "art-pop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/breakcore.ts b/apps/feeds/src/algos/breakcore.ts new file mode 100644 index 00000000..f8c9ff74 --- /dev/null +++ b/apps/feeds/src/algos/breakcore.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["breakcore"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "breakcore"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/chicago-drill.ts b/apps/feeds/src/algos/chicago-drill.ts new file mode 100644 index 00000000..06c955c9 --- /dev/null +++ b/apps/feeds/src/algos/chicago-drill.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["chicago drill"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "chicago-drill"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/chillwave.ts b/apps/feeds/src/algos/chillwave.ts new file mode 100644 index 00000000..64ed10d1 --- /dev/null +++ b/apps/feeds/src/algos/chillwave.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["chillwave"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "chillwave"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/country-hip-hop.ts b/apps/feeds/src/algos/country-hip-hop.ts new file mode 100644 index 00000000..8a8c526a --- /dev/null +++ b/apps/feeds/src/algos/country-hip-hop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["country hip hop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "country-hip-hop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/crunk.ts b/apps/feeds/src/algos/crunk.ts new file mode 100644 index 00000000..2de48c24 --- /dev/null +++ b/apps/feeds/src/algos/crunk.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["crunk"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "crunk"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/dance-pop.ts b/apps/feeds/src/algos/dance-pop.ts new file mode 100644 index 00000000..cb1ff480 --- /dev/null +++ b/apps/feeds/src/algos/dance-pop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["dance pop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "dance-pop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/deep-house.ts b/apps/feeds/src/algos/deep-house.ts new file mode 100644 index 00000000..ed58efb7 --- /dev/null +++ b/apps/feeds/src/algos/deep-house.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["deep house"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "deep-house"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/drill.ts b/apps/feeds/src/algos/drill.ts new file mode 100644 index 00000000..f464bf15 --- /dev/null +++ b/apps/feeds/src/algos/drill.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["drill"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "drill"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/dubstep.ts b/apps/feeds/src/algos/dubstep.ts new file mode 100644 index 00000000..ba7b6ebb --- /dev/null +++ b/apps/feeds/src/algos/dubstep.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["dubstep"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "dubstep"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/emo.ts b/apps/feeds/src/algos/emo.ts new file mode 100644 index 00000000..d5b1286b --- /dev/null +++ b/apps/feeds/src/algos/emo.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["emo"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "emo"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/grunge.ts b/apps/feeds/src/algos/grunge.ts new file mode 100644 index 00000000..506bdfc6 --- /dev/null +++ b/apps/feeds/src/algos/grunge.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["grunge"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "grunge"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/hard-rock.ts b/apps/feeds/src/algos/hard-rock.ts new file mode 100644 index 00000000..0f55f39b --- /dev/null +++ b/apps/feeds/src/algos/hard-rock.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["hard rock"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "hard-rock"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/heavy-metal.ts b/apps/feeds/src/algos/heavy-metal.ts new file mode 100644 index 00000000..ae19fa1d --- /dev/null +++ b/apps/feeds/src/algos/heavy-metal.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["heavy metal"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "heavy-metal"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/hip-hop.ts b/apps/feeds/src/algos/hip-hop.ts new file mode 100644 index 00000000..bbe9ee33 --- /dev/null +++ b/apps/feeds/src/algos/hip-hop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["hip hop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "hip-hop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/house.ts b/apps/feeds/src/algos/house.ts new file mode 100644 index 00000000..7837517b --- /dev/null +++ b/apps/feeds/src/algos/house.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["house"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "house"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/hyperpop.ts b/apps/feeds/src/algos/hyperpop.ts new file mode 100644 index 00000000..8a540d1b --- /dev/null +++ b/apps/feeds/src/algos/hyperpop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["hyperpop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "hyperpop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/indie-rock.ts b/apps/feeds/src/algos/indie-rock.ts new file mode 100644 index 00000000..055e10d6 --- /dev/null +++ b/apps/feeds/src/algos/indie-rock.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["indie rock"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "indie-rock"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/indie.ts b/apps/feeds/src/algos/indie.ts new file mode 100644 index 00000000..76728d9b --- /dev/null +++ b/apps/feeds/src/algos/indie.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["indie"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "indie"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/j-pop.ts b/apps/feeds/src/algos/j-pop.ts new file mode 100644 index 00000000..e94613b1 --- /dev/null +++ b/apps/feeds/src/algos/j-pop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["j-pop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "j-pop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/j-rock.ts b/apps/feeds/src/algos/j-rock.ts new file mode 100644 index 00000000..df6d38ef --- /dev/null +++ b/apps/feeds/src/algos/j-rock.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["j-rock"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "j-rock"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/jazz.ts b/apps/feeds/src/algos/jazz.ts new file mode 100644 index 00000000..27c0c7f0 --- /dev/null +++ b/apps/feeds/src/algos/jazz.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["jazz"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "jazz"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/k-pop.ts b/apps/feeds/src/algos/k-pop.ts new file mode 100644 index 00000000..7b6ef5fb --- /dev/null +++ b/apps/feeds/src/algos/k-pop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["k-pop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "k-pop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/lo-fi.ts b/apps/feeds/src/algos/lo-fi.ts new file mode 100644 index 00000000..fed0fa31 --- /dev/null +++ b/apps/feeds/src/algos/lo-fi.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["lo-fi"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "lo-fi"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/metal.ts b/apps/feeds/src/algos/metal.ts new file mode 100644 index 00000000..ec78799d --- /dev/null +++ b/apps/feeds/src/algos/metal.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["metal"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "metal"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/metalcore.ts b/apps/feeds/src/algos/metalcore.ts new file mode 100644 index 00000000..96166180 --- /dev/null +++ b/apps/feeds/src/algos/metalcore.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["metalcore"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "metalcore"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/midwest-emo.ts b/apps/feeds/src/algos/midwest-emo.ts new file mode 100644 index 00000000..fd3877cb --- /dev/null +++ b/apps/feeds/src/algos/midwest-emo.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["midwest emo"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "midwest-emo"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/mod.ts b/apps/feeds/src/algos/mod.ts new file mode 100644 index 00000000..b5dc0032 --- /dev/null +++ b/apps/feeds/src/algos/mod.ts @@ -0,0 +1,117 @@ +import * as afrobeat from "./afrobeat.ts"; +import * as afrobeats from "./afrobeats.ts"; +import * as alternativeMetal from "./alternative-metal.ts"; +import * as alternativeRnb from "./alternative-rnb.ts"; +import * as anime from "./anime.ts"; +import * as artPop from "./art-pop.ts"; +import * as breakcore from "./breakcore.ts"; +import * as chicagoDrill from "./chicago-drill.ts"; +import * as chillwave from "./chillwave.ts"; +import * as countryHipHop from "./country-hip-hop.ts"; +import * as crunk from "./crunk.ts"; +import * as dancePop from "./dance-pop.ts"; +import * as deepHouse from "./deep-house.ts"; +import * as drill from "./drill.ts"; +import * as dubstep from "./dubstep.ts"; +import * as emo from "./emo.ts"; +import * as grunge from "./grunge.ts"; +import * as hardRock from "./hard-rock.ts"; +import * as heavyMetal from "./heavy-metal.ts"; +import * as hipHop from "./hip-hop.ts"; +import * as house from "./house.ts"; +import * as hyperpop from "./hyperpop.ts"; +import * as indie from "./indie.ts"; +import * as indieRock from "./indie-rock.ts"; +import * as jpop from "./j-pop.ts"; +import * as jrock from "./j-rock.ts"; +import * as jazz from "./jazz.ts"; +import * as kpop from "./k-pop.ts"; +import * as lofi from "./lo-fi.ts"; +import * as metal from "./metal.ts"; +import * as metalcore from "./metalcore.ts"; +import * as midwestEmo from "./midwest-emo.ts"; +import * as numetal from "./nu-metal.ts"; +import * as popPunk from "./pop-punk.ts"; +import * as postGrunge from "./post-grunge.ts"; +import * as rap from "./rap.ts"; +import * as rapMetal from "./rap-metal.ts"; +import * as rnb from "./rnb.ts"; +import * as rock from "./rock.ts"; +import * as southernHipHop from "./southern-hip-hop.ts"; +import * as speedcore from "./speedcore.ts"; +import * as synthwave from "./synthwave.ts"; +import * as swedishPop from "./swedish-pop.ts"; +import * as thrashMetal from "./thrash-metal.ts"; +import * as trap from "./trap.ts"; +import * as trapSoul from "./trap-soul.ts"; +import * as tropicalHouse from "./tropical-house.ts"; +import * as vaporwave from "./vaporwave.ts"; +import * as visualKei from "./visual-kei.ts"; +import * as vocaloid from "./vocaloid.ts"; +import * as westCoastHipHop from "./west-coast-hip-hop.ts"; +import { Algorithm } from "./types.ts"; + +const algos: Algorithm[] = [ + afrobeat.info, + afrobeats.info, + alternativeMetal.info, + alternativeRnb.info, + anime.info, + artPop.info, + breakcore.info, + chicagoDrill.info, + chillwave.info, + countryHipHop.info, + crunk.info, + dancePop.info, + deepHouse.info, + drill.info, + dubstep.info, + emo.info, + grunge.info, + hardRock.info, + heavyMetal.info, + hipHop.info, + house.info, + hyperpop.info, + indie.info, + indieRock.info, + jpop.info, + jrock.info, + jazz.info, + kpop.info, + lofi.info, + metal.info, + metalcore.info, + midwestEmo.info, + numetal.info, + popPunk.info, + postGrunge.info, + rap.info, + rapMetal.info, + rnb.info, + rock.info, + southernHipHop.info, + speedcore.info, + synthwave.info, + swedishPop.info, + thrashMetal.info, + trap.info, + trapSoul.info, + tropicalHouse.info, + vaporwave.info, + visualKei.info, + vocaloid.info, + westCoastHipHop.info, +]; + +export function getAlgo(publisherDid: string, rkey: string) { + for (const algo of algos) { + if (algo.rkey === rkey && algo.publisherDid === publisherDid) { + return algo; + } + } + return null; +} + +export default algos; diff --git a/apps/feeds/src/algos/nu-metal.ts b/apps/feeds/src/algos/nu-metal.ts new file mode 100644 index 00000000..993f038a --- /dev/null +++ b/apps/feeds/src/algos/nu-metal.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["nu metal"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "nu-metal"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/pop-punk.ts b/apps/feeds/src/algos/pop-punk.ts new file mode 100644 index 00000000..ba5dec4b --- /dev/null +++ b/apps/feeds/src/algos/pop-punk.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["pop punk"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "pop-punk"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/post-grunge.ts b/apps/feeds/src/algos/post-grunge.ts new file mode 100644 index 00000000..02642265 --- /dev/null +++ b/apps/feeds/src/algos/post-grunge.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["post grunge"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "post-grunge"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/rap-metal.ts b/apps/feeds/src/algos/rap-metal.ts new file mode 100644 index 00000000..b63362c1 --- /dev/null +++ b/apps/feeds/src/algos/rap-metal.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["rap metal"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "rap-metal"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/rap.ts b/apps/feeds/src/algos/rap.ts new file mode 100644 index 00000000..7fea8bd8 --- /dev/null +++ b/apps/feeds/src/algos/rap.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["rap"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "rap"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/rnb.ts b/apps/feeds/src/algos/rnb.ts new file mode 100644 index 00000000..880ee7a9 --- /dev/null +++ b/apps/feeds/src/algos/rnb.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["rnb"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "rnb"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/rock.ts b/apps/feeds/src/algos/rock.ts new file mode 100644 index 00000000..a53fd4ab --- /dev/null +++ b/apps/feeds/src/algos/rock.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["rock"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "rock"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/southern-hip-hop.ts b/apps/feeds/src/algos/southern-hip-hop.ts new file mode 100644 index 00000000..88804131 --- /dev/null +++ b/apps/feeds/src/algos/southern-hip-hop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["southern hip hop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "southern-hip-hop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/speedcore.ts b/apps/feeds/src/algos/speedcore.ts new file mode 100644 index 00000000..927c04e8 --- /dev/null +++ b/apps/feeds/src/algos/speedcore.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["speedcore"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "speedcore"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/swedish-pop.ts b/apps/feeds/src/algos/swedish-pop.ts new file mode 100644 index 00000000..d6a4812e --- /dev/null +++ b/apps/feeds/src/algos/swedish-pop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["swedish pop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "swedish-pop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/synthwave.ts b/apps/feeds/src/algos/synthwave.ts new file mode 100644 index 00000000..a8ef457e --- /dev/null +++ b/apps/feeds/src/algos/synthwave.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["synthwave"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "synthwave"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/thrash-metal.ts b/apps/feeds/src/algos/thrash-metal.ts new file mode 100644 index 00000000..be6e6441 --- /dev/null +++ b/apps/feeds/src/algos/thrash-metal.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["thrash metal"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "thrash-metal"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/trap-soul.ts b/apps/feeds/src/algos/trap-soul.ts new file mode 100644 index 00000000..455b25f3 --- /dev/null +++ b/apps/feeds/src/algos/trap-soul.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["trap soul"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "trap-soul"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/trap.ts b/apps/feeds/src/algos/trap.ts new file mode 100644 index 00000000..33dfccf3 --- /dev/null +++ b/apps/feeds/src/algos/trap.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["trap"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "trap"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/tropical-house.ts b/apps/feeds/src/algos/tropical-house.ts new file mode 100644 index 00000000..f98eb71d --- /dev/null +++ b/apps/feeds/src/algos/tropical-house.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["tropical house"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "tropical-house"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/types.ts b/apps/feeds/src/algos/types.ts new file mode 100644 index 00000000..b02d8660 --- /dev/null +++ b/apps/feeds/src/algos/types.ts @@ -0,0 +1,25 @@ +import { Context } from "../context.ts"; + +export interface Algorithm { + handler: AlgoHandler; + needsAuth: boolean; + publisherDid: string; + rkey: string; +} + +export interface feedParams { + feed: string; + limit?: number; + cursor?: string; +} + +export interface FeedResponse { + cursor?: string; + feed: Array<{ scrobble: string }>; +} + +export type AlgoHandler = ( + ctx: Context, + params: feedParams, + did?: string | null, +) => Promise; diff --git a/apps/feeds/src/algos/vaporwave.ts b/apps/feeds/src/algos/vaporwave.ts new file mode 100644 index 00000000..0a8e7002 --- /dev/null +++ b/apps/feeds/src/algos/vaporwave.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["vaporwave"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "vaporwave"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/visual-kei.ts b/apps/feeds/src/algos/visual-kei.ts new file mode 100644 index 00000000..c6bd9e76 --- /dev/null +++ b/apps/feeds/src/algos/visual-kei.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["visual kei"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "visual-kei"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/vocaloid.ts b/apps/feeds/src/algos/vocaloid.ts new file mode 100644 index 00000000..2d76ba25 --- /dev/null +++ b/apps/feeds/src/algos/vocaloid.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["vocaloid"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "vocaloid"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/algos/west-coast-hip-hop.ts b/apps/feeds/src/algos/west-coast-hip-hop.ts new file mode 100644 index 00000000..4ed1967a --- /dev/null +++ b/apps/feeds/src/algos/west-coast-hip-hop.ts @@ -0,0 +1,57 @@ +import { Context } from "../context.ts"; +import { Algorithm, feedParams } from "./types.ts"; +import schema from "../schema/mod.ts"; +import { arrayContains, desc, eq } from "drizzle-orm"; + +interface QueryFilter { + indexedAt?: { $lt: Date }; +} + +const handler = async ( + ctx: Context, + params: feedParams, + _did?: string | null, +) => { + const { limit = 50, cursor } = params; + + const query: QueryFilter = {}; + + if (cursor) { + query.indexedAt = { $lt: new Date(parseInt(cursor, 10)) }; + } + + const scrobbles = await ctx.db + .select() + .from(schema.scrobbles) + .leftJoin(schema.artists, eq(schema.scrobbles.artistId, schema.artists.id)) + .where(arrayContains(schema.artists.genres, ["west coast hip hop"])) + .orderBy(desc(schema.scrobbles.timestamp)) + .limit(limit) + .execute(); + + const feed = scrobbles.map(({ scrobbles }) => ({ + scrobble: scrobbles.uri, + timestamp: scrobbles.timestamp, + })); + + const { scrobbles: lastScrobble } = + scrobbles.length > 0 ? scrobbles.at(-1)! : { scrobbles: null }; + const nextCursor = lastScrobble + ? lastScrobble.timestamp.getTime().toString(10) + : undefined; + + return { + cursor: nextCursor, + feed, + }; +}; + +export const publisherDid = "did:plc:vegqomyce4ssoqs7zwqvgqty"; +export const rkey = "west-coast-hip-hop"; + +export const info = { + handler, + needsAuth: false, + publisherDid, + rkey, +} as Algorithm; diff --git a/apps/feeds/src/api/describeFeedGenerator.ts b/apps/feeds/src/api/describeFeedGenerator.ts new file mode 100644 index 00000000..ee9c9882 --- /dev/null +++ b/apps/feeds/src/api/describeFeedGenerator.ts @@ -0,0 +1,24 @@ +import { Server } from "../lex/index.ts"; +import { Context } from "../context.ts"; +import algos from "../algos/mod.ts"; +import { AtUri } from "@atp/syntax"; +import { Algorithm } from "../algos/types.ts"; + +export default function (server: Server, ctx: Context) { + server.app.rocksky.feed.describeFeedGenerator(() => { + const feeds = algos.map((algo: Algorithm) => ({ + uri: AtUri.make( + algo.publisherDid, + "app.rocksky.feed.generator", + algo.rkey, + ).toString(), + })); + return { + encoding: "application/json", + body: { + did: ctx.ownDid, + feeds, + }, + }; + }); +} diff --git a/apps/feeds/src/api/getFeedSkeleton.ts b/apps/feeds/src/api/getFeedSkeleton.ts new file mode 100644 index 00000000..a5a1a4cc --- /dev/null +++ b/apps/feeds/src/api/getFeedSkeleton.ts @@ -0,0 +1,32 @@ +import { AuthRequiredError, InvalidRequestError } from "@atp/xrpc-server"; +import { Server } from "../lex/index.ts"; +import { getAlgo } from "../algos/mod.ts"; +import { Context } from "../context.ts"; +import { AtUri } from "@atp/syntax"; + +export default function (server: Server, ctx: Context) { + server.app.rocksky.feed.getFeedSkeleton({ + auth: ctx.authVerifier.standardOptional, + handler: async ({ params, auth }) => { + const feedUri = new AtUri(params.feed); + const algo = getAlgo(feedUri.hostname, feedUri.rkey); + if (feedUri.collection !== "app.rocksky.feed.generator" || !algo) { + throw new InvalidRequestError( + "Unsupported algorithm", + "UnsupportedAlgorithm", + ); + } + const did = + auth.credentials.type === "standard" ? auth.credentials.iss : null; + if (algo.needsAuth && !did) { + throw new AuthRequiredError(); + } + + const body = await algo.handler(ctx, params, did); + return { + encoding: "application/json", + body: body, + }; + }, + }); +} diff --git a/apps/feeds/src/api/health.ts b/apps/feeds/src/api/health.ts new file mode 100644 index 00000000..7460e394 --- /dev/null +++ b/apps/feeds/src/api/health.ts @@ -0,0 +1,22 @@ +import { Hono } from "@hono/hono"; + +const app = new Hono(); + +app.get("/", (c) => { + return c.text( + ` +This is a feed generator for the "rocksky.app" application. +Learn more at https://tangled.org/rocksky.app/rocksky + +Most API routes are under /xrpc/ + + `, + ); +}); + +app.get("/xrpc/_health", (c) => { + const version = Deno.env.get("COMMIT_SHA") ?? "unknown"; + return c.json({ version }); +}); + +export default app; diff --git a/apps/feeds/src/api/well-known.ts b/apps/feeds/src/api/well-known.ts new file mode 100644 index 00000000..9aa3a458 --- /dev/null +++ b/apps/feeds/src/api/well-known.ts @@ -0,0 +1,20 @@ +import { Hono } from "@hono/hono"; +import { env } from "../utils/env.ts"; + +const app = new Hono(); + +app.get("/.well-known/did.json", (c) => { + return c.json({ + "@context": ["https://www.w3.org/ns/did/v1"], + id: `did:web:${env.ROCKSKY_FEEDGEN_DOMAIN}`, + service: [ + { + id: "#rocksky_fg", + type: "RockskyFeedGenerator", + serviceEndpoint: `https://${env.ROCKSKY_FEEDGEN_DOMAIN}`, + }, + ], + }); +}); + +export default app; diff --git a/apps/feeds/src/context.ts b/apps/feeds/src/context.ts new file mode 100644 index 00000000..274064e3 --- /dev/null +++ b/apps/feeds/src/context.ts @@ -0,0 +1,42 @@ +import drizzle from "./drizzle.ts"; +import { configure, getConsoleSink, getLogger } from "@logtape/logtape"; +import { getPrettyFormatter } from "@logtape/pretty"; +import { DidResolver } from "@atp/identity"; +import { AuthVerifier } from "./utils/auth.ts"; +import { env } from "./utils/env.ts"; + +await configure({ + sinks: { + console: getConsoleSink({ + formatter: getPrettyFormatter({ + properties: true, + categoryStyle: "underline", + messageColor: "rgb(255, 255, 255)", + categoryColor: "rgb(255, 255, 255)", + messageStyle: "reset", + }), + }), + }, + loggers: [ + { category: "feedgen", lowestLevel: "info", sinks: ["console"] }, + { category: ["logtape", "meta"], lowestLevel: "error", sinks: ["console"] }, + ], +}); + +const logger = getLogger("feedgen"); +const ownDid = `did:web:${env.ROCKSKY_FEEDGEN_DOMAIN}`; +const didResolver = new DidResolver({}); +const authVerifier = new AuthVerifier(ownDid, didResolver); + +export const ctx = { + db: drizzle.db, + logger, + ownDid, + authVerifier, +}; + +export type Context = typeof ctx; + +export type AppEnv = { + Bindings: Context; +}; diff --git a/apps/feeds/src/drizzle.ts b/apps/feeds/src/drizzle.ts new file mode 100644 index 00000000..a7334854 --- /dev/null +++ b/apps/feeds/src/drizzle.ts @@ -0,0 +1,11 @@ +import { drizzle } from "drizzle-orm/node-postgres"; +import { env } from "./utils/env.ts"; +import pg from "pg"; + +const pool = new pg.Pool({ + connectionString: env.XATA_POSTGRES_URL, + max: 20, +}); +const db = drizzle(pool); + +export default { db }; diff --git a/apps/feeds/src/lex/index.ts b/apps/feeds/src/lex/index.ts new file mode 100644 index 00000000..1316acb0 --- /dev/null +++ b/apps/feeds/src/lex/index.ts @@ -0,0 +1,1280 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { + type Auth, + createServer as createXrpcServer, + type MethodConfigOrHandler, + type Options as XrpcOptions, + type Server as XrpcServer, +} from "@atp/xrpc-server"; +import { schemas } from "./lexicons.ts"; +import type * as AppRockskyShoutGetAlbumShouts from "./types/app/rocksky/shout/getAlbumShouts.ts"; +import type * as AppRockskyShoutReportShout from "./types/app/rocksky/shout/reportShout.ts"; +import type * as AppRockskyShoutGetTrackShouts from "./types/app/rocksky/shout/getTrackShouts.ts"; +import type * as AppRockskyShoutReplyShout from "./types/app/rocksky/shout/replyShout.ts"; +import type * as AppRockskyShoutRemoveShout from "./types/app/rocksky/shout/removeShout.ts"; +import type * as AppRockskyShoutGetProfileShouts from "./types/app/rocksky/shout/getProfileShouts.ts"; +import type * as AppRockskyShoutGetArtistShouts from "./types/app/rocksky/shout/getArtistShouts.ts"; +import type * as AppRockskyShoutGetShoutReplies from "./types/app/rocksky/shout/getShoutReplies.ts"; +import type * as AppRockskyShoutCreateShout from "./types/app/rocksky/shout/createShout.ts"; +import type * as AppRockskyScrobbleCreateScrobble from "./types/app/rocksky/scrobble/createScrobble.ts"; +import type * as AppRockskyScrobbleGetScrobbles from "./types/app/rocksky/scrobble/getScrobbles.ts"; +import type * as AppRockskyScrobbleGetScrobble from "./types/app/rocksky/scrobble/getScrobble.ts"; +import type * as AppRockskyLikeDislikeShout from "./types/app/rocksky/like/dislikeShout.ts"; +import type * as AppRockskyLikeLikeSong from "./types/app/rocksky/like/likeSong.ts"; +import type * as AppRockskyLikeDislikeSong from "./types/app/rocksky/like/dislikeSong.ts"; +import type * as AppRockskyLikeLikeShout from "./types/app/rocksky/like/likeShout.ts"; +import type * as AppRockskyPlaylistCreatePlaylist from "./types/app/rocksky/playlist/createPlaylist.ts"; +import type * as AppRockskyPlaylistStartPlaylist from "./types/app/rocksky/playlist/startPlaylist.ts"; +import type * as AppRockskyPlaylistGetPlaylists from "./types/app/rocksky/playlist/getPlaylists.ts"; +import type * as AppRockskyPlaylistInsertDirectory from "./types/app/rocksky/playlist/insertDirectory.ts"; +import type * as AppRockskyPlaylistRemoveTrack from "./types/app/rocksky/playlist/removeTrack.ts"; +import type * as AppRockskyPlaylistRemovePlaylist from "./types/app/rocksky/playlist/removePlaylist.ts"; +import type * as AppRockskyPlaylistInsertFiles from "./types/app/rocksky/playlist/insertFiles.ts"; +import type * as AppRockskyPlaylistGetPlaylist from "./types/app/rocksky/playlist/getPlaylist.ts"; +import type * as AppRockskySpotifySeek from "./types/app/rocksky/spotify/seek.ts"; +import type * as AppRockskySpotifyNext from "./types/app/rocksky/spotify/next.ts"; +import type * as AppRockskySpotifyGetCurrentlyPlaying from "./types/app/rocksky/spotify/getCurrentlyPlaying.ts"; +import type * as AppRockskySpotifyPrevious from "./types/app/rocksky/spotify/previous.ts"; +import type * as AppRockskySpotifyPause from "./types/app/rocksky/spotify/pause.ts"; +import type * as AppRockskySpotifyPlay from "./types/app/rocksky/spotify/play.ts"; +import type * as AppRockskyChartsGetScrobblesChart from "./types/app/rocksky/charts/getScrobblesChart.ts"; +import type * as AppRockskySongGetSongs from "./types/app/rocksky/song/getSongs.ts"; +import type * as AppRockskySongGetSong from "./types/app/rocksky/song/getSong.ts"; +import type * as AppRockskySongCreateSong from "./types/app/rocksky/song/createSong.ts"; +import type * as AppRockskyApikeyGetApikeys from "./types/app/rocksky/apikey/getApikeys.ts"; +import type * as AppRockskyApikeyUpdateApikey from "./types/app/rocksky/apikey/updateApikey.ts"; +import type * as AppRockskyApikeyCreateApikey from "./types/app/rocksky/apikey/createApikey.ts"; +import type * as AppRockskyApikeyRemoveApikey from "./types/app/rocksky/apikey/removeApikey.ts"; +import type * as AppRockskyFeedGetFeedGenerators from "./types/app/rocksky/feed/getFeedGenerators.ts"; +import type * as AppRockskyFeedGetFeedGenerator from "./types/app/rocksky/feed/getFeedGenerator.ts"; +import type * as AppRockskyFeedSearch from "./types/app/rocksky/feed/search.ts"; +import type * as AppRockskyFeedGetNowPlayings from "./types/app/rocksky/feed/getNowPlayings.ts"; +import type * as AppRockskyFeedDescribeFeedGenerator from "./types/app/rocksky/feed/describeFeedGenerator.ts"; +import type * as AppRockskyFeedGetFeed from "./types/app/rocksky/feed/getFeed.ts"; +import type * as AppRockskyFeedGetFeedSkeleton from "./types/app/rocksky/feed/getFeedSkeleton.ts"; +import type * as AppRockskyDropboxDownloadFile from "./types/app/rocksky/dropbox/downloadFile.ts"; +import type * as AppRockskyDropboxGetFiles from "./types/app/rocksky/dropbox/getFiles.ts"; +import type * as AppRockskyDropboxGetMetadata from "./types/app/rocksky/dropbox/getMetadata.ts"; +import type * as AppRockskyDropboxGetTemporaryLink from "./types/app/rocksky/dropbox/getTemporaryLink.ts"; +import type * as AppRockskyGoogledriveGetFile from "./types/app/rocksky/googledrive/getFile.ts"; +import type * as AppRockskyGoogledriveDownloadFile from "./types/app/rocksky/googledrive/downloadFile.ts"; +import type * as AppRockskyGoogledriveGetFiles from "./types/app/rocksky/googledrive/getFiles.ts"; +import type * as AppRockskyAlbumGetAlbumTracks from "./types/app/rocksky/album/getAlbumTracks.ts"; +import type * as AppRockskyAlbumGetAlbum from "./types/app/rocksky/album/getAlbum.ts"; +import type * as AppRockskyAlbumGetAlbums from "./types/app/rocksky/album/getAlbums.ts"; +import type * as AppRockskyActorGetActorPlaylists from "./types/app/rocksky/actor/getActorPlaylists.ts"; +import type * as AppRockskyActorGetActorSongs from "./types/app/rocksky/actor/getActorSongs.ts"; +import type * as AppRockskyActorGetActorArtists from "./types/app/rocksky/actor/getActorArtists.ts"; +import type * as AppRockskyActorGetProfile from "./types/app/rocksky/actor/getProfile.ts"; +import type * as AppRockskyActorGetActorLovedSongs from "./types/app/rocksky/actor/getActorLovedSongs.ts"; +import type * as AppRockskyActorGetActorAlbums from "./types/app/rocksky/actor/getActorAlbums.ts"; +import type * as AppRockskyActorGetActorScrobbles from "./types/app/rocksky/actor/getActorScrobbles.ts"; +import type * as AppRockskyArtistGetArtistAlbums from "./types/app/rocksky/artist/getArtistAlbums.ts"; +import type * as AppRockskyArtistGetArtistListeners from "./types/app/rocksky/artist/getArtistListeners.ts"; +import type * as AppRockskyArtistGetArtists from "./types/app/rocksky/artist/getArtists.ts"; +import type * as AppRockskyArtistGetArtist from "./types/app/rocksky/artist/getArtist.ts"; +import type * as AppRockskyArtistGetArtistTracks from "./types/app/rocksky/artist/getArtistTracks.ts"; +import type * as AppRockskyStatsGetStats from "./types/app/rocksky/stats/getStats.ts"; +import type * as AppRockskyPlayerSeek from "./types/app/rocksky/player/seek.ts"; +import type * as AppRockskyPlayerGetPlaybackQueue from "./types/app/rocksky/player/getPlaybackQueue.ts"; +import type * as AppRockskyPlayerNext from "./types/app/rocksky/player/next.ts"; +import type * as AppRockskyPlayerPlayFile from "./types/app/rocksky/player/playFile.ts"; +import type * as AppRockskyPlayerGetCurrentlyPlaying from "./types/app/rocksky/player/getCurrentlyPlaying.ts"; +import type * as AppRockskyPlayerPrevious from "./types/app/rocksky/player/previous.ts"; +import type * as AppRockskyPlayerAddItemsToQueue from "./types/app/rocksky/player/addItemsToQueue.ts"; +import type * as AppRockskyPlayerPause from "./types/app/rocksky/player/pause.ts"; +import type * as AppRockskyPlayerPlay from "./types/app/rocksky/player/play.ts"; +import type * as AppRockskyPlayerPlayDirectory from "./types/app/rocksky/player/playDirectory.ts"; +import type * as AppRockskyPlayerAddDirectoryToQueue from "./types/app/rocksky/player/addDirectoryToQueue.ts"; + +export function createServer(options?: XrpcOptions): Server { + return new Server(options); +} + +export class Server { + xrpc: XrpcServer; + com: ComNS; + app: AppNS; + + constructor(options?: XrpcOptions) { + this.xrpc = createXrpcServer(schemas, options); + this.com = new ComNS(this); + this.app = new AppNS(this); + } +} + +export class ComNS { + _server: Server; + atproto: ComAtprotoNS; + + constructor(server: Server) { + this._server = server; + this.atproto = new ComAtprotoNS(server); + } +} + +export class ComAtprotoNS { + _server: Server; + repo: ComAtprotoRepoNS; + + constructor(server: Server) { + this._server = server; + this.repo = new ComAtprotoRepoNS(server); + } +} + +export class ComAtprotoRepoNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } +} + +export class AppNS { + _server: Server; + rocksky: AppRockskyNS; + bsky: AppBskyNS; + + constructor(server: Server) { + this._server = server; + this.rocksky = new AppRockskyNS(server); + this.bsky = new AppBskyNS(server); + } +} + +export class AppRockskyNS { + _server: Server; + shout: AppRockskyShoutNS; + scrobble: AppRockskyScrobbleNS; + like: AppRockskyLikeNS; + playlist: AppRockskyPlaylistNS; + spotify: AppRockskySpotifyNS; + charts: AppRockskyChartsNS; + song: AppRockskySongNS; + apikey: AppRockskyApikeyNS; + feed: AppRockskyFeedNS; + dropbox: AppRockskyDropboxNS; + googledrive: AppRockskyGoogledriveNS; + album: AppRockskyAlbumNS; + actor: AppRockskyActorNS; + artist: AppRockskyArtistNS; + stats: AppRockskyStatsNS; + player: AppRockskyPlayerNS; + + constructor(server: Server) { + this._server = server; + this.shout = new AppRockskyShoutNS(server); + this.scrobble = new AppRockskyScrobbleNS(server); + this.like = new AppRockskyLikeNS(server); + this.playlist = new AppRockskyPlaylistNS(server); + this.spotify = new AppRockskySpotifyNS(server); + this.charts = new AppRockskyChartsNS(server); + this.song = new AppRockskySongNS(server); + this.apikey = new AppRockskyApikeyNS(server); + this.feed = new AppRockskyFeedNS(server); + this.dropbox = new AppRockskyDropboxNS(server); + this.googledrive = new AppRockskyGoogledriveNS(server); + this.album = new AppRockskyAlbumNS(server); + this.actor = new AppRockskyActorNS(server); + this.artist = new AppRockskyArtistNS(server); + this.stats = new AppRockskyStatsNS(server); + this.player = new AppRockskyPlayerNS(server); + } +} + +export class AppRockskyShoutNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getAlbumShouts( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutGetAlbumShouts.QueryParams, + AppRockskyShoutGetAlbumShouts.HandlerInput, + AppRockskyShoutGetAlbumShouts.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.getAlbumShouts"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + reportShout( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutReportShout.QueryParams, + AppRockskyShoutReportShout.HandlerInput, + AppRockskyShoutReportShout.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.reportShout"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getTrackShouts( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutGetTrackShouts.QueryParams, + AppRockskyShoutGetTrackShouts.HandlerInput, + AppRockskyShoutGetTrackShouts.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.getTrackShouts"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + replyShout( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutReplyShout.QueryParams, + AppRockskyShoutReplyShout.HandlerInput, + AppRockskyShoutReplyShout.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.replyShout"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + removeShout( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutRemoveShout.QueryParams, + AppRockskyShoutRemoveShout.HandlerInput, + AppRockskyShoutRemoveShout.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.removeShout"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getProfileShouts( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutGetProfileShouts.QueryParams, + AppRockskyShoutGetProfileShouts.HandlerInput, + AppRockskyShoutGetProfileShouts.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.getProfileShouts"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getArtistShouts( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutGetArtistShouts.QueryParams, + AppRockskyShoutGetArtistShouts.HandlerInput, + AppRockskyShoutGetArtistShouts.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.getArtistShouts"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getShoutReplies( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutGetShoutReplies.QueryParams, + AppRockskyShoutGetShoutReplies.HandlerInput, + AppRockskyShoutGetShoutReplies.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.getShoutReplies"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + createShout( + cfg: MethodConfigOrHandler< + A, + AppRockskyShoutCreateShout.QueryParams, + AppRockskyShoutCreateShout.HandlerInput, + AppRockskyShoutCreateShout.HandlerOutput + >, + ) { + const nsid = "app.rocksky.shout.createShout"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyScrobbleNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + createScrobble( + cfg: MethodConfigOrHandler< + A, + AppRockskyScrobbleCreateScrobble.QueryParams, + AppRockskyScrobbleCreateScrobble.HandlerInput, + AppRockskyScrobbleCreateScrobble.HandlerOutput + >, + ) { + const nsid = "app.rocksky.scrobble.createScrobble"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getScrobbles( + cfg: MethodConfigOrHandler< + A, + AppRockskyScrobbleGetScrobbles.QueryParams, + AppRockskyScrobbleGetScrobbles.HandlerInput, + AppRockskyScrobbleGetScrobbles.HandlerOutput + >, + ) { + const nsid = "app.rocksky.scrobble.getScrobbles"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getScrobble( + cfg: MethodConfigOrHandler< + A, + AppRockskyScrobbleGetScrobble.QueryParams, + AppRockskyScrobbleGetScrobble.HandlerInput, + AppRockskyScrobbleGetScrobble.HandlerOutput + >, + ) { + const nsid = "app.rocksky.scrobble.getScrobble"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyLikeNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + dislikeShout( + cfg: MethodConfigOrHandler< + A, + AppRockskyLikeDislikeShout.QueryParams, + AppRockskyLikeDislikeShout.HandlerInput, + AppRockskyLikeDislikeShout.HandlerOutput + >, + ) { + const nsid = "app.rocksky.like.dislikeShout"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + likeSong( + cfg: MethodConfigOrHandler< + A, + AppRockskyLikeLikeSong.QueryParams, + AppRockskyLikeLikeSong.HandlerInput, + AppRockskyLikeLikeSong.HandlerOutput + >, + ) { + const nsid = "app.rocksky.like.likeSong"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + dislikeSong( + cfg: MethodConfigOrHandler< + A, + AppRockskyLikeDislikeSong.QueryParams, + AppRockskyLikeDislikeSong.HandlerInput, + AppRockskyLikeDislikeSong.HandlerOutput + >, + ) { + const nsid = "app.rocksky.like.dislikeSong"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + likeShout( + cfg: MethodConfigOrHandler< + A, + AppRockskyLikeLikeShout.QueryParams, + AppRockskyLikeLikeShout.HandlerInput, + AppRockskyLikeLikeShout.HandlerOutput + >, + ) { + const nsid = "app.rocksky.like.likeShout"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyPlaylistNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + createPlaylist( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistCreatePlaylist.QueryParams, + AppRockskyPlaylistCreatePlaylist.HandlerInput, + AppRockskyPlaylistCreatePlaylist.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.createPlaylist"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + startPlaylist( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistStartPlaylist.QueryParams, + AppRockskyPlaylistStartPlaylist.HandlerInput, + AppRockskyPlaylistStartPlaylist.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.startPlaylist"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getPlaylists( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistGetPlaylists.QueryParams, + AppRockskyPlaylistGetPlaylists.HandlerInput, + AppRockskyPlaylistGetPlaylists.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.getPlaylists"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + insertDirectory( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistInsertDirectory.QueryParams, + AppRockskyPlaylistInsertDirectory.HandlerInput, + AppRockskyPlaylistInsertDirectory.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.insertDirectory"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + removeTrack( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistRemoveTrack.QueryParams, + AppRockskyPlaylistRemoveTrack.HandlerInput, + AppRockskyPlaylistRemoveTrack.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.removeTrack"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + removePlaylist( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistRemovePlaylist.QueryParams, + AppRockskyPlaylistRemovePlaylist.HandlerInput, + AppRockskyPlaylistRemovePlaylist.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.removePlaylist"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + insertFiles( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistInsertFiles.QueryParams, + AppRockskyPlaylistInsertFiles.HandlerInput, + AppRockskyPlaylistInsertFiles.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.insertFiles"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getPlaylist( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlaylistGetPlaylist.QueryParams, + AppRockskyPlaylistGetPlaylist.HandlerInput, + AppRockskyPlaylistGetPlaylist.HandlerOutput + >, + ) { + const nsid = "app.rocksky.playlist.getPlaylist"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskySpotifyNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + seek( + cfg: MethodConfigOrHandler< + A, + AppRockskySpotifySeek.QueryParams, + AppRockskySpotifySeek.HandlerInput, + AppRockskySpotifySeek.HandlerOutput + >, + ) { + const nsid = "app.rocksky.spotify.seek"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + next( + cfg: MethodConfigOrHandler< + A, + AppRockskySpotifyNext.QueryParams, + AppRockskySpotifyNext.HandlerInput, + AppRockskySpotifyNext.HandlerOutput + >, + ) { + const nsid = "app.rocksky.spotify.next"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getCurrentlyPlaying( + cfg: MethodConfigOrHandler< + A, + AppRockskySpotifyGetCurrentlyPlaying.QueryParams, + AppRockskySpotifyGetCurrentlyPlaying.HandlerInput, + AppRockskySpotifyGetCurrentlyPlaying.HandlerOutput + >, + ) { + const nsid = "app.rocksky.spotify.getCurrentlyPlaying"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + previous( + cfg: MethodConfigOrHandler< + A, + AppRockskySpotifyPrevious.QueryParams, + AppRockskySpotifyPrevious.HandlerInput, + AppRockskySpotifyPrevious.HandlerOutput + >, + ) { + const nsid = "app.rocksky.spotify.previous"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + pause( + cfg: MethodConfigOrHandler< + A, + AppRockskySpotifyPause.QueryParams, + AppRockskySpotifyPause.HandlerInput, + AppRockskySpotifyPause.HandlerOutput + >, + ) { + const nsid = "app.rocksky.spotify.pause"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + play( + cfg: MethodConfigOrHandler< + A, + AppRockskySpotifyPlay.QueryParams, + AppRockskySpotifyPlay.HandlerInput, + AppRockskySpotifyPlay.HandlerOutput + >, + ) { + const nsid = "app.rocksky.spotify.play"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyChartsNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getScrobblesChart( + cfg: MethodConfigOrHandler< + A, + AppRockskyChartsGetScrobblesChart.QueryParams, + AppRockskyChartsGetScrobblesChart.HandlerInput, + AppRockskyChartsGetScrobblesChart.HandlerOutput + >, + ) { + const nsid = "app.rocksky.charts.getScrobblesChart"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskySongNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getSongs( + cfg: MethodConfigOrHandler< + A, + AppRockskySongGetSongs.QueryParams, + AppRockskySongGetSongs.HandlerInput, + AppRockskySongGetSongs.HandlerOutput + >, + ) { + const nsid = "app.rocksky.song.getSongs"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getSong( + cfg: MethodConfigOrHandler< + A, + AppRockskySongGetSong.QueryParams, + AppRockskySongGetSong.HandlerInput, + AppRockskySongGetSong.HandlerOutput + >, + ) { + const nsid = "app.rocksky.song.getSong"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + createSong( + cfg: MethodConfigOrHandler< + A, + AppRockskySongCreateSong.QueryParams, + AppRockskySongCreateSong.HandlerInput, + AppRockskySongCreateSong.HandlerOutput + >, + ) { + const nsid = "app.rocksky.song.createSong"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyApikeyNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getApikeys( + cfg: MethodConfigOrHandler< + A, + AppRockskyApikeyGetApikeys.QueryParams, + AppRockskyApikeyGetApikeys.HandlerInput, + AppRockskyApikeyGetApikeys.HandlerOutput + >, + ) { + const nsid = "app.rocksky.apikey.getApikeys"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + updateApikey( + cfg: MethodConfigOrHandler< + A, + AppRockskyApikeyUpdateApikey.QueryParams, + AppRockskyApikeyUpdateApikey.HandlerInput, + AppRockskyApikeyUpdateApikey.HandlerOutput + >, + ) { + const nsid = "app.rocksky.apikey.updateApikey"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + createApikey( + cfg: MethodConfigOrHandler< + A, + AppRockskyApikeyCreateApikey.QueryParams, + AppRockskyApikeyCreateApikey.HandlerInput, + AppRockskyApikeyCreateApikey.HandlerOutput + >, + ) { + const nsid = "app.rocksky.apikey.createApikey"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + removeApikey( + cfg: MethodConfigOrHandler< + A, + AppRockskyApikeyRemoveApikey.QueryParams, + AppRockskyApikeyRemoveApikey.HandlerInput, + AppRockskyApikeyRemoveApikey.HandlerOutput + >, + ) { + const nsid = "app.rocksky.apikey.removeApikey"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyFeedNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getFeedGenerators( + cfg: MethodConfigOrHandler< + A, + AppRockskyFeedGetFeedGenerators.QueryParams, + AppRockskyFeedGetFeedGenerators.HandlerInput, + AppRockskyFeedGetFeedGenerators.HandlerOutput + >, + ) { + const nsid = "app.rocksky.feed.getFeedGenerators"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getFeedGenerator( + cfg: MethodConfigOrHandler< + A, + AppRockskyFeedGetFeedGenerator.QueryParams, + AppRockskyFeedGetFeedGenerator.HandlerInput, + AppRockskyFeedGetFeedGenerator.HandlerOutput + >, + ) { + const nsid = "app.rocksky.feed.getFeedGenerator"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + search( + cfg: MethodConfigOrHandler< + A, + AppRockskyFeedSearch.QueryParams, + AppRockskyFeedSearch.HandlerInput, + AppRockskyFeedSearch.HandlerOutput + >, + ) { + const nsid = "app.rocksky.feed.search"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getNowPlayings( + cfg: MethodConfigOrHandler< + A, + AppRockskyFeedGetNowPlayings.QueryParams, + AppRockskyFeedGetNowPlayings.HandlerInput, + AppRockskyFeedGetNowPlayings.HandlerOutput + >, + ) { + const nsid = "app.rocksky.feed.getNowPlayings"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + describeFeedGenerator( + cfg: MethodConfigOrHandler< + A, + AppRockskyFeedDescribeFeedGenerator.QueryParams, + AppRockskyFeedDescribeFeedGenerator.HandlerInput, + AppRockskyFeedDescribeFeedGenerator.HandlerOutput + >, + ) { + const nsid = "app.rocksky.feed.describeFeedGenerator"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getFeed( + cfg: MethodConfigOrHandler< + A, + AppRockskyFeedGetFeed.QueryParams, + AppRockskyFeedGetFeed.HandlerInput, + AppRockskyFeedGetFeed.HandlerOutput + >, + ) { + const nsid = "app.rocksky.feed.getFeed"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getFeedSkeleton( + cfg: MethodConfigOrHandler< + A, + AppRockskyFeedGetFeedSkeleton.QueryParams, + AppRockskyFeedGetFeedSkeleton.HandlerInput, + AppRockskyFeedGetFeedSkeleton.HandlerOutput + >, + ) { + const nsid = "app.rocksky.feed.getFeedSkeleton"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyDropboxNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + downloadFile( + cfg: MethodConfigOrHandler< + A, + AppRockskyDropboxDownloadFile.QueryParams, + AppRockskyDropboxDownloadFile.HandlerInput, + AppRockskyDropboxDownloadFile.HandlerOutput + >, + ) { + const nsid = "app.rocksky.dropbox.downloadFile"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getFiles( + cfg: MethodConfigOrHandler< + A, + AppRockskyDropboxGetFiles.QueryParams, + AppRockskyDropboxGetFiles.HandlerInput, + AppRockskyDropboxGetFiles.HandlerOutput + >, + ) { + const nsid = "app.rocksky.dropbox.getFiles"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getMetadata( + cfg: MethodConfigOrHandler< + A, + AppRockskyDropboxGetMetadata.QueryParams, + AppRockskyDropboxGetMetadata.HandlerInput, + AppRockskyDropboxGetMetadata.HandlerOutput + >, + ) { + const nsid = "app.rocksky.dropbox.getMetadata"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getTemporaryLink( + cfg: MethodConfigOrHandler< + A, + AppRockskyDropboxGetTemporaryLink.QueryParams, + AppRockskyDropboxGetTemporaryLink.HandlerInput, + AppRockskyDropboxGetTemporaryLink.HandlerOutput + >, + ) { + const nsid = "app.rocksky.dropbox.getTemporaryLink"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyGoogledriveNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getFile( + cfg: MethodConfigOrHandler< + A, + AppRockskyGoogledriveGetFile.QueryParams, + AppRockskyGoogledriveGetFile.HandlerInput, + AppRockskyGoogledriveGetFile.HandlerOutput + >, + ) { + const nsid = "app.rocksky.googledrive.getFile"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + downloadFile( + cfg: MethodConfigOrHandler< + A, + AppRockskyGoogledriveDownloadFile.QueryParams, + AppRockskyGoogledriveDownloadFile.HandlerInput, + AppRockskyGoogledriveDownloadFile.HandlerOutput + >, + ) { + const nsid = "app.rocksky.googledrive.downloadFile"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getFiles( + cfg: MethodConfigOrHandler< + A, + AppRockskyGoogledriveGetFiles.QueryParams, + AppRockskyGoogledriveGetFiles.HandlerInput, + AppRockskyGoogledriveGetFiles.HandlerOutput + >, + ) { + const nsid = "app.rocksky.googledrive.getFiles"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyAlbumNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getAlbumTracks( + cfg: MethodConfigOrHandler< + A, + AppRockskyAlbumGetAlbumTracks.QueryParams, + AppRockskyAlbumGetAlbumTracks.HandlerInput, + AppRockskyAlbumGetAlbumTracks.HandlerOutput + >, + ) { + const nsid = "app.rocksky.album.getAlbumTracks"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getAlbum( + cfg: MethodConfigOrHandler< + A, + AppRockskyAlbumGetAlbum.QueryParams, + AppRockskyAlbumGetAlbum.HandlerInput, + AppRockskyAlbumGetAlbum.HandlerOutput + >, + ) { + const nsid = "app.rocksky.album.getAlbum"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getAlbums( + cfg: MethodConfigOrHandler< + A, + AppRockskyAlbumGetAlbums.QueryParams, + AppRockskyAlbumGetAlbums.HandlerInput, + AppRockskyAlbumGetAlbums.HandlerOutput + >, + ) { + const nsid = "app.rocksky.album.getAlbums"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyActorNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getActorPlaylists( + cfg: MethodConfigOrHandler< + A, + AppRockskyActorGetActorPlaylists.QueryParams, + AppRockskyActorGetActorPlaylists.HandlerInput, + AppRockskyActorGetActorPlaylists.HandlerOutput + >, + ) { + const nsid = "app.rocksky.actor.getActorPlaylists"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getActorSongs( + cfg: MethodConfigOrHandler< + A, + AppRockskyActorGetActorSongs.QueryParams, + AppRockskyActorGetActorSongs.HandlerInput, + AppRockskyActorGetActorSongs.HandlerOutput + >, + ) { + const nsid = "app.rocksky.actor.getActorSongs"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getActorArtists( + cfg: MethodConfigOrHandler< + A, + AppRockskyActorGetActorArtists.QueryParams, + AppRockskyActorGetActorArtists.HandlerInput, + AppRockskyActorGetActorArtists.HandlerOutput + >, + ) { + const nsid = "app.rocksky.actor.getActorArtists"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getProfile( + cfg: MethodConfigOrHandler< + A, + AppRockskyActorGetProfile.QueryParams, + AppRockskyActorGetProfile.HandlerInput, + AppRockskyActorGetProfile.HandlerOutput + >, + ) { + const nsid = "app.rocksky.actor.getProfile"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getActorLovedSongs( + cfg: MethodConfigOrHandler< + A, + AppRockskyActorGetActorLovedSongs.QueryParams, + AppRockskyActorGetActorLovedSongs.HandlerInput, + AppRockskyActorGetActorLovedSongs.HandlerOutput + >, + ) { + const nsid = "app.rocksky.actor.getActorLovedSongs"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getActorAlbums( + cfg: MethodConfigOrHandler< + A, + AppRockskyActorGetActorAlbums.QueryParams, + AppRockskyActorGetActorAlbums.HandlerInput, + AppRockskyActorGetActorAlbums.HandlerOutput + >, + ) { + const nsid = "app.rocksky.actor.getActorAlbums"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getActorScrobbles( + cfg: MethodConfigOrHandler< + A, + AppRockskyActorGetActorScrobbles.QueryParams, + AppRockskyActorGetActorScrobbles.HandlerInput, + AppRockskyActorGetActorScrobbles.HandlerOutput + >, + ) { + const nsid = "app.rocksky.actor.getActorScrobbles"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyArtistNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getArtistAlbums( + cfg: MethodConfigOrHandler< + A, + AppRockskyArtistGetArtistAlbums.QueryParams, + AppRockskyArtistGetArtistAlbums.HandlerInput, + AppRockskyArtistGetArtistAlbums.HandlerOutput + >, + ) { + const nsid = "app.rocksky.artist.getArtistAlbums"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getArtistListeners( + cfg: MethodConfigOrHandler< + A, + AppRockskyArtistGetArtistListeners.QueryParams, + AppRockskyArtistGetArtistListeners.HandlerInput, + AppRockskyArtistGetArtistListeners.HandlerOutput + >, + ) { + const nsid = "app.rocksky.artist.getArtistListeners"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getArtists( + cfg: MethodConfigOrHandler< + A, + AppRockskyArtistGetArtists.QueryParams, + AppRockskyArtistGetArtists.HandlerInput, + AppRockskyArtistGetArtists.HandlerOutput + >, + ) { + const nsid = "app.rocksky.artist.getArtists"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getArtist( + cfg: MethodConfigOrHandler< + A, + AppRockskyArtistGetArtist.QueryParams, + AppRockskyArtistGetArtist.HandlerInput, + AppRockskyArtistGetArtist.HandlerOutput + >, + ) { + const nsid = "app.rocksky.artist.getArtist"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getArtistTracks( + cfg: MethodConfigOrHandler< + A, + AppRockskyArtistGetArtistTracks.QueryParams, + AppRockskyArtistGetArtistTracks.HandlerInput, + AppRockskyArtistGetArtistTracks.HandlerOutput + >, + ) { + const nsid = "app.rocksky.artist.getArtistTracks"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyStatsNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + getStats( + cfg: MethodConfigOrHandler< + A, + AppRockskyStatsGetStats.QueryParams, + AppRockskyStatsGetStats.HandlerInput, + AppRockskyStatsGetStats.HandlerOutput + >, + ) { + const nsid = "app.rocksky.stats.getStats"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppRockskyPlayerNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } + + seek( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerSeek.QueryParams, + AppRockskyPlayerSeek.HandlerInput, + AppRockskyPlayerSeek.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.seek"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getPlaybackQueue( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerGetPlaybackQueue.QueryParams, + AppRockskyPlayerGetPlaybackQueue.HandlerInput, + AppRockskyPlayerGetPlaybackQueue.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.getPlaybackQueue"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + next( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerNext.QueryParams, + AppRockskyPlayerNext.HandlerInput, + AppRockskyPlayerNext.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.next"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + playFile( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerPlayFile.QueryParams, + AppRockskyPlayerPlayFile.HandlerInput, + AppRockskyPlayerPlayFile.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.playFile"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + getCurrentlyPlaying( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerGetCurrentlyPlaying.QueryParams, + AppRockskyPlayerGetCurrentlyPlaying.HandlerInput, + AppRockskyPlayerGetCurrentlyPlaying.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.getCurrentlyPlaying"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + previous( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerPrevious.QueryParams, + AppRockskyPlayerPrevious.HandlerInput, + AppRockskyPlayerPrevious.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.previous"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + addItemsToQueue( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerAddItemsToQueue.QueryParams, + AppRockskyPlayerAddItemsToQueue.HandlerInput, + AppRockskyPlayerAddItemsToQueue.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.addItemsToQueue"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + pause( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerPause.QueryParams, + AppRockskyPlayerPause.HandlerInput, + AppRockskyPlayerPause.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.pause"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + play( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerPlay.QueryParams, + AppRockskyPlayerPlay.HandlerInput, + AppRockskyPlayerPlay.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.play"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + playDirectory( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerPlayDirectory.QueryParams, + AppRockskyPlayerPlayDirectory.HandlerInput, + AppRockskyPlayerPlayDirectory.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.playDirectory"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } + + addDirectoryToQueue( + cfg: MethodConfigOrHandler< + A, + AppRockskyPlayerAddDirectoryToQueue.QueryParams, + AppRockskyPlayerAddDirectoryToQueue.HandlerInput, + AppRockskyPlayerAddDirectoryToQueue.HandlerOutput + >, + ) { + const nsid = "app.rocksky.player.addDirectoryToQueue"; // @ts-ignore - dynamically generated + return this._server.xrpc.method(nsid, cfg); + } +} + +export class AppBskyNS { + _server: Server; + actor: AppBskyActorNS; + + constructor(server: Server) { + this._server = server; + this.actor = new AppBskyActorNS(server); + } +} + +export class AppBskyActorNS { + _server: Server; + + constructor(server: Server) { + this._server = server; + } +} diff --git a/apps/feeds/src/lex/lexicons.ts b/apps/feeds/src/lex/lexicons.ts new file mode 100644 index 00000000..6986bc9c --- /dev/null +++ b/apps/feeds/src/lex/lexicons.ts @@ -0,0 +1,5056 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { + type LexiconDoc, + Lexicons, + ValidationError, + type ValidationResult, +} from "@atp/lexicon"; +import { is$typed, maybe$typed } from "./util.ts"; + +export const schemaDict = { + "ComAtprotoRepoStrongRef": { + "lexicon": 1, + "id": "com.atproto.repo.strongRef", + "description": "A URI with a content-hash fingerprint.", + "defs": { + "main": { + "type": "object", + "required": [ + "uri", + "cid", + ], + "properties": { + "uri": { + "type": "string", + "format": "at-uri", + }, + "cid": { + "type": "string", + "format": "cid", + }, + }, + }, + }, + }, + "AppRockskyShoutGetAlbumShouts": { + "lexicon": 1, + "id": "app.rocksky.shout.getAlbumShouts", + "defs": { + "main": { + "type": "query", + "description": "Get shouts for an album", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": + "The unique identifier of the album to retrieve shouts for", + "format": "at-uri", + }, + "limit": { + "type": "integer", + "description": "The maximum number of shouts to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": + "The number of shouts to skip before starting to collect the result set", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "shouts": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyShoutDefs": { + "lexicon": 1, + "id": "app.rocksky.shout.defs", + "defs": { + "author": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the author.", + }, + "did": { + "type": "string", + "description": "The decentralized identifier (DID) of the author.", + "format": "at-identifier", + }, + "handle": { + "type": "string", + "description": "The handle of the author.", + "format": "at-identifier", + }, + "displayName": { + "type": "string", + "description": "The display name of the author.", + }, + "avatar": { + "type": "string", + "description": "The URL of the author's avatar image.", + "format": "uri", + }, + }, + }, + "shoutView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the shout.", + }, + "message": { + "type": "string", + "description": "The content of the shout.", + }, + "parent": { + "type": "string", + "description": + "The ID of the parent shout if this is a reply, otherwise null.", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the shout was created.", + "format": "datetime", + }, + "author": { + "type": "ref", + "description": "The author of the shout.", + "ref": "lex:app.rocksky.shout.defs#author", + }, + }, + }, + }, + }, + "AppRockskyShoutReportShout": { + "lexicon": 1, + "id": "app.rocksky.shout.reportShout", + "defs": { + "main": { + "type": "procedure", + "description": "Report a shout for moderation", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "shoutId", + ], + "properties": { + "shoutId": { + "type": "string", + "description": "The unique identifier of the shout to report", + }, + "reason": { + "type": "string", + "description": "The reason for reporting the shout", + "minLength": 1, + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutView", + }, + }, + }, + }, + }, + "AppRockskyShoutGetTrackShouts": { + "lexicon": 1, + "id": "app.rocksky.shout.getTrackShouts", + "defs": { + "main": { + "type": "query", + "description": "Get all shouts for a specific track", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the track to retrieve shouts for", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "shouts": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyShoutReplyShout": { + "lexicon": 1, + "id": "app.rocksky.shout.replyShout", + "defs": { + "main": { + "type": "procedure", + "description": "Reply to a shout", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "shoutId", + "message", + ], + "properties": { + "shoutId": { + "type": "string", + "description": "The unique identifier of the shout to reply to", + }, + "message": { + "type": "string", + "description": "The content of the reply", + "minLength": 1, + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutView", + }, + }, + }, + }, + }, + "AppRockskyShoutRemoveShout": { + "lexicon": 1, + "id": "app.rocksky.shout.removeShout", + "defs": { + "main": { + "type": "procedure", + "description": "Remove a shout by its ID", + "parameters": { + "type": "params", + "required": [ + "id", + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the shout to be removed", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutView", + }, + }, + }, + }, + }, + "AppRockskyShoutGetProfileShouts": { + "lexicon": 1, + "id": "app.rocksky.shout.getProfileShouts", + "defs": { + "main": { + "type": "query", + "description": "Get the shouts of an actor's profile", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + "limit": { + "type": "integer", + "description": "The maximum number of shouts to return", + "minimum": 1, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "shouts": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyShout": { + "lexicon": 1, + "id": "app.rocksky.shout", + "defs": { + "main": { + "type": "record", + "description": "A declaration of a shout.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "message", + "createdAt", + "subject", + ], + "properties": { + "message": { + "type": "string", + "description": "The message of the shout.", + "minLength": 1, + "maxLength": 1000, + }, + "createdAt": { + "type": "string", + "description": "The date when the shout was created.", + "format": "datetime", + }, + "parent": { + "type": "ref", + "ref": "lex:com.atproto.repo.strongRef", + }, + "subject": { + "type": "ref", + "ref": "lex:com.atproto.repo.strongRef", + }, + }, + }, + }, + }, + }, + "AppRockskyShoutGetArtistShouts": { + "lexicon": 1, + "id": "app.rocksky.shout.getArtistShouts", + "defs": { + "main": { + "type": "query", + "description": "Get shouts for an artist", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the artist to retrieve shouts for", + "format": "at-uri", + }, + "limit": { + "type": "integer", + "description": "The maximum number of shouts to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": + "The number of shouts to skip before starting to collect the result set", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "shouts": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyShoutGetShoutReplies": { + "lexicon": 1, + "id": "app.rocksky.shout.getShoutReplies", + "defs": { + "main": { + "type": "query", + "description": "Get replies to a shout", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the shout to retrieve replies for", + "format": "at-uri", + }, + "limit": { + "type": "integer", + "description": "The maximum number of shouts to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": + "The number of shouts to skip before starting to collect the result set", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "shouts": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyShoutCreateShout": { + "lexicon": 1, + "id": "app.rocksky.shout.createShout", + "defs": { + "main": { + "type": "procedure", + "description": "Create a new shout", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The content of the shout", + "minLength": 1, + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutView", + }, + }, + }, + }, + }, + "AppRockskyScrobbleDefs": { + "lexicon": 1, + "id": "app.rocksky.scrobble.defs", + "defs": { + "scrobbleViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the scrobble.", + }, + "user": { + "type": "string", + "description": "The handle of the user who created the scrobble.", + }, + "userDisplayName": { + "type": "string", + "description": + "The display name of the user who created the scrobble.", + }, + "userAvatar": { + "type": "string", + "description": + "The avatar URL of the user who created the scrobble.", + "format": "uri", + }, + "title": { + "type": "string", + "description": "The title of the scrobble.", + }, + "artist": { + "type": "string", + "description": "The artist of the song.", + }, + "artistUri": { + "type": "string", + "description": "The URI of the artist.", + "format": "at-uri", + }, + "album": { + "type": "string", + "description": "The album of the song.", + }, + "albumUri": { + "type": "string", + "description": "The URI of the album.", + "format": "at-uri", + }, + "cover": { + "type": "string", + "description": "The album art URL of the song.", + "format": "uri", + }, + "date": { + "type": "string", + "description": "The timestamp when the scrobble was created.", + "format": "datetime", + }, + "uri": { + "type": "string", + "description": "The URI of the scrobble.", + "format": "uri", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the scrobble data.", + }, + }, + }, + "scrobbleViewDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the scrobble.", + }, + "user": { + "type": "string", + "description": "The handle of the user who created the scrobble.", + }, + "title": { + "type": "string", + "description": "The title of the scrobble.", + }, + "artist": { + "type": "string", + "description": "The artist of the song.", + }, + "artistUri": { + "type": "string", + "description": "The URI of the artist.", + "format": "at-uri", + }, + "album": { + "type": "string", + "description": "The album of the song.", + }, + "albumUri": { + "type": "string", + "description": "The URI of the album.", + "format": "at-uri", + }, + "cover": { + "type": "string", + "description": "The album art URL of the song.", + "format": "uri", + }, + "date": { + "type": "string", + "description": "The timestamp when the scrobble was created.", + "format": "datetime", + }, + "uri": { + "type": "string", + "description": "The URI of the scrobble.", + "format": "uri", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the scrobble data.", + }, + "listeners": { + "type": "integer", + "description": "The number of listeners", + }, + "scrobbles": { + "type": "integer", + "description": "The number of scrobbles for this song", + }, + }, + }, + }, + }, + "AppRockskyScrobble": { + "lexicon": 1, + "id": "app.rocksky.scrobble", + "defs": { + "main": { + "type": "record", + "description": "A declaration of a scrobble.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "title", + "artist", + "album", + "albumArtist", + "duration", + "createdAt", + ], + "properties": { + "title": { + "type": "string", + "description": "The title of the song.", + "minLength": 1, + "maxLength": 512, + }, + "artist": { + "type": "string", + "description": "The artist of the song.", + "minLength": 1, + "maxLength": 256, + }, + "artists": { + "type": "array", + "description": "The artists of the song with MusicBrainz IDs.", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.artist.defs#artistMbid", + }, + }, + "albumArtist": { + "type": "string", + "description": "The album artist of the song.", + "minLength": 1, + "maxLength": 256, + }, + "album": { + "type": "string", + "description": "The album of the song.", + "minLength": 1, + "maxLength": 256, + }, + "duration": { + "type": "integer", + "description": "The duration of the song in seconds.", + "minimum": 1, + }, + "trackNumber": { + "type": "integer", + "description": "The track number of the song in the album.", + "minimum": 1, + }, + "discNumber": { + "type": "integer", + "description": "The disc number of the song in the album.", + "minimum": 1, + }, + "releaseDate": { + "type": "string", + "description": "The release date of the song.", + "format": "datetime", + }, + "year": { + "type": "integer", + "description": "The year the song was released.", + }, + "genre": { + "type": "string", + "description": "The genre of the song.", + "maxLength": 256, + }, + "tags": { + "type": "array", + "description": "The tags of the song.", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256, + }, + }, + "composer": { + "type": "string", + "description": "The composer of the song.", + "maxLength": 256, + }, + "lyrics": { + "type": "string", + "description": "The lyrics of the song.", + "maxLength": 10000, + }, + "copyrightMessage": { + "type": "string", + "description": "The copyright message of the song.", + "maxLength": 256, + }, + "wiki": { + "type": "string", + "description": "Informations about the song", + "maxLength": 10000, + }, + "albumArt": { + "type": "blob", + "description": "The album art of the song.", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 2000000, + }, + "albumArtUrl": { + "type": "string", + "description": "The URL of the album art of the song.", + "format": "uri", + }, + "youtubeLink": { + "type": "string", + "description": "The YouTube link of the song.", + "format": "uri", + }, + "spotifyLink": { + "type": "string", + "description": "The Spotify link of the song.", + "format": "uri", + }, + "tidalLink": { + "type": "string", + "description": "The Tidal link of the song.", + "format": "uri", + }, + "appleMusicLink": { + "type": "string", + "description": "The Apple Music link of the song.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date when the song was created.", + "format": "datetime", + }, + "mbid": { + "type": "string", + "description": "The MusicBrainz ID of the song.", + }, + "label": { + "type": "string", + "description": "The label of the song.", + "maxLength": 256, + }, + }, + }, + }, + }, + }, + "AppRockskyScrobbleCreateScrobble": { + "lexicon": 1, + "id": "app.rocksky.scrobble.createScrobble", + "defs": { + "main": { + "type": "procedure", + "description": "Create a new scrobble", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "title", + "artist", + ], + "properties": { + "title": { + "type": "string", + "description": "The title of the track being scrobbled", + }, + "artist": { + "type": "string", + "description": "The artist of the track being scrobbled", + }, + "album": { + "type": "string", + "description": "The album of the track being scrobbled", + }, + "duration": { + "type": "integer", + "description": "The duration of the track in seconds", + }, + "mbId": { + "type": "string", + "description": "The MusicBrainz ID of the track, if available", + }, + "albumArt": { + "type": "string", + "description": "The URL of the album art for the track", + "format": "uri", + }, + "trackNumber": { + "type": "integer", + "description": "The track number of the track in the album", + }, + "releaseDate": { + "type": "string", + "description": + "The release date of the track, formatted as YYYY-MM-DD", + }, + "year": { + "type": "integer", + "description": "The year the track was released", + }, + "discNumber": { + "type": "integer", + "description": + "The disc number of the track in the album, if applicable", + }, + "lyrics": { + "type": "string", + "description": "The lyrics of the track, if available", + }, + "composer": { + "type": "string", + "description": "The composer of the track, if available", + }, + "copyrightMessage": { + "type": "string", + "description": + "The copyright message for the track, if available", + }, + "label": { + "type": "string", + "description": "The record label of the track, if available", + }, + "artistPicture": { + "type": "string", + "description": "The URL of the artist's picture, if available", + "format": "uri", + }, + "spotifyLink": { + "type": "string", + "description": "The Spotify link for the track, if available", + "format": "uri", + }, + "lastfmLink": { + "type": "string", + "description": "The Last.fm link for the track, if available", + "format": "uri", + }, + "tidalLink": { + "type": "string", + "description": "The Tidal link for the track, if available", + "format": "uri", + }, + "appleMusicLink": { + "type": "string", + "description": + "The Apple Music link for the track, if available", + "format": "uri", + }, + "youtubeLink": { + "type": "string", + "description": "The Youtube link for the track, if available", + "format": "uri", + }, + "deezerLink": { + "type": "string", + "description": "The Deezer link for the track, if available", + "format": "uri", + }, + "timestamp": { + "type": "integer", + "description": + "The timestamp of the scrobble in milliseconds since epoch", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.scrobble.defs#scrobbleViewBasic", + }, + }, + }, + }, + }, + "AppRockskyScrobbleGetScrobbles": { + "lexicon": 1, + "id": "app.rocksky.scrobble.getScrobbles", + "defs": { + "main": { + "type": "query", + "description": "Get scrobbles all scrobbles", + "parameters": { + "type": "params", + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "limit": { + "type": "integer", + "description": "The maximum number of scrobbles to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "scrobbles": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.scrobble.defs#scrobbleViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyScrobbleGetScrobble": { + "lexicon": 1, + "id": "app.rocksky.scrobble.getScrobble", + "defs": { + "main": { + "type": "query", + "description": "Get a scrobble by its unique identifier", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The unique identifier of the scrobble", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.scrobble.defs#scrobbleViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyLikeDislikeShout": { + "lexicon": 1, + "id": "app.rocksky.like.dislikeShout", + "defs": { + "main": { + "type": "procedure", + "description": "Dislike a shout", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "The unique identifier of the shout to dislike", + "format": "at-uri", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutView", + }, + }, + }, + }, + }, + "AppRockskyLike": { + "lexicon": 1, + "id": "app.rocksky.like", + "defs": { + "main": { + "type": "record", + "description": "A declaration of a like.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "createdAt", + "subject", + ], + "properties": { + "createdAt": { + "type": "string", + "description": "The date when the like was created.", + "format": "datetime", + }, + "subject": { + "type": "ref", + "ref": "lex:com.atproto.repo.strongRef", + }, + }, + }, + }, + }, + }, + "AppRockskyLikeLikeSong": { + "lexicon": 1, + "id": "app.rocksky.like.likeSong", + "defs": { + "main": { + "type": "procedure", + "description": "Like a song", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "The unique identifier of the song to like", + "format": "at-uri", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyLikeDislikeSong": { + "lexicon": 1, + "id": "app.rocksky.like.dislikeSong", + "defs": { + "main": { + "type": "procedure", + "description": "Dislike a song", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "The unique identifier of the song to dislike", + "format": "at-uri", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyLikeLikeShout": { + "lexicon": 1, + "id": "app.rocksky.like.likeShout", + "defs": { + "main": { + "type": "procedure", + "description": "Like a shout", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "The unique identifier of the shout to like", + "format": "at-uri", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.shout.defs#shoutView", + }, + }, + }, + }, + }, + "AppRockskyPlaylistCreatePlaylist": { + "lexicon": 1, + "id": "app.rocksky.playlist.createPlaylist", + "defs": { + "main": { + "type": "procedure", + "description": "Create a new playlist", + "parameters": { + "type": "params", + "required": [ + "name", + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the playlist", + }, + "description": { + "type": "string", + "description": "A brief description of the playlist", + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistStartPlaylist": { + "lexicon": 1, + "id": "app.rocksky.playlist.startPlaylist", + "defs": { + "main": { + "type": "procedure", + "description": "Start a playlist", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the playlist to start", + "format": "at-uri", + }, + "shuffle": { + "type": "boolean", + "description": "Whether to shuffle the playlist when starting it", + }, + "position": { + "type": "integer", + "description": + "The position in the playlist to start from, if not specified, starts from the beginning", + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistDefs": { + "lexicon": 1, + "id": "app.rocksky.playlist.defs", + "defs": { + "playlistViewDetailed": { + "type": "object", + "description": + "Detailed view of a playlist, including its tracks and metadata", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the playlist.", + }, + "title": { + "type": "string", + "description": "The title of the playlist.", + }, + "uri": { + "type": "string", + "description": "The URI of the playlist.", + "format": "at-uri", + }, + "curatorDid": { + "type": "string", + "description": "The DID of the curator of the playlist.", + "format": "at-identifier", + }, + "curatorHandle": { + "type": "string", + "description": "The handle of the curator of the playlist.", + "format": "at-identifier", + }, + "curatorName": { + "type": "string", + "description": "The name of the curator of the playlist.", + }, + "curatorAvatarUrl": { + "type": "string", + "description": "The URL of the avatar image of the curator.", + "format": "uri", + }, + "description": { + "type": "string", + "description": "A description of the playlist.", + }, + "coverImageUrl": { + "type": "string", + "description": "The URL of the cover image for the playlist.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the playlist was created.", + "format": "datetime", + }, + "tracks": { + "type": "array", + "description": "A list of tracks in the playlist.", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewBasic", + }, + }, + }, + }, + "playlistViewBasic": { + "type": "object", + "description": "Basic view of a playlist, including its metadata", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the playlist.", + }, + "title": { + "type": "string", + "description": "The title of the playlist.", + }, + "uri": { + "type": "string", + "description": "The URI of the playlist.", + "format": "at-uri", + }, + "curatorDid": { + "type": "string", + "description": "The DID of the curator of the playlist.", + "format": "at-identifier", + }, + "curatorHandle": { + "type": "string", + "description": "The handle of the curator of the playlist.", + "format": "at-identifier", + }, + "curatorName": { + "type": "string", + "description": "The name of the curator of the playlist.", + }, + "curatorAvatarUrl": { + "type": "string", + "description": "The URL of the avatar image of the curator.", + "format": "uri", + }, + "description": { + "type": "string", + "description": "A description of the playlist.", + }, + "coverImageUrl": { + "type": "string", + "description": "The URL of the cover image for the playlist.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the playlist was created.", + "format": "datetime", + }, + "trackCount": { + "type": "integer", + "description": "The number of tracks in the playlist.", + "minimum": 0, + }, + }, + }, + }, + }, + "AppRockskyPlaylist": { + "lexicon": 1, + "id": "app.rocksky.playlist", + "defs": { + "main": { + "type": "record", + "description": "A declaration of a playlist.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "name", + "createdAt", + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the playlist.", + "minLength": 1, + "maxLength": 512, + }, + "description": { + "type": "string", + "description": "The playlist description.", + "minLength": 1, + "maxLength": 256, + }, + "picture": { + "type": "blob", + "description": "The picture of the playlist.", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 2000000, + }, + "tracks": { + "type": "array", + "description": "The tracks in the playlist.", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song#record", + }, + }, + "createdAt": { + "type": "string", + "description": "The date the playlist was created.", + "format": "datetime", + }, + "spotifyLink": { + "type": "string", + "description": "The Spotify link of the playlist.", + }, + "tidalLink": { + "type": "string", + "description": "The Tidal link of the playlist.", + }, + "youtubeLink": { + "type": "string", + "description": "The YouTube link of the playlist.", + }, + "appleMusicLink": { + "type": "string", + "description": "The Apple Music link of the playlist.", + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistGetPlaylists": { + "lexicon": 1, + "id": "app.rocksky.playlist.getPlaylists", + "defs": { + "main": { + "type": "query", + "description": "Retrieve a list of playlists", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "description": "The maximum number of playlists to return.", + }, + "offset": { + "type": "integer", + "description": + "The offset for pagination, used to skip a number of playlists.", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "playlists": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.playlist.defs#playlistViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistInsertDirectory": { + "lexicon": 1, + "id": "app.rocksky.playlist.insertDirectory", + "defs": { + "main": { + "type": "procedure", + "description": "Insert a directory into a playlist", + "parameters": { + "type": "params", + "required": [ + "uri", + "directory", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the playlist to start", + "format": "at-uri", + }, + "directory": { + "type": "string", + "description": "The directory (id) to insert into the playlist", + }, + "position": { + "type": "integer", + "description": + "The position in the playlist to insert the directory at, if not specified, the directory will be appended", + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistRemoveTrack": { + "lexicon": 1, + "id": "app.rocksky.playlist.removeTrack", + "defs": { + "main": { + "type": "procedure", + "description": "Remove a track from a playlist", + "parameters": { + "type": "params", + "required": [ + "uri", + "position", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the playlist to remove the track from", + "format": "at-uri", + }, + "position": { + "type": "integer", + "description": + "The position of the track to remove in the playlist", + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistRemovePlaylist": { + "lexicon": 1, + "id": "app.rocksky.playlist.removePlaylist", + "defs": { + "main": { + "type": "procedure", + "description": "Remove a playlist", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the playlist to remove", + "format": "at-uri", + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistInsertFiles": { + "lexicon": 1, + "id": "app.rocksky.playlist.insertFiles", + "defs": { + "main": { + "type": "procedure", + "description": "Insert files into a playlist", + "parameters": { + "type": "params", + "required": [ + "uri", + "files", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the playlist to start", + "format": "at-uri", + }, + "files": { + "type": "array", + "items": { + "type": "string", + "description": "List of file (id) to insert into the playlist", + }, + }, + "position": { + "type": "integer", + "description": + "The position in the playlist to insert the files at, if not specified, files will be appended", + }, + }, + }, + }, + }, + }, + "AppRockskyPlaylistGetPlaylist": { + "lexicon": 1, + "id": "app.rocksky.playlist.getPlaylist", + "defs": { + "main": { + "type": "query", + "description": "Retrieve a playlist by its ID", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the playlist to retrieve.", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.playlist.defs#playlistViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyRadioDefs": { + "lexicon": 1, + "id": "app.rocksky.radio.defs", + "defs": { + "radioViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the radio.", + }, + "name": { + "type": "string", + "description": "The name of the radio.", + }, + "description": { + "type": "string", + "description": "A brief description of the radio.", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the radio was created.", + "format": "datetime", + }, + }, + }, + "radioViewDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the radio.", + }, + "name": { + "type": "string", + "description": "The name of the radio.", + }, + "description": { + "type": "string", + "description": "A brief description of the radio.", + }, + "website": { + "type": "string", + "description": "The website of the radio.", + "format": "uri", + }, + "url": { + "type": "string", + "description": "The streaming URL of the radio.", + "format": "uri", + }, + "genre": { + "type": "string", + "description": "The genre of the radio.", + }, + "logo": { + "type": "string", + "description": "The logo of the radio station.", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the radio was created.", + "format": "datetime", + }, + }, + }, + }, + }, + "AppRockskyRadio": { + "lexicon": 1, + "id": "app.rocksky.radio", + "defs": { + "main": { + "type": "record", + "description": "A declaration of a radio station.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "name", + "url", + "createdAt", + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the radio station.", + "minLength": 1, + "maxLength": 512, + }, + "url": { + "type": "string", + "description": "The URL of the radio station.", + "format": "uri", + }, + "description": { + "type": "string", + "description": "A description of the radio station.", + "minLength": 1, + "maxLength": 1000, + }, + "genre": { + "type": "string", + "description": "The genre of the radio station.", + "minLength": 1, + "maxLength": 256, + }, + "logo": { + "type": "blob", + "description": "The logo of the radio station.", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 2000000, + }, + "website": { + "type": "string", + "description": "The website of the radio station.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date when the radio station was created.", + "format": "datetime", + }, + }, + }, + }, + }, + }, + "AppRockskySpotifySeek": { + "lexicon": 1, + "id": "app.rocksky.spotify.seek", + "defs": { + "main": { + "type": "procedure", + "description": + "Seek to a specific position in the currently playing track", + "parameters": { + "type": "params", + "required": [ + "position", + ], + "properties": { + "position": { + "type": "integer", + "description": "The position in seconds to seek to", + }, + }, + }, + }, + }, + }, + "AppRockskySpotifyDefs": { + "lexicon": 1, + "id": "app.rocksky.spotify.defs", + "defs": { + "spotifyTrackView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the Spotify track.", + }, + "name": { + "type": "string", + "description": "The name of the track.", + }, + "artist": { + "type": "string", + "description": "The name of the artist.", + }, + "album": { + "type": "string", + "description": "The name of the album.", + }, + "duration": { + "type": "integer", + "description": "The duration of the track in milliseconds.", + }, + "previewUrl": { + "type": "string", + "description": "A URL to a preview of the track.", + }, + }, + }, + }, + }, + "AppRockskySpotifyNext": { + "lexicon": 1, + "id": "app.rocksky.spotify.next", + "defs": { + "main": { + "type": "procedure", + "description": "Play the next track in the queue", + }, + }, + }, + "AppRockskySpotifyGetCurrentlyPlaying": { + "lexicon": 1, + "id": "app.rocksky.spotify.getCurrentlyPlaying", + "defs": { + "main": { + "type": "query", + "description": "Get the currently playing track", + "parameters": { + "type": "params", + "properties": { + "actor": { + "type": "string", + "description": + "Handle or DID of the actor to retrieve the currently playing track for. If not provided, defaults to the current user.", + "format": "at-identifier", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.player.defs#currentlyPlayingViewDetailed", + }, + }, + }, + }, + }, + "AppRockskySpotifyPrevious": { + "lexicon": 1, + "id": "app.rocksky.spotify.previous", + "defs": { + "main": { + "type": "procedure", + "description": "Play the previous track in the queue", + }, + }, + }, + "AppRockskySpotifyPause": { + "lexicon": 1, + "id": "app.rocksky.spotify.pause", + "defs": { + "main": { + "type": "procedure", + "description": "Pause the currently playing track", + }, + }, + }, + "AppRockskySpotifyPlay": { + "lexicon": 1, + "id": "app.rocksky.spotify.play", + "defs": { + "main": { + "type": "procedure", + "description": "Resume playback of the currently paused track", + }, + }, + }, + "AppRockskyChartsDefs": { + "lexicon": 1, + "id": "app.rocksky.charts.defs", + "defs": { + "chartsView": { + "type": "object", + "properties": { + "scrobbles": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.charts.defs#scrobbleViewBasic", + }, + }, + }, + }, + "scrobbleViewBasic": { + "type": "object", + "properties": { + "date": { + "type": "string", + "description": "The date of the scrobble.", + "format": "datetime", + }, + "count": { + "type": "integer", + "description": "The number of scrobbles on this date.", + }, + }, + }, + }, + }, + "AppRockskyChartsGetScrobblesChart": { + "lexicon": 1, + "id": "app.rocksky.charts.getScrobblesChart", + "defs": { + "main": { + "type": "query", + "description": "Get the scrobbles chart", + "parameters": { + "type": "params", + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "artisturi": { + "type": "string", + "description": "The URI of the artist to filter by", + "format": "at-uri", + }, + "albumuri": { + "type": "string", + "description": "The URI of the album to filter by", + "format": "at-uri", + }, + "songuri": { + "type": "string", + "description": "The URI of the track to filter by", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.charts.defs#chartsView", + }, + }, + }, + }, + }, + "AppRockskySongDefs": { + "lexicon": 1, + "id": "app.rocksky.song.defs", + "defs": { + "songViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the song.", + }, + "title": { + "type": "string", + "description": "The title of the song.", + }, + "artist": { + "type": "string", + "description": "The artist of the song.", + }, + "albumArtist": { + "type": "string", + "description": "The artist of the album the song belongs to.", + }, + "albumArt": { + "type": "string", + "description": "The URL of the album art image.", + "format": "uri", + }, + "uri": { + "type": "string", + "description": "The URI of the song.", + "format": "at-uri", + }, + "album": { + "type": "string", + "description": "The album of the song.", + }, + "duration": { + "type": "integer", + "description": "The duration of the song in milliseconds.", + }, + "trackNumber": { + "type": "integer", + "description": "The track number of the song in the album.", + }, + "discNumber": { + "type": "integer", + "description": "The disc number of the song in the album.", + }, + "playCount": { + "type": "integer", + "description": "The number of times the song has been played.", + "minimum": 0, + }, + "uniqueListeners": { + "type": "integer", + "description": + "The number of unique listeners who have played the song.", + "minimum": 0, + }, + "albumUri": { + "type": "string", + "description": "The URI of the album the song belongs to.", + "format": "at-uri", + }, + "artistUri": { + "type": "string", + "description": "The URI of the artist of the song.", + "format": "at-uri", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the song.", + }, + "createdAt": { + "type": "string", + "description": "The timestamp when the song was created.", + "format": "datetime", + }, + }, + }, + "songViewDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the song.", + }, + "title": { + "type": "string", + "description": "The title of the song.", + }, + "artist": { + "type": "string", + "description": "The artist of the song.", + }, + "albumArtist": { + "type": "string", + "description": "The artist of the album the song belongs to.", + }, + "albumArt": { + "type": "string", + "description": "The URL of the album art image.", + "format": "uri", + }, + "uri": { + "type": "string", + "description": "The URI of the song.", + "format": "at-uri", + }, + "album": { + "type": "string", + "description": "The album of the song.", + }, + "duration": { + "type": "integer", + "description": "The duration of the song in milliseconds.", + }, + "trackNumber": { + "type": "integer", + "description": "The track number of the song in the album.", + }, + "discNumber": { + "type": "integer", + "description": "The disc number of the song in the album.", + }, + "playCount": { + "type": "integer", + "description": "The number of times the song has been played.", + "minimum": 0, + }, + "uniqueListeners": { + "type": "integer", + "description": + "The number of unique listeners who have played the song.", + "minimum": 0, + }, + "albumUri": { + "type": "string", + "description": "The URI of the album the song belongs to.", + "format": "at-uri", + }, + "artistUri": { + "type": "string", + "description": "The URI of the artist of the song.", + "format": "at-uri", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the song.", + }, + "createdAt": { + "type": "string", + "description": "The timestamp when the song was created.", + "format": "datetime", + }, + }, + }, + }, + }, + "AppRockskySongGetSongs": { + "lexicon": 1, + "id": "app.rocksky.song.getSongs", + "defs": { + "main": { + "type": "query", + "description": "Get songs", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "description": "The maximum number of songs to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "songs": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskySongGetSong": { + "lexicon": 1, + "id": "app.rocksky.song.getSong", + "defs": { + "main": { + "type": "query", + "description": "Get a song by its uri", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The unique identifier of the song to retrieve", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewDetailed", + }, + }, + }, + }, + }, + "AppRockskySong": { + "lexicon": 1, + "id": "app.rocksky.song", + "defs": { + "main": { + "type": "record", + "description": "A declaration of a song.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "title", + "artist", + "album", + "albumArtist", + "duration", + "createdAt", + ], + "properties": { + "title": { + "type": "string", + "description": "The title of the song.", + "minLength": 1, + "maxLength": 512, + }, + "artist": { + "type": "string", + "description": "The artist of the song.", + "minLength": 1, + "maxLength": 256, + }, + "artists": { + "type": "array", + "description": "The artists of the song with MusicBrainz IDs.", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.artist.defs#artistMbid", + }, + }, + "albumArtist": { + "type": "string", + "description": "The album artist of the song.", + "minLength": 1, + "maxLength": 256, + }, + "album": { + "type": "string", + "description": "The album of the song.", + "minLength": 1, + "maxLength": 256, + }, + "duration": { + "type": "integer", + "description": "The duration of the song in seconds.", + "minimum": 1, + }, + "trackNumber": { + "type": "integer", + "description": "The track number of the song in the album.", + "minimum": 1, + }, + "discNumber": { + "type": "integer", + "description": "The disc number of the song in the album.", + "minimum": 1, + }, + "releaseDate": { + "type": "string", + "description": "The release date of the song.", + "format": "datetime", + }, + "year": { + "type": "integer", + "description": "The year the song was released.", + }, + "genre": { + "type": "string", + "description": "The genre of the song.", + "minLength": 1, + "maxLength": 256, + }, + "tags": { + "type": "array", + "description": "The tags of the song.", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256, + }, + }, + "composer": { + "type": "string", + "description": "The composer of the song.", + "maxLength": 256, + }, + "lyrics": { + "type": "string", + "description": "The lyrics of the song.", + "maxLength": 10000, + }, + "copyrightMessage": { + "type": "string", + "description": "The copyright message of the song.", + "maxLength": 256, + }, + "wiki": { + "type": "string", + "description": "Informations about the song", + "maxLength": 10000, + }, + "albumArt": { + "type": "blob", + "description": "The album art of the song.", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 2000000, + }, + "albumArtUrl": { + "type": "string", + "description": "The URL of the album art of the song.", + "format": "uri", + }, + "youtubeLink": { + "type": "string", + "description": "The YouTube link of the song.", + "format": "uri", + }, + "spotifyLink": { + "type": "string", + "description": "The Spotify link of the song.", + "format": "uri", + }, + "tidalLink": { + "type": "string", + "description": "The Tidal link of the song.", + "format": "uri", + }, + "appleMusicLink": { + "type": "string", + "description": "The Apple Music link of the song.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date when the song was created.", + "format": "datetime", + }, + "mbid": { + "type": "string", + "description": "The MusicBrainz ID of the song.", + }, + "label": { + "type": "string", + "description": "The label of the song.", + "maxLength": 256, + }, + }, + }, + }, + }, + }, + "AppRockskySongCreateSong": { + "lexicon": 1, + "id": "app.rocksky.song.createSong", + "defs": { + "main": { + "type": "procedure", + "description": "Create a new song", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "title", + "artist", + "album", + "albumArtist", + ], + "properties": { + "title": { + "type": "string", + "description": "The title of the song", + }, + "artist": { + "type": "string", + "description": "The artist of the song", + }, + "albumArtist": { + "type": "string", + "description": + "The album artist of the song, if different from the main artist", + }, + "album": { + "type": "string", + "description": "The album of the song, if applicable", + }, + "duration": { + "type": "integer", + "description": "The duration of the song in seconds", + }, + "mbId": { + "type": "string", + "description": "The MusicBrainz ID of the song, if available", + }, + "albumArt": { + "type": "string", + "description": "The URL of the album art for the song", + "format": "uri", + }, + "trackNumber": { + "type": "integer", + "description": + "The track number of the song in the album, if applicable", + }, + "releaseDate": { + "type": "string", + "description": + "The release date of the song, formatted as YYYY-MM-DD", + }, + "year": { + "type": "integer", + "description": "The year the song was released", + }, + "discNumber": { + "type": "integer", + "description": + "The disc number of the song in the album, if applicable", + }, + "lyrics": { + "type": "string", + "description": "The lyrics of the song, if available", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyApikeysDefs": { + "lexicon": 1, + "id": "app.rocksky.apikeys.defs", + "defs": {}, + }, + "AppRockskyApikeyGetApikeys": { + "lexicon": 1, + "id": "app.rocksky.apikey.getApikeys", + "defs": { + "main": { + "type": "query", + "description": "Get a list of API keys for the authenticated user", + "parameters": { + "type": "params", + "properties": { + "offset": { + "type": "integer", + "description": + "The number of API keys to skip before starting to collect the result set.", + }, + "limit": { + "type": "integer", + "description": "The number of API keys to return per page.", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.apikey.defs#apikeyView", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyApikeyUpdateApikey": { + "lexicon": 1, + "id": "app.rocksky.apikey.updateApikey", + "defs": { + "main": { + "type": "procedure", + "description": "Update an existing API key for the authenticated user", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "id", + "name", + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the API key to update.", + }, + "name": { + "type": "string", + "description": "The new name of the API key.", + }, + "description": { + "type": "string", + "description": "A new description for the API key.", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.apikey.defs#apiKey", + }, + }, + }, + }, + }, + "AppRockskyApikeyCreateApikey": { + "lexicon": 1, + "id": "app.rocksky.apikey.createApikey", + "defs": { + "main": { + "type": "procedure", + "description": "Create a new API key for the authenticated user", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "name", + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the API key.", + }, + "description": { + "type": "string", + "description": "A description for the API key.", + }, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.apikey.defs#apiKey", + }, + }, + }, + }, + }, + "AppRockskyApikeyRemoveApikey": { + "lexicon": 1, + "id": "app.rocksky.apikey.removeApikey", + "defs": { + "main": { + "type": "procedure", + "description": "Remove an API key for the authenticated user", + "parameters": { + "type": "params", + "required": [ + "id", + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the API key to remove.", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.apikey.defs#apiKey", + }, + }, + }, + }, + }, + "AppRockskyApikeyDefs": { + "lexicon": 1, + "id": "app.rocksky.apikey.defs", + "defs": { + "apiKeyView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the API key.", + }, + "name": { + "type": "string", + "description": "The name of the API key.", + }, + "description": { + "type": "string", + "description": "A description for the API key.", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the API key was created.", + "format": "datetime", + }, + }, + }, + }, + }, + "AppRockskyFeedGenerator": { + "lexicon": 1, + "id": "app.rocksky.feed.generator", + "defs": { + "main": { + "type": "record", + "description": + "Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "did", + "displayName", + "createdAt", + ], + "properties": { + "did": { + "type": "string", + "format": "did", + }, + "avatar": { + "type": "blob", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 1000000, + }, + "displayName": { + "type": "string", + "maxGraphemes": 24, + "maxLength": 240, + }, + "description": { + "type": "string", + "maxGraphemes": 300, + "maxLength": 3000, + }, + "createdAt": { + "type": "string", + "format": "datetime", + }, + }, + }, + }, + }, + }, + "AppRockskyFeedDefs": { + "lexicon": 1, + "id": "app.rocksky.feed.defs", + "defs": { + "searchResultsView": { + "type": "object", + "properties": { + "hits": { + "type": "array", + "items": { + "type": "union", + "refs": [ + "lex:app.rocksky.song.defs#songViewBasic", + "lex:app.rocksky.album.defs#albumViewBasic", + "lex:app.rocksky.artist.defs#artistViewBasic", + "lex:app.rocksky.playlist.defs#playlistViewBasic", + "lex:app.rocksky.actor.defs#profileViewBasic", + ], + }, + }, + "processingTimeMs": { + "type": "integer", + }, + "limit": { + "type": "integer", + }, + "offset": { + "type": "integer", + }, + "estimatedTotalHits": { + "type": "integer", + }, + }, + }, + "nowPlayingView": { + "type": "object", + "properties": { + "album": { + "type": "string", + }, + "albumArt": { + "type": "string", + "format": "uri", + }, + "albumArtist": { + "type": "string", + }, + "albumUri": { + "type": "string", + "format": "at-uri", + }, + "artist": { + "type": "string", + }, + "artistUri": { + "type": "string", + "format": "at-uri", + }, + "avatar": { + "type": "string", + "format": "uri", + }, + "createdAt": { + "type": "string", + }, + "did": { + "type": "string", + "format": "at-identifier", + }, + "handle": { + "type": "string", + }, + "id": { + "type": "string", + }, + "title": { + "type": "string", + }, + "trackId": { + "type": "string", + }, + "trackUri": { + "type": "string", + "format": "at-uri", + }, + "uri": { + "type": "string", + "format": "at-uri", + }, + }, + }, + "nowPlayingsView": { + "type": "object", + "properties": { + "nowPlayings": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.feed.defs#nowPlayingView", + }, + }, + }, + }, + "feedGeneratorsView": { + "type": "object", + "properties": { + "feeds": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.feed.defs#feedGeneratorView", + }, + }, + }, + }, + "feedGeneratorView": { + "type": "object", + "properties": { + "id": { + "type": "string", + }, + "name": { + "type": "string", + }, + "description": { + "type": "string", + }, + "uri": { + "type": "string", + "format": "at-uri", + }, + "avatar": { + "type": "string", + "format": "uri", + }, + "creator": { + "type": "ref", + "ref": "lex:app.rocksky.actor.defs#profileViewBasic", + }, + }, + }, + "feedUriView": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "The feed URI.", + "format": "at-uri", + }, + }, + }, + }, + }, + "AppRockskyFeedGetFeedGenerators": { + "lexicon": 1, + "id": "app.rocksky.feed.getFeedGenerators", + "defs": { + "main": { + "type": "query", + "description": "Get all feed generators", + "parameters": { + "type": "params", + "properties": { + "size": { + "type": "integer", + "description": "The maximum number of feed generators to return.", + "minimum": 1, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.feed.defs#feedGeneratorsView", + }, + }, + }, + }, + }, + "AppRockskyFeedGetFeedGenerator": { + "lexicon": 1, + "id": "app.rocksky.feed.getFeedGenerator", + "defs": { + "main": { + "type": "query", + "description": "Get information about a feed generator", + "parameters": { + "type": "params", + "required": [ + "feed", + ], + "properties": { + "feed": { + "type": "string", + "description": "AT-URI of the feed generator record.", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "view": { + "type": "ref", + "ref": "lex:app.rocksky.feed.defs#feedGeneratorView", + }, + }, + }, + }, + }, + }, + }, + "AppRockskyFeedSearch": { + "lexicon": 1, + "id": "app.rocksky.feed.search", + "defs": { + "main": { + "type": "query", + "description": "Search for content in the feed", + "parameters": { + "type": "params", + "required": [ + "query", + ], + "properties": { + "query": { + "type": "string", + "description": "The search query string", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.feed.defs#searchResultsView", + }, + }, + }, + }, + }, + "AppRockskyFeedGetNowPlayings": { + "lexicon": 1, + "id": "app.rocksky.feed.getNowPlayings", + "defs": { + "main": { + "type": "query", + "description": "Get all currently playing tracks by users", + "parameters": { + "type": "params", + "properties": { + "size": { + "type": "integer", + "description": + "The maximum number of now playing tracks to return.", + "minimum": 1, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.feed.defs#nowPlayingsView", + }, + }, + }, + }, + }, + "AppRockskyFeedDescribeFeedGenerator": { + "lexicon": 1, + "id": "app.rocksky.feed.describeFeedGenerator", + "defs": { + "main": { + "type": "query", + "description": "Get information about a feed generator", + "parameters": { + "type": "params", + "properties": {}, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "The DID of the feed generator.", + "format": "at-identifier", + }, + "feeds": { + "type": "array", + "description": + "List of feed URIs generated by this feed generator.", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.feed.defs#feedUriView", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyFeedGetFeed": { + "lexicon": 1, + "id": "app.rocksky.feed.getFeed", + "defs": { + "main": { + "type": "query", + "description": "Get the feed by uri", + "parameters": { + "type": "params", + "required": [ + "feed", + ], + "properties": { + "feed": { + "type": "string", + "description": "The feed URI.", + "format": "at-uri", + }, + "limit": { + "type": "integer", + "description": "The maximum number of scrobbles to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "scrobbles": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.scrobble.defs#scrobbleViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyFeedGetFeedSkeleton": { + "lexicon": 1, + "id": "app.rocksky.feed.getFeedSkeleton", + "defs": { + "main": { + "type": "query", + "description": "Get the feed by uri", + "parameters": { + "type": "params", + "required": [ + "feed", + ], + "properties": { + "feed": { + "type": "string", + "description": "The feed URI.", + "format": "at-uri", + }, + "limit": { + "type": "integer", + "description": "The maximum number of scrobbles to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + "cursor": { + "type": "string", + "description": "The pagination cursor.", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "scrobbles": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.scrobble.defs#scrobbleViewBasic", + }, + }, + "cursor": { + "type": "string", + "description": + "The pagination cursor for the next set of results.", + }, + }, + }, + }, + }, + }, + }, + "AppRockskyDropboxDefs": { + "lexicon": 1, + "id": "app.rocksky.dropbox.defs", + "defs": { + "fileView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the file.", + }, + "name": { + "type": "string", + "description": "The name of the file.", + }, + "pathLower": { + "type": "string", + "description": "The lowercased path of the file.", + }, + "pathDisplay": { + "type": "string", + "description": "The display path of the file.", + }, + "clientModified": { + "type": "string", + "description": + "The last modified date and time of the file on the client.", + "format": "datetime", + }, + "serverModified": { + "type": "string", + "description": + "The last modified date and time of the file on the server.", + "format": "datetime", + }, + }, + }, + "fileListView": { + "type": "object", + "properties": { + "files": { + "type": "array", + "description": "A list of files in the Dropbox.", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.dropbox.defs#fileView", + }, + }, + }, + }, + "temporaryLinkView": { + "type": "object", + "properties": { + "link": { + "type": "string", + "description": "The temporary link to access the file.", + "format": "uri", + }, + }, + }, + }, + }, + "AppRockskyDropboxDownloadFile": { + "lexicon": 1, + "id": "app.rocksky.dropbox.downloadFile", + "defs": { + "main": { + "type": "query", + "description": "Download a file from Dropbox by its unique identifier", + "parameters": { + "type": "params", + "required": [ + "fileId", + ], + "properties": { + "fileId": { + "type": "string", + "description": "The unique identifier of the file to download", + }, + }, + }, + "output": { + "encoding": "application/octet-stream", + }, + }, + }, + }, + "AppRockskyDropboxGetFiles": { + "lexicon": 1, + "id": "app.rocksky.dropbox.getFiles", + "defs": { + "main": { + "type": "query", + "description": "Retrieve a list of files from Dropbox", + "parameters": { + "type": "params", + "properties": { + "at": { + "type": "string", + "description": "Path to the Dropbox folder or root directory", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.dropbox.defs#fileListView", + }, + }, + }, + }, + }, + "AppRockskyDropboxGetMetadata": { + "lexicon": 1, + "id": "app.rocksky.dropbox.getMetadata", + "defs": { + "main": { + "type": "query", + "description": "Retrieve metadata of a file or folder in Dropbox", + "parameters": { + "type": "params", + "required": [ + "path", + ], + "properties": { + "path": { + "type": "string", + "description": "Path to the file or folder in Dropbox", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.dropbox.defs#fileView", + }, + }, + }, + }, + }, + "AppRockskyDropboxGetTemporaryLink": { + "lexicon": 1, + "id": "app.rocksky.dropbox.getTemporaryLink", + "defs": { + "main": { + "type": "query", + "description": "Retrieve a temporary link to access a file in Dropbox", + "parameters": { + "type": "params", + "required": [ + "path", + ], + "properties": { + "path": { + "type": "string", + "description": "Path to the file in Dropbox", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.dropbox.defs#temporaryLinkView", + }, + }, + }, + }, + }, + "AppRockskyGoogledriveGetFile": { + "lexicon": 1, + "id": "app.rocksky.googledrive.getFile", + "defs": { + "main": { + "type": "query", + "description": "Get a file from Google Drive by its unique identifier", + "parameters": { + "type": "params", + "required": [ + "fileId", + ], + "properties": { + "fileId": { + "type": "string", + "description": "The unique identifier of the file to retrieve", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.googledrive.defs#fileView", + }, + }, + }, + }, + }, + "AppRockskyGoogledriveDefs": { + "lexicon": 1, + "id": "app.rocksky.googledrive.defs", + "defs": { + "fileView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the file.", + }, + }, + }, + "fileListView": { + "type": "object", + "properties": { + "files": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.googledrive.defs#fileView", + }, + }, + }, + }, + }, + }, + "AppRockskyGoogledriveDownloadFile": { + "lexicon": 1, + "id": "app.rocksky.googledrive.downloadFile", + "defs": { + "main": { + "type": "query", + "description": + "Download a file from Google Drive by its unique identifier", + "parameters": { + "type": "params", + "required": [ + "fileId", + ], + "properties": { + "fileId": { + "type": "string", + "description": "The unique identifier of the file to download", + }, + }, + }, + "output": { + "encoding": "application/octet-stream", + }, + }, + }, + }, + "AppRockskyGoogledriveGetFiles": { + "lexicon": 1, + "id": "app.rocksky.googledrive.getFiles", + "defs": { + "main": { + "type": "query", + "description": "Get a list of files from Google Drive", + "parameters": { + "type": "params", + "properties": { + "at": { + "type": "string", + "description": + "Path to the Google Drive folder or root directory", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.googledrive.defs#fileListView", + }, + }, + }, + }, + }, + "AppRockskyAlbumGetAlbumTracks": { + "lexicon": 1, + "id": "app.rocksky.album.getAlbumTracks", + "defs": { + "main": { + "type": "query", + "description": "Get tracks for an album", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the album to retrieve tracks from", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "tracks": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyAlbumDefs": { + "lexicon": 1, + "id": "app.rocksky.album.defs", + "defs": { + "albumViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the album.", + }, + "uri": { + "type": "string", + "description": "The URI of the album.", + "format": "at-uri", + }, + "title": { + "type": "string", + "description": "The title of the album.", + }, + "artist": { + "type": "string", + "description": "The artist of the album.", + }, + "artistUri": { + "type": "string", + "description": "The URI of the album's artist.", + "format": "at-uri", + }, + "year": { + "type": "integer", + "description": "The year the album was released.", + }, + "albumArt": { + "type": "string", + "description": "The URL of the album art image.", + "format": "uri", + }, + "releaseDate": { + "type": "string", + "description": "The release date of the album.", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the album.", + }, + "playCount": { + "type": "integer", + "description": "The number of times the album has been played.", + "minimum": 0, + }, + "uniqueListeners": { + "type": "integer", + "description": + "The number of unique listeners who have played the album.", + "minimum": 0, + }, + }, + }, + "albumViewDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the album.", + }, + "uri": { + "type": "string", + "description": "The URI of the album.", + "format": "at-uri", + }, + "title": { + "type": "string", + "description": "The title of the album.", + }, + "artist": { + "type": "string", + "description": "The artist of the album.", + }, + "artistUri": { + "type": "string", + "description": "The URI of the album's artist.", + "format": "at-uri", + }, + "year": { + "type": "integer", + "description": "The year the album was released.", + }, + "albumArt": { + "type": "string", + "description": "The URL of the album art image.", + "format": "uri", + }, + "releaseDate": { + "type": "string", + "description": "The release date of the album.", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the album.", + }, + "playCount": { + "type": "integer", + "description": "The number of times the album has been played.", + "minimum": 0, + }, + "uniqueListeners": { + "type": "integer", + "description": + "The number of unique listeners who have played the album.", + "minimum": 0, + }, + "tracks": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs.songViewBasic", + }, + }, + }, + }, + }, + }, + "AppRockskyAlbumGetAlbum": { + "lexicon": 1, + "id": "app.rocksky.album.getAlbum", + "defs": { + "main": { + "type": "query", + "description": "Get detailed album view", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the album to retrieve.", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.album.defs#albumViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyAlbum": { + "lexicon": 1, + "id": "app.rocksky.album", + "defs": { + "main": { + "type": "record", + "description": "A declaration of an album.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "title", + "artist", + "createdAt", + ], + "properties": { + "title": { + "type": "string", + "description": "The title of the album.", + "minLength": 1, + "maxLength": 512, + }, + "artist": { + "type": "string", + "description": "The artist of the album.", + "minLength": 1, + "maxLength": 256, + }, + "duration": { + "type": "integer", + "description": "The duration of the album in seconds.", + }, + "releaseDate": { + "type": "string", + "description": "The release date of the album.", + "format": "datetime", + }, + "year": { + "type": "integer", + "description": "The year the album was released.", + }, + "genre": { + "type": "string", + "description": "The genre of the album.", + "maxLength": 256, + }, + "albumArt": { + "type": "blob", + "description": "The album art of the album.", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 2000000, + }, + "albumArtUrl": { + "type": "string", + "description": "The URL of the album art of the album.", + "format": "uri", + }, + "tags": { + "type": "array", + "description": "The tags of the album.", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256, + }, + }, + "youtubeLink": { + "type": "string", + "description": "The YouTube link of the album.", + "format": "uri", + }, + "spotifyLink": { + "type": "string", + "description": "The Spotify link of the album.", + "format": "uri", + }, + "tidalLink": { + "type": "string", + "description": "The tidal link of the album.", + "format": "uri", + }, + "appleMusicLink": { + "type": "string", + "description": "The Apple Music link of the album.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the album was created.", + "format": "datetime", + }, + }, + }, + }, + }, + }, + "AppRockskyAlbumGetAlbums": { + "lexicon": 1, + "id": "app.rocksky.album.getAlbums", + "defs": { + "main": { + "type": "query", + "description": "Get albums", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "description": "The maximum number of albums to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "albums": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.album.defs#albumViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyActorGetActorPlaylists": { + "lexicon": 1, + "id": "app.rocksky.actor.getActorPlaylists", + "defs": { + "main": { + "type": "query", + "description": "Get playlists for an actor", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "limit": { + "type": "integer", + "description": "The maximum number of albums to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "playlists": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.playlist.defs#playlistViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyActorGetActorSongs": { + "lexicon": 1, + "id": "app.rocksky.actor.getActorSongs", + "defs": { + "main": { + "type": "query", + "description": "Get songs for an actor", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "limit": { + "type": "integer", + "description": "The maximum number of albums to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "songs": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyActorGetActorArtists": { + "lexicon": 1, + "id": "app.rocksky.actor.getActorArtists", + "defs": { + "main": { + "type": "query", + "description": "Get artists for an actor", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "limit": { + "type": "integer", + "description": "The maximum number of albums to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "artists": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.artist.defs#artistViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyActorDefs": { + "lexicon": 1, + "id": "app.rocksky.actor.defs", + "defs": { + "profileViewDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the actor.", + }, + "did": { + "type": "string", + "description": "The DID of the actor.", + }, + "handle": { + "type": "string", + "description": "The handle of the actor.", + }, + "displayName": { + "type": "string", + "description": "The display name of the actor.", + }, + "avatar": { + "type": "string", + "description": "The URL of the actor's avatar image.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the actor was created.", + "format": "datetime", + }, + "updatedAt": { + "type": "string", + "description": "The date and time when the actor was last updated.", + "format": "datetime", + }, + }, + }, + "profileViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the actor.", + }, + "did": { + "type": "string", + "description": "The DID of the actor.", + }, + "handle": { + "type": "string", + "description": "The handle of the actor.", + }, + "displayName": { + "type": "string", + "description": "The display name of the actor.", + }, + "avatar": { + "type": "string", + "description": "The URL of the actor's avatar image.", + "format": "uri", + }, + "createdAt": { + "type": "string", + "description": "The date and time when the actor was created.", + "format": "datetime", + }, + "updatedAt": { + "type": "string", + "description": "The date and time when the actor was last updated.", + "format": "datetime", + }, + }, + }, + }, + }, + "AppRockskyActorGetProfile": { + "lexicon": 1, + "id": "app.rocksky.actor.getProfile", + "defs": { + "main": { + "type": "query", + "description": "Get the profile of an actor", + "parameters": { + "type": "params", + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.actor.defs#profileViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyActorGetActorLovedSongs": { + "lexicon": 1, + "id": "app.rocksky.actor.getActorLovedSongs", + "defs": { + "main": { + "type": "query", + "description": "Get loved songs for an actor", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "limit": { + "type": "integer", + "description": "The maximum number of albums to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "tracks": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyActorGetActorAlbums": { + "lexicon": 1, + "id": "app.rocksky.actor.getActorAlbums", + "defs": { + "main": { + "type": "query", + "description": "Get albums for an actor", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "limit": { + "type": "integer", + "description": "The maximum number of albums to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "albums": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.album.defs#albumViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyActorGetActorScrobbles": { + "lexicon": 1, + "id": "app.rocksky.actor.getActorScrobbles", + "defs": { + "main": { + "type": "query", + "description": "Get scrobbles for an actor", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier", + }, + "limit": { + "type": "integer", + "description": "The maximum number of albums to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "scrobbles": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.scrobble.defs#scrobbleViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppBskyActorProfile": { + "lexicon": 1, + "id": "app.bsky.actor.profile", + "defs": { + "main": { + "type": "record", + "description": "A declaration of a Bluesky account profile.", + "key": "literal:self", + "record": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "maxGraphemes": 64, + "maxLength": 640, + }, + "description": { + "type": "string", + "description": "Free-form profile description text.", + "maxGraphemes": 256, + "maxLength": 2560, + }, + "avatar": { + "type": "blob", + "description": + "Small image to be displayed next to posts from account. AKA, 'profile picture'", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 1000000, + }, + "banner": { + "type": "blob", + "description": + "Larger horizontal image to display behind profile view.", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 10000000, + }, + "labels": { + "type": "union", + "description": + "Self-label values, specific to the Bluesky application, on the overall account.", + "refs": [ + "lex:com.atproto.label.defs#selfLabels", + ], + }, + "joinedViaStarterPack": { + "type": "ref", + "ref": "lex:com.atproto.repo.strongRef", + }, + "createdAt": { + "type": "string", + "format": "datetime", + }, + }, + }, + }, + }, + }, + "AppRockskyArtistDefs": { + "lexicon": 1, + "id": "app.rocksky.artist.defs", + "defs": { + "artistViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the artist.", + }, + "uri": { + "type": "string", + "description": "The URI of the artist.", + "format": "at-uri", + }, + "name": { + "type": "string", + "description": "The name of the artist.", + }, + "picture": { + "type": "string", + "description": "The picture of the artist.", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the artist.", + }, + "playCount": { + "type": "integer", + "description": "The number of times the artist has been played.", + "minimum": 0, + }, + "uniqueListeners": { + "type": "integer", + "description": + "The number of unique listeners who have played the artist.", + "minimum": 0, + }, + }, + }, + "artistViewDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the artist.", + }, + "uri": { + "type": "string", + "description": "The URI of the artist.", + "format": "at-uri", + }, + "name": { + "type": "string", + "description": "The name of the artist.", + }, + "picture": { + "type": "string", + "description": "The picture of the artist.", + }, + "sha256": { + "type": "string", + "description": "The SHA256 hash of the artist.", + }, + "playCount": { + "type": "integer", + "description": "The number of times the artist has been played.", + "minimum": 0, + }, + "uniqueListeners": { + "type": "integer", + "description": + "The number of unique listeners who have played the artist.", + "minimum": 0, + }, + }, + }, + "songViewBasic": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "The URI of the song.", + "format": "at-uri", + }, + "title": { + "type": "string", + "description": "The title of the song.", + }, + "playCount": { + "type": "integer", + "description": "The number of times the song has been played.", + "minimum": 0, + }, + }, + }, + "listenerViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the actor.", + }, + "did": { + "type": "string", + "description": "The DID of the listener.", + }, + "handle": { + "type": "string", + "description": "The handle of the listener.", + }, + "displayName": { + "type": "string", + "description": "The display name of the listener.", + }, + "avatar": { + "type": "string", + "description": "The URL of the listener's avatar image.", + "format": "uri", + }, + "mostListenedSong": { + "type": "ref", + "ref": "lex:app.rocksky.artist.defs#songViewBasic", + }, + "totalPlays": { + "type": "integer", + "description": "The total number of plays by the listener.", + "minimum": 0, + }, + "rank": { + "type": "integer", + "description": + "The rank of the listener among all listeners of the artist.", + "minimum": 1, + }, + }, + }, + "artistMbid": { + "type": "object", + "properties": { + "mbid": { + "type": "string", + "description": "The MusicBrainz Identifier (MBID) of the artist.", + }, + "name": { + "type": "string", + "description": "The name of the artist.", + "minLength": 1, + "maxLength": 256, + }, + }, + }, + }, + }, + "AppRockskyArtist": { + "lexicon": 1, + "id": "app.rocksky.artist", + "defs": { + "main": { + "type": "record", + "description": "A declaration of an artist.", + "key": "tid", + "record": { + "type": "object", + "required": [ + "name", + "createdAt", + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the artist.", + "minLength": 1, + "maxLength": 512, + }, + "bio": { + "type": "string", + "description": "The biography of the artist.", + "maxLength": 1000, + }, + "picture": { + "type": "blob", + "description": "The picture of the artist.", + "accept": [ + "image/png", + "image/jpeg", + ], + "maxSize": 2000000, + }, + "pictureUrl": { + "type": "string", + "description": "The URL of the picture of the artist.", + "format": "uri", + }, + "tags": { + "type": "array", + "description": "The tags of the artist.", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256, + }, + }, + "born": { + "type": "string", + "description": "The birth date of the artist.", + "format": "datetime", + }, + "died": { + "type": "string", + "description": "The death date of the artist.", + "format": "datetime", + }, + "bornIn": { + "type": "string", + "description": "The birth place of the artist.", + "maxLength": 256, + }, + "createdAt": { + "type": "string", + "description": "The date when the artist was created.", + "format": "datetime", + }, + }, + }, + }, + }, + }, + "AppRockskyArtistGetArtistAlbums": { + "lexicon": 1, + "id": "app.rocksky.artist.getArtistAlbums", + "defs": { + "main": { + "type": "query", + "description": "Get artist's albums", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the artist to retrieve albums from", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "albums": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.album.defs#albumViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyArtistGetArtistListeners": { + "lexicon": 1, + "id": "app.rocksky.artist.getArtistListeners", + "defs": { + "main": { + "type": "query", + "description": "Get artist listeners", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the artist to retrieve listeners from", + "format": "at-uri", + }, + "offset": { + "type": "integer", + "description": "Number of items to skip before returning results", + }, + "limit": { + "type": "integer", + "description": "Maximum number of results to return", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "listeners": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.artist.defs#listenerViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyArtistGetArtists": { + "lexicon": 1, + "id": "app.rocksky.artist.getArtists", + "defs": { + "main": { + "type": "query", + "description": "Get artists", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "description": "The maximum number of artists to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + "names": { + "type": "string", + "description": "The names of the artists to return", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "artists": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.artist.defs#artistViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyArtistGetArtist": { + "lexicon": 1, + "id": "app.rocksky.artist.getArtist", + "defs": { + "main": { + "type": "query", + "description": "Get artist details", + "parameters": { + "type": "params", + "required": [ + "uri", + ], + "properties": { + "uri": { + "type": "string", + "description": "The URI of the artist to retrieve details from", + "format": "at-uri", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.artist.defs#artistViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyArtistGetArtistTracks": { + "lexicon": 1, + "id": "app.rocksky.artist.getArtistTracks", + "defs": { + "main": { + "type": "query", + "description": "Get artist's tracks", + "parameters": { + "type": "params", + "properties": { + "uri": { + "type": "string", + "description": "The URI of the artist to retrieve albums from", + "format": "at-uri", + }, + "limit": { + "type": "integer", + "description": "The maximum number of tracks to return", + "minimum": 1, + }, + "offset": { + "type": "integer", + "description": "The offset for pagination", + "minimum": 0, + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "tracks": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs#songViewBasic", + }, + }, + }, + }, + }, + }, + }, + }, + "AppRockskyStatsDefs": { + "lexicon": 1, + "id": "app.rocksky.stats.defs", + "defs": { + "statsView": { + "type": "object", + "properties": { + "scrobbles": { + "type": "integer", + "description": "The total number of scrobbles.", + }, + "artists": { + "type": "integer", + "description": "The total number of unique artists scrobbled.", + }, + "lovedTracks": { + "type": "integer", + "description": "The total number of tracks marked as loved.", + }, + "albums": { + "type": "integer", + "description": "The total number of unique albums scrobbled.", + }, + "tracks": { + "type": "integer", + "description": "The total number of unique tracks scrobbled.", + }, + }, + }, + }, + }, + "AppRockskyStatsGetStats": { + "lexicon": 1, + "id": "app.rocksky.stats.getStats", + "defs": { + "main": { + "type": "query", + "parameters": { + "type": "params", + "required": [ + "did", + ], + "properties": { + "did": { + "type": "string", + "description": "The DID or handle of the user to get stats for.", + "format": "at-identifier", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.stats.defs#statsView", + }, + }, + }, + }, + }, + "AppRockskyPlayerSeek": { + "lexicon": 1, + "id": "app.rocksky.player.seek", + "defs": { + "main": { + "type": "procedure", + "description": + "Seek to a specific position in the currently playing track", + "parameters": { + "type": "params", + "required": [ + "position", + ], + "properties": { + "playerId": { + "type": "string", + }, + "position": { + "type": "integer", + "description": "The position in seconds to seek to", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerDefs": { + "lexicon": 1, + "id": "app.rocksky.player.defs", + "defs": { + "currentlyPlayingViewDetailed": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the currently playing track", + }, + }, + }, + "playbackQueueViewDetailed": { + "type": "object", + "properties": { + "tracks": { + "type": "array", + "items": { + "type": "ref", + "ref": "lex:app.rocksky.song.defs.songViewBasic", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerGetPlaybackQueue": { + "lexicon": 1, + "id": "app.rocksky.player.getPlaybackQueue", + "defs": { + "main": { + "type": "query", + "description": "Retrieve the current playback queue", + "parameters": { + "type": "params", + "properties": { + "playerId": { + "type": "string", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.player.defs#playbackQueueViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyPlayerNext": { + "lexicon": 1, + "id": "app.rocksky.player.next", + "defs": { + "main": { + "type": "procedure", + "description": "Play the next track in the queue", + "parameters": { + "type": "params", + "properties": { + "playerId": { + "type": "string", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerPlayFile": { + "lexicon": 1, + "id": "app.rocksky.player.playFile", + "defs": { + "main": { + "type": "procedure", + "description": "Play a specific audio file", + "parameters": { + "type": "params", + "required": [ + "fileId", + ], + "properties": { + "playerId": { + "type": "string", + }, + "fileId": { + "type": "string", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerGetCurrentlyPlaying": { + "lexicon": 1, + "id": "app.rocksky.player.getCurrentlyPlaying", + "defs": { + "main": { + "type": "query", + "description": "Get the currently playing track", + "parameters": { + "type": "params", + "properties": { + "playerId": { + "type": "string", + }, + "actor": { + "type": "string", + "description": + "Handle or DID of the actor to retrieve the currently playing track for. If not provided, defaults to the current user.", + "format": "at-identifier", + }, + }, + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "ref", + "ref": "lex:app.rocksky.player.defs#currentlyPlayingViewDetailed", + }, + }, + }, + }, + }, + "AppRockskyPlayerPrevious": { + "lexicon": 1, + "id": "app.rocksky.player.previous", + "defs": { + "main": { + "type": "procedure", + "description": "Play the previous track in the queue", + "parameters": { + "type": "params", + "properties": { + "playerId": { + "type": "string", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerAddItemsToQueue": { + "lexicon": 1, + "id": "app.rocksky.player.addItemsToQueue", + "defs": { + "main": { + "type": "procedure", + "description": "Add items to the player's queue", + "parameters": { + "type": "params", + "required": [ + "items", + ], + "properties": { + "playerId": { + "type": "string", + }, + "items": { + "type": "array", + "items": { + "type": "string", + "description": "List of file identifiers to add to the queue", + }, + }, + "position": { + "type": "integer", + "description": + "Position in the queue to insert the items at, defaults to the end if not specified", + }, + "shuffle": { + "type": "boolean", + "description": "Whether to shuffle the added items in the queue", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerPause": { + "lexicon": 1, + "id": "app.rocksky.player.pause", + "defs": { + "main": { + "type": "procedure", + "description": "Pause the currently playing track", + "parameters": { + "type": "params", + "properties": { + "playerId": { + "type": "string", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerPlay": { + "lexicon": 1, + "id": "app.rocksky.player.play", + "defs": { + "main": { + "type": "procedure", + "description": "Resume playback of the currently paused track", + "parameters": { + "type": "params", + "properties": { + "playerId": { + "type": "string", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerPlayDirectory": { + "lexicon": 1, + "id": "app.rocksky.player.playDirectory", + "defs": { + "main": { + "type": "procedure", + "description": "Play all tracks in a directory", + "parameters": { + "type": "params", + "required": [ + "directoryId", + ], + "properties": { + "playerId": { + "type": "string", + }, + "directoryId": { + "type": "string", + }, + "shuffle": { + "type": "boolean", + }, + "recurse": { + "type": "boolean", + }, + "position": { + "type": "integer", + }, + }, + }, + }, + }, + }, + "AppRockskyPlayerAddDirectoryToQueue": { + "lexicon": 1, + "id": "app.rocksky.player.addDirectoryToQueue", + "defs": { + "main": { + "type": "procedure", + "description": "Add directory to the player's queue", + "parameters": { + "type": "params", + "required": [ + "directory", + ], + "properties": { + "playerId": { + "type": "string", + }, + "directory": { + "type": "string", + "description": "The directory to add to the queue", + }, + "position": { + "type": "integer", + "description": + "Position in the queue to insert the directory at, defaults to the end if not specified", + }, + "shuffle": { + "type": "boolean", + "description": + "Whether to shuffle the added directory in the queue", + }, + }, + }, + }, + }, + }, +} as Record; +export const schemas = Object.values(schemaDict) satisfies LexiconDoc[]; +export const lexicons: Lexicons = new Lexicons(schemas); + +export function validate( + v: unknown, + id: string, + hash: string, + requiredType: true, +): ValidationResult; +export function validate( + v: unknown, + id: string, + hash: string, + requiredType?: false, +): ValidationResult; +export function validate( + v: unknown, + id: string, + hash: string, + requiredType?: boolean, +): ValidationResult { + return (requiredType ? is$typed : maybe$typed)(v, id, hash) + ? lexicons.validate(`${id}#${hash}`, v) + : { + success: false, + error: new ValidationError( + `Must be an object with "${ + hash === "main" ? id : `${id}#${hash}` + }" $type property`, + ), + }; +} + +export const ids = { + ComAtprotoRepoStrongRef: "com.atproto.repo.strongRef", + AppRockskyShoutGetAlbumShouts: "app.rocksky.shout.getAlbumShouts", + AppRockskyShoutDefs: "app.rocksky.shout.defs", + AppRockskyShoutReportShout: "app.rocksky.shout.reportShout", + AppRockskyShoutGetTrackShouts: "app.rocksky.shout.getTrackShouts", + AppRockskyShoutReplyShout: "app.rocksky.shout.replyShout", + AppRockskyShoutRemoveShout: "app.rocksky.shout.removeShout", + AppRockskyShoutGetProfileShouts: "app.rocksky.shout.getProfileShouts", + AppRockskyShout: "app.rocksky.shout", + AppRockskyShoutGetArtistShouts: "app.rocksky.shout.getArtistShouts", + AppRockskyShoutGetShoutReplies: "app.rocksky.shout.getShoutReplies", + AppRockskyShoutCreateShout: "app.rocksky.shout.createShout", + AppRockskyScrobbleDefs: "app.rocksky.scrobble.defs", + AppRockskyScrobble: "app.rocksky.scrobble", + AppRockskyScrobbleCreateScrobble: "app.rocksky.scrobble.createScrobble", + AppRockskyScrobbleGetScrobbles: "app.rocksky.scrobble.getScrobbles", + AppRockskyScrobbleGetScrobble: "app.rocksky.scrobble.getScrobble", + AppRockskyLikeDislikeShout: "app.rocksky.like.dislikeShout", + AppRockskyLike: "app.rocksky.like", + AppRockskyLikeLikeSong: "app.rocksky.like.likeSong", + AppRockskyLikeDislikeSong: "app.rocksky.like.dislikeSong", + AppRockskyLikeLikeShout: "app.rocksky.like.likeShout", + AppRockskyPlaylistCreatePlaylist: "app.rocksky.playlist.createPlaylist", + AppRockskyPlaylistStartPlaylist: "app.rocksky.playlist.startPlaylist", + AppRockskyPlaylistDefs: "app.rocksky.playlist.defs", + AppRockskyPlaylist: "app.rocksky.playlist", + AppRockskyPlaylistGetPlaylists: "app.rocksky.playlist.getPlaylists", + AppRockskyPlaylistInsertDirectory: "app.rocksky.playlist.insertDirectory", + AppRockskyPlaylistRemoveTrack: "app.rocksky.playlist.removeTrack", + AppRockskyPlaylistRemovePlaylist: "app.rocksky.playlist.removePlaylist", + AppRockskyPlaylistInsertFiles: "app.rocksky.playlist.insertFiles", + AppRockskyPlaylistGetPlaylist: "app.rocksky.playlist.getPlaylist", + AppRockskyRadioDefs: "app.rocksky.radio.defs", + AppRockskyRadio: "app.rocksky.radio", + AppRockskySpotifySeek: "app.rocksky.spotify.seek", + AppRockskySpotifyDefs: "app.rocksky.spotify.defs", + AppRockskySpotifyNext: "app.rocksky.spotify.next", + AppRockskySpotifyGetCurrentlyPlaying: + "app.rocksky.spotify.getCurrentlyPlaying", + AppRockskySpotifyPrevious: "app.rocksky.spotify.previous", + AppRockskySpotifyPause: "app.rocksky.spotify.pause", + AppRockskySpotifyPlay: "app.rocksky.spotify.play", + AppRockskyChartsDefs: "app.rocksky.charts.defs", + AppRockskyChartsGetScrobblesChart: "app.rocksky.charts.getScrobblesChart", + AppRockskySongDefs: "app.rocksky.song.defs", + AppRockskySongGetSongs: "app.rocksky.song.getSongs", + AppRockskySongGetSong: "app.rocksky.song.getSong", + AppRockskySong: "app.rocksky.song", + AppRockskySongCreateSong: "app.rocksky.song.createSong", + AppRockskyApikeysDefs: "app.rocksky.apikeys.defs", + AppRockskyApikeyGetApikeys: "app.rocksky.apikey.getApikeys", + AppRockskyApikeyUpdateApikey: "app.rocksky.apikey.updateApikey", + AppRockskyApikeyCreateApikey: "app.rocksky.apikey.createApikey", + AppRockskyApikeyRemoveApikey: "app.rocksky.apikey.removeApikey", + AppRockskyApikeyDefs: "app.rocksky.apikey.defs", + AppRockskyFeedGenerator: "app.rocksky.feed.generator", + AppRockskyFeedDefs: "app.rocksky.feed.defs", + AppRockskyFeedGetFeedGenerators: "app.rocksky.feed.getFeedGenerators", + AppRockskyFeedGetFeedGenerator: "app.rocksky.feed.getFeedGenerator", + AppRockskyFeedSearch: "app.rocksky.feed.search", + AppRockskyFeedGetNowPlayings: "app.rocksky.feed.getNowPlayings", + AppRockskyFeedDescribeFeedGenerator: "app.rocksky.feed.describeFeedGenerator", + AppRockskyFeedGetFeed: "app.rocksky.feed.getFeed", + AppRockskyFeedGetFeedSkeleton: "app.rocksky.feed.getFeedSkeleton", + AppRockskyDropboxDefs: "app.rocksky.dropbox.defs", + AppRockskyDropboxDownloadFile: "app.rocksky.dropbox.downloadFile", + AppRockskyDropboxGetFiles: "app.rocksky.dropbox.getFiles", + AppRockskyDropboxGetMetadata: "app.rocksky.dropbox.getMetadata", + AppRockskyDropboxGetTemporaryLink: "app.rocksky.dropbox.getTemporaryLink", + AppRockskyGoogledriveGetFile: "app.rocksky.googledrive.getFile", + AppRockskyGoogledriveDefs: "app.rocksky.googledrive.defs", + AppRockskyGoogledriveDownloadFile: "app.rocksky.googledrive.downloadFile", + AppRockskyGoogledriveGetFiles: "app.rocksky.googledrive.getFiles", + AppRockskyAlbumGetAlbumTracks: "app.rocksky.album.getAlbumTracks", + AppRockskyAlbumDefs: "app.rocksky.album.defs", + AppRockskyAlbumGetAlbum: "app.rocksky.album.getAlbum", + AppRockskyAlbum: "app.rocksky.album", + AppRockskyAlbumGetAlbums: "app.rocksky.album.getAlbums", + AppRockskyActorGetActorPlaylists: "app.rocksky.actor.getActorPlaylists", + AppRockskyActorGetActorSongs: "app.rocksky.actor.getActorSongs", + AppRockskyActorGetActorArtists: "app.rocksky.actor.getActorArtists", + AppRockskyActorDefs: "app.rocksky.actor.defs", + AppRockskyActorGetProfile: "app.rocksky.actor.getProfile", + AppRockskyActorGetActorLovedSongs: "app.rocksky.actor.getActorLovedSongs", + AppRockskyActorGetActorAlbums: "app.rocksky.actor.getActorAlbums", + AppRockskyActorGetActorScrobbles: "app.rocksky.actor.getActorScrobbles", + AppBskyActorProfile: "app.bsky.actor.profile", + AppRockskyArtistDefs: "app.rocksky.artist.defs", + AppRockskyArtist: "app.rocksky.artist", + AppRockskyArtistGetArtistAlbums: "app.rocksky.artist.getArtistAlbums", + AppRockskyArtistGetArtistListeners: "app.rocksky.artist.getArtistListeners", + AppRockskyArtistGetArtists: "app.rocksky.artist.getArtists", + AppRockskyArtistGetArtist: "app.rocksky.artist.getArtist", + AppRockskyArtistGetArtistTracks: "app.rocksky.artist.getArtistTracks", + AppRockskyStatsDefs: "app.rocksky.stats.defs", + AppRockskyStatsGetStats: "app.rocksky.stats.getStats", + AppRockskyPlayerSeek: "app.rocksky.player.seek", + AppRockskyPlayerDefs: "app.rocksky.player.defs", + AppRockskyPlayerGetPlaybackQueue: "app.rocksky.player.getPlaybackQueue", + AppRockskyPlayerNext: "app.rocksky.player.next", + AppRockskyPlayerPlayFile: "app.rocksky.player.playFile", + AppRockskyPlayerGetCurrentlyPlaying: "app.rocksky.player.getCurrentlyPlaying", + AppRockskyPlayerPrevious: "app.rocksky.player.previous", + AppRockskyPlayerAddItemsToQueue: "app.rocksky.player.addItemsToQueue", + AppRockskyPlayerPause: "app.rocksky.player.pause", + AppRockskyPlayerPlay: "app.rocksky.player.play", + AppRockskyPlayerPlayDirectory: "app.rocksky.player.playDirectory", + AppRockskyPlayerAddDirectoryToQueue: "app.rocksky.player.addDirectoryToQueue", +} as const; diff --git a/apps/feeds/src/lex/types/app/bsky/actor/profile.ts b/apps/feeds/src/lex/types/app/bsky/actor/profile.ts new file mode 100644 index 00000000..8477e70b --- /dev/null +++ b/apps/feeds/src/lex/types/app/bsky/actor/profile.ts @@ -0,0 +1,38 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../../lexicons.ts"; +import { type $Typed, is$typed as _is$typed } from "../../../../util.ts"; +import type * as ComAtprotoLabelDefs from "../../../com/atproto/label/defs.ts"; +import type * as ComAtprotoRepoStrongRef from "../../../com/atproto/repo/strongRef.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.bsky.actor.profile"; + +export interface Record { + $type: "app.bsky.actor.profile"; + displayName?: string; + /** Free-form profile description text. */ + description?: string; + /** Small image to be displayed next to posts from account. AKA, 'profile picture' */ + avatar?: BlobRef; + /** Larger horizontal image to display behind profile view. */ + banner?: BlobRef; + labels?: $Typed | { $type: string }; + joinedViaStarterPack?: ComAtprotoRepoStrongRef.Main; + createdAt?: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/defs.ts b/apps/feeds/src/lex/types/app/rocksky/actor/defs.ts new file mode 100644 index 00000000..6136ba68 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/defs.ts @@ -0,0 +1,64 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.actor.defs"; + +export interface ProfileViewDetailed { + $type?: "app.rocksky.actor.defs#profileViewDetailed"; + /** The unique identifier of the actor. */ + id?: string; + /** The DID of the actor. */ + did?: string; + /** The handle of the actor. */ + handle?: string; + /** The display name of the actor. */ + displayName?: string; + /** The URL of the actor's avatar image. */ + avatar?: string; + /** The date and time when the actor was created. */ + createdAt?: string; + /** The date and time when the actor was last updated. */ + updatedAt?: string; +} + +const hashProfileViewDetailed = "profileViewDetailed"; + +export function isProfileViewDetailed(v: V) { + return is$typed(v, id, hashProfileViewDetailed); +} + +export function validateProfileViewDetailed(v: V) { + return validate(v, id, hashProfileViewDetailed); +} + +export interface ProfileViewBasic { + $type?: "app.rocksky.actor.defs#profileViewBasic"; + /** The unique identifier of the actor. */ + id?: string; + /** The DID of the actor. */ + did?: string; + /** The handle of the actor. */ + handle?: string; + /** The display name of the actor. */ + displayName?: string; + /** The URL of the actor's avatar image. */ + avatar?: string; + /** The date and time when the actor was created. */ + createdAt?: string; + /** The date and time when the actor was last updated. */ + updatedAt?: string; +} + +const hashProfileViewBasic = "profileViewBasic"; + +export function isProfileViewBasic(v: V) { + return is$typed(v, id, hashProfileViewBasic); +} + +export function validateProfileViewBasic(v: V) { + return validate(v, id, hashProfileViewBasic); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/getActorAlbums.ts b/apps/feeds/src/lex/types/app/rocksky/actor/getActorAlbums.ts new file mode 100644 index 00000000..4c99f896 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/getActorAlbums.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyAlbumDefs from "../album/defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did: string; + /** The maximum number of albums to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + albums?: (AppRockskyAlbumDefs.AlbumViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/getActorArtists.ts b/apps/feeds/src/lex/types/app/rocksky/actor/getActorArtists.ts new file mode 100644 index 00000000..202efff2 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/getActorArtists.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyArtistDefs from "../artist/defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did: string; + /** The maximum number of albums to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + artists?: (AppRockskyArtistDefs.ArtistViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/getActorLovedSongs.ts b/apps/feeds/src/lex/types/app/rocksky/actor/getActorLovedSongs.ts new file mode 100644 index 00000000..6d0b7a51 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/getActorLovedSongs.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "../song/defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did: string; + /** The maximum number of albums to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + tracks?: (AppRockskySongDefs.SongViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/getActorPlaylists.ts b/apps/feeds/src/lex/types/app/rocksky/actor/getActorPlaylists.ts new file mode 100644 index 00000000..314324b2 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/getActorPlaylists.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyPlaylistDefs from "../playlist/defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did: string; + /** The maximum number of albums to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + playlists?: (AppRockskyPlaylistDefs.PlaylistViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/getActorScrobbles.ts b/apps/feeds/src/lex/types/app/rocksky/actor/getActorScrobbles.ts new file mode 100644 index 00000000..08c1395b --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/getActorScrobbles.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyScrobbleDefs from "../scrobble/defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did: string; + /** The maximum number of albums to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + scrobbles?: (AppRockskyScrobbleDefs.ScrobbleViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/getActorSongs.ts b/apps/feeds/src/lex/types/app/rocksky/actor/getActorSongs.ts new file mode 100644 index 00000000..bcd66b2a --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/getActorSongs.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "../song/defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did: string; + /** The maximum number of albums to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + songs?: (AppRockskySongDefs.SongViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/actor/getProfile.ts b/apps/feeds/src/lex/types/app/rocksky/actor/getProfile.ts new file mode 100644 index 00000000..38f5b4d5 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/actor/getProfile.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyActorDefs from "./defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did?: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyActorDefs.ProfileViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/album.ts b/apps/feeds/src/lex/types/app/rocksky/album.ts new file mode 100644 index 00000000..d1e1c443 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/album.ts @@ -0,0 +1,54 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.album"; + +export interface Record { + $type: "app.rocksky.album"; + /** The title of the album. */ + title: string; + /** The artist of the album. */ + artist: string; + /** The duration of the album in seconds. */ + duration?: number; + /** The release date of the album. */ + releaseDate?: string; + /** The year the album was released. */ + year?: number; + /** The genre of the album. */ + genre?: string; + /** The album art of the album. */ + albumArt?: BlobRef; + /** The URL of the album art of the album. */ + albumArtUrl?: string; + /** The tags of the album. */ + tags?: (string)[]; + /** The YouTube link of the album. */ + youtubeLink?: string; + /** The Spotify link of the album. */ + spotifyLink?: string; + /** The tidal link of the album. */ + tidalLink?: string; + /** The Apple Music link of the album. */ + appleMusicLink?: string; + /** The date and time when the album was created. */ + createdAt: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/album/defs.ts b/apps/feeds/src/lex/types/app/rocksky/album/defs.ts new file mode 100644 index 00000000..85bcf756 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/album/defs.ts @@ -0,0 +1,82 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; +import type * as AppRockskySongDefsSongViewBasic from "../song/defs/songViewBasic.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.album.defs"; + +export interface AlbumViewBasic { + $type?: "app.rocksky.album.defs#albumViewBasic"; + /** The unique identifier of the album. */ + id?: string; + /** The URI of the album. */ + uri?: string; + /** The title of the album. */ + title?: string; + /** The artist of the album. */ + artist?: string; + /** The URI of the album's artist. */ + artistUri?: string; + /** The year the album was released. */ + year?: number; + /** The URL of the album art image. */ + albumArt?: string; + /** The release date of the album. */ + releaseDate?: string; + /** The SHA256 hash of the album. */ + sha256?: string; + /** The number of times the album has been played. */ + playCount?: number; + /** The number of unique listeners who have played the album. */ + uniqueListeners?: number; +} + +const hashAlbumViewBasic = "albumViewBasic"; + +export function isAlbumViewBasic(v: V) { + return is$typed(v, id, hashAlbumViewBasic); +} + +export function validateAlbumViewBasic(v: V) { + return validate(v, id, hashAlbumViewBasic); +} + +export interface AlbumViewDetailed { + $type?: "app.rocksky.album.defs#albumViewDetailed"; + /** The unique identifier of the album. */ + id?: string; + /** The URI of the album. */ + uri?: string; + /** The title of the album. */ + title?: string; + /** The artist of the album. */ + artist?: string; + /** The URI of the album's artist. */ + artistUri?: string; + /** The year the album was released. */ + year?: number; + /** The URL of the album art image. */ + albumArt?: string; + /** The release date of the album. */ + releaseDate?: string; + /** The SHA256 hash of the album. */ + sha256?: string; + /** The number of times the album has been played. */ + playCount?: number; + /** The number of unique listeners who have played the album. */ + uniqueListeners?: number; + tracks?: (AppRockskySongDefsSongViewBasic.Main)[]; +} + +const hashAlbumViewDetailed = "albumViewDetailed"; + +export function isAlbumViewDetailed(v: V) { + return is$typed(v, id, hashAlbumViewDetailed); +} + +export function validateAlbumViewDetailed(v: V) { + return validate(v, id, hashAlbumViewDetailed); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/album/getAlbum.ts b/apps/feeds/src/lex/types/app/rocksky/album/getAlbum.ts new file mode 100644 index 00000000..8c0ed701 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/album/getAlbum.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyAlbumDefs from "./defs.ts"; + +export type QueryParams = { + /** The URI of the album to retrieve. */ + uri: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyAlbumDefs.AlbumViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/album/getAlbumTracks.ts b/apps/feeds/src/lex/types/app/rocksky/album/getAlbumTracks.ts new file mode 100644 index 00000000..a7f1fe04 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/album/getAlbumTracks.ts @@ -0,0 +1,29 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "../song/defs.ts"; + +export type QueryParams = { + /** The URI of the album to retrieve tracks from */ + uri: string; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + tracks?: (AppRockskySongDefs.SongViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/album/getAlbums.ts b/apps/feeds/src/lex/types/app/rocksky/album/getAlbums.ts new file mode 100644 index 00000000..5f41250f --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/album/getAlbums.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyAlbumDefs from "./defs.ts"; + +export type QueryParams = { + /** The maximum number of albums to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + albums?: (AppRockskyAlbumDefs.AlbumViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/apikey/createApikey.ts b/apps/feeds/src/lex/types/app/rocksky/apikey/createApikey.ts new file mode 100644 index 00000000..71d9ae82 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/apikey/createApikey.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyApikeyDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The name of the API key. */ + name: string; + /** A description for the API key. */ + description?: string; +} + +export type OutputSchema = AppRockskyApikeyDefs.ApiKey; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/apikey/defs.ts b/apps/feeds/src/lex/types/app/rocksky/apikey/defs.ts new file mode 100644 index 00000000..2abbef37 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/apikey/defs.ts @@ -0,0 +1,30 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.apikey.defs"; + +export interface ApiKeyView { + $type?: "app.rocksky.apikey.defs#apiKeyView"; + /** The unique identifier of the API key. */ + id?: string; + /** The name of the API key. */ + name?: string; + /** A description for the API key. */ + description?: string; + /** The date and time when the API key was created. */ + createdAt?: string; +} + +const hashApiKeyView = "apiKeyView"; + +export function isApiKeyView(v: V) { + return is$typed(v, id, hashApiKeyView); +} + +export function validateApiKeyView(v: V) { + return validate(v, id, hashApiKeyView); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/apikey/getApikeys.ts b/apps/feeds/src/lex/types/app/rocksky/apikey/getApikeys.ts new file mode 100644 index 00000000..e6d803f2 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/apikey/getApikeys.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyApikeyDefs from "./defs.ts"; + +export type QueryParams = { + /** The number of API keys to skip before starting to collect the result set. */ + offset?: number; + /** The number of API keys to return per page. */ + limit?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + apiKeys?: (AppRockskyApikeyDefs.ApikeyView)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/apikey/removeApikey.ts b/apps/feeds/src/lex/types/app/rocksky/apikey/removeApikey.ts new file mode 100644 index 00000000..66c7501e --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/apikey/removeApikey.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyApikeyDefs from "./defs.ts"; + +export type QueryParams = { + /** The ID of the API key to remove. */ + id: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyApikeyDefs.ApiKey; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/apikey/updateApikey.ts b/apps/feeds/src/lex/types/app/rocksky/apikey/updateApikey.ts new file mode 100644 index 00000000..56c03c34 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/apikey/updateApikey.ts @@ -0,0 +1,35 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyApikeyDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The ID of the API key to update. */ + id: string; + /** The new name of the API key. */ + name: string; + /** A new description for the API key. */ + description?: string; +} + +export type OutputSchema = AppRockskyApikeyDefs.ApiKey; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/apikeys/defs.ts b/apps/feeds/src/lex/types/app/rocksky/apikeys/defs.ts new file mode 100644 index 00000000..df93fbaa --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/apikeys/defs.ts @@ -0,0 +1,3 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ diff --git a/apps/feeds/src/lex/types/app/rocksky/artist.ts b/apps/feeds/src/lex/types/app/rocksky/artist.ts new file mode 100644 index 00000000..54f0befa --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/artist.ts @@ -0,0 +1,44 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.artist"; + +export interface Record { + $type: "app.rocksky.artist"; + /** The name of the artist. */ + name: string; + /** The biography of the artist. */ + bio?: string; + /** The picture of the artist. */ + picture?: BlobRef; + /** The URL of the picture of the artist. */ + pictureUrl?: string; + /** The tags of the artist. */ + tags?: (string)[]; + /** The birth date of the artist. */ + born?: string; + /** The death date of the artist. */ + died?: string; + /** The birth place of the artist. */ + bornIn?: string; + /** The date when the artist was created. */ + createdAt: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/artist/defs.ts b/apps/feeds/src/lex/types/app/rocksky/artist/defs.ts new file mode 100644 index 00000000..89230b9a --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/artist/defs.ts @@ -0,0 +1,131 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.artist.defs"; + +export interface ArtistViewBasic { + $type?: "app.rocksky.artist.defs#artistViewBasic"; + /** The unique identifier of the artist. */ + id?: string; + /** The URI of the artist. */ + uri?: string; + /** The name of the artist. */ + name?: string; + /** The picture of the artist. */ + picture?: string; + /** The SHA256 hash of the artist. */ + sha256?: string; + /** The number of times the artist has been played. */ + playCount?: number; + /** The number of unique listeners who have played the artist. */ + uniqueListeners?: number; +} + +const hashArtistViewBasic = "artistViewBasic"; + +export function isArtistViewBasic(v: V) { + return is$typed(v, id, hashArtistViewBasic); +} + +export function validateArtistViewBasic(v: V) { + return validate(v, id, hashArtistViewBasic); +} + +export interface ArtistViewDetailed { + $type?: "app.rocksky.artist.defs#artistViewDetailed"; + /** The unique identifier of the artist. */ + id?: string; + /** The URI of the artist. */ + uri?: string; + /** The name of the artist. */ + name?: string; + /** The picture of the artist. */ + picture?: string; + /** The SHA256 hash of the artist. */ + sha256?: string; + /** The number of times the artist has been played. */ + playCount?: number; + /** The number of unique listeners who have played the artist. */ + uniqueListeners?: number; +} + +const hashArtistViewDetailed = "artistViewDetailed"; + +export function isArtistViewDetailed(v: V) { + return is$typed(v, id, hashArtistViewDetailed); +} + +export function validateArtistViewDetailed(v: V) { + return validate(v, id, hashArtistViewDetailed); +} + +export interface SongViewBasic { + $type?: "app.rocksky.artist.defs#songViewBasic"; + /** The URI of the song. */ + uri?: string; + /** The title of the song. */ + title?: string; + /** The number of times the song has been played. */ + playCount?: number; +} + +const hashSongViewBasic = "songViewBasic"; + +export function isSongViewBasic(v: V) { + return is$typed(v, id, hashSongViewBasic); +} + +export function validateSongViewBasic(v: V) { + return validate(v, id, hashSongViewBasic); +} + +export interface ListenerViewBasic { + $type?: "app.rocksky.artist.defs#listenerViewBasic"; + /** The unique identifier of the actor. */ + id?: string; + /** The DID of the listener. */ + did?: string; + /** The handle of the listener. */ + handle?: string; + /** The display name of the listener. */ + displayName?: string; + /** The URL of the listener's avatar image. */ + avatar?: string; + mostListenedSong?: SongViewBasic; + /** The total number of plays by the listener. */ + totalPlays?: number; + /** The rank of the listener among all listeners of the artist. */ + rank?: number; +} + +const hashListenerViewBasic = "listenerViewBasic"; + +export function isListenerViewBasic(v: V) { + return is$typed(v, id, hashListenerViewBasic); +} + +export function validateListenerViewBasic(v: V) { + return validate(v, id, hashListenerViewBasic); +} + +export interface ArtistMbid { + $type?: "app.rocksky.artist.defs#artistMbid"; + /** The MusicBrainz Identifier (MBID) of the artist. */ + mbid?: string; + /** The name of the artist. */ + name?: string; +} + +const hashArtistMbid = "artistMbid"; + +export function isArtistMbid(v: V) { + return is$typed(v, id, hashArtistMbid); +} + +export function validateArtistMbid(v: V) { + return validate(v, id, hashArtistMbid); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/artist/getArtist.ts b/apps/feeds/src/lex/types/app/rocksky/artist/getArtist.ts new file mode 100644 index 00000000..7a8427ec --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/artist/getArtist.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyArtistDefs from "./defs.ts"; + +export type QueryParams = { + /** The URI of the artist to retrieve details from */ + uri: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyArtistDefs.ArtistViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/artist/getArtistAlbums.ts b/apps/feeds/src/lex/types/app/rocksky/artist/getArtistAlbums.ts new file mode 100644 index 00000000..6cdf7afb --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/artist/getArtistAlbums.ts @@ -0,0 +1,29 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyAlbumDefs from "../album/defs.ts"; + +export type QueryParams = { + /** The URI of the artist to retrieve albums from */ + uri: string; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + albums?: (AppRockskyAlbumDefs.AlbumViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/artist/getArtistListeners.ts b/apps/feeds/src/lex/types/app/rocksky/artist/getArtistListeners.ts new file mode 100644 index 00000000..1eda9316 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/artist/getArtistListeners.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyArtistDefs from "./defs.ts"; + +export type QueryParams = { + /** The URI of the artist to retrieve listeners from */ + uri: string; + /** Number of items to skip before returning results */ + offset?: number; + /** Maximum number of results to return */ + limit?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + listeners?: (AppRockskyArtistDefs.ListenerViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/artist/getArtistTracks.ts b/apps/feeds/src/lex/types/app/rocksky/artist/getArtistTracks.ts new file mode 100644 index 00000000..0a318a46 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/artist/getArtistTracks.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "../song/defs.ts"; + +export type QueryParams = { + /** The URI of the artist to retrieve albums from */ + uri?: string; + /** The maximum number of tracks to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + tracks?: (AppRockskySongDefs.SongViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/artist/getArtists.ts b/apps/feeds/src/lex/types/app/rocksky/artist/getArtists.ts new file mode 100644 index 00000000..78b5e7fd --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/artist/getArtists.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyArtistDefs from "./defs.ts"; + +export type QueryParams = { + /** The maximum number of artists to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; + /** The names of the artists to return */ + names?: string; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + artists?: (AppRockskyArtistDefs.ArtistViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/charts/defs.ts b/apps/feeds/src/lex/types/app/rocksky/charts/defs.ts new file mode 100644 index 00000000..7d2a4068 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/charts/defs.ts @@ -0,0 +1,41 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.charts.defs"; + +export interface ChartsView { + $type?: "app.rocksky.charts.defs#chartsView"; + scrobbles?: (ScrobbleViewBasic)[]; +} + +const hashChartsView = "chartsView"; + +export function isChartsView(v: V) { + return is$typed(v, id, hashChartsView); +} + +export function validateChartsView(v: V) { + return validate(v, id, hashChartsView); +} + +export interface ScrobbleViewBasic { + $type?: "app.rocksky.charts.defs#scrobbleViewBasic"; + /** The date of the scrobble. */ + date?: string; + /** The number of scrobbles on this date. */ + count?: number; +} + +const hashScrobbleViewBasic = "scrobbleViewBasic"; + +export function isScrobbleViewBasic(v: V) { + return is$typed(v, id, hashScrobbleViewBasic); +} + +export function validateScrobbleViewBasic(v: V) { + return validate(v, id, hashScrobbleViewBasic); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/charts/getScrobblesChart.ts b/apps/feeds/src/lex/types/app/rocksky/charts/getScrobblesChart.ts new file mode 100644 index 00000000..9cf7bc47 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/charts/getScrobblesChart.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyChartsDefs from "./defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did?: string; + /** The URI of the artist to filter by */ + artisturi?: string; + /** The URI of the album to filter by */ + albumuri?: string; + /** The URI of the track to filter by */ + songuri?: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyChartsDefs.ChartsView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/dropbox/defs.ts b/apps/feeds/src/lex/types/app/rocksky/dropbox/defs.ts new file mode 100644 index 00000000..5b0fd433 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/dropbox/defs.ts @@ -0,0 +1,66 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.dropbox.defs"; + +export interface FileView { + $type?: "app.rocksky.dropbox.defs#fileView"; + /** The unique identifier of the file. */ + id?: string; + /** The name of the file. */ + name?: string; + /** The lowercased path of the file. */ + pathLower?: string; + /** The display path of the file. */ + pathDisplay?: string; + /** The last modified date and time of the file on the client. */ + clientModified?: string; + /** The last modified date and time of the file on the server. */ + serverModified?: string; +} + +const hashFileView = "fileView"; + +export function isFileView(v: V) { + return is$typed(v, id, hashFileView); +} + +export function validateFileView(v: V) { + return validate(v, id, hashFileView); +} + +export interface FileListView { + $type?: "app.rocksky.dropbox.defs#fileListView"; + /** A list of files in the Dropbox. */ + files?: (FileView)[]; +} + +const hashFileListView = "fileListView"; + +export function isFileListView(v: V) { + return is$typed(v, id, hashFileListView); +} + +export function validateFileListView(v: V) { + return validate(v, id, hashFileListView); +} + +export interface TemporaryLinkView { + $type?: "app.rocksky.dropbox.defs#temporaryLinkView"; + /** The temporary link to access the file. */ + link?: string; +} + +const hashTemporaryLinkView = "temporaryLinkView"; + +export function isTemporaryLinkView(v: V) { + return is$typed(v, id, hashTemporaryLinkView); +} + +export function validateTemporaryLinkView(v: V) { + return validate(v, id, hashTemporaryLinkView); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/dropbox/downloadFile.ts b/apps/feeds/src/lex/types/app/rocksky/dropbox/downloadFile.ts new file mode 100644 index 00000000..9a026971 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/dropbox/downloadFile.ts @@ -0,0 +1,22 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The unique identifier of the file to download */ + fileId: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/octet-stream"; + body: Uint8Array | ReadableStream; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/dropbox/getFiles.ts b/apps/feeds/src/lex/types/app/rocksky/dropbox/getFiles.ts new file mode 100644 index 00000000..99555920 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/dropbox/getFiles.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyDropboxDefs from "./defs.ts"; + +export type QueryParams = { + /** Path to the Dropbox folder or root directory */ + at?: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyDropboxDefs.FileListView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/dropbox/getMetadata.ts b/apps/feeds/src/lex/types/app/rocksky/dropbox/getMetadata.ts new file mode 100644 index 00000000..b124daad --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/dropbox/getMetadata.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyDropboxDefs from "./defs.ts"; + +export type QueryParams = { + /** Path to the file or folder in Dropbox */ + path: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyDropboxDefs.FileView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/dropbox/getTemporaryLink.ts b/apps/feeds/src/lex/types/app/rocksky/dropbox/getTemporaryLink.ts new file mode 100644 index 00000000..f4c5e586 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/dropbox/getTemporaryLink.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyDropboxDefs from "./defs.ts"; + +export type QueryParams = { + /** Path to the file in Dropbox */ + path: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyDropboxDefs.TemporaryLinkView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/defs.ts b/apps/feeds/src/lex/types/app/rocksky/feed/defs.ts new file mode 100644 index 00000000..71d7c577 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/defs.ts @@ -0,0 +1,134 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { type $Typed, is$typed as _is$typed } from "../../../../util.ts"; +import type * as AppRockskySongDefs from "../song/defs.ts"; +import type * as AppRockskyAlbumDefs from "../album/defs.ts"; +import type * as AppRockskyArtistDefs from "../artist/defs.ts"; +import type * as AppRockskyPlaylistDefs from "../playlist/defs.ts"; +import type * as AppRockskyActorDefs from "../actor/defs.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.feed.defs"; + +export interface SearchResultsView { + $type?: "app.rocksky.feed.defs#searchResultsView"; + hits?: ( + | $Typed + | $Typed + | $Typed + | $Typed + | $Typed + | { $type: string } + )[]; + processingTimeMs?: number; + limit?: number; + offset?: number; + estimatedTotalHits?: number; +} + +const hashSearchResultsView = "searchResultsView"; + +export function isSearchResultsView(v: V) { + return is$typed(v, id, hashSearchResultsView); +} + +export function validateSearchResultsView(v: V) { + return validate(v, id, hashSearchResultsView); +} + +export interface NowPlayingView { + $type?: "app.rocksky.feed.defs#nowPlayingView"; + album?: string; + albumArt?: string; + albumArtist?: string; + albumUri?: string; + artist?: string; + artistUri?: string; + avatar?: string; + createdAt?: string; + did?: string; + handle?: string; + id?: string; + title?: string; + trackId?: string; + trackUri?: string; + uri?: string; +} + +const hashNowPlayingView = "nowPlayingView"; + +export function isNowPlayingView(v: V) { + return is$typed(v, id, hashNowPlayingView); +} + +export function validateNowPlayingView(v: V) { + return validate(v, id, hashNowPlayingView); +} + +export interface NowPlayingsView { + $type?: "app.rocksky.feed.defs#nowPlayingsView"; + nowPlayings?: (NowPlayingView)[]; +} + +const hashNowPlayingsView = "nowPlayingsView"; + +export function isNowPlayingsView(v: V) { + return is$typed(v, id, hashNowPlayingsView); +} + +export function validateNowPlayingsView(v: V) { + return validate(v, id, hashNowPlayingsView); +} + +export interface FeedGeneratorsView { + $type?: "app.rocksky.feed.defs#feedGeneratorsView"; + feeds?: (FeedGeneratorView)[]; +} + +const hashFeedGeneratorsView = "feedGeneratorsView"; + +export function isFeedGeneratorsView(v: V) { + return is$typed(v, id, hashFeedGeneratorsView); +} + +export function validateFeedGeneratorsView(v: V) { + return validate(v, id, hashFeedGeneratorsView); +} + +export interface FeedGeneratorView { + $type?: "app.rocksky.feed.defs#feedGeneratorView"; + id?: string; + name?: string; + description?: string; + uri?: string; + avatar?: string; + creator?: AppRockskyActorDefs.ProfileViewBasic; +} + +const hashFeedGeneratorView = "feedGeneratorView"; + +export function isFeedGeneratorView(v: V) { + return is$typed(v, id, hashFeedGeneratorView); +} + +export function validateFeedGeneratorView(v: V) { + return validate(v, id, hashFeedGeneratorView); +} + +export interface FeedUriView { + $type?: "app.rocksky.feed.defs#feedUriView"; + /** The feed URI. */ + uri?: string; +} + +const hashFeedUriView = "feedUriView"; + +export function isFeedUriView(v: V) { + return is$typed(v, id, hashFeedUriView); +} + +export function validateFeedUriView(v: V) { + return validate(v, id, hashFeedUriView); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/describeFeedGenerator.ts b/apps/feeds/src/lex/types/app/rocksky/feed/describeFeedGenerator.ts new file mode 100644 index 00000000..d1193124 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/describeFeedGenerator.ts @@ -0,0 +1,29 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyFeedDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; +export type InputSchema = undefined; + +export interface OutputSchema { + /** The DID of the feed generator. */ + did?: string; + /** List of feed URIs generated by this feed generator. */ + feeds?: (AppRockskyFeedDefs.FeedUriView)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/generator.ts b/apps/feeds/src/lex/types/app/rocksky/feed/generator.ts new file mode 100644 index 00000000..646c3d24 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/generator.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.feed.generator"; + +export interface Record { + $type: "app.rocksky.feed.generator"; + did: string; + avatar?: BlobRef; + displayName: string; + description?: string; + createdAt: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/getFeed.ts b/apps/feeds/src/lex/types/app/rocksky/feed/getFeed.ts new file mode 100644 index 00000000..0d657094 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/getFeed.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyScrobbleDefs from "../scrobble/defs.ts"; + +export type QueryParams = { + /** The feed URI. */ + feed: string; + /** The maximum number of scrobbles to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + scrobbles?: (AppRockskyScrobbleDefs.ScrobbleViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/getFeedGenerator.ts b/apps/feeds/src/lex/types/app/rocksky/feed/getFeedGenerator.ts new file mode 100644 index 00000000..0e5715bb --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/getFeedGenerator.ts @@ -0,0 +1,29 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyFeedDefs from "./defs.ts"; + +export type QueryParams = { + /** AT-URI of the feed generator record. */ + feed: string; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + view?: AppRockskyFeedDefs.FeedGeneratorView; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/getFeedGenerators.ts b/apps/feeds/src/lex/types/app/rocksky/feed/getFeedGenerators.ts new file mode 100644 index 00000000..d1aea506 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/getFeedGenerators.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyFeedDefs from "./defs.ts"; + +export type QueryParams = { + /** The maximum number of feed generators to return. */ + size?: number; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyFeedDefs.FeedGeneratorsView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/getFeedSkeleton.ts b/apps/feeds/src/lex/types/app/rocksky/feed/getFeedSkeleton.ts new file mode 100644 index 00000000..02736f82 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/getFeedSkeleton.ts @@ -0,0 +1,37 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyScrobbleDefs from "../scrobble/defs.ts"; + +export type QueryParams = { + /** The feed URI. */ + feed: string; + /** The maximum number of scrobbles to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; + /** The pagination cursor. */ + cursor?: string; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + scrobbles?: (AppRockskyScrobbleDefs.ScrobbleViewBasic)[]; + /** The pagination cursor for the next set of results. */ + cursor?: string; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/getNowPlayings.ts b/apps/feeds/src/lex/types/app/rocksky/feed/getNowPlayings.ts new file mode 100644 index 00000000..0aa1d5f9 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/getNowPlayings.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyFeedDefs from "./defs.ts"; + +export type QueryParams = { + /** The maximum number of now playing tracks to return. */ + size?: number; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyFeedDefs.NowPlayingsView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/feed/search.ts b/apps/feeds/src/lex/types/app/rocksky/feed/search.ts new file mode 100644 index 00000000..13f1aaaf --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/feed/search.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyFeedDefs from "./defs.ts"; + +export type QueryParams = { + /** The search query string */ + query: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyFeedDefs.SearchResultsView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/googledrive/defs.ts b/apps/feeds/src/lex/types/app/rocksky/googledrive/defs.ts new file mode 100644 index 00000000..dc38bf40 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/googledrive/defs.ts @@ -0,0 +1,39 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.googledrive.defs"; + +export interface FileView { + $type?: "app.rocksky.googledrive.defs#fileView"; + /** The unique identifier of the file. */ + id?: string; +} + +const hashFileView = "fileView"; + +export function isFileView(v: V) { + return is$typed(v, id, hashFileView); +} + +export function validateFileView(v: V) { + return validate(v, id, hashFileView); +} + +export interface FileListView { + $type?: "app.rocksky.googledrive.defs#fileListView"; + files?: (FileView)[]; +} + +const hashFileListView = "fileListView"; + +export function isFileListView(v: V) { + return is$typed(v, id, hashFileListView); +} + +export function validateFileListView(v: V) { + return validate(v, id, hashFileListView); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/googledrive/downloadFile.ts b/apps/feeds/src/lex/types/app/rocksky/googledrive/downloadFile.ts new file mode 100644 index 00000000..9a026971 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/googledrive/downloadFile.ts @@ -0,0 +1,22 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The unique identifier of the file to download */ + fileId: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/octet-stream"; + body: Uint8Array | ReadableStream; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/googledrive/getFile.ts b/apps/feeds/src/lex/types/app/rocksky/googledrive/getFile.ts new file mode 100644 index 00000000..e49aaef8 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/googledrive/getFile.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyGoogledriveDefs from "./defs.ts"; + +export type QueryParams = { + /** The unique identifier of the file to retrieve */ + fileId: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyGoogledriveDefs.FileView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/googledrive/getFiles.ts b/apps/feeds/src/lex/types/app/rocksky/googledrive/getFiles.ts new file mode 100644 index 00000000..6a54ffbb --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/googledrive/getFiles.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyGoogledriveDefs from "./defs.ts"; + +export type QueryParams = { + /** Path to the Google Drive folder or root directory */ + at?: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyGoogledriveDefs.FileListView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/like.ts b/apps/feeds/src/lex/types/app/rocksky/like.ts new file mode 100644 index 00000000..7f2df044 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/like.ts @@ -0,0 +1,29 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; +import type * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.like"; + +export interface Record { + $type: "app.rocksky.like"; + /** The date when the like was created. */ + createdAt: string; + subject: ComAtprotoRepoStrongRef.Main; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/like/dislikeShout.ts b/apps/feeds/src/lex/types/app/rocksky/like/dislikeShout.ts new file mode 100644 index 00000000..b583a549 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/like/dislikeShout.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "../shout/defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The unique identifier of the shout to dislike */ + uri?: string; +} + +export type OutputSchema = AppRockskyShoutDefs.ShoutView; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/like/dislikeSong.ts b/apps/feeds/src/lex/types/app/rocksky/like/dislikeSong.ts new file mode 100644 index 00000000..4ecff06f --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/like/dislikeSong.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "../song/defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The unique identifier of the song to dislike */ + uri?: string; +} + +export type OutputSchema = AppRockskySongDefs.SongViewDetailed; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/like/likeShout.ts b/apps/feeds/src/lex/types/app/rocksky/like/likeShout.ts new file mode 100644 index 00000000..dc1e7bda --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/like/likeShout.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "../shout/defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The unique identifier of the shout to like */ + uri?: string; +} + +export type OutputSchema = AppRockskyShoutDefs.ShoutView; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/like/likeSong.ts b/apps/feeds/src/lex/types/app/rocksky/like/likeSong.ts new file mode 100644 index 00000000..16314f88 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/like/likeSong.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "../song/defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The unique identifier of the song to like */ + uri?: string; +} + +export type OutputSchema = AppRockskySongDefs.SongViewDetailed; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/addDirectoryToQueue.ts b/apps/feeds/src/lex/types/app/rocksky/player/addDirectoryToQueue.ts new file mode 100644 index 00000000..68fd53ce --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/addDirectoryToQueue.ts @@ -0,0 +1,21 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; + /** The directory to add to the queue */ + directory: string; + /** Position in the queue to insert the directory at, defaults to the end if not specified */ + position?: number; + /** Whether to shuffle the added directory in the queue */ + shuffle?: boolean; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/addItemsToQueue.ts b/apps/feeds/src/lex/types/app/rocksky/player/addItemsToQueue.ts new file mode 100644 index 00000000..04809652 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/addItemsToQueue.ts @@ -0,0 +1,20 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; + items: string[]; + /** Position in the queue to insert the items at, defaults to the end if not specified */ + position?: number; + /** Whether to shuffle the added items in the queue */ + shuffle?: boolean; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/defs.ts b/apps/feeds/src/lex/types/app/rocksky/player/defs.ts new file mode 100644 index 00000000..b1fd93a5 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/defs.ts @@ -0,0 +1,48 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; +import type * as AppRockskySongDefsSongViewBasic from "../song/defs/songViewBasic.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.player.defs"; + +export interface CurrentlyPlayingViewDetailed { + $type?: "app.rocksky.player.defs#currentlyPlayingViewDetailed"; + /** The title of the currently playing track */ + title?: string; +} + +const hashCurrentlyPlayingViewDetailed = "currentlyPlayingViewDetailed"; + +export function isCurrentlyPlayingViewDetailed(v: V) { + return is$typed(v, id, hashCurrentlyPlayingViewDetailed); +} + +export function validateCurrentlyPlayingViewDetailed(v: V) { + return validate( + v, + id, + hashCurrentlyPlayingViewDetailed, + ); +} + +export interface PlaybackQueueViewDetailed { + $type?: "app.rocksky.player.defs#playbackQueueViewDetailed"; + tracks?: (AppRockskySongDefsSongViewBasic.Main)[]; +} + +const hashPlaybackQueueViewDetailed = "playbackQueueViewDetailed"; + +export function isPlaybackQueueViewDetailed(v: V) { + return is$typed(v, id, hashPlaybackQueueViewDetailed); +} + +export function validatePlaybackQueueViewDetailed(v: V) { + return validate( + v, + id, + hashPlaybackQueueViewDetailed, + ); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/player/getCurrentlyPlaying.ts b/apps/feeds/src/lex/types/app/rocksky/player/getCurrentlyPlaying.ts new file mode 100644 index 00000000..9cf7c1c0 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/getCurrentlyPlaying.ts @@ -0,0 +1,26 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyPlayerDefs from "./defs.ts"; + +export type QueryParams = { + playerId?: string; + /** Handle or DID of the actor to retrieve the currently playing track for. If not provided, defaults to the current user. */ + actor?: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyPlayerDefs.CurrentlyPlayingViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/getPlaybackQueue.ts b/apps/feeds/src/lex/types/app/rocksky/player/getPlaybackQueue.ts new file mode 100644 index 00000000..7b22334c --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/getPlaybackQueue.ts @@ -0,0 +1,24 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyPlayerDefs from "./defs.ts"; + +export type QueryParams = { + playerId?: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyPlayerDefs.PlaybackQueueViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/next.ts b/apps/feeds/src/lex/types/app/rocksky/player/next.ts new file mode 100644 index 00000000..d01b497b --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/next.ts @@ -0,0 +1,15 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/pause.ts b/apps/feeds/src/lex/types/app/rocksky/player/pause.ts new file mode 100644 index 00000000..d01b497b --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/pause.ts @@ -0,0 +1,15 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/play.ts b/apps/feeds/src/lex/types/app/rocksky/player/play.ts new file mode 100644 index 00000000..d01b497b --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/play.ts @@ -0,0 +1,15 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/playDirectory.ts b/apps/feeds/src/lex/types/app/rocksky/player/playDirectory.ts new file mode 100644 index 00000000..120983df --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/playDirectory.ts @@ -0,0 +1,19 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; + directoryId: string; + shuffle?: boolean; + recurse?: boolean; + position?: number; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/playFile.ts b/apps/feeds/src/lex/types/app/rocksky/player/playFile.ts new file mode 100644 index 00000000..b4fc51a4 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/playFile.ts @@ -0,0 +1,16 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; + fileId: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/previous.ts b/apps/feeds/src/lex/types/app/rocksky/player/previous.ts new file mode 100644 index 00000000..d01b497b --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/previous.ts @@ -0,0 +1,15 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/player/seek.ts b/apps/feeds/src/lex/types/app/rocksky/player/seek.ts new file mode 100644 index 00000000..45b938a5 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/player/seek.ts @@ -0,0 +1,17 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + playerId?: string; + /** The position in seconds to seek to */ + position: number; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist.ts b/apps/feeds/src/lex/types/app/rocksky/playlist.ts new file mode 100644 index 00000000..4b29675c --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist.ts @@ -0,0 +1,45 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; +import type * as AppRockskySong from "./song.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.playlist"; + +export interface Record { + $type: "app.rocksky.playlist"; + /** The name of the playlist. */ + name: string; + /** The playlist description. */ + description?: string; + /** The picture of the playlist. */ + picture?: BlobRef; + /** The tracks in the playlist. */ + tracks?: (AppRockskySong.Record)[]; + /** The date the playlist was created. */ + createdAt: string; + /** The Spotify link of the playlist. */ + spotifyLink?: string; + /** The Tidal link of the playlist. */ + tidalLink?: string; + /** The YouTube link of the playlist. */ + youtubeLink?: string; + /** The Apple Music link of the playlist. */ + appleMusicLink?: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/createPlaylist.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/createPlaylist.ts new file mode 100644 index 00000000..6c962c4e --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/createPlaylist.ts @@ -0,0 +1,18 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The name of the playlist */ + name: string; + /** A brief description of the playlist */ + description?: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/defs.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/defs.ts new file mode 100644 index 00000000..9b8da851 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/defs.ts @@ -0,0 +1,83 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; +import type * as AppRockskySongDefs from "../song/defs.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.playlist.defs"; + +/** Detailed view of a playlist, including its tracks and metadata */ +export interface PlaylistViewDetailed { + $type?: "app.rocksky.playlist.defs#playlistViewDetailed"; + /** The unique identifier of the playlist. */ + id?: string; + /** The title of the playlist. */ + title?: string; + /** The URI of the playlist. */ + uri?: string; + /** The DID of the curator of the playlist. */ + curatorDid?: string; + /** The handle of the curator of the playlist. */ + curatorHandle?: string; + /** The name of the curator of the playlist. */ + curatorName?: string; + /** The URL of the avatar image of the curator. */ + curatorAvatarUrl?: string; + /** A description of the playlist. */ + description?: string; + /** The URL of the cover image for the playlist. */ + coverImageUrl?: string; + /** The date and time when the playlist was created. */ + createdAt?: string; + /** A list of tracks in the playlist. */ + tracks?: (AppRockskySongDefs.SongViewBasic)[]; +} + +const hashPlaylistViewDetailed = "playlistViewDetailed"; + +export function isPlaylistViewDetailed(v: V) { + return is$typed(v, id, hashPlaylistViewDetailed); +} + +export function validatePlaylistViewDetailed(v: V) { + return validate(v, id, hashPlaylistViewDetailed); +} + +/** Basic view of a playlist, including its metadata */ +export interface PlaylistViewBasic { + $type?: "app.rocksky.playlist.defs#playlistViewBasic"; + /** The unique identifier of the playlist. */ + id?: string; + /** The title of the playlist. */ + title?: string; + /** The URI of the playlist. */ + uri?: string; + /** The DID of the curator of the playlist. */ + curatorDid?: string; + /** The handle of the curator of the playlist. */ + curatorHandle?: string; + /** The name of the curator of the playlist. */ + curatorName?: string; + /** The URL of the avatar image of the curator. */ + curatorAvatarUrl?: string; + /** A description of the playlist. */ + description?: string; + /** The URL of the cover image for the playlist. */ + coverImageUrl?: string; + /** The date and time when the playlist was created. */ + createdAt?: string; + /** The number of tracks in the playlist. */ + trackCount?: number; +} + +const hashPlaylistViewBasic = "playlistViewBasic"; + +export function isPlaylistViewBasic(v: V) { + return is$typed(v, id, hashPlaylistViewBasic); +} + +export function validatePlaylistViewBasic(v: V) { + return validate(v, id, hashPlaylistViewBasic); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/getPlaylist.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/getPlaylist.ts new file mode 100644 index 00000000..c03e1e67 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/getPlaylist.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyPlaylistDefs from "./defs.ts"; + +export type QueryParams = { + /** The URI of the playlist to retrieve. */ + uri: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyPlaylistDefs.PlaylistViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/getPlaylists.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/getPlaylists.ts new file mode 100644 index 00000000..cded1d86 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/getPlaylists.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyPlaylistDefs from "./defs.ts"; + +export type QueryParams = { + /** The maximum number of playlists to return. */ + limit?: number; + /** The offset for pagination, used to skip a number of playlists. */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + playlists?: (AppRockskyPlaylistDefs.PlaylistViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/insertDirectory.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/insertDirectory.ts new file mode 100644 index 00000000..1da61794 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/insertDirectory.ts @@ -0,0 +1,20 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The URI of the playlist to start */ + uri: string; + /** The directory (id) to insert into the playlist */ + directory: string; + /** The position in the playlist to insert the directory at, if not specified, the directory will be appended */ + position?: number; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/insertFiles.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/insertFiles.ts new file mode 100644 index 00000000..ab6deb2b --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/insertFiles.ts @@ -0,0 +1,19 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The URI of the playlist to start */ + uri: string; + files: string[]; + /** The position in the playlist to insert the files at, if not specified, files will be appended */ + position?: number; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/removePlaylist.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/removePlaylist.ts new file mode 100644 index 00000000..49583f62 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/removePlaylist.ts @@ -0,0 +1,16 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The URI of the playlist to remove */ + uri: string; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/removeTrack.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/removeTrack.ts new file mode 100644 index 00000000..edc42507 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/removeTrack.ts @@ -0,0 +1,18 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The URI of the playlist to remove the track from */ + uri: string; + /** The position of the track to remove in the playlist */ + position: number; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/playlist/startPlaylist.ts b/apps/feeds/src/lex/types/app/rocksky/playlist/startPlaylist.ts new file mode 100644 index 00000000..dd78b0b8 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/playlist/startPlaylist.ts @@ -0,0 +1,20 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The URI of the playlist to start */ + uri: string; + /** Whether to shuffle the playlist when starting it */ + shuffle?: boolean; + /** The position in the playlist to start from, if not specified, starts from the beginning */ + position?: number; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/radio.ts b/apps/feeds/src/lex/types/app/rocksky/radio.ts new file mode 100644 index 00000000..5bb8b133 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/radio.ts @@ -0,0 +1,40 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.radio"; + +export interface Record { + $type: "app.rocksky.radio"; + /** The name of the radio station. */ + name: string; + /** The URL of the radio station. */ + url: string; + /** A description of the radio station. */ + description?: string; + /** The genre of the radio station. */ + genre?: string; + /** The logo of the radio station. */ + logo?: BlobRef; + /** The website of the radio station. */ + website?: string; + /** The date when the radio station was created. */ + createdAt: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/radio/defs.ts b/apps/feeds/src/lex/types/app/rocksky/radio/defs.ts new file mode 100644 index 00000000..1b221e20 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/radio/defs.ts @@ -0,0 +1,60 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.radio.defs"; + +export interface RadioViewBasic { + $type?: "app.rocksky.radio.defs#radioViewBasic"; + /** The unique identifier of the radio. */ + id?: string; + /** The name of the radio. */ + name?: string; + /** A brief description of the radio. */ + description?: string; + /** The date and time when the radio was created. */ + createdAt?: string; +} + +const hashRadioViewBasic = "radioViewBasic"; + +export function isRadioViewBasic(v: V) { + return is$typed(v, id, hashRadioViewBasic); +} + +export function validateRadioViewBasic(v: V) { + return validate(v, id, hashRadioViewBasic); +} + +export interface RadioViewDetailed { + $type?: "app.rocksky.radio.defs#radioViewDetailed"; + /** The unique identifier of the radio. */ + id?: string; + /** The name of the radio. */ + name?: string; + /** A brief description of the radio. */ + description?: string; + /** The website of the radio. */ + website?: string; + /** The streaming URL of the radio. */ + url?: string; + /** The genre of the radio. */ + genre?: string; + /** The logo of the radio station. */ + logo?: string; + /** The date and time when the radio was created. */ + createdAt?: string; +} + +const hashRadioViewDetailed = "radioViewDetailed"; + +export function isRadioViewDetailed(v: V) { + return is$typed(v, id, hashRadioViewDetailed); +} + +export function validateRadioViewDetailed(v: V) { + return validate(v, id, hashRadioViewDetailed); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/scrobble.ts b/apps/feeds/src/lex/types/app/rocksky/scrobble.ts new file mode 100644 index 00000000..771d7ea4 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/scrobble.ts @@ -0,0 +1,77 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; +import type * as AppRockskyArtistDefs from "./artist/defs.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.scrobble"; + +export interface Record { + $type: "app.rocksky.scrobble"; + /** The title of the song. */ + title: string; + /** The artist of the song. */ + artist: string; + /** The artists of the song with MusicBrainz IDs. */ + artists?: (AppRockskyArtistDefs.ArtistMbid)[]; + /** The album artist of the song. */ + albumArtist: string; + /** The album of the song. */ + album: string; + /** The duration of the song in seconds. */ + duration: number; + /** The track number of the song in the album. */ + trackNumber?: number; + /** The disc number of the song in the album. */ + discNumber?: number; + /** The release date of the song. */ + releaseDate?: string; + /** The year the song was released. */ + year?: number; + /** The genre of the song. */ + genre?: string; + /** The tags of the song. */ + tags?: (string)[]; + /** The composer of the song. */ + composer?: string; + /** The lyrics of the song. */ + lyrics?: string; + /** The copyright message of the song. */ + copyrightMessage?: string; + /** Informations about the song */ + wiki?: string; + /** The album art of the song. */ + albumArt?: BlobRef; + /** The URL of the album art of the song. */ + albumArtUrl?: string; + /** The YouTube link of the song. */ + youtubeLink?: string; + /** The Spotify link of the song. */ + spotifyLink?: string; + /** The Tidal link of the song. */ + tidalLink?: string; + /** The Apple Music link of the song. */ + appleMusicLink?: string; + /** The date when the song was created. */ + createdAt: string; + /** The MusicBrainz ID of the song. */ + mbid?: string; + /** The label of the song. */ + label?: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/scrobble/createScrobble.ts b/apps/feeds/src/lex/types/app/rocksky/scrobble/createScrobble.ts new file mode 100644 index 00000000..aa481abd --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/scrobble/createScrobble.ts @@ -0,0 +1,73 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyScrobbleDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The title of the track being scrobbled */ + title: string; + /** The artist of the track being scrobbled */ + artist: string; + /** The album of the track being scrobbled */ + album?: string; + /** The duration of the track in seconds */ + duration?: number; + /** The MusicBrainz ID of the track, if available */ + mbId?: string; + /** The URL of the album art for the track */ + albumArt?: string; + /** The track number of the track in the album */ + trackNumber?: number; + /** The release date of the track, formatted as YYYY-MM-DD */ + releaseDate?: string; + /** The year the track was released */ + year?: number; + /** The disc number of the track in the album, if applicable */ + discNumber?: number; + /** The lyrics of the track, if available */ + lyrics?: string; + /** The composer of the track, if available */ + composer?: string; + /** The copyright message for the track, if available */ + copyrightMessage?: string; + /** The record label of the track, if available */ + label?: string; + /** The URL of the artist's picture, if available */ + artistPicture?: string; + /** The Spotify link for the track, if available */ + spotifyLink?: string; + /** The Last.fm link for the track, if available */ + lastfmLink?: string; + /** The Tidal link for the track, if available */ + tidalLink?: string; + /** The Apple Music link for the track, if available */ + appleMusicLink?: string; + /** The Youtube link for the track, if available */ + youtubeLink?: string; + /** The Deezer link for the track, if available */ + deezerLink?: string; + /** The timestamp of the scrobble in milliseconds since epoch */ + timestamp?: number; +} + +export type OutputSchema = AppRockskyScrobbleDefs.ScrobbleViewBasic; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/scrobble/defs.ts b/apps/feeds/src/lex/types/app/rocksky/scrobble/defs.ts new file mode 100644 index 00000000..24c5e883 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/scrobble/defs.ts @@ -0,0 +1,88 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.scrobble.defs"; + +export interface ScrobbleViewBasic { + $type?: "app.rocksky.scrobble.defs#scrobbleViewBasic"; + /** The unique identifier of the scrobble. */ + id?: string; + /** The handle of the user who created the scrobble. */ + user?: string; + /** The display name of the user who created the scrobble. */ + userDisplayName?: string; + /** The avatar URL of the user who created the scrobble. */ + userAvatar?: string; + /** The title of the scrobble. */ + title?: string; + /** The artist of the song. */ + artist?: string; + /** The URI of the artist. */ + artistUri?: string; + /** The album of the song. */ + album?: string; + /** The URI of the album. */ + albumUri?: string; + /** The album art URL of the song. */ + cover?: string; + /** The timestamp when the scrobble was created. */ + date?: string; + /** The URI of the scrobble. */ + uri?: string; + /** The SHA256 hash of the scrobble data. */ + sha256?: string; +} + +const hashScrobbleViewBasic = "scrobbleViewBasic"; + +export function isScrobbleViewBasic(v: V) { + return is$typed(v, id, hashScrobbleViewBasic); +} + +export function validateScrobbleViewBasic(v: V) { + return validate(v, id, hashScrobbleViewBasic); +} + +export interface ScrobbleViewDetailed { + $type?: "app.rocksky.scrobble.defs#scrobbleViewDetailed"; + /** The unique identifier of the scrobble. */ + id?: string; + /** The handle of the user who created the scrobble. */ + user?: string; + /** The title of the scrobble. */ + title?: string; + /** The artist of the song. */ + artist?: string; + /** The URI of the artist. */ + artistUri?: string; + /** The album of the song. */ + album?: string; + /** The URI of the album. */ + albumUri?: string; + /** The album art URL of the song. */ + cover?: string; + /** The timestamp when the scrobble was created. */ + date?: string; + /** The URI of the scrobble. */ + uri?: string; + /** The SHA256 hash of the scrobble data. */ + sha256?: string; + /** The number of listeners */ + listeners?: number; + /** The number of scrobbles for this song */ + scrobbles?: number; +} + +const hashScrobbleViewDetailed = "scrobbleViewDetailed"; + +export function isScrobbleViewDetailed(v: V) { + return is$typed(v, id, hashScrobbleViewDetailed); +} + +export function validateScrobbleViewDetailed(v: V) { + return validate(v, id, hashScrobbleViewDetailed); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/scrobble/getScrobble.ts b/apps/feeds/src/lex/types/app/rocksky/scrobble/getScrobble.ts new file mode 100644 index 00000000..71dbd4dd --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/scrobble/getScrobble.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyScrobbleDefs from "./defs.ts"; + +export type QueryParams = { + /** The unique identifier of the scrobble */ + uri: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyScrobbleDefs.ScrobbleViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/scrobble/getScrobbles.ts b/apps/feeds/src/lex/types/app/rocksky/scrobble/getScrobbles.ts new file mode 100644 index 00000000..807fefa9 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/scrobble/getScrobbles.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyScrobbleDefs from "./defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did?: string; + /** The maximum number of scrobbles to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + scrobbles?: (AppRockskyScrobbleDefs.ScrobbleViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout.ts b/apps/feeds/src/lex/types/app/rocksky/shout.ts new file mode 100644 index 00000000..5b9368a9 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout.ts @@ -0,0 +1,32 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; +import type * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.shout"; + +export interface Record { + $type: "app.rocksky.shout"; + /** The message of the shout. */ + message: string; + /** The date when the shout was created. */ + createdAt: string; + parent?: ComAtprotoRepoStrongRef.Main; + subject: ComAtprotoRepoStrongRef.Main; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/createShout.ts b/apps/feeds/src/lex/types/app/rocksky/shout/createShout.ts new file mode 100644 index 00000000..cfbb8d7e --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/createShout.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The content of the shout */ + message?: string; +} + +export type OutputSchema = AppRockskyShoutDefs.ShoutView; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/defs.ts b/apps/feeds/src/lex/types/app/rocksky/shout/defs.ts new file mode 100644 index 00000000..bb46a477 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/defs.ts @@ -0,0 +1,55 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.shout.defs"; + +export interface Author { + $type?: "app.rocksky.shout.defs#author"; + /** The unique identifier of the author. */ + id?: string; + /** The decentralized identifier (DID) of the author. */ + did?: string; + /** The handle of the author. */ + handle?: string; + /** The display name of the author. */ + displayName?: string; + /** The URL of the author's avatar image. */ + avatar?: string; +} + +const hashAuthor = "author"; + +export function isAuthor(v: V) { + return is$typed(v, id, hashAuthor); +} + +export function validateAuthor(v: V) { + return validate(v, id, hashAuthor); +} + +export interface ShoutView { + $type?: "app.rocksky.shout.defs#shoutView"; + /** The unique identifier of the shout. */ + id?: string; + /** The content of the shout. */ + message?: string; + /** The ID of the parent shout if this is a reply, otherwise null. */ + parent?: string; + /** The date and time when the shout was created. */ + createdAt?: string; + author?: Author; +} + +const hashShoutView = "shoutView"; + +export function isShoutView(v: V) { + return is$typed(v, id, hashShoutView); +} + +export function validateShoutView(v: V) { + return validate(v, id, hashShoutView); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/getAlbumShouts.ts b/apps/feeds/src/lex/types/app/rocksky/shout/getAlbumShouts.ts new file mode 100644 index 00000000..75736048 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/getAlbumShouts.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = { + /** The unique identifier of the album to retrieve shouts for */ + uri: string; + /** The maximum number of shouts to return */ + limit?: number; + /** The number of shouts to skip before starting to collect the result set */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + shouts?: (AppRockskyShoutDefs.ShoutViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/getArtistShouts.ts b/apps/feeds/src/lex/types/app/rocksky/shout/getArtistShouts.ts new file mode 100644 index 00000000..edbdf5f1 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/getArtistShouts.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = { + /** The URI of the artist to retrieve shouts for */ + uri: string; + /** The maximum number of shouts to return */ + limit?: number; + /** The number of shouts to skip before starting to collect the result set */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + shouts?: (AppRockskyShoutDefs.ShoutViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/getProfileShouts.ts b/apps/feeds/src/lex/types/app/rocksky/shout/getProfileShouts.ts new file mode 100644 index 00000000..fd0f7ea1 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/getProfileShouts.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = { + /** The DID or handle of the actor */ + did: string; + /** The offset for pagination */ + offset?: number; + /** The maximum number of shouts to return */ + limit?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + shouts?: (AppRockskyShoutDefs.ShoutViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/getShoutReplies.ts b/apps/feeds/src/lex/types/app/rocksky/shout/getShoutReplies.ts new file mode 100644 index 00000000..11537b73 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/getShoutReplies.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = { + /** The URI of the shout to retrieve replies for */ + uri: string; + /** The maximum number of shouts to return */ + limit?: number; + /** The number of shouts to skip before starting to collect the result set */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + shouts?: (AppRockskyShoutDefs.ShoutViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/getTrackShouts.ts b/apps/feeds/src/lex/types/app/rocksky/shout/getTrackShouts.ts new file mode 100644 index 00000000..00593e92 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/getTrackShouts.ts @@ -0,0 +1,29 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = { + /** The URI of the track to retrieve shouts for */ + uri: string; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + shouts?: (AppRockskyShoutDefs.ShoutViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/removeShout.ts b/apps/feeds/src/lex/types/app/rocksky/shout/removeShout.ts new file mode 100644 index 00000000..1828ae65 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/removeShout.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = { + /** The ID of the shout to be removed */ + id: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyShoutDefs.ShoutView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/replyShout.ts b/apps/feeds/src/lex/types/app/rocksky/shout/replyShout.ts new file mode 100644 index 00000000..55374b08 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/replyShout.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The unique identifier of the shout to reply to */ + shoutId: string; + /** The content of the reply */ + message: string; +} + +export type OutputSchema = AppRockskyShoutDefs.ShoutView; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/shout/reportShout.ts b/apps/feeds/src/lex/types/app/rocksky/shout/reportShout.ts new file mode 100644 index 00000000..239dc4fc --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/shout/reportShout.ts @@ -0,0 +1,33 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyShoutDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The unique identifier of the shout to report */ + shoutId: string; + /** The reason for reporting the shout */ + reason?: string; +} + +export type OutputSchema = AppRockskyShoutDefs.ShoutView; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/song.ts b/apps/feeds/src/lex/types/app/rocksky/song.ts new file mode 100644 index 00000000..c4328da8 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/song.ts @@ -0,0 +1,77 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type { BlobRef } from "@atp/lexicon"; +import { validate as _validate } from "../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../util.ts"; +import type * as AppRockskyArtistDefs from "./artist/defs.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.song"; + +export interface Record { + $type: "app.rocksky.song"; + /** The title of the song. */ + title: string; + /** The artist of the song. */ + artist: string; + /** The artists of the song with MusicBrainz IDs. */ + artists?: (AppRockskyArtistDefs.ArtistMbid)[]; + /** The album artist of the song. */ + albumArtist: string; + /** The album of the song. */ + album: string; + /** The duration of the song in seconds. */ + duration: number; + /** The track number of the song in the album. */ + trackNumber?: number; + /** The disc number of the song in the album. */ + discNumber?: number; + /** The release date of the song. */ + releaseDate?: string; + /** The year the song was released. */ + year?: number; + /** The genre of the song. */ + genre?: string; + /** The tags of the song. */ + tags?: (string)[]; + /** The composer of the song. */ + composer?: string; + /** The lyrics of the song. */ + lyrics?: string; + /** The copyright message of the song. */ + copyrightMessage?: string; + /** Informations about the song */ + wiki?: string; + /** The album art of the song. */ + albumArt?: BlobRef; + /** The URL of the album art of the song. */ + albumArtUrl?: string; + /** The YouTube link of the song. */ + youtubeLink?: string; + /** The Spotify link of the song. */ + spotifyLink?: string; + /** The Tidal link of the song. */ + tidalLink?: string; + /** The Apple Music link of the song. */ + appleMusicLink?: string; + /** The date when the song was created. */ + createdAt: string; + /** The MusicBrainz ID of the song. */ + mbid?: string; + /** The label of the song. */ + label?: string; + [k: string]: unknown; +} + +const hashRecord = "main"; + +export function isRecord(v: V) { + return is$typed(v, id, hashRecord); +} + +export function validateRecord(v: V) { + return validate(v, id, hashRecord, true); +} + +export type Main = Record; diff --git a/apps/feeds/src/lex/types/app/rocksky/song/createSong.ts b/apps/feeds/src/lex/types/app/rocksky/song/createSong.ts new file mode 100644 index 00000000..21d0c7b1 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/song/createSong.ts @@ -0,0 +1,53 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "./defs.ts"; + +export type QueryParams = globalThis.Record; + +export interface InputSchema { + /** The title of the song */ + title: string; + /** The artist of the song */ + artist: string; + /** The album artist of the song, if different from the main artist */ + albumArtist: string; + /** The album of the song, if applicable */ + album: string; + /** The duration of the song in seconds */ + duration?: number; + /** The MusicBrainz ID of the song, if available */ + mbId?: string; + /** The URL of the album art for the song */ + albumArt?: string; + /** The track number of the song in the album, if applicable */ + trackNumber?: number; + /** The release date of the song, formatted as YYYY-MM-DD */ + releaseDate?: string; + /** The year the song was released */ + year?: number; + /** The disc number of the song in the album, if applicable */ + discNumber?: number; + /** The lyrics of the song, if available */ + lyrics?: string; +} + +export type OutputSchema = AppRockskySongDefs.SongViewDetailed; + +export interface HandlerInput { + encoding: "application/json"; + body: InputSchema; +} + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/song/defs.ts b/apps/feeds/src/lex/types/app/rocksky/song/defs.ts new file mode 100644 index 00000000..dca38ac5 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/song/defs.ts @@ -0,0 +1,100 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.song.defs"; + +export interface SongViewBasic { + $type?: "app.rocksky.song.defs#songViewBasic"; + /** The unique identifier of the song. */ + id?: string; + /** The title of the song. */ + title?: string; + /** The artist of the song. */ + artist?: string; + /** The artist of the album the song belongs to. */ + albumArtist?: string; + /** The URL of the album art image. */ + albumArt?: string; + /** The URI of the song. */ + uri?: string; + /** The album of the song. */ + album?: string; + /** The duration of the song in milliseconds. */ + duration?: number; + /** The track number of the song in the album. */ + trackNumber?: number; + /** The disc number of the song in the album. */ + discNumber?: number; + /** The number of times the song has been played. */ + playCount?: number; + /** The number of unique listeners who have played the song. */ + uniqueListeners?: number; + /** The URI of the album the song belongs to. */ + albumUri?: string; + /** The URI of the artist of the song. */ + artistUri?: string; + /** The SHA256 hash of the song. */ + sha256?: string; + /** The timestamp when the song was created. */ + createdAt?: string; +} + +const hashSongViewBasic = "songViewBasic"; + +export function isSongViewBasic(v: V) { + return is$typed(v, id, hashSongViewBasic); +} + +export function validateSongViewBasic(v: V) { + return validate(v, id, hashSongViewBasic); +} + +export interface SongViewDetailed { + $type?: "app.rocksky.song.defs#songViewDetailed"; + /** The unique identifier of the song. */ + id?: string; + /** The title of the song. */ + title?: string; + /** The artist of the song. */ + artist?: string; + /** The artist of the album the song belongs to. */ + albumArtist?: string; + /** The URL of the album art image. */ + albumArt?: string; + /** The URI of the song. */ + uri?: string; + /** The album of the song. */ + album?: string; + /** The duration of the song in milliseconds. */ + duration?: number; + /** The track number of the song in the album. */ + trackNumber?: number; + /** The disc number of the song in the album. */ + discNumber?: number; + /** The number of times the song has been played. */ + playCount?: number; + /** The number of unique listeners who have played the song. */ + uniqueListeners?: number; + /** The URI of the album the song belongs to. */ + albumUri?: string; + /** The URI of the artist of the song. */ + artistUri?: string; + /** The SHA256 hash of the song. */ + sha256?: string; + /** The timestamp when the song was created. */ + createdAt?: string; +} + +const hashSongViewDetailed = "songViewDetailed"; + +export function isSongViewDetailed(v: V) { + return is$typed(v, id, hashSongViewDetailed); +} + +export function validateSongViewDetailed(v: V) { + return validate(v, id, hashSongViewDetailed); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/song/getSong.ts b/apps/feeds/src/lex/types/app/rocksky/song/getSong.ts new file mode 100644 index 00000000..cce18d38 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/song/getSong.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "./defs.ts"; + +export type QueryParams = { + /** The unique identifier of the song to retrieve */ + uri: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskySongDefs.SongViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/song/getSongs.ts b/apps/feeds/src/lex/types/app/rocksky/song/getSongs.ts new file mode 100644 index 00000000..d82061a6 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/song/getSongs.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskySongDefs from "./defs.ts"; + +export type QueryParams = { + /** The maximum number of songs to return */ + limit?: number; + /** The offset for pagination */ + offset?: number; +}; +export type InputSchema = undefined; + +export interface OutputSchema { + songs?: (AppRockskySongDefs.SongViewBasic)[]; +} + +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/spotify/defs.ts b/apps/feeds/src/lex/types/app/rocksky/spotify/defs.ts new file mode 100644 index 00000000..95e26560 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/spotify/defs.ts @@ -0,0 +1,34 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.spotify.defs"; + +export interface SpotifyTrackView { + $type?: "app.rocksky.spotify.defs#spotifyTrackView"; + /** The unique identifier of the Spotify track. */ + id?: string; + /** The name of the track. */ + name?: string; + /** The name of the artist. */ + artist?: string; + /** The name of the album. */ + album?: string; + /** The duration of the track in milliseconds. */ + duration?: number; + /** A URL to a preview of the track. */ + previewUrl?: string; +} + +const hashSpotifyTrackView = "spotifyTrackView"; + +export function isSpotifyTrackView(v: V) { + return is$typed(v, id, hashSpotifyTrackView); +} + +export function validateSpotifyTrackView(v: V) { + return validate(v, id, hashSpotifyTrackView); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/spotify/getCurrentlyPlaying.ts b/apps/feeds/src/lex/types/app/rocksky/spotify/getCurrentlyPlaying.ts new file mode 100644 index 00000000..f24159f6 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/spotify/getCurrentlyPlaying.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyPlayerDefs from "../player/defs.ts"; + +export type QueryParams = { + /** Handle or DID of the actor to retrieve the currently playing track for. If not provided, defaults to the current user. */ + actor?: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyPlayerDefs.CurrentlyPlayingViewDetailed; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/app/rocksky/spotify/next.ts b/apps/feeds/src/lex/types/app/rocksky/spotify/next.ts new file mode 100644 index 00000000..ed8f6295 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/spotify/next.ts @@ -0,0 +1,13 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = globalThis.Record; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/spotify/pause.ts b/apps/feeds/src/lex/types/app/rocksky/spotify/pause.ts new file mode 100644 index 00000000..ed8f6295 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/spotify/pause.ts @@ -0,0 +1,13 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = globalThis.Record; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/spotify/play.ts b/apps/feeds/src/lex/types/app/rocksky/spotify/play.ts new file mode 100644 index 00000000..ed8f6295 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/spotify/play.ts @@ -0,0 +1,13 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = globalThis.Record; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/spotify/previous.ts b/apps/feeds/src/lex/types/app/rocksky/spotify/previous.ts new file mode 100644 index 00000000..ed8f6295 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/spotify/previous.ts @@ -0,0 +1,13 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = globalThis.Record; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/spotify/seek.ts b/apps/feeds/src/lex/types/app/rocksky/spotify/seek.ts new file mode 100644 index 00000000..266ae9da --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/spotify/seek.ts @@ -0,0 +1,16 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +export type QueryParams = { + /** The position in seconds to seek to */ + position: number; +}; +export type InputSchema = undefined; +export type HandlerInput = void; + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | void; diff --git a/apps/feeds/src/lex/types/app/rocksky/stats/defs.ts b/apps/feeds/src/lex/types/app/rocksky/stats/defs.ts new file mode 100644 index 00000000..cb4566d4 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/stats/defs.ts @@ -0,0 +1,32 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "app.rocksky.stats.defs"; + +export interface StatsView { + $type?: "app.rocksky.stats.defs#statsView"; + /** The total number of scrobbles. */ + scrobbles?: number; + /** The total number of unique artists scrobbled. */ + artists?: number; + /** The total number of tracks marked as loved. */ + lovedTracks?: number; + /** The total number of unique albums scrobbled. */ + albums?: number; + /** The total number of unique tracks scrobbled. */ + tracks?: number; +} + +const hashStatsView = "statsView"; + +export function isStatsView(v: V) { + return is$typed(v, id, hashStatsView); +} + +export function validateStatsView(v: V) { + return validate(v, id, hashStatsView); +} diff --git a/apps/feeds/src/lex/types/app/rocksky/stats/getStats.ts b/apps/feeds/src/lex/types/app/rocksky/stats/getStats.ts new file mode 100644 index 00000000..71af5f61 --- /dev/null +++ b/apps/feeds/src/lex/types/app/rocksky/stats/getStats.ts @@ -0,0 +1,25 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import type * as AppRockskyStatsDefs from "./defs.ts"; + +export type QueryParams = { + /** The DID or handle of the user to get stats for. */ + did: string; +}; +export type InputSchema = undefined; +export type OutputSchema = AppRockskyStatsDefs.StatsView; +export type HandlerInput = void; + +export interface HandlerSuccess { + encoding: "application/json"; + body: OutputSchema; + headers?: { [key: string]: string }; +} + +export interface HandlerError { + status: number; + message?: string; +} + +export type HandlerOutput = HandlerError | HandlerSuccess; diff --git a/apps/feeds/src/lex/types/com/atproto/repo/strongRef.ts b/apps/feeds/src/lex/types/com/atproto/repo/strongRef.ts new file mode 100644 index 00000000..6f63e509 --- /dev/null +++ b/apps/feeds/src/lex/types/com/atproto/repo/strongRef.ts @@ -0,0 +1,24 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { validate as _validate } from "../../../../lexicons.ts"; +import { is$typed as _is$typed } from "../../../../util.ts"; + +const is$typed = _is$typed, validate = _validate; +const id = "com.atproto.repo.strongRef"; + +export interface Main { + $type?: "com.atproto.repo.strongRef"; + uri: string; + cid: string; +} + +const hashMain = "main"; + +export function isMain(v: V) { + return is$typed(v, id, hashMain); +} + +export function validateMain(v: V) { + return validate
(v, id, hashMain); +} diff --git a/apps/feeds/src/lex/util.ts b/apps/feeds/src/lex/util.ts new file mode 100644 index 00000000..a42351ee --- /dev/null +++ b/apps/feeds/src/lex/util.ts @@ -0,0 +1,78 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ + +import type { ValidationResult } from "@atp/lexicon"; + +export type OmitKey = { + [K2 in keyof T as K2 extends K ? never : K2]: T[K2]; +}; + +export type $Typed = V & { $type: T }; +export type Un$Typed = OmitKey; + +export type $Type = Hash extends "main" + ? Id + : `${Id}#${Hash}`; + +function isObject(v: V): v is V & object { + return v != null && typeof v === "object"; +} + +function is$type( + $type: unknown, + id: Id, + hash: Hash, +): $type is $Type { + return hash === "main" + ? $type === id + // $type === `${id}#${hash}` + : typeof $type === "string" && + $type.length === id.length + 1 + hash.length && + $type.charCodeAt(id.length) === 35 /* '#' */ && + $type.startsWith(id) && + $type.endsWith(hash); +} + +export type $TypedObject = V extends + { + $type: $Type; + } ? V + : V extends { $type?: string } + ? V extends { $type?: infer T extends $Type } ? V & { $type: T } + : never + : V & { $type: $Type }; + +export function is$typed( + v: V, + id: Id, + hash: Hash, +): v is $TypedObject { + return isObject(v) && "$type" in v && is$type(v.$type, id, hash); +} + +export function maybe$typed( + v: V, + id: Id, + hash: Hash, +): v is V & object & { $type?: $Type } { + return ( + isObject(v) && + ("$type" in v ? v.$type === undefined || is$type(v.$type, id, hash) : true) + ); +} + +export type Validator = (v: unknown) => ValidationResult; +export type ValidatorParam = V extends Validator + ? R + : never; + +/** + * Utility function that allows to convert a "validate*" utility function into a + * type predicate. + */ +export function asPredicate(validate: V) { + return function (v: T): v is T & ValidatorParam { + return validate(v).success; + }; +} diff --git a/apps/feeds/src/schema/albums.ts b/apps/feeds/src/schema/albums.ts new file mode 100644 index 00000000..eb765242 --- /dev/null +++ b/apps/feeds/src/schema/albums.ts @@ -0,0 +1,28 @@ +import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; +import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; + +const albums = pgTable("albums", { + id: text("xata_id") + .primaryKey() + .default(sql`xata_id()`), + title: text("title").notNull(), + artist: text("artist").notNull(), + releaseDate: text("release_date"), + year: integer("year"), + albumArt: text("album_art"), + uri: text("uri").unique(), + artistUri: text("artist_uri"), + appleMusicLink: text("apple_music_link").unique(), + spotifyLink: text("spotify_link").unique(), + tidalLink: text("tidal_link").unique(), + youtubeLink: text("youtube_link").unique(), + sha256: text("sha256").unique().notNull(), + createdAt: timestamp("xata_createdat").defaultNow().notNull(), + updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), + xataVersion: integer("xata_version"), +}); + +export type SelectAlbum = InferSelectModel; +export type InsertAlbum = InferInsertModel; + +export default albums; diff --git a/apps/feeds/src/schema/artists.ts b/apps/feeds/src/schema/artists.ts new file mode 100644 index 00000000..b9d3e034 --- /dev/null +++ b/apps/feeds/src/schema/artists.ts @@ -0,0 +1,29 @@ +import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; +import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; + +const artists = pgTable("artists", { + id: text("xata_id") + .primaryKey() + .default(sql`xata_id()`), + name: text("name").notNull(), + biography: text("biography"), + born: timestamp("born"), + bornIn: text("born_in"), + died: timestamp("died"), + picture: text("picture"), + sha256: text("sha256").unique().notNull(), + uri: text("uri").unique(), + appleMusicLink: text("apple_music_link"), + spotifyLink: text("spotify_link"), + tidalLink: text("tidal_link"), + youtubeLink: text("youtube_link"), + genres: text("genres").array(), + createdAt: timestamp("xata_createdat").defaultNow().notNull(), + updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), + xataVersion: integer("xata_version"), +}); + +export type SelectArtist = InferSelectModel; +export type InsertArtist = InferInsertModel; + +export default artists; diff --git a/apps/feeds/src/schema/feeds.ts b/apps/feeds/src/schema/feeds.ts new file mode 100644 index 00000000..a14bec0b --- /dev/null +++ b/apps/feeds/src/schema/feeds.ts @@ -0,0 +1,26 @@ +import type { InferInsertModel, InferSelectModel } from "drizzle-orm"; +import { sql } from "drizzle-orm"; +import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import users from "./users.ts"; + +const feeds = pgTable("feeds", { + id: text("xata_id") + .primaryKey() + .default(sql`xata_id()`), + displayName: text("display_name").notNull(), + description: text("description"), + did: text("did").notNull(), + uri: text("uri").notNull().unique(), + avatar: text("avatar"), + userId: text("user_id") + .notNull() + .references(() => users.id), + xataVersion: integer("xata_version"), + createdAt: timestamp("xata_createdat").defaultNow().notNull(), + updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), +}); + +export type SelectFeed = InferSelectModel; +export type InsertFeed = InferInsertModel; + +export default feeds; diff --git a/apps/feeds/src/schema/loved-tracks.ts b/apps/feeds/src/schema/loved-tracks.ts new file mode 100644 index 00000000..fc8959d9 --- /dev/null +++ b/apps/feeds/src/schema/loved-tracks.ts @@ -0,0 +1,23 @@ +import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; +import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import tracks from "./tracks.ts"; +import users from "./users.ts"; + +const lovedTracks = pgTable("loved_tracks", { + id: text("xata_id") + .primaryKey() + .default(sql`xata_id()`), + userId: text("user_id") + .notNull() + .references(() => users.id), + trackId: text("track_id") + .notNull() + .references(() => tracks.id), + uri: text("uri").unique(), + createdAt: timestamp("xata_createdat").defaultNow().notNull(), +}); + +export type SelectLovedTrack = InferSelectModel; +export type InsertLovedTrack = InferInsertModel; + +export default lovedTracks; diff --git a/apps/feeds/src/schema/mod.ts b/apps/feeds/src/schema/mod.ts new file mode 100644 index 00000000..4206f074 --- /dev/null +++ b/apps/feeds/src/schema/mod.ts @@ -0,0 +1,17 @@ +import albums from "./albums.ts"; +import artists from "./artists.ts"; +import tracks from "./tracks.ts"; +import scrobbles from "./scrobbles.ts"; +import users from "./users.ts"; +import lovedTracks from "./loved-tracks.ts"; +import feeds from "./feeds.ts"; + +export default { + albums, + artists, + lovedTracks, + tracks, + scrobbles, + users, + feeds, +}; diff --git a/apps/feeds/src/schema/scrobbles.ts b/apps/feeds/src/schema/scrobbles.ts new file mode 100644 index 00000000..2150da7d --- /dev/null +++ b/apps/feeds/src/schema/scrobbles.ts @@ -0,0 +1,26 @@ +import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; +import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import albums from "./albums.ts"; +import artists from "./artists.ts"; +import tracks from "./tracks.ts"; +import users from "./users.ts"; + +const scrobbles = pgTable("scrobbles", { + id: text("xata_id") + .primaryKey() + .default(sql`xata_id()`), + userId: text("user_id").references(() => users.id), + trackId: text("track_id").references(() => tracks.id), + albumId: text("album_id").references(() => albums.id), + artistId: text("artist_id").references(() => artists.id), + uri: text("uri").unique(), + createdAt: timestamp("xata_createdat").defaultNow().notNull(), + updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), + xataVersion: integer("xata_version"), + timestamp: timestamp("timestamp").defaultNow().notNull(), +}); + +export type SelectScrobble = InferSelectModel; +export type InsertScrobble = InferInsertModel; + +export default scrobbles; diff --git a/apps/feeds/src/schema/tracks.ts b/apps/feeds/src/schema/tracks.ts new file mode 100644 index 00000000..601ce598 --- /dev/null +++ b/apps/feeds/src/schema/tracks.ts @@ -0,0 +1,38 @@ +import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; +import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; + +const tracks = pgTable("tracks", { + id: text("xata_id") + .primaryKey() + .default(sql`xata_id()`), + title: text("title").notNull(), + artist: text("artist").notNull(), + albumArtist: text("album_artist").notNull(), + albumArt: text("album_art"), + album: text("album").notNull(), + trackNumber: integer("track_number"), + duration: integer("duration").notNull(), + mbId: text("mb_id").unique(), + youtubeLink: text("youtube_link").unique(), + spotifyLink: text("spotify_link").unique(), + appleMusicLink: text("apple_music_link").unique(), + tidalLink: text("tidal_link").unique(), + sha256: text("sha256").unique().notNull(), + discNumber: integer("disc_number"), + lyrics: text("lyrics"), + composer: text("composer"), + genre: text("genre"), + label: text("label"), + copyrightMessage: text("copyright_message"), + uri: text("uri").unique(), + albumUri: text("album_uri"), + artistUri: text("artist_uri"), + createdAt: timestamp("xata_createdat").defaultNow().notNull(), + updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), + xataVersion: integer("xata_version"), +}); + +export type SelectTrack = InferSelectModel; +export type InsertTrack = InferInsertModel; + +export default tracks; diff --git a/apps/feeds/src/schema/users.ts b/apps/feeds/src/schema/users.ts new file mode 100644 index 00000000..4b4df2bc --- /dev/null +++ b/apps/feeds/src/schema/users.ts @@ -0,0 +1,20 @@ +import { type InferSelectModel, sql } from "drizzle-orm"; +import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; + +const users = pgTable("users", { + id: text("xata_id") + .primaryKey() + .default(sql`xata_id()`), + did: text("did").unique().notNull(), + displayName: text("display_name"), + handle: text("handle").unique().notNull(), + avatar: text("avatar").notNull(), + createdAt: timestamp("xata_createdat").defaultNow().notNull(), + updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), + xataVersion: integer("xata_version"), +}); + +export type SelectUser = InferSelectModel; +export type InsertUser = InferSelectModel; + +export default users; diff --git a/apps/feeds/src/utils/auth.ts b/apps/feeds/src/utils/auth.ts new file mode 100644 index 00000000..7009ab5f --- /dev/null +++ b/apps/feeds/src/utils/auth.ts @@ -0,0 +1,87 @@ +import { MethodAuthContext, verifyJwt } from "@atp/xrpc-server"; +import { DidResolver } from "@atp/identity"; + +export type NullOutput = { + credentials: { + type: "none"; + iss: null; + }; + artifacts: unknown; +}; + +export type StandardOutput = { + credentials: { + type: "standard"; + iss: string; + }; + artifacts: unknown; +}; + +export class AuthVerifier { + ownDid: string; + didResolver: DidResolver; + constructor(ownDid: string, didResolver: DidResolver) { + this.ownDid = ownDid ?? ""; + this.didResolver = didResolver; + } + + standardOptional = async ( + ctx: MethodAuthContext, + ): Promise => { + try { + const authorization = ctx.req.headers.get("Authorization") ?? ""; + + if (!authorization) { + return this.nullCreds(); + } + + // Check for Bearer token + const BEARER = "Bearer "; + if (authorization.startsWith(BEARER)) { + const jwt = authorization.replace(BEARER, "").trim(); + + try { + const parsed = await verifyJwt( + jwt, + null, + null, + async (did: string) => { + return await this.didResolver.resolveAtprotoKey(did); + }, + ); + return { + credentials: { + type: "standard", + iss: parsed.iss, + }, + artifacts: null, + }; + } catch (error) { + // Log JWT verification errors for debugging + console.error("JWT verification failed:", error); + console.error( + "JWT preview:", + jwt.length > 20 ? jwt.substring(0, 20) + "..." : jwt, + ); + console.error("ownDid:", this.ownDid); + // If JWT verification fails, treat as unauthenticated + return this.nullCreds(); + } + } else { + return this.nullCreds(); + } + } catch (error) { + console.error("Unexpected error in standardOptional:", error); + return this.nullCreds(); + } + }; + nullCreds = (): NullOutput => { + return { + credentials: { + type: "none", + iss: null, + }, + artifacts: null, + }; + }; +} diff --git a/apps/feeds/src/utils/env.ts b/apps/feeds/src/utils/env.ts new file mode 100644 index 00000000..956571ce --- /dev/null +++ b/apps/feeds/src/utils/env.ts @@ -0,0 +1,16 @@ +import { cleanEnv, str, port, host, testOnly } from "envalid"; +import process from "node:process"; + +export const env = cleanEnv(process.env, { + NODE_ENV: str({ + devDefault: testOnly("test"), + choices: ["development", "production", "test"], + }), + + ROCKSKY_FEEDGEN_DOMAIN: host({ devDefault: "localhost" }), + ROCKSKY_FEEDGEN_PORT: port({ devDefault: 8002 }), + XATA_POSTGRES_URL: str({ + devDefault: + "postgresql://postgres:mysecretpassword@localhost:5433/rocksky?sslmode=disable", + }), +});