@rocksky/sdk 0.12.0 → 0.14.0

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/README.md CHANGED
@@ -45,6 +45,29 @@ methods cover the rest: `album`, `artist`, `song`, `feed`, `playlists`,
45
45
  Every named method is sugar over the universal escape hatch **`rk.get(nsid,
46
46
  params)`**, which calls ANY read query by nsid and returns `unknown`.
47
47
 
48
+ **Filtering**: `catalogSongs`, `catalogArtists`, `catalogAlbums`, and
49
+ `scrobbleFeed` take an optional RSQL `filter` (string or `Filter`) — build one
50
+ fluently, with the per-endpoint field constants for discoverability:
51
+
52
+ ```ts
53
+ import { Filter, RockskyClient, ScrobbleFields, SongFields } from "@rocksky/sdk";
54
+
55
+ const rk = new RockskyClient();
56
+ const filter = Filter.eq(SongFields.artist, "Daft Punk")
57
+ .and(Filter.gt(SongFields.duration, 200_000))
58
+ .or(Filter.in(SongFields.genre, ["house", "electro"]));
59
+ const songs = await rk.catalogSongs(50, 0, undefined, filter);
60
+ // filter sent: artist=="Daft Punk";duration=gt=200000,genre=in=(house,electro)
61
+
62
+ // scrobbles support dotted selectors into the joined track/user/artist:
63
+ await rk.scrobbleFeed(undefined, false, 50, 0,
64
+ Filter.eq(ScrobbleFields.trackArtist, "Daft Punk").and(Filter.ge(ScrobbleFields.date, "2025-01-01")));
65
+ ```
66
+
67
+ Operators: `eq` (supports `*` wildcards), `ne`, `gt`, `ge`, `lt`, `le`, `in`,
68
+ `out`, `isNull`, `isNotNull`, chained with `.and()` / `.or()` (parentheses
69
+ inserted automatically per RSQL precedence).
70
+
48
71
  **Typed date-window charts**: `topTracksInterval(limit, offset, interval)` and
49
72
  `topArtistsInterval(...)` take a `DateInterval` built with the `Interval`
50
73
  factories — `Interval.allTime()`, `Interval.lastDays(n)`, `Interval.lastWeeks(n)`,
@@ -86,10 +109,12 @@ SHA-256, identical to the server and every other Rocksky SDK.
86
109
  ## Duplicate prevention + real-time sync
87
110
 
88
111
  An optional local index (embedded [classic-level](https://github.com/Level/classic-level)
89
- LevelDB) prevents duplicate writes and stays live off the firehose:
112
+ LevelDB) prevents duplicate writes and stays live off the firehose. It is
113
+ Node-only, so it lives on its own subpath — the main `@rocksky/sdk` entry stays
114
+ browser-safe:
90
115
 
91
116
  ```ts
92
- import { RockskyIndex } from "@rocksky/sdk";
117
+ import { RockskyIndex } from "@rocksky/sdk/dedup";
93
118
 
94
119
  const idx = new RockskyIndex("./dedup");
95
120
  await idx.open();
package/dist/client.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import type { Filter } from "./filter.js";
1
2
  import { RockskyLibrary } from "./library.js";
2
- import type { ActorProfileViewBasic, ActorProfileViewDetailed, AlbumViewBasic, AlbumViewDetailed, ArtistViewBasic, ArtistViewDetailed, ChartsView, FeedGeneratorsView, FeedRecommendationsView, FeedRecommendedAlbumsView, FeedRecommendedArtistsView, FeedSearchResultsView, FeedStoriesView, FeedView, GetActorCompatibilityOutput, GetActorNeighboursOutput, GetActorPlaylistsOutput, GetAlbumShoutsOutput, GetApikeysOutput, GetArtistListenersOutput, GetArtistRecentListenersOutput, GetArtistShoutsOutput, GetFeedGeneratorOutput, GetMirrorSourcesOutput, GetProfileShoutsOutput, GetShoutRepliesOutput, GetSongRecentListenersOutput, GetTrackShoutsOutput, GetUnreadCountOutput, ListNotificationsOutput, PlayerCurrentlyPlayingViewDetailed, PlayerPlaybackQueueViewDetailed, PlaylistGetPlaylistsOutput, PlaylistViewDetailed, RockboxSettingsView, ScrobbleViewBasic, SongViewBasic, SongViewDetailed, StatsGlobalStatsView, StatsView, StatsWrappedView, UpdateSeenOutput } from "./generated/types.js";
3
+ import type { ActorProfileViewBasic, ActorProfileViewDetailed, AlbumViewBasic, AlbumViewDetailed, ArtistViewBasic, ArtistViewDetailed, ChartsView, CreateScrobbleInput, FollowAccountOutput, FeedGeneratorsView, FeedRecommendationsView, FeedRecommendedAlbumsView, FeedRecommendedArtistsView, FeedSearchResultsView, FeedStoriesView, FeedView, GetActorCompatibilityOutput, GetActorNeighboursOutput, GetActorPlaylistsOutput, GetAlbumShoutsOutput, GetApikeysOutput, GetArtistListenersOutput, GetArtistRecentListenersOutput, GetArtistShoutsOutput, GetFeedGeneratorOutput, GetMirrorSourcesOutput, GetProfileShoutsOutput, GetShoutRepliesOutput, GetSongRecentListenersOutput, GetTrackShoutsOutput, GetUnreadCountOutput, ListNotificationsOutput, MirrorSourceView, PlayerCurrentlyPlayingViewDetailed, PlayerPlaybackQueueViewDetailed, PlaylistGetPlaylistsOutput, PlaylistViewDetailed, PutAudioSettingsInput, PutMirrorSourceInput, RockboxSettingsView, ScrobbleViewBasic, SongViewBasic, SongViewDetailed, StatsGlobalStatsView, StatsView, StatsWrappedView, UnfollowAccountOutput, UpdateSeenOutput } from "./generated/types.js";
3
4
  /**
4
5
  * A typed date window for the `top*` charts. Build one with the {@link Interval}
5
6
  * factories; `range` bounds are RFC-3339 datetimes.
@@ -50,6 +51,13 @@ export declare class RockskyClient {
50
51
  /** Call any AppView read query by nsid; returns the raw JSON response. Every
51
52
  * method here is sugar over this — use it for queries without a wrapper. */
52
53
  get(nsid: string, params?: Record<string, unknown>): Promise<unknown>;
54
+ /** Call any AppView procedure by nsid. `params` ride the query string (some
55
+ * procedures take their arguments there), `body` is the JSON input — omitted
56
+ * entirely when `undefined`. Escape hatch for procedures without a wrapper. */
57
+ post<T = unknown>(nsid: string, opts?: {
58
+ params?: Record<string, unknown>;
59
+ body?: unknown;
60
+ }): Promise<T>;
53
61
  /** An actor's most-played songs. */
54
62
  songs(actor: string, limit?: number, offset?: number): Promise<SongViewBasic[]>;
55
63
  /** An actor's loved (liked) songs. */
@@ -66,12 +74,15 @@ export declare class RockskyClient {
66
74
  topTracksInterval(limit: number, offset: number, interval: DateInterval): Promise<SongViewBasic[]>;
67
75
  /** The top artists chart over a typed {@link DateInterval}. */
68
76
  topArtistsInterval(limit: number, offset: number, interval: DateInterval): Promise<ArtistViewBasic[]>;
69
- /** The album catalog, optionally filtered by `genre`. */
70
- catalogAlbums(limit?: number, offset?: number, genre?: string): Promise<AlbumViewBasic[]>;
71
- /** The artist catalog, optionally filtered by `genre`. */
72
- catalogArtists(limit?: number, offset?: number, genre?: string): Promise<ArtistViewBasic[]>;
73
- /** The song catalog, optionally filtered by `genre`. */
74
- catalogSongs(limit?: number, offset?: number, genre?: string): Promise<SongViewBasic[]>;
77
+ /** The album catalog, optionally filtered by `genre` and/or an RSQL
78
+ * {@link Filter} expression (see {@link AlbumFields}). */
79
+ catalogAlbums(limit?: number, offset?: number, genre?: string, filter?: string | Filter): Promise<AlbumViewBasic[]>;
80
+ /** The artist catalog, optionally filtered by `genre` and/or an RSQL
81
+ * {@link Filter} expression (see {@link ArtistFields}). */
82
+ catalogArtists(limit?: number, offset?: number, genre?: string, filter?: string | Filter): Promise<ArtistViewBasic[]>;
83
+ /** The song catalog, optionally filtered by `genre` and/or an RSQL
84
+ * {@link Filter} expression (see {@link SongFields}). */
85
+ catalogSongs(limit?: number, offset?: number, genre?: string, filter?: string | Filter): Promise<SongViewBasic[]>;
75
86
  /** An album's tracklist by album at:// URI. */
76
87
  albumTracks(uri: string): Promise<SongViewBasic[]>;
77
88
  /** An artist's albums by artist at:// URI. */
@@ -79,8 +90,9 @@ export declare class RockskyClient {
79
90
  /** An artist's top tracks by artist at:// URI. */
80
91
  artistTracks(uri: string, limit?: number, offset?: number): Promise<SongViewBasic[]>;
81
92
  /** A social/global scrobbles feed. Pass `did` to scope to an actor and
82
- * `following = true` for their follow graph. */
83
- scrobbleFeed(did?: string, following?: boolean, limit?: number, offset?: number): Promise<ScrobbleViewBasic[]>;
93
+ * `following = true` for their follow graph. `filter` takes an RSQL
94
+ * {@link Filter} expression (see {@link ScrobbleFields}). */
95
+ scrobbleFeed(did?: string, following?: boolean, limit?: number, offset?: number, filter?: string | Filter): Promise<ScrobbleViewBasic[]>;
84
96
  /** A single scrobble by its at:// URI. */
85
97
  scrobble(uri: string): Promise<ScrobbleViewBasic>;
86
98
  /** The accounts `actor` follows. */
@@ -183,5 +195,17 @@ export declare class RockskyClient {
183
195
  * to mark **all** of the viewer's notifications. Returns the number remaining
184
196
  * unread. */
185
197
  updateSeen(ids?: string[]): Promise<UpdateSeenOutput>;
198
+ /** Follow an account by DID or handle (`app.rocksky.graph.followAccount`). Auth required. */
199
+ followAccount(account: string): Promise<FollowAccountOutput>;
200
+ /** Unfollow an account by DID or handle (`app.rocksky.graph.unfollowAccount`). Auth required. */
201
+ unfollowAccount(account: string): Promise<UnfollowAccountOutput>;
202
+ /** Submit a scrobble through the AppView (`app.rocksky.scrobble.createScrobble`).
203
+ * Auth required. For direct-to-PDS scrobbling use {@link Agent} instead. */
204
+ createScrobble(input: CreateScrobbleInput): Promise<ScrobbleViewBasic>;
205
+ /** Create or update a mirror source (`app.rocksky.mirror.putMirrorSource`). Auth required. */
206
+ putMirrorSource(input: PutMirrorSourceInput): Promise<MirrorSourceView>;
207
+ /** Patch the viewer's Rockbox audio settings (`app.rocksky.rockbox.putAudioSettings`).
208
+ * Auth required. */
209
+ putAudioSettings(input: PutAudioSettingsInput): Promise<RockboxSettingsView>;
186
210
  }
187
211
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/dedup.js ADDED
@@ -0,0 +1,215 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __returnValue = (v) => v;
3
+ function __exportSetter(name, newValue) {
4
+ this[name] = __returnValue.bind(null, newValue);
5
+ }
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true,
11
+ configurable: true,
12
+ set: __exportSetter.bind(all, name)
13
+ });
14
+ };
15
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
16
+
17
+ // src/dedup.ts
18
+ import { fromUint8Array } from "@atcute/car";
19
+ import { decode as cborDecode, fromBytes, isBytes, isCidLink } from "@atcute/cbor";
20
+ import { toString as cidToString } from "@atcute/cid";
21
+ import { ClassicLevel } from "classic-level";
22
+
23
+ // src/hash.ts
24
+ import { sha256 } from "@noble/hashes/sha2.js";
25
+ import { bytesToHex } from "@noble/hashes/utils.js";
26
+ function sha256Lower(s) {
27
+ return bytesToHex(sha256(new TextEncoder().encode(s.toLowerCase())));
28
+ }
29
+ function songHash(title, artist, album) {
30
+ return sha256Lower(`${title} - ${artist} - ${album}`);
31
+ }
32
+ function albumHash(album, albumArtist) {
33
+ return sha256Lower(`${album} - ${albumArtist}`);
34
+ }
35
+ function artistHash(albumArtist) {
36
+ return sha256Lower(albumArtist);
37
+ }
38
+
39
+ // src/dedup.ts
40
+ var C_ARTIST = "app.rocksky.artist";
41
+ var C_ALBUM = "app.rocksky.album";
42
+ var C_SONG = "app.rocksky.song";
43
+ var C_SCROBBLE = "app.rocksky.scrobble";
44
+ var SEP = "\x00";
45
+ function totalIndexed(s) {
46
+ return s.artists + s.albums + s.songs + s.scrobbles;
47
+ }
48
+ function identKey(did, col, hash) {
49
+ return `${did}${SEP}${col}${SEP}${hash}`;
50
+ }
51
+ function scrobbleKey(did, songH, secs) {
52
+ return `${did}${SEP}${C_SCROBBLE}${SEP}${songH}${SEP}${secs}`;
53
+ }
54
+ function primaryFor(did, col, rec) {
55
+ const s = (k) => typeof rec[k] === "string" ? rec[k] : "";
56
+ switch (col) {
57
+ case C_ARTIST:
58
+ return s("name") ? identKey(did, C_ARTIST, artistHash(s("name"))) : undefined;
59
+ case C_ALBUM:
60
+ return s("title") && s("artist") ? identKey(did, C_ALBUM, albumHash(s("title"), s("artist"))) : undefined;
61
+ case C_SONG:
62
+ return s("title") && s("artist") && s("album") ? identKey(did, C_SONG, songHash(s("title"), s("artist"), s("album"))) : undefined;
63
+ case C_SCROBBLE: {
64
+ if (s("title") && s("artist") && s("album") && s("createdAt")) {
65
+ const secs = Math.floor(Date.parse(s("createdAt")) / 1000);
66
+ if (!Number.isNaN(secs))
67
+ return scrobbleKey(did, songHash(s("title"), s("artist"), s("album")), secs);
68
+ }
69
+ return;
70
+ }
71
+ }
72
+ return;
73
+ }
74
+
75
+ class RockskyIndex {
76
+ db;
77
+ constructor(path) {
78
+ this.db = new ClassicLevel(path, { keyEncoding: "utf8", valueEncoding: "utf8" });
79
+ }
80
+ open() {
81
+ return this.db.open();
82
+ }
83
+ close() {
84
+ return this.db.close();
85
+ }
86
+ async get(key) {
87
+ try {
88
+ return await this.db.get(key);
89
+ } catch {
90
+ return;
91
+ }
92
+ }
93
+ songUri(did, title, artist, album) {
94
+ return this.get(identKey(did, C_SONG, songHash(title, artist, album)));
95
+ }
96
+ albumUri(did, album, albumArtist) {
97
+ return this.get(identKey(did, C_ALBUM, albumHash(album, albumArtist)));
98
+ }
99
+ artistUri(did, albumArtist) {
100
+ return this.get(identKey(did, C_ARTIST, artistHash(albumArtist)));
101
+ }
102
+ scrobbleUri(did, title, artist, album, secs) {
103
+ return this.get(scrobbleKey(did, songHash(title, artist, album), secs));
104
+ }
105
+ async putPrimary(did, col, primary, uri) {
106
+ const rkey = uri.slice(uri.lastIndexOf("/") + 1);
107
+ await this.db.batch([
108
+ { type: "put", key: primary, value: uri },
109
+ { type: "put", key: `${SEP}rk${SEP}${did}${SEP}${col}${SEP}${rkey}`, value: primary }
110
+ ]);
111
+ }
112
+ recordSong(did, title, artist, album, uri) {
113
+ return this.putPrimary(did, C_SONG, identKey(did, C_SONG, songHash(title, artist, album)), uri);
114
+ }
115
+ recordAlbum(did, album, albumArtist, uri) {
116
+ return this.putPrimary(did, C_ALBUM, identKey(did, C_ALBUM, albumHash(album, albumArtist)), uri);
117
+ }
118
+ recordArtist(did, albumArtist, uri) {
119
+ return this.putPrimary(did, C_ARTIST, identKey(did, C_ARTIST, artistHash(albumArtist)), uri);
120
+ }
121
+ recordScrobble(did, title, artist, album, secs, uri) {
122
+ return this.putPrimary(did, C_SCROBBLE, scrobbleKey(did, songHash(title, artist, album), secs), uri);
123
+ }
124
+ cursor(did) {
125
+ return this.get(`${SEP}meta${SEP}cursor${SEP}${did}`).then((v) => v ? Number(v) : 0);
126
+ }
127
+ async setCursor(did, timeUS) {
128
+ await this.db.put(`${SEP}meta${SEP}cursor${SEP}${did}`, String(timeUS));
129
+ }
130
+ async indexCar(did, car) {
131
+ const reader = fromUint8Array(car);
132
+ const blocks = new Map;
133
+ for (const entry of reader)
134
+ blocks.set(cidToString(entry.cid), entry.bytes);
135
+ const root = reader.roots[0];
136
+ if (!root)
137
+ throw new Error("CAR has no root");
138
+ const commit = cborDecode(blocks.get(root.$link));
139
+ const stats = { artists: 0, albums: 0, songs: 0, scrobbles: 0 };
140
+ const ops = [];
141
+ for (const [path, valueLink] of walkMst(blocks, commit.data.$link)) {
142
+ const slash = path.indexOf("/");
143
+ if (slash < 0)
144
+ continue;
145
+ const col = path.slice(0, slash);
146
+ const rkey = path.slice(slash + 1);
147
+ if (col !== C_ARTIST && col !== C_ALBUM && col !== C_SONG && col !== C_SCROBBLE)
148
+ continue;
149
+ const recBytes = blocks.get(valueLink);
150
+ if (!recBytes)
151
+ continue;
152
+ const rec = cborDecode(recBytes);
153
+ const primary = primaryFor(did, col, rec);
154
+ if (!primary)
155
+ continue;
156
+ const uri = `at://${did}/${col}/${rkey}`;
157
+ ops.push({ type: "put", key: primary, value: uri });
158
+ ops.push({ type: "put", key: `${SEP}rk${SEP}${did}${SEP}${col}${SEP}${rkey}`, value: primary });
159
+ if (col === C_ARTIST)
160
+ stats.artists++;
161
+ else if (col === C_ALBUM)
162
+ stats.albums++;
163
+ else if (col === C_SONG)
164
+ stats.songs++;
165
+ else
166
+ stats.scrobbles++;
167
+ }
168
+ if (commit.rev)
169
+ ops.push({ type: "put", key: `${SEP}meta${SEP}rev${SEP}${did}`, value: commit.rev });
170
+ await this.db.batch(ops);
171
+ return stats;
172
+ }
173
+ async applyCommit(did, col, operation, rkey, record) {
174
+ if (operation === "create" || operation === "update") {
175
+ if (!record)
176
+ return;
177
+ const primary = primaryFor(did, col, record);
178
+ if (!primary)
179
+ return;
180
+ await this.putPrimary(did, col, primary, `at://${did}/${col}/${rkey}`);
181
+ } else if (operation === "delete") {
182
+ const rk = `${SEP}rk${SEP}${did}${SEP}${col}${SEP}${rkey}`;
183
+ const primary = await this.get(rk);
184
+ if (primary) {
185
+ await this.db.batch([
186
+ { type: "del", key: primary },
187
+ { type: "del", key: rk }
188
+ ]);
189
+ }
190
+ }
191
+ }
192
+ }
193
+ function* walkMst(blocks, cid) {
194
+ const raw = blocks.get(cid);
195
+ if (!raw)
196
+ return;
197
+ const node = cborDecode(raw);
198
+ if (node.l && isCidLink(node.l))
199
+ yield* walkMst(blocks, node.l.$link);
200
+ let last = new Uint8Array(0);
201
+ for (const e of node.e) {
202
+ const suffix = isBytes(e.k) ? fromBytes(e.k) : e.k;
203
+ const key = new Uint8Array(e.p + suffix.length);
204
+ key.set(last.subarray(0, e.p), 0);
205
+ key.set(suffix, e.p);
206
+ yield [new TextDecoder().decode(key), e.v.$link];
207
+ last = key;
208
+ if (e.t && isCidLink(e.t))
209
+ yield* walkMst(blocks, e.t.$link);
210
+ }
211
+ }
212
+ export {
213
+ RockskyIndex,
214
+ totalIndexed
215
+ };
package/dist/errors.d.ts CHANGED
@@ -1,6 +1,9 @@
1
- /** Error thrown when a Rocksky XRPC call returns a non-2xx `{ error, message }`. */
2
1
  export declare class RockskyError extends Error {
2
+ /** The XRPC error code (e.g. "InvalidRequest", "AuthMissing"), when the
3
+ * server sent one. */
3
4
  readonly kind?: string;
4
- constructor(payload: unknown);
5
+ /** The HTTP status of the failed response, when known. */
6
+ readonly status?: number;
7
+ constructor(payload: unknown, status?: number);
5
8
  }
6
9
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBACX,OAAO,EAAE,OAAO;CAM7B"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;IACrC;0BACsB;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEb,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM;CAO9C"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Fluent builder for RSQL filter expressions, accepted by the `filter`
3
+ * parameter of the catalog and scrobble-feed queries
4
+ * (app.rocksky.song.getSongs, app.rocksky.artist.getArtists,
5
+ * app.rocksky.album.getAlbums, app.rocksky.scrobble.getScrobbles).
6
+ *
7
+ * ```ts
8
+ * import { Filter } from "@rocksky/sdk";
9
+ *
10
+ * const filter = Filter.eq("artist", "Daft Punk")
11
+ * .and(Filter.gt("duration", 200_000))
12
+ * .or(Filter.in("genre", ["house", "electro"]));
13
+ *
14
+ * await client.catalogSongs(50, 0, undefined, filter);
15
+ * // artist=="Daft Punk";duration=gt=200000,genre=in=(house,electro)
16
+ * ```
17
+ *
18
+ * String values are quoted and escaped automatically when they contain
19
+ * characters RSQL reserves; `*` wildcards pass through unquoted so
20
+ * `Filter.eq("artist", "Daft*")` performs a case-insensitive match.
21
+ */
22
+ export type FilterValue = string | number | boolean;
23
+ export declare class Filter {
24
+ private readonly expr;
25
+ private readonly kind;
26
+ private constructor();
27
+ private static comparison;
28
+ private static list;
29
+ /** `field==value` — equals; `*` in string values is a wildcard. */
30
+ static eq(field: string, value: FilterValue): Filter;
31
+ /** `field!=value` — not equals. */
32
+ static ne(field: string, value: FilterValue): Filter;
33
+ /** `field=gt=value` — greater than. */
34
+ static gt(field: string, value: FilterValue): Filter;
35
+ /** `field=ge=value` — greater than or equal. */
36
+ static ge(field: string, value: FilterValue): Filter;
37
+ /** `field=lt=value` — less than. */
38
+ static lt(field: string, value: FilterValue): Filter;
39
+ /** `field=le=value` — less than or equal. */
40
+ static le(field: string, value: FilterValue): Filter;
41
+ /** `field=in=(a,b)` — matches any of the values. */
42
+ static in(field: string, values: FilterValue[]): Filter;
43
+ /** `field=out=(a,b)` — matches none of the values. */
44
+ static out(field: string, values: FilterValue[]): Filter;
45
+ /** `field==null` — the field is NULL. */
46
+ static isNull(field: string): Filter;
47
+ /** `field!=null` — the field is not NULL. */
48
+ static isNotNull(field: string): Filter;
49
+ /** Both sides must match (`;`). An `or` operand is parenthesized to keep RSQL precedence. */
50
+ and(other: Filter): Filter;
51
+ /** Either side may match (`,`). */
52
+ or(other: Filter): Filter;
53
+ private renderIn;
54
+ /** The RSQL expression string to send as the `filter` query param. */
55
+ build(): string;
56
+ toString(): string;
57
+ }
58
+ /** Filterable fields of app.rocksky.song.getSongs. */
59
+ export declare const SongFields: {
60
+ readonly title: "title";
61
+ readonly artist: "artist";
62
+ readonly album: "album";
63
+ readonly albumArtist: "albumArtist";
64
+ readonly genre: "genre";
65
+ readonly composer: "composer";
66
+ readonly label: "label";
67
+ readonly duration: "duration";
68
+ readonly trackNumber: "trackNumber";
69
+ readonly discNumber: "discNumber";
70
+ readonly mbId: "mbId";
71
+ readonly isrc: "isrc";
72
+ readonly sha256: "sha256";
73
+ readonly uri: "uri";
74
+ readonly albumUri: "albumUri";
75
+ readonly artistUri: "artistUri";
76
+ readonly createdAt: "createdAt";
77
+ };
78
+ /** Filterable fields of app.rocksky.album.getAlbums. */
79
+ export declare const AlbumFields: {
80
+ readonly title: "title";
81
+ readonly artist: "artist";
82
+ readonly year: "year";
83
+ readonly releaseDate: "releaseDate";
84
+ readonly sha256: "sha256";
85
+ readonly uri: "uri";
86
+ readonly artistUri: "artistUri";
87
+ readonly createdAt: "createdAt";
88
+ };
89
+ /** Filterable fields of app.rocksky.artist.getArtists. */
90
+ export declare const ArtistFields: {
91
+ readonly name: "name";
92
+ readonly genres: "genres";
93
+ readonly bornIn: "bornIn";
94
+ readonly born: "born";
95
+ readonly died: "died";
96
+ readonly sha256: "sha256";
97
+ readonly uri: "uri";
98
+ readonly createdAt: "createdAt";
99
+ };
100
+ /** Filterable fields of app.rocksky.scrobble.getScrobbles (dotted selectors reach the joined track/user/artist). */
101
+ export declare const ScrobbleFields: {
102
+ readonly uri: "uri";
103
+ readonly date: "date";
104
+ readonly timestamp: "timestamp";
105
+ readonly title: "title";
106
+ readonly artist: "artist";
107
+ readonly album: "album";
108
+ readonly trackTitle: "track.title";
109
+ readonly trackArtist: "track.artist";
110
+ readonly trackAlbum: "track.album";
111
+ readonly trackAlbumArtist: "track.albumArtist";
112
+ readonly trackGenre: "track.genre";
113
+ readonly trackDuration: "track.duration";
114
+ readonly trackIsrc: "track.isrc";
115
+ readonly trackMbId: "track.mbId";
116
+ readonly userDid: "user.did";
117
+ readonly userHandle: "user.handle";
118
+ readonly userDisplayName: "user.displayName";
119
+ readonly artistName: "artist.name";
120
+ readonly artistGenres: "artist.genres";
121
+ };
122
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAapD,qBAAa,MAAM;IAEf,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFvB,OAAO;IAKP,OAAO,CAAC,MAAM,CAAC,UAAU;IAIzB,OAAO,CAAC,MAAM,CAAC,IAAI;IAOnB,mEAAmE;IACnE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;IAIpD,mCAAmC;IACnC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;IAIpD,uCAAuC;IACvC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;IAIpD,gDAAgD;IAChD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;IAIpD,oCAAoC;IACpC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;IAIpD,6CAA6C;IAC7C,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;IAIpD,oDAAoD;IACpD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM;IAIvD,sDAAsD;IACtD,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM;IAIxD,yCAAyC;IACzC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIpC,6CAA6C;IAC7C,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIvC,6FAA6F;IAC7F,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAI1B,mCAAmC;IACnC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIzB,OAAO,CAAC,QAAQ;IAIhB,sEAAsE;IACtE,KAAK,IAAI,MAAM;IAIf,QAAQ,IAAI,MAAM;CAGnB;AAED,sDAAsD;AACtD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;CAkBb,CAAC;AAEX,wDAAwD;AACxD,eAAO,MAAM,WAAW;;;;;;;;;CASd,CAAC;AAEX,0DAA0D;AAC1D,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAC;AAEX,oHAAoH;AACpH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;CAoBjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=filter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.test.d.ts","sourceRoot":"","sources":["../src/filter.test.ts"],"names":[],"mappings":""}
@@ -224,6 +224,8 @@ export interface ArtistGetArtistsParams {
224
224
  names?: string;
225
225
  /** The genre to filter artists by */
226
226
  genre?: string;
227
+ /** RSQL filter expression, e.g. `name==Daft*;genres=in=(house,electro)`. Supports ==, !=, <, <=, >, >=, =in=, =out=, and `;`/`and`, `,`/`or` combinators, `*` wildcards in string values. Filterable fields: name, genres, bornIn, born, died, sha256, uri, createdAt */
228
+ filter?: string;
227
229
  }
228
230
  export interface ArtistListenerViewBasic {
229
231
  /** The unique identifier of the actor. */
@@ -754,6 +756,8 @@ export interface GetAlbumsParams {
754
756
  offset?: number;
755
757
  /** The genre to filter artists by */
756
758
  genre?: string;
759
+ /** RSQL filter expression, e.g. `artist=="Daft Punk";year=ge=2000`. Supports ==, !=, <, <=, >, >=, =in=, =out=, and `;`/`and`, `,`/`or` combinators, `*` wildcards in string values. Filterable fields: title, artist, year, releaseDate, sha256, uri, artistUri, createdAt */
760
+ filter?: string;
757
761
  }
758
762
  export interface GetAlbumTracksOutput {
759
763
  tracks?: SongViewBasic[];
@@ -1058,6 +1062,8 @@ export interface GetScrobblesParams {
1058
1062
  limit?: number;
1059
1063
  /** The offset for pagination */
1060
1064
  offset?: number;
1065
+ /** RSQL filter expression, e.g. `track.artist=="Daft Punk";date=ge=2025-01-01`. Supports ==, !=, <, <=, >, >=, =in=, =out=, and `;`/`and`, `,`/`or` combinators, `*` wildcards in string values. Filterable fields: uri, date, timestamp, title, artist, album, track.title, track.artist, track.album, track.albumArtist, track.genre, track.duration, track.isrc, track.mbId, user.did, user.handle, user.displayName, artist.name, artist.genres */
1066
+ filter?: string;
1061
1067
  }
1062
1068
  export interface GetShoutRepliesOutput {
1063
1069
  shouts?: unknown[];
@@ -1115,6 +1121,8 @@ export interface GetSongsParams {
1115
1121
  isrc?: string;
1116
1122
  /** Filter songs by Spotify track ID (resolved internally to the Spotify track URL) */
1117
1123
  spotifyId?: string;
1124
+ /** RSQL filter expression, 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, createdAt */
1125
+ filter?: string;
1118
1126
  }
1119
1127
  export interface GetStarredOutput {
1120
1128
  }
@@ -1362,6 +1370,17 @@ export interface NotificationActor {
1362
1370
  /** The URL of the actor's avatar image. */
1363
1371
  avatar?: Uri;
1364
1372
  }
1373
+ /** The song, album, or scrobble a notification relates to, for rich display. */
1374
+ export interface NotificationSubjectView {
1375
+ /** The at-uri of the subject. */
1376
+ uri: string;
1377
+ /** The title of the track or album. */
1378
+ title?: string;
1379
+ /** The artist of the track or album. */
1380
+ artist?: string;
1381
+ /** The album art image URL. */
1382
+ albumArt?: Uri;
1383
+ }
1365
1384
  export interface NotificationView {
1366
1385
  /** The unique identifier of the notification. */
1367
1386
  id: string;
@@ -1378,6 +1397,7 @@ export interface NotificationView {
1378
1397
  /** The content of the related shout, if any. */
1379
1398
  shoutContent?: string;
1380
1399
  actor?: NotificationActor;
1400
+ subject?: NotificationSubjectView;
1381
1401
  }
1382
1402
  export interface PingOutput {
1383
1403
  }