@rocksky/sdk 0.14.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/library.d.ts CHANGED
@@ -1,4 +1,82 @@
1
1
  import type { Client } from "@atcute/client";
2
+ /** A song in the library, in the Subsonic `Child` shape. */
3
+ export interface LibrarySong {
4
+ id: string;
5
+ title: string;
6
+ artist: string;
7
+ album: string;
8
+ albumArtist?: string;
9
+ /** Seconds, not milliseconds — Subsonic's unit. */
10
+ duration: number;
11
+ coverArt?: string;
12
+ albumId?: string;
13
+ artistId?: string;
14
+ track?: number;
15
+ discNumber?: number;
16
+ genre?: string;
17
+ suffix?: string;
18
+ contentType?: string;
19
+ size?: number;
20
+ musicBrainzId?: string;
21
+ samplingRate?: number;
22
+ }
23
+ /**
24
+ * A library playlist. Subsonic's `Playlist` shape plus two Rocksky extensions:
25
+ * `uri` and `trackArts`.
26
+ */
27
+ export interface LibraryPlaylist {
28
+ id: string;
29
+ name: string;
30
+ songCount: number;
31
+ /** Seconds. */
32
+ duration: number;
33
+ created: string;
34
+ changed: string;
35
+ public: boolean;
36
+ comment?: string;
37
+ coverArt?: string;
38
+ /**
39
+ * AT-URI of the `app.rocksky.playlist` record this playlist is mirrored to.
40
+ * Absent while the record has yet to be published.
41
+ */
42
+ uri?: string;
43
+ /**
44
+ * Album art of up to four of the playlist's tracks, oldest first — enough
45
+ * for a cover mosaic. Absent when none of them have art.
46
+ */
47
+ trackArts?: string[];
48
+ /** Only present on `getPlaylist`. */
49
+ entry?: LibrarySong[];
50
+ }
51
+ /** Envelope every navidrome method replies with. */
52
+ interface SubsonicResponse {
53
+ status: string;
54
+ version?: string;
55
+ type?: string;
56
+ }
57
+ /**
58
+ * Reply to a playlist mutation.
59
+ *
60
+ * The playlist is mirrored to the caller's PDS as an `app.rocksky.playlist`
61
+ * record. That mirror runs after the library has already been updated, so it
62
+ * can't fail the call: when it does fail, the library change still stands and
63
+ * the reason lands in `atprotoError` for the caller to surface.
64
+ */
65
+ export interface LibraryPlaylistMutation extends SubsonicResponse {
66
+ /** The resulting playlist — `createPlaylist` only. */
67
+ playlist?: LibraryPlaylist;
68
+ /** AT-URI of the mirrored record, when one was published or already existed. */
69
+ uri?: string;
70
+ atprotoError?: string;
71
+ }
72
+ export interface LibraryPlaylistsResponse extends SubsonicResponse {
73
+ playlists: {
74
+ playlist: LibraryPlaylist[];
75
+ };
76
+ }
77
+ export interface LibraryPlaylistResponse extends SubsonicResponse {
78
+ playlist: LibraryPlaylist;
79
+ }
2
80
  /**
3
81
  * Authenticated client for the `app.rocksky.library.*` API — the Subsonic /
4
82
  * navidrome-compatible surface over a user's uploaded music.
@@ -98,23 +176,34 @@ export declare class RockskyLibrary {
98
176
  artistId?: string;
99
177
  }): Promise<unknown>;
100
178
  /** `app.rocksky.library.getPlaylists` — requires auth. */
101
- getPlaylists(): Promise<unknown>;
179
+ getPlaylists(): Promise<LibraryPlaylistsResponse>;
102
180
  /** `app.rocksky.library.getPlaylist` — requires auth. */
103
- getPlaylist(id: string): Promise<unknown>;
104
- /** `app.rocksky.library.createPlaylist` — requires auth. */
105
- createPlaylist(name: string): Promise<unknown>;
106
- /** `app.rocksky.library.updatePlaylist` — requires auth. */
181
+ getPlaylist(id: string): Promise<LibraryPlaylistResponse>;
182
+ /**
183
+ * `app.rocksky.library.createPlaylist` requires auth.
184
+ *
185
+ * Also publishes an `app.rocksky.playlist` record to the caller's PDS; see
186
+ * {@link LibraryPlaylistMutation} for how a failure there is reported.
187
+ */
188
+ createPlaylist(name: string): Promise<LibraryPlaylistMutation>;
189
+ /**
190
+ * `app.rocksky.library.updatePlaylist` — requires auth.
191
+ *
192
+ * Renames, adds a song or removes the song at a position, and replays the
193
+ * same change onto the mirrored record.
194
+ */
107
195
  updatePlaylist(playlistId: string, opts?: {
108
196
  name?: string;
109
197
  comment?: string;
110
198
  songIdToAdd?: string;
111
199
  songIndexToRemove?: number;
112
- }): Promise<unknown>;
113
- /** `app.rocksky.library.deletePlaylist` — requires auth. */
114
- deletePlaylist(id: string): Promise<{
115
- status: string;
116
- deleted: number;
117
- }>;
200
+ }): Promise<LibraryPlaylistMutation>;
201
+ /**
202
+ * `app.rocksky.library.deletePlaylist` requires auth.
203
+ *
204
+ * Retracts the mirrored record and the caller's entries in it too.
205
+ */
206
+ deletePlaylist(id: string): Promise<LibraryPlaylistMutation>;
118
207
  /** `app.rocksky.library.deleteSong` — requires auth. */
119
208
  deleteSong(id: string): Promise<{
120
209
  status: string;
@@ -162,4 +251,5 @@ export declare class RockskyLibrary {
162
251
  /** `app.rocksky.library.getInternetRadioStations` — requires auth. */
163
252
  getInternetRadioStations(): Promise<unknown>;
164
253
  }
254
+ export {};
165
255
  //# sourceMappingURL=library.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../src/library.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../src/library.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocksky/sdk",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "TypeScript SDK for Rocksky — built on atcute: AppView reads, AT Protocol PDS writes (scrobble, like, follow, shout), a local dedup index, and Jetstream real-time sync.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,83 @@
1
+ import { afterEach, describe, expect, test } from "bun:test";
2
+
3
+ import { RockskyClient } from "./client.js";
4
+
5
+ const TOKEN = "test-token";
6
+
7
+ /**
8
+ * Swap in a fetch that records the request instead of making one. The client
9
+ * builds its fetch handler in the constructor, so install this first.
10
+ */
11
+ function captureFetch(): {
12
+ calls: Request[];
13
+ only: () => Request;
14
+ restore: () => void;
15
+ } {
16
+ const calls: Request[] = [];
17
+ const real = globalThis.fetch;
18
+ globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
19
+ calls.push(new Request(input as RequestInfo, init));
20
+ return new Response(JSON.stringify({ status: "ok" }), {
21
+ status: 200,
22
+ headers: { "content-type": "application/json" },
23
+ });
24
+ }) as typeof globalThis.fetch;
25
+ return {
26
+ calls,
27
+ /** The single request that was made; fails loudly if there wasn't exactly one. */
28
+ only: () => {
29
+ expect(calls).toHaveLength(1);
30
+ return calls[0] as Request;
31
+ },
32
+ restore: () => {
33
+ globalThis.fetch = real;
34
+ },
35
+ };
36
+ }
37
+
38
+ let restore: (() => void) | null = null;
39
+ afterEach(() => {
40
+ restore?.();
41
+ restore = null;
42
+ });
43
+
44
+ describe("authenticated request headers", () => {
45
+ test("a JSON procedure keeps its content-type alongside the bearer token", async () => {
46
+ // Regression: the auth wrapper used to merge headers with an object spread.
47
+ // atcute passes a Headers instance, which has no own enumerable properties,
48
+ // so the spread produced `{}` and dropped the `application/json` content-type
49
+ // atcute sets for a JSON body. The AppView then saw text/plain and replied
50
+ // `InvalidRequest: Wrong request encoding (Content-Type): text/plain`.
51
+ const cap = captureFetch();
52
+ restore = cap.restore;
53
+
54
+ const client = new RockskyClient("https://appview.test", TOKEN);
55
+ await client.library().createPlaylist("Late night drive");
56
+
57
+ const req = cap.only();
58
+ expect(req.method).toBe("POST");
59
+ expect(req.headers.get("content-type")).toBe("application/json");
60
+ expect(req.headers.get("authorization")).toBe(`Bearer ${TOKEN}`);
61
+ expect(await req.json()).toEqual({ name: "Late night drive" });
62
+ });
63
+
64
+ test("a query still carries the bearer token", async () => {
65
+ const cap = captureFetch();
66
+ restore = cap.restore;
67
+
68
+ const client = new RockskyClient("https://appview.test", TOKEN);
69
+ await client.library().getPlaylists();
70
+
71
+ expect(cap.only().headers.get("authorization")).toBe(`Bearer ${TOKEN}`);
72
+ });
73
+
74
+ test("no token means no authorization header", async () => {
75
+ const cap = captureFetch();
76
+ restore = cap.restore;
77
+
78
+ const client = new RockskyClient("https://appview.test");
79
+ await client.get("app.rocksky.actor.getProfile", { did: "did:plc:test" });
80
+
81
+ expect(cap.only().headers.get("authorization")).toBeNull();
82
+ });
83
+ });
package/src/client.ts CHANGED
@@ -53,6 +53,9 @@ import type {
53
53
  StatsGlobalStatsView,
54
54
  StatsView,
55
55
  StatsWrappedView,
56
+ PlaylistCreatePlaylistOutput,
57
+ PlaylistUpdatePlaylistOutput,
58
+ AddSongsOutput,
56
59
  UnfollowAccountOutput,
57
60
  UpdateSeenOutput,
58
61
  } from "./generated/types.js";
@@ -113,11 +116,16 @@ export class RockskyClient {
113
116
  let handler = simpleFetchHandler({ service: appview });
114
117
  if (token) {
115
118
  const inner = handler;
116
- handler = ((pathname: string, init?: RequestInit) =>
117
- inner(pathname, {
118
- ...init,
119
- headers: { ...(init?.headers as Record<string, string>), authorization: `Bearer ${token}` },
120
- })) as typeof handler;
119
+ handler = ((pathname: string, init?: RequestInit) => {
120
+ // `new Headers(init.headers)`, not a spread: atcute hands us a Headers
121
+ // instance, and a Headers has no own enumerable properties — spreading
122
+ // it yields `{}` and silently drops everything already set. That threw
123
+ // away the `content-type: application/json` atcute adds for a JSON
124
+ // body, so the AppView saw text/plain and rejected the request.
125
+ const headers = new Headers(init?.headers);
126
+ headers.set("authorization", `Bearer ${token}`);
127
+ return inner(pathname, { ...init, headers });
128
+ }) as typeof handler;
121
129
  }
122
130
  this.rpc = new Client({ handler });
123
131
  }
@@ -516,6 +524,54 @@ export class RockskyClient {
516
524
  playlist(uri: string): Promise<PlaylistViewDetailed> {
517
525
  return this.query("app.rocksky.playlist.getPlaylist", { uri });
518
526
  }
527
+
528
+ /**
529
+ * Create a playlist (`app.rocksky.playlist.createPlaylist`). Auth required.
530
+ * Publishes an app.rocksky.playlist record to the caller's repo; the AppView
531
+ * only lists it once the commit has been ingested.
532
+ */
533
+ createPlaylist(input: {
534
+ name: string;
535
+ description?: string;
536
+ pictureUrl?: string;
537
+ }): Promise<PlaylistCreatePlaylistOutput> {
538
+ return this.post("app.rocksky.playlist.createPlaylist", { params: input });
539
+ }
540
+
541
+ /** Rename or re-describe a playlist (`app.rocksky.playlist.updatePlaylist`). Owner only. */
542
+ updatePlaylist(input: {
543
+ uri: string;
544
+ name?: string;
545
+ description?: string;
546
+ pictureUrl?: string;
547
+ }): Promise<PlaylistUpdatePlaylistOutput> {
548
+ return this.post("app.rocksky.playlist.updatePlaylist", { params: input });
549
+ }
550
+
551
+ /**
552
+ * Add songs to a playlist (`app.rocksky.playlist.addSongs`). Owner only.
553
+ * `songs` are app.rocksky.song AT-URIs; returns the created entry URIs.
554
+ */
555
+ addSongs(uri: string, songs: string[]): Promise<AddSongsOutput> {
556
+ return this.post("app.rocksky.playlist.addSongs", {
557
+ params: { uri, songs },
558
+ });
559
+ }
560
+
561
+ /** Delete a playlist and the caller's own entries (`app.rocksky.playlist.removePlaylist`). Owner only. */
562
+ removePlaylist(uri: string): Promise<void> {
563
+ return this.post("app.rocksky.playlist.removePlaylist", { params: { uri } });
564
+ }
565
+
566
+ /**
567
+ * Remove a song from a playlist (`app.rocksky.playlist.removeTrack`). An
568
+ * entry can only be retracted by the repo that published it.
569
+ */
570
+ removeTrack(uri: string, songUri: string): Promise<void> {
571
+ return this.post("app.rocksky.playlist.removeTrack", {
572
+ params: { uri, songUri },
573
+ });
574
+ }
519
575
  /** Shouts on an album. */
520
576
  albumShouts(uri: string, limit = 50, offset = 0): Promise<GetAlbumShoutsOutput> {
521
577
  return this.query("app.rocksky.shout.getAlbumShouts", { uri, limit, offset });
@@ -126,6 +126,18 @@ export interface AddItemsToQueueParams {
126
126
  shuffle?: boolean;
127
127
  }
128
128
 
129
+ export interface AddSongsOutput {
130
+ /** AT-URIs of the created app.rocksky.playlist.song records */
131
+ uris: AtUri[];
132
+ }
133
+
134
+ export interface AddSongsParams {
135
+ /** The URI of the playlist to add the songs to */
136
+ uri: AtUri;
137
+ /** AT-URIs of the app.rocksky.song records to add */
138
+ songs: AtUri[];
139
+ }
140
+
129
141
  export interface AlbumGetAlbumParams {
130
142
  /** The URI of the album to retrieve. */
131
143
  uri: AtUri;
@@ -755,10 +767,12 @@ export interface GetActorPlaylistsOutput {
755
767
  export interface GetActorPlaylistsParams {
756
768
  /** The DID or handle of the actor */
757
769
  did: AtIdentifier;
758
- /** The maximum number of albums to return */
770
+ /** The maximum number of playlists to return */
759
771
  limit?: number;
760
772
  /** The offset for pagination */
761
773
  offset?: number;
774
+ /** RSQL filter expression, e.g. `name=="Road trip*";track.artist=="Daft Punk"`. Supports ==, !=, <, <=, >, >=, =in=, =out=, and `;`/`and`, `,`/`or` combinators, `*` wildcards in string values. Filterable fields: name, title, description, uri, spotifyLink, tidalLink, appleMusicLink, createdAt, updatedAt. The `track.title`, `track.artist`, `track.album` and `track.albumArtist` selectors match the playlist's contents, returning playlists that contain a matching track; several `track.*` terms joined with `;` must all be satisfied by the same track. */
775
+ filter?: string;
762
776
  }
763
777
 
764
778
  export interface GetActorScrobblesOutput {
@@ -1565,6 +1579,23 @@ export interface LibrarySearchParams {
1565
1579
  songOffset?: number;
1566
1580
  }
1567
1581
 
1582
+ export interface LibraryUpdatePlaylistInput {
1583
+ /** The playlist id to update. */
1584
+ playlistId: string;
1585
+ /** New playlist name. */
1586
+ name?: string;
1587
+ /** New playlist comment. */
1588
+ comment?: string;
1589
+ /** A song id to add to the playlist. */
1590
+ songIdToAdd?: string;
1591
+ /** A track index to remove from the playlist. */
1592
+ songIndexToRemove?: number;
1593
+ }
1594
+
1595
+ export interface LibraryUpdatePlaylistOutput {
1596
+
1597
+ }
1598
+
1568
1599
  export interface LikeRecord {
1569
1600
  /** The date when the like was created. */
1570
1601
  createdAt: DateTime;
@@ -1723,16 +1754,27 @@ export interface PlayFileParams {
1723
1754
  fileId: string;
1724
1755
  }
1725
1756
 
1757
+ export interface PlaylistCreatePlaylistOutput {
1758
+ /** The AT-URI of the created app.rocksky.playlist record. */
1759
+ uri: AtUri;
1760
+ /** The CID of the created app.rocksky.playlist record. */
1761
+ cid: string;
1762
+ }
1763
+
1726
1764
  export interface PlaylistCreatePlaylistParams {
1727
1765
  /** The name of the playlist */
1728
1766
  name: string;
1729
1767
  /** A brief description of the playlist */
1730
1768
  description?: string;
1769
+ /** The URL of the cover image for the playlist */
1770
+ pictureUrl?: Uri;
1731
1771
  }
1732
1772
 
1733
1773
  export interface PlaylistGetPlaylistParams {
1734
1774
  /** The URI of the playlist to retrieve. */
1735
1775
  uri: AtUri;
1776
+ /** RSQL filter expression applied to the playlist's tracks, e.g. `artist=="Daft Punk";duration=gt=200000`. Supports ==, !=, <, <=, >, >=, =in=, =out=, and `;`/`and`, `,`/`or` combinators, `*` wildcards in string values. Filterable fields: title, artist, album, albumArtist, genre, composer, label, duration, trackNumber, discNumber, mbId, isrc, sha256, uri, albumUri, artistUri, addedAt */
1777
+ filter?: string;
1736
1778
  }
1737
1779
 
1738
1780
  export interface PlaylistGetPlaylistsOutput {
@@ -1744,15 +1786,8 @@ export interface PlaylistGetPlaylistsParams {
1744
1786
  limit?: number;
1745
1787
  /** The offset for pagination, used to skip a number of playlists. */
1746
1788
  offset?: number;
1747
- }
1748
-
1749
- export interface PlaylistItemRecord {
1750
- subject: StrongRef;
1751
- /** The date the playlist was created. */
1752
- createdAt: DateTime;
1753
- track: SongViewBasic;
1754
- /** The order of the item in the playlist. */
1755
- order: number;
1789
+ /** RSQL filter expression, e.g. `name=="Road trip*";track.artist=="Daft Punk"`. Supports ==, !=, <, <=, >, >=, =in=, =out=, and `;`/`and`, `,`/`or` combinators, `*` wildcards in string values. Filterable fields: name, title, description, uri, spotifyLink, tidalLink, appleMusicLink, createdAt, updatedAt, curatorDid, curatorHandle, curatorName. The `track.title`, `track.artist`, `track.album` and `track.albumArtist` selectors match the playlist's contents, returning playlists that contain a matching track; several `track.*` terms joined with `;` must all be satisfied by the same track. */
1790
+ filter?: string;
1756
1791
  }
1757
1792
 
1758
1793
  export interface PlaylistRecord {
@@ -1776,6 +1811,45 @@ export interface PlaylistRecord {
1776
1811
  appleMusicLink?: string;
1777
1812
  }
1778
1813
 
1814
+ export interface PlaylistSongRecord {
1815
+ /** Strong reference (AT-URI + CID) to the parent app.rocksky.playlist record. */
1816
+ playlist: StrongRef;
1817
+ /** Strong reference (AT-URI + CID) to the app.rocksky.song record this entry points at. */
1818
+ song: StrongRef;
1819
+ /** The title of the song. */
1820
+ title: string;
1821
+ /** The artist of the song. */
1822
+ artist: string;
1823
+ /** The album the song belongs to. */
1824
+ album: string;
1825
+ /** The album artist of the song. */
1826
+ albumArtist: string;
1827
+ /** The duration of the song in milliseconds. */
1828
+ duration: number;
1829
+ /** The URL of the album art of the song. */
1830
+ albumArtUrl?: Uri;
1831
+ /** The date and time the song was added to the playlist. */
1832
+ addedAt: DateTime;
1833
+ }
1834
+
1835
+ export interface PlaylistUpdatePlaylistOutput {
1836
+ /** The AT-URI of the updated app.rocksky.playlist record. */
1837
+ uri: AtUri;
1838
+ /** The CID of the updated app.rocksky.playlist record. */
1839
+ cid: string;
1840
+ }
1841
+
1842
+ export interface PlaylistUpdatePlaylistParams {
1843
+ /** The URI of the playlist to update */
1844
+ uri: AtUri;
1845
+ /** The new name of the playlist */
1846
+ name?: string;
1847
+ /** The new description of the playlist */
1848
+ description?: string;
1849
+ /** The new cover image URL for the playlist */
1850
+ pictureUrl?: Uri;
1851
+ }
1852
+
1779
1853
  /** Basic view of a playlist, including its metadata */
1780
1854
  export interface PlaylistViewBasic {
1781
1855
  /** The unique identifier of the playlist. */
@@ -1800,6 +1874,8 @@ export interface PlaylistViewBasic {
1800
1874
  createdAt?: DateTime;
1801
1875
  /** The number of tracks in the playlist. */
1802
1876
  trackCount?: number;
1877
+ /** Album-art URLs of up to four of the playlist's tracks, for rendering a cover mosaic when the playlist has no picture of its own. */
1878
+ trackArts?: Uri[];
1803
1879
  }
1804
1880
 
1805
1881
  /** Detailed view of a playlist, including its tracks and metadata */
@@ -1929,8 +2005,8 @@ export interface RemoveShoutParams {
1929
2005
  export interface RemoveTrackParams {
1930
2006
  /** The URI of the playlist to remove the track from */
1931
2007
  uri: AtUri;
1932
- /** The position of the track to remove in the playlist */
1933
- position: number;
2008
+ /** The URI of the app.rocksky.song record to remove from the playlist */
2009
+ songUri: AtUri;
1934
2010
  }
1935
2011
 
1936
2012
  export interface ReplyShoutInput {
@@ -2714,23 +2790,6 @@ export interface UpdateNowPlayingOutput {
2714
2790
 
2715
2791
  }
2716
2792
 
2717
- export interface UpdatePlaylistInput {
2718
- /** The playlist id to update. */
2719
- playlistId: string;
2720
- /** New playlist name. */
2721
- name?: string;
2722
- /** New playlist comment. */
2723
- comment?: string;
2724
- /** A song id to add to the playlist. */
2725
- songIdToAdd?: string;
2726
- /** A track index to remove from the playlist. */
2727
- songIndexToRemove?: number;
2728
- }
2729
-
2730
- export interface UpdatePlaylistOutput {
2731
-
2732
- }
2733
-
2734
2793
  export interface UpdateSeenInput {
2735
2794
  /** The ids of the notifications to mark as viewed. Omit to mark all. */
2736
2795
  ids?: string[];
@@ -2835,7 +2894,7 @@ export interface Endpoints {
2835
2894
  "app.rocksky.library.startScan": StartScanOutput;
2836
2895
  "app.rocksky.library.unstar": UnstarOutput;
2837
2896
  "app.rocksky.library.updateNowPlaying": UpdateNowPlayingOutput;
2838
- "app.rocksky.library.updatePlaylist": UpdatePlaylistOutput;
2897
+ "app.rocksky.library.updatePlaylist": LibraryUpdatePlaylistOutput;
2839
2898
  "app.rocksky.like.dislikeShout": ShoutView;
2840
2899
  "app.rocksky.like.dislikeSong": SongViewDetailed;
2841
2900
  "app.rocksky.like.likeShout": ShoutView;
@@ -2856,7 +2915,8 @@ export interface Endpoints {
2856
2915
  "app.rocksky.player.playFile": void;
2857
2916
  "app.rocksky.player.previous": void;
2858
2917
  "app.rocksky.player.seek": void;
2859
- "app.rocksky.playlist.createPlaylist": void;
2918
+ "app.rocksky.playlist.addSongs": AddSongsOutput;
2919
+ "app.rocksky.playlist.createPlaylist": PlaylistCreatePlaylistOutput;
2860
2920
  "app.rocksky.playlist.getPlaylist": PlaylistViewDetailed;
2861
2921
  "app.rocksky.playlist.getPlaylists": PlaylistGetPlaylistsOutput;
2862
2922
  "app.rocksky.playlist.insertDirectory": void;
@@ -2864,6 +2924,7 @@ export interface Endpoints {
2864
2924
  "app.rocksky.playlist.removePlaylist": void;
2865
2925
  "app.rocksky.playlist.removeTrack": void;
2866
2926
  "app.rocksky.playlist.startPlaylist": void;
2927
+ "app.rocksky.playlist.updatePlaylist": PlaylistUpdatePlaylistOutput;
2867
2928
  "app.rocksky.rockbox.getAudioSettings": RockboxSettingsView;
2868
2929
  "app.rocksky.rockbox.putAudioSettings": RockboxSettingsView;
2869
2930
  "app.rocksky.scrobble.createScrobble": ScrobbleViewBasic;
package/src/index.ts CHANGED
@@ -10,7 +10,14 @@
10
10
  */
11
11
  export { RockskyClient, DEFAULT_APPVIEW, Interval } from "./client.js";
12
12
  export type { DateInterval } from "./client.js";
13
- export { RockskyLibrary } from "./library.js";
13
+ export {
14
+ RockskyLibrary,
15
+ type LibrarySong,
16
+ type LibraryPlaylist,
17
+ type LibraryPlaylistMutation,
18
+ type LibraryPlaylistResponse,
19
+ type LibraryPlaylistsResponse,
20
+ } from "./library.js";
14
21
  export {
15
22
  Agent,
16
23
  MAX_SAFE_WRITES_PER_HOUR,