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

Add Story and Stories schemas and update getStories

+269 -15
+69
apps/api/lexicons/feed/defs.json
··· 101 101 } 102 102 } 103 103 }, 104 + "storyView": { 105 + "type": "object", 106 + "properties": { 107 + "album": { 108 + "type": "string" 109 + }, 110 + "albumArt": { 111 + "type": "string", 112 + "format": "uri" 113 + }, 114 + "albumArtist": { 115 + "type": "string" 116 + }, 117 + "albumUri": { 118 + "type": "string", 119 + "format": "at-uri" 120 + }, 121 + "artist": { 122 + "type": "string" 123 + }, 124 + "artistUri": { 125 + "type": "string", 126 + "format": "at-uri" 127 + }, 128 + "avatar": { 129 + "type": "string", 130 + "format": "uri" 131 + }, 132 + "createdAt": { 133 + "type": "string" 134 + }, 135 + "did": { 136 + "type": "string", 137 + "format": "at-identifier" 138 + }, 139 + "handle": { 140 + "type": "string" 141 + }, 142 + "id": { 143 + "type": "string" 144 + }, 145 + "title": { 146 + "type": "string" 147 + }, 148 + "trackId": { 149 + "type": "string" 150 + }, 151 + "trackUri": { 152 + "type": "string", 153 + "format": "at-uri" 154 + }, 155 + "uri": { 156 + "type": "string", 157 + "format": "at-uri" 158 + } 159 + } 160 + }, 161 + "storiesView": { 162 + "type": "object", 163 + "properties": { 164 + "stories": { 165 + "type": "array", 166 + "items": { 167 + "type": "ref", 168 + "ref": "app.rocksky.feed.defs#storyView" 169 + } 170 + } 171 + } 172 + }, 104 173 "feedGeneratorsView": { 105 174 "type": "object", 106 175 "properties": {
+1 -1
apps/api/lexicons/feed/getStories.json
··· 19 19 "encoding": "application/json", 20 20 "schema": { 21 21 "type": "ref", 22 - "ref": "app.rocksky.feed.defs#nowPlayingsView" 22 + "ref": "app.rocksky.feed.defs#storiesView" 23 23 } 24 24 } 25 25 }
+69
apps/api/pkl/defs/feed/defs.pkl
··· 103 103 } 104 104 } 105 105 } 106 + ["storyView"] = new ObjectType { 107 + type = "object" 108 + properties { 109 + ["album"] = new StringType { 110 + type = "string" 111 + } 112 + ["albumArt"] = new StringType { 113 + type = "string" 114 + format = "uri" 115 + } 116 + ["albumArtist"] = new StringType { 117 + type = "string" 118 + } 119 + ["albumUri"] = new StringType { 120 + type = "string" 121 + format = "at-uri" 122 + } 123 + ["artist"] = new StringType { 124 + type = "string" 125 + } 126 + ["artistUri"] = new StringType { 127 + type = "string" 128 + format = "at-uri" 129 + } 130 + ["avatar"] = new StringType { 131 + type = "string" 132 + format = "uri" 133 + } 134 + ["createdAt"] = new StringType { 135 + type = "string" 136 + } 137 + ["did"] = new StringType { 138 + type = "string" 139 + format = "at-identifier" 140 + } 141 + ["handle"] = new StringType { 142 + type = "string" 143 + } 144 + ["id"] = new StringType { 145 + type = "string" 146 + } 147 + ["title"] = new StringType { 148 + type = "string" 149 + } 150 + ["trackId"] = new StringType { 151 + type = "string" 152 + } 153 + ["trackUri"] = new StringType { 154 + type = "string" 155 + format = "at-uri" 156 + } 157 + ["uri"] = new StringType { 158 + type = "string" 159 + format = "at-uri" 160 + } 161 + } 162 + } 163 + ["storiesView"] = new ObjectType { 164 + type = "object" 165 + properties { 166 + ["stories"] = new Array { 167 + type = "array" 168 + items = new Ref { 169 + type = "ref" 170 + ref = "app.rocksky.feed.defs#storyView" 171 + } 172 + } 173 + } 174 + } 106 175 ["feedGeneratorsView"] = new ObjectType { 107 176 type = "object" 108 177 properties {
+1 -1
apps/api/pkl/defs/feed/getStories.pkl
··· 20 20 encoding = "application/json" 21 21 schema = new Ref { 22 22 type = "ref" 23 - ref = "app.rocksky.feed.defs#nowPlayingsView" 23 + ref = "app.rocksky.feed.defs#storiesView" 24 24 } 25 25 } 26 26 }
+70 -1
apps/api/src/lexicon/lexicons.ts
··· 2617 2617 }, 2618 2618 }, 2619 2619 }, 2620 + storyView: { 2621 + type: "object", 2622 + properties: { 2623 + album: { 2624 + type: "string", 2625 + }, 2626 + albumArt: { 2627 + type: "string", 2628 + format: "uri", 2629 + }, 2630 + albumArtist: { 2631 + type: "string", 2632 + }, 2633 + albumUri: { 2634 + type: "string", 2635 + format: "at-uri", 2636 + }, 2637 + artist: { 2638 + type: "string", 2639 + }, 2640 + artistUri: { 2641 + type: "string", 2642 + format: "at-uri", 2643 + }, 2644 + avatar: { 2645 + type: "string", 2646 + format: "uri", 2647 + }, 2648 + createdAt: { 2649 + type: "string", 2650 + }, 2651 + did: { 2652 + type: "string", 2653 + format: "at-identifier", 2654 + }, 2655 + handle: { 2656 + type: "string", 2657 + }, 2658 + id: { 2659 + type: "string", 2660 + }, 2661 + title: { 2662 + type: "string", 2663 + }, 2664 + trackId: { 2665 + type: "string", 2666 + }, 2667 + trackUri: { 2668 + type: "string", 2669 + format: "at-uri", 2670 + }, 2671 + uri: { 2672 + type: "string", 2673 + format: "at-uri", 2674 + }, 2675 + }, 2676 + }, 2677 + storiesView: { 2678 + type: "object", 2679 + properties: { 2680 + stories: { 2681 + type: "array", 2682 + items: { 2683 + type: "ref", 2684 + ref: "lex:app.rocksky.feed.defs#storyView", 2685 + }, 2686 + }, 2687 + }, 2688 + }, 2620 2689 feedGeneratorsView: { 2621 2690 type: "object", 2622 2691 properties: { ··· 2970 3039 encoding: "application/json", 2971 3040 schema: { 2972 3041 type: "ref", 2973 - ref: "lex:app.rocksky.feed.defs#nowPlayingsView", 3042 + ref: "lex:app.rocksky.feed.defs#storiesView", 2974 3043 }, 2975 3044 }, 2976 3045 },
+48
apps/api/src/lexicon/types/app/rocksky/feed/defs.ts
··· 88 88 return lexicons.validate("app.rocksky.feed.defs#nowPlayingsView", v); 89 89 } 90 90 91 + export interface StoryView { 92 + album?: string; 93 + albumArt?: string; 94 + albumArtist?: string; 95 + albumUri?: string; 96 + artist?: string; 97 + artistUri?: string; 98 + avatar?: string; 99 + createdAt?: string; 100 + did?: string; 101 + handle?: string; 102 + id?: string; 103 + title?: string; 104 + trackId?: string; 105 + trackUri?: string; 106 + uri?: string; 107 + [k: string]: unknown; 108 + } 109 + 110 + export function isStoryView(v: unknown): v is StoryView { 111 + return ( 112 + isObj(v) && 113 + hasProp(v, "$type") && 114 + v.$type === "app.rocksky.feed.defs#storyView" 115 + ); 116 + } 117 + 118 + export function validateStoryView(v: unknown): ValidationResult { 119 + return lexicons.validate("app.rocksky.feed.defs#storyView", v); 120 + } 121 + 122 + export interface StoriesView { 123 + stories?: StoryView[]; 124 + [k: string]: unknown; 125 + } 126 + 127 + export function isStoriesView(v: unknown): v is StoriesView { 128 + return ( 129 + isObj(v) && 130 + hasProp(v, "$type") && 131 + v.$type === "app.rocksky.feed.defs#storiesView" 132 + ); 133 + } 134 + 135 + export function validateStoriesView(v: unknown): ValidationResult { 136 + return lexicons.validate("app.rocksky.feed.defs#storiesView", v); 137 + } 138 + 91 139 export interface FeedGeneratorsView { 92 140 feeds?: FeedGeneratorView[]; 93 141 [k: string]: unknown;
+1 -1
apps/api/src/lexicon/types/app/rocksky/feed/getStories.ts
··· 15 15 } 16 16 17 17 export type InputSchema = undefined; 18 - export type OutputSchema = AppRockskyFeedDefs.NowPlayingsView; 18 + export type OutputSchema = AppRockskyFeedDefs.StoriesView; 19 19 export type HandlerInput = undefined; 20 20 21 21 export interface HandlerSuccess {
+3 -3
apps/api/src/xrpc/app/rocksky/feed/getStories.ts
··· 3 3 import { desc, eq, sql } from "drizzle-orm"; 4 4 import { Cache, Duration, Effect, pipe } from "effect"; 5 5 import type { Server } from "lexicon"; 6 - import type { NowPlayingView } from "lexicon/types/app/rocksky/feed/defs"; 6 + import type { StoriesView } from "lexicon/types/app/rocksky/feed/defs"; 7 7 import type { QueryParams } from "lexicon/types/app/rocksky/feed/getStories"; 8 8 import albums from "schema/albums"; 9 9 import artists from "schema/artists"; ··· 97 97 data, 98 98 }: { 99 99 data: NowPlayingRecord[]; 100 - }): Effect.Effect<{ nowPlayings: NowPlayingView[] }, never> => { 100 + }): Effect.Effect<StoriesView, never> => { 101 101 return Effect.sync(() => ({ 102 - nowPlayings: data.map((record) => ({ 102 + stories: data.map((record) => ({ 103 103 album: record.album, 104 104 albumArt: record.albumArt, 105 105 albumArtist: record.albumArtist,
+7 -8
apps/web/src/hooks/useNowPlaying.tsx
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 2 import { client } from "../api"; 3 3 4 - export type NowPlayings = { 4 + export type Stories = { 5 5 id: string; 6 6 title: string; 7 7 artist: string; ··· 16 16 trackUri: string; 17 17 }[]; 18 18 19 - export const useNowPlayingsQuery = () => 19 + export const useStoriesQuery = () => 20 20 useQuery({ 21 - queryKey: ["now-playings"], 21 + queryKey: ["stories"], 22 22 queryFn: () => 23 - client.get<{ nowPlayings: NowPlayings }>( 24 - "/xrpc/app.rocksky.feed.getNowPlayings", 25 - { params: { size: 100 } }, 26 - ), 27 - select: (res) => res.data.nowPlayings || [], 23 + client.get<{ stories: Stories }>("/xrpc/app.rocksky.feed.getStories", { 24 + params: { size: 100 }, 25 + }), 26 + select: (res) => res.data.stories || [], 28 27 });