A decentralized music tracking and discovery platform built on AT Protocol 🎵

implement search xrpc method

+128 -108
+17 -27
rockskyapi/rocksky-auth/lexicons/feed/defs.json
··· 5 5 "searchResultsView": { 6 6 "type": "object", 7 7 "properties": { 8 - "artists": { 8 + "hits": { 9 9 "type": "array", 10 10 "items": { 11 - "type": "ref", 12 - "ref": "app.rocksky.artist.defs#artistViewBasic" 11 + "type": "union", 12 + "refs": [ 13 + "app.rocksky.song.defs#songViewBasic", 14 + "app.rocksky.album.defs#albumViewBasic", 15 + "app.rocksky.artist.defs#artistViewBasic", 16 + "app.rocksky.playlist.defs#playlistViewBasic", 17 + "app.rocksky.actor.defs#profileViewBasic" 18 + ] 13 19 } 14 20 }, 15 - "tracks": { 16 - "type": "array", 17 - "items": { 18 - "type": "ref", 19 - "ref": "app.rocksky.song.defs#songViewBasic" 20 - } 21 + "processingTimeMs": { 22 + "type": "integer" 21 23 }, 22 - "albums": { 23 - "type": "array", 24 - "items": { 25 - "type": "ref", 26 - "ref": "app.rocksky.album.defs#albumViewBasic" 27 - } 24 + "limit": { 25 + "type": "integer" 28 26 }, 29 - "users": { 30 - "type": "array", 31 - "items": { 32 - "type": "ref", 33 - "ref": "app.rocksky.actor.defs#profileViewBasic" 34 - } 27 + "offset": { 28 + "type": "integer" 35 29 }, 36 - "playlists": { 37 - "type": "array", 38 - "items": { 39 - "type": "ref", 40 - "ref": "app.rocksky.playlist.defs#playlistViewBasic" 41 - } 30 + "estimatedTotalHits": { 31 + "type": "integer" 42 32 } 43 33 } 44 34 },
+23 -34
rockskyapi/rocksky-auth/pkl/defs/feed/defs.pkl
··· 3 3 lexicon = 1 4 4 id = "app.rocksky.feed.defs" 5 5 defs = new Mapping<String, ObjectType> { 6 - ["searchResultsView"] { 6 + ["searchResultsView"] = new ObjectType { 7 7 type = "object" 8 - properties { 9 - ["artists"] = new Array { 8 + properties { 9 + ["hits"] = new Array { 10 10 type = "array" 11 - items = new Ref { 12 - type = "ref" 13 - ref = "app.rocksky.artist.defs#artistViewBasic" 11 + items = new Union { 12 + type = "union" 13 + refs = List( 14 + "app.rocksky.song.defs#songViewBasic", 15 + "app.rocksky.album.defs#albumViewBasic", 16 + "app.rocksky.artist.defs#artistViewBasic", 17 + "app.rocksky.playlist.defs#playlistViewBasic", 18 + "app.rocksky.actor.defs#profileViewBasic" 19 + ) 14 20 } 15 21 } 16 - ["tracks"] = new Array { 17 - type = "array" 18 - items = new Ref { 19 - type = "ref" 20 - ref = "app.rocksky.song.defs#songViewBasic" 21 - } 22 + ["processingTimeMs"] = new IntegerType { 23 + type = "integer" 22 24 } 23 - ["albums"] = new Array { 24 - type = "array" 25 - items = new Ref { 26 - type = "ref" 27 - ref = "app.rocksky.album.defs#albumViewBasic" 28 - } 25 + ["limit"] = new IntegerType { 26 + type = "integer" 29 27 } 30 - 31 - ["users"] = new Array { 32 - type = "array" 33 - items = new Ref { 34 - type = "ref" 35 - ref = "app.rocksky.actor.defs#profileViewBasic" 36 - } 28 + ["offset"] = new IntegerType { 29 + type = "integer" 37 30 } 38 - ["playlists"] = new Array { 39 - type = "array" 40 - items = new Ref { 41 - type = "ref" 42 - ref = "app.rocksky.playlist.defs#playlistViewBasic" 43 - } 31 + ["estimatedTotalHits"] = new IntegerType { 32 + type = "integer" 44 33 } 45 34 } 46 - } 47 35 48 - ["nowPlayingView"] { 36 + } 37 + ["nowPlayingView"] = new ObjectType { 49 38 type = "object" 50 39 properties { 51 40 ["album"] = new StringType { ··· 102 91 } 103 92 } 104 93 } 105 - ["nowPlayingsView"] { 94 + ["nowPlayingsView"] = new ObjectType { 106 95 type = "object" 107 96 properties { 108 97 ["nowPlayings"] = new Array {
+2 -2
rockskyapi/rocksky-auth/pkl/schema/lexicon.pkl
··· 25 25 26 26 class Array extends BaseType { 27 27 type: "array" 28 - items: StringType | IntegerType | Blob | Ref 28 + items: StringType | IntegerType | Blob | Ref | Union 29 29 } 30 30 31 31 class Params { ··· 82 82 lexicon: Int = 1 83 83 id: String 84 84 description: String? 85 - defs: Mapping<String, Procedure> | Mapping<String, Record> | Mapping<String, ObjectType> | Mapping<String, Query> | Null = null 85 + defs: Mapping<String, Procedure> | Mapping<String, Record> | Mapping<String, ObjectType> | Mapping<String, Query> | Mapping<String, Array> | Mapping<String, ObjectType | Array> | Null = null 86 86 87 87
+17 -27
rockskyapi/rocksky-auth/src/lexicon/lexicons.ts
··· 1463 1463 searchResultsView: { 1464 1464 type: 'object', 1465 1465 properties: { 1466 - artists: { 1466 + hits: { 1467 1467 type: 'array', 1468 1468 items: { 1469 - type: 'ref', 1470 - ref: 'lex:app.rocksky.artist.defs#artistViewBasic', 1469 + type: 'union', 1470 + refs: [ 1471 + 'lex:app.rocksky.song.defs#songViewBasic', 1472 + 'lex:app.rocksky.album.defs#albumViewBasic', 1473 + 'lex:app.rocksky.artist.defs#artistViewBasic', 1474 + 'lex:app.rocksky.playlist.defs#playlistViewBasic', 1475 + 'lex:app.rocksky.actor.defs#profileViewBasic', 1476 + ], 1471 1477 }, 1472 1478 }, 1473 - tracks: { 1474 - type: 'array', 1475 - items: { 1476 - type: 'ref', 1477 - ref: 'lex:app.rocksky.song.defs#songViewBasic', 1478 - }, 1479 + processingTimeMs: { 1480 + type: 'integer', 1479 1481 }, 1480 - albums: { 1481 - type: 'array', 1482 - items: { 1483 - type: 'ref', 1484 - ref: 'lex:app.rocksky.album.defs#albumViewBasic', 1485 - }, 1482 + limit: { 1483 + type: 'integer', 1486 1484 }, 1487 - users: { 1488 - type: 'array', 1489 - items: { 1490 - type: 'ref', 1491 - ref: 'lex:app.rocksky.actor.defs#profileViewBasic', 1492 - }, 1485 + offset: { 1486 + type: 'integer', 1493 1487 }, 1494 - playlists: { 1495 - type: 'array', 1496 - items: { 1497 - type: 'ref', 1498 - ref: 'lex:app.rocksky.playlist.defs#playlistViewBasic', 1499 - }, 1488 + estimatedTotalHits: { 1489 + type: 'integer', 1500 1490 }, 1501 1491 }, 1502 1492 },
+14 -7
rockskyapi/rocksky-auth/src/lexicon/types/app/rocksky/feed/defs.ts
··· 5 5 import { lexicons } from '../../../../lexicons' 6 6 import { isObj, hasProp } from '../../../../util' 7 7 import { CID } from 'multiformats/cid' 8 - import * as AppRockskyArtistDefs from '../artist/defs' 9 8 import * as AppRockskySongDefs from '../song/defs' 10 9 import * as AppRockskyAlbumDefs from '../album/defs' 11 - import * as AppRockskyActorDefs from '../actor/defs' 10 + import * as AppRockskyArtistDefs from '../artist/defs' 12 11 import * as AppRockskyPlaylistDefs from '../playlist/defs' 12 + import * as AppRockskyActorDefs from '../actor/defs' 13 13 14 14 export interface SearchResultsView { 15 - artists?: AppRockskyArtistDefs.ArtistViewBasic[] 16 - tracks?: AppRockskySongDefs.SongViewBasic[] 17 - albums?: AppRockskyAlbumDefs.AlbumViewBasic[] 18 - users?: AppRockskyActorDefs.ProfileViewBasic[] 19 - playlists?: AppRockskyPlaylistDefs.PlaylistViewBasic[] 15 + hits?: ( 16 + | AppRockskySongDefs.SongViewBasic 17 + | AppRockskyAlbumDefs.AlbumViewBasic 18 + | AppRockskyArtistDefs.ArtistViewBasic 19 + | AppRockskyPlaylistDefs.PlaylistViewBasic 20 + | AppRockskyActorDefs.ProfileViewBasic 21 + | { $type: string; [k: string]: unknown } 22 + )[] 23 + processingTimeMs?: number 24 + limit?: number 25 + offset?: number 26 + estimatedTotalHits?: number 20 27 [k: string]: unknown 21 28 } 22 29
+55 -11
rockskyapi/rocksky-auth/src/xrpc/app/rocksky/feed/search.ts
··· 1 1 import { Context } from "context"; 2 - import { pipe } from "effect"; 2 + import { Effect, pipe } from "effect"; 3 3 import { Server } from "lexicon"; 4 + import { ProfileViewBasic } from "lexicon/types/app/rocksky/actor/defs"; 5 + import { AlbumViewBasic } from "lexicon/types/app/rocksky/album/defs"; 6 + import { ArtistViewBasic } from "lexicon/types/app/rocksky/artist/defs"; 7 + import { SearchResultsView } from "lexicon/types/app/rocksky/feed/defs"; 8 + import { QueryParams } from "lexicon/types/app/rocksky/feed/search"; 9 + import { PlaylistViewBasic } from "lexicon/types/app/rocksky/playlist/defs"; 10 + import { SongViewBasic } from "lexicon/types/app/rocksky/song/defs"; 4 11 5 12 export default function (server: Server, ctx: Context) { 6 - const search = (params) => pipe(params, retrieve, presentation); 13 + const search = (params) => 14 + pipe({ params, ctx }, retrieve, Effect.flatMap(presentation)); 7 15 server.app.rocksky.feed.search({ 8 16 handler: async ({ params }) => { 9 - const result = search(params); 17 + const result = await Effect.runPromise(search(params)); 10 18 return { 11 19 encoding: "application/json", 12 20 body: result, ··· 15 23 }); 16 24 } 17 25 18 - const retrieve = () => { 19 - // Logic to retrieve search results 20 - return []; 26 + const retrieve = ({ params, ctx }: { params: QueryParams; ctx: Context }) => { 27 + return Effect.tryPromise(async () => 28 + ctx.meilisearch 29 + .post<SearchResults>("multi-search", { 30 + federation: {}, 31 + queries: [ 32 + { 33 + indexUid: "albums", 34 + q: params.query, 35 + }, 36 + { 37 + indexUid: "artists", 38 + q: params.query, 39 + }, 40 + { 41 + indexUid: "tracks", 42 + q: params.query, 43 + }, 44 + { 45 + indexUid: "playlists", 46 + q: params.query, 47 + }, 48 + { 49 + indexUid: "users", 50 + q: params.query, 51 + }, 52 + ], 53 + }) 54 + .then((res) => res.data) 55 + ); 21 56 }; 22 57 23 - const presentation = (results) => { 24 - // Logic to format the search results for presentation 25 - return { 26 - results: [], 27 - }; 58 + const presentation = ( 59 + results: SearchResults 60 + ): Effect.Effect<SearchResultsView, never> => { 61 + return Effect.succeed(results); 62 + }; 63 + 64 + type SearchResults = { 65 + hits: Array< 66 + | SongViewBasic 67 + | ArtistViewBasic 68 + | AlbumViewBasic 69 + | PlaylistViewBasic 70 + | ProfileViewBasic 71 + >; 28 72 };