@rocksky/sdk 0.13.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 +4 -2
- package/dist/client.d.ts +20 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/dedup.js +215 -0
- package/dist/errors.d.ts +5 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/hash.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -205
- package/dist/remote.d.ts.map +1 -1
- package/package.json +8 -2
- package/src/agent.ts +3 -3
- package/src/client.ts +53 -2
- package/src/errors.ts +7 -2
- package/src/hash.ts +4 -2
- package/src/index.ts +3 -1
- package/src/library.ts +2 -2
- package/src/remote.ts +4 -5
package/README.md
CHANGED
|
@@ -109,10 +109,12 @@ SHA-256, identical to the server and every other Rocksky SDK.
|
|
|
109
109
|
## Duplicate prevention + real-time sync
|
|
110
110
|
|
|
111
111
|
An optional local index (embedded [classic-level](https://github.com/Level/classic-level)
|
|
112
|
-
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:
|
|
113
115
|
|
|
114
116
|
```ts
|
|
115
|
-
import { RockskyIndex } from "@rocksky/sdk";
|
|
117
|
+
import { RockskyIndex } from "@rocksky/sdk/dedup";
|
|
116
118
|
|
|
117
119
|
const idx = new RockskyIndex("./dedup");
|
|
118
120
|
await idx.open();
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Filter } from "./filter.js";
|
|
2
2
|
import { RockskyLibrary } from "./library.js";
|
|
3
|
-
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";
|
|
4
4
|
/**
|
|
5
5
|
* A typed date window for the `top*` charts. Build one with the {@link Interval}
|
|
6
6
|
* factories; `range` bounds are RFC-3339 datetimes.
|
|
@@ -51,6 +51,13 @@ export declare class RockskyClient {
|
|
|
51
51
|
/** Call any AppView read query by nsid; returns the raw JSON response. Every
|
|
52
52
|
* method here is sugar over this — use it for queries without a wrapper. */
|
|
53
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>;
|
|
54
61
|
/** An actor's most-played songs. */
|
|
55
62
|
songs(actor: string, limit?: number, offset?: number): Promise<SongViewBasic[]>;
|
|
56
63
|
/** An actor's loved (liked) songs. */
|
|
@@ -188,5 +195,17 @@ export declare class RockskyClient {
|
|
|
188
195
|
* to mark **all** of the viewer's notifications. Returns the number remaining
|
|
189
196
|
* unread. */
|
|
190
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>;
|
|
191
210
|
}
|
|
192
211
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -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
|
-
|
|
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
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,
|
|
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"}
|
package/dist/hash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAUA,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { RockskyClient, DEFAULT_APPVIEW, Interval } from "./client.js";
|
|
|
12
12
|
export type { DateInterval } from "./client.js";
|
|
13
13
|
export { RockskyLibrary } from "./library.js";
|
|
14
14
|
export { Agent, MAX_SAFE_WRITES_PER_HOUR, DEFAULT_MATCH_SONG_PER_HOUR, type ScrobbleInput, type ScrobbleMatchInput, type SongInput, type AlbumInput, type ArtistInput, type RateLimitOptions, type RateLimitState, } from "./agent.js";
|
|
15
|
-
export {
|
|
15
|
+
export type { IndexStats, RockskyIndex } from "./dedup.js";
|
|
16
16
|
export { runJetstream, DEFAULT_JETSTREAM_SERVERS, type JetstreamOptions } from "./jetstream.js";
|
|
17
17
|
export { RemotePlayer, DEFAULT_REMOTE_WS, type RemotePlayerOptions, type RemotePlayerHandlers, type RemoteNowPlaying, type RemoteQueueItem, type EnqueueCommand, } from "./remote-player.js";
|
|
18
18
|
export { RemoteController, type RemoteControllerOptions, type RemoteControllerEvents, type RemoteDevice, type RemoteStatus, } from "./remote-controller.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,KAAK,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,KAAK,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAChG,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,MAAM,EACN,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,mBAAmB,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -19,11 +19,13 @@ var RockskyError;
|
|
|
19
19
|
var init_errors = __esm(() => {
|
|
20
20
|
RockskyError = class RockskyError extends Error {
|
|
21
21
|
kind;
|
|
22
|
-
|
|
22
|
+
status;
|
|
23
|
+
constructor(payload, status) {
|
|
23
24
|
const p = payload;
|
|
24
25
|
super(p?.message || p?.error || "rocksky request failed");
|
|
25
26
|
this.name = "RockskyError";
|
|
26
27
|
this.kind = p?.error;
|
|
28
|
+
this.status = status;
|
|
27
29
|
}
|
|
28
30
|
};
|
|
29
31
|
});
|
|
@@ -42,7 +44,7 @@ class RockskyLibrary {
|
|
|
42
44
|
}
|
|
43
45
|
const res = await this.rpc.get(nsid, { params: clean });
|
|
44
46
|
if (!res.ok)
|
|
45
|
-
throw new RockskyError(res.data);
|
|
47
|
+
throw new RockskyError(res.data, res.status);
|
|
46
48
|
return res.data;
|
|
47
49
|
}
|
|
48
50
|
async procedure(nsid, input) {
|
|
@@ -53,7 +55,7 @@ class RockskyLibrary {
|
|
|
53
55
|
}
|
|
54
56
|
const res = await this.rpc.post(nsid, { input: clean });
|
|
55
57
|
if (!res.ok)
|
|
56
|
-
throw new RockskyError(res.data);
|
|
58
|
+
throw new RockskyError(res.data, res.status);
|
|
57
59
|
return res.data;
|
|
58
60
|
}
|
|
59
61
|
ping() {
|
|
@@ -230,7 +232,7 @@ class RockskyClient {
|
|
|
230
232
|
}
|
|
231
233
|
const res = await this.rpc.get(nsid, { params: clean });
|
|
232
234
|
if (!res.ok)
|
|
233
|
-
throw new RockskyError(res.data);
|
|
235
|
+
throw new RockskyError(res.data, res.status);
|
|
234
236
|
return res.data;
|
|
235
237
|
}
|
|
236
238
|
profile(actor) {
|
|
@@ -247,6 +249,20 @@ class RockskyClient {
|
|
|
247
249
|
get(nsid, params = {}) {
|
|
248
250
|
return this.query(nsid, params);
|
|
249
251
|
}
|
|
252
|
+
async post(nsid, opts = {}) {
|
|
253
|
+
const clean = {};
|
|
254
|
+
for (const [k, v] of Object.entries(opts.params ?? {})) {
|
|
255
|
+
if (v !== undefined && v !== "")
|
|
256
|
+
clean[k] = v;
|
|
257
|
+
}
|
|
258
|
+
const call = { params: clean };
|
|
259
|
+
if (opts.body !== undefined)
|
|
260
|
+
call.input = opts.body;
|
|
261
|
+
const res = await this.rpc.post(nsid, call);
|
|
262
|
+
if (!res.ok)
|
|
263
|
+
throw new RockskyError(res.data, res.status);
|
|
264
|
+
return res.data;
|
|
265
|
+
}
|
|
250
266
|
async songs(actor, limit = 50, offset = 0) {
|
|
251
267
|
const out = await this.query("app.rocksky.actor.getActorSongs", {
|
|
252
268
|
did: actor,
|
|
@@ -489,9 +505,24 @@ class RockskyClient {
|
|
|
489
505
|
input: ids && ids.length ? { ids } : {}
|
|
490
506
|
});
|
|
491
507
|
if (!res.ok)
|
|
492
|
-
throw new RockskyError(res.data);
|
|
508
|
+
throw new RockskyError(res.data, res.status);
|
|
493
509
|
return res.data;
|
|
494
510
|
}
|
|
511
|
+
followAccount(account) {
|
|
512
|
+
return this.post("app.rocksky.graph.followAccount", { params: { account } });
|
|
513
|
+
}
|
|
514
|
+
unfollowAccount(account) {
|
|
515
|
+
return this.post("app.rocksky.graph.unfollowAccount", { params: { account } });
|
|
516
|
+
}
|
|
517
|
+
createScrobble(input) {
|
|
518
|
+
return this.post("app.rocksky.scrobble.createScrobble", { body: input });
|
|
519
|
+
}
|
|
520
|
+
putMirrorSource(input) {
|
|
521
|
+
return this.post("app.rocksky.mirror.putMirrorSource", { body: input });
|
|
522
|
+
}
|
|
523
|
+
putAudioSettings(input) {
|
|
524
|
+
return this.post("app.rocksky.rockbox.putAudioSettings", { body: input });
|
|
525
|
+
}
|
|
495
526
|
}
|
|
496
527
|
var Interval, DEFAULT_APPVIEW = "https://api.rocksky.app";
|
|
497
528
|
var init_client = __esm(() => {
|
|
@@ -745,7 +776,7 @@ class Agent {
|
|
|
745
776
|
input: { repo: this.did, collection, record: { ...record, $type: collection } }
|
|
746
777
|
});
|
|
747
778
|
if (!res.ok)
|
|
748
|
-
throw new RockskyError(res.data);
|
|
779
|
+
throw new RockskyError(res.data, res.status);
|
|
749
780
|
return res.data.uri;
|
|
750
781
|
}
|
|
751
782
|
async putRecord(collection, rkey, record) {
|
|
@@ -754,7 +785,7 @@ class Agent {
|
|
|
754
785
|
input: { repo: this.did, collection, rkey, record: { ...record, $type: collection } }
|
|
755
786
|
});
|
|
756
787
|
if (!res.ok)
|
|
757
|
-
throw new RockskyError(res.data);
|
|
788
|
+
throw new RockskyError(res.data, res.status);
|
|
758
789
|
return res.data.uri;
|
|
759
790
|
}
|
|
760
791
|
async delete(collection, rkey) {
|
|
@@ -763,7 +794,7 @@ class Agent {
|
|
|
763
794
|
input: { repo: this.did, collection, rkey }
|
|
764
795
|
});
|
|
765
796
|
if (!res.ok)
|
|
766
|
-
throw new RockskyError(res.data);
|
|
797
|
+
throw new RockskyError(res.data, res.status);
|
|
767
798
|
}
|
|
768
799
|
async scrobble(rec) {
|
|
769
800
|
const record = { ...rec, createdAt: rec.createdAt || nowISO() };
|
|
@@ -904,200 +935,6 @@ class Agent {
|
|
|
904
935
|
return this.delete(C_STATUS, "self");
|
|
905
936
|
}
|
|
906
937
|
}
|
|
907
|
-
// src/dedup.ts
|
|
908
|
-
import { fromUint8Array } from "@atcute/car";
|
|
909
|
-
import { decode as cborDecode, fromBytes, isBytes, isCidLink } from "@atcute/cbor";
|
|
910
|
-
import { toString as cidToString } from "@atcute/cid";
|
|
911
|
-
import { ClassicLevel } from "classic-level";
|
|
912
|
-
|
|
913
|
-
// src/hash.ts
|
|
914
|
-
import { createHash } from "node:crypto";
|
|
915
|
-
function sha256Lower(s) {
|
|
916
|
-
return createHash("sha256").update(s.toLowerCase()).digest("hex");
|
|
917
|
-
}
|
|
918
|
-
function songHash(title, artist, album) {
|
|
919
|
-
return sha256Lower(`${title} - ${artist} - ${album}`);
|
|
920
|
-
}
|
|
921
|
-
function albumHash(album, albumArtist) {
|
|
922
|
-
return sha256Lower(`${album} - ${albumArtist}`);
|
|
923
|
-
}
|
|
924
|
-
function artistHash(albumArtist) {
|
|
925
|
-
return sha256Lower(albumArtist);
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
// src/dedup.ts
|
|
929
|
-
var C_ARTIST2 = "app.rocksky.artist";
|
|
930
|
-
var C_ALBUM2 = "app.rocksky.album";
|
|
931
|
-
var C_SONG2 = "app.rocksky.song";
|
|
932
|
-
var C_SCROBBLE2 = "app.rocksky.scrobble";
|
|
933
|
-
var SEP = "\x00";
|
|
934
|
-
function totalIndexed(s) {
|
|
935
|
-
return s.artists + s.albums + s.songs + s.scrobbles;
|
|
936
|
-
}
|
|
937
|
-
function identKey(did, col, hash) {
|
|
938
|
-
return `${did}${SEP}${col}${SEP}${hash}`;
|
|
939
|
-
}
|
|
940
|
-
function scrobbleKey(did, songH, secs) {
|
|
941
|
-
return `${did}${SEP}${C_SCROBBLE2}${SEP}${songH}${SEP}${secs}`;
|
|
942
|
-
}
|
|
943
|
-
function primaryFor(did, col, rec) {
|
|
944
|
-
const s = (k) => typeof rec[k] === "string" ? rec[k] : "";
|
|
945
|
-
switch (col) {
|
|
946
|
-
case C_ARTIST2:
|
|
947
|
-
return s("name") ? identKey(did, C_ARTIST2, artistHash(s("name"))) : undefined;
|
|
948
|
-
case C_ALBUM2:
|
|
949
|
-
return s("title") && s("artist") ? identKey(did, C_ALBUM2, albumHash(s("title"), s("artist"))) : undefined;
|
|
950
|
-
case C_SONG2:
|
|
951
|
-
return s("title") && s("artist") && s("album") ? identKey(did, C_SONG2, songHash(s("title"), s("artist"), s("album"))) : undefined;
|
|
952
|
-
case C_SCROBBLE2: {
|
|
953
|
-
if (s("title") && s("artist") && s("album") && s("createdAt")) {
|
|
954
|
-
const secs = Math.floor(Date.parse(s("createdAt")) / 1000);
|
|
955
|
-
if (!Number.isNaN(secs))
|
|
956
|
-
return scrobbleKey(did, songHash(s("title"), s("artist"), s("album")), secs);
|
|
957
|
-
}
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
return;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
class RockskyIndex {
|
|
965
|
-
db;
|
|
966
|
-
constructor(path) {
|
|
967
|
-
this.db = new ClassicLevel(path, { keyEncoding: "utf8", valueEncoding: "utf8" });
|
|
968
|
-
}
|
|
969
|
-
open() {
|
|
970
|
-
return this.db.open();
|
|
971
|
-
}
|
|
972
|
-
close() {
|
|
973
|
-
return this.db.close();
|
|
974
|
-
}
|
|
975
|
-
async get(key) {
|
|
976
|
-
try {
|
|
977
|
-
return await this.db.get(key);
|
|
978
|
-
} catch {
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
songUri(did, title, artist, album) {
|
|
983
|
-
return this.get(identKey(did, C_SONG2, songHash(title, artist, album)));
|
|
984
|
-
}
|
|
985
|
-
albumUri(did, album, albumArtist) {
|
|
986
|
-
return this.get(identKey(did, C_ALBUM2, albumHash(album, albumArtist)));
|
|
987
|
-
}
|
|
988
|
-
artistUri(did, albumArtist) {
|
|
989
|
-
return this.get(identKey(did, C_ARTIST2, artistHash(albumArtist)));
|
|
990
|
-
}
|
|
991
|
-
scrobbleUri(did, title, artist, album, secs) {
|
|
992
|
-
return this.get(scrobbleKey(did, songHash(title, artist, album), secs));
|
|
993
|
-
}
|
|
994
|
-
async putPrimary(did, col, primary, uri) {
|
|
995
|
-
const rkey = uri.slice(uri.lastIndexOf("/") + 1);
|
|
996
|
-
await this.db.batch([
|
|
997
|
-
{ type: "put", key: primary, value: uri },
|
|
998
|
-
{ type: "put", key: `${SEP}rk${SEP}${did}${SEP}${col}${SEP}${rkey}`, value: primary }
|
|
999
|
-
]);
|
|
1000
|
-
}
|
|
1001
|
-
recordSong(did, title, artist, album, uri) {
|
|
1002
|
-
return this.putPrimary(did, C_SONG2, identKey(did, C_SONG2, songHash(title, artist, album)), uri);
|
|
1003
|
-
}
|
|
1004
|
-
recordAlbum(did, album, albumArtist, uri) {
|
|
1005
|
-
return this.putPrimary(did, C_ALBUM2, identKey(did, C_ALBUM2, albumHash(album, albumArtist)), uri);
|
|
1006
|
-
}
|
|
1007
|
-
recordArtist(did, albumArtist, uri) {
|
|
1008
|
-
return this.putPrimary(did, C_ARTIST2, identKey(did, C_ARTIST2, artistHash(albumArtist)), uri);
|
|
1009
|
-
}
|
|
1010
|
-
recordScrobble(did, title, artist, album, secs, uri) {
|
|
1011
|
-
return this.putPrimary(did, C_SCROBBLE2, scrobbleKey(did, songHash(title, artist, album), secs), uri);
|
|
1012
|
-
}
|
|
1013
|
-
cursor(did) {
|
|
1014
|
-
return this.get(`${SEP}meta${SEP}cursor${SEP}${did}`).then((v) => v ? Number(v) : 0);
|
|
1015
|
-
}
|
|
1016
|
-
async setCursor(did, timeUS) {
|
|
1017
|
-
await this.db.put(`${SEP}meta${SEP}cursor${SEP}${did}`, String(timeUS));
|
|
1018
|
-
}
|
|
1019
|
-
async indexCar(did, car) {
|
|
1020
|
-
const reader = fromUint8Array(car);
|
|
1021
|
-
const blocks = new Map;
|
|
1022
|
-
for (const entry of reader)
|
|
1023
|
-
blocks.set(cidToString(entry.cid), entry.bytes);
|
|
1024
|
-
const root = reader.roots[0];
|
|
1025
|
-
if (!root)
|
|
1026
|
-
throw new Error("CAR has no root");
|
|
1027
|
-
const commit = cborDecode(blocks.get(root.$link));
|
|
1028
|
-
const stats = { artists: 0, albums: 0, songs: 0, scrobbles: 0 };
|
|
1029
|
-
const ops = [];
|
|
1030
|
-
for (const [path, valueLink] of walkMst(blocks, commit.data.$link)) {
|
|
1031
|
-
const slash = path.indexOf("/");
|
|
1032
|
-
if (slash < 0)
|
|
1033
|
-
continue;
|
|
1034
|
-
const col = path.slice(0, slash);
|
|
1035
|
-
const rkey = path.slice(slash + 1);
|
|
1036
|
-
if (col !== C_ARTIST2 && col !== C_ALBUM2 && col !== C_SONG2 && col !== C_SCROBBLE2)
|
|
1037
|
-
continue;
|
|
1038
|
-
const recBytes = blocks.get(valueLink);
|
|
1039
|
-
if (!recBytes)
|
|
1040
|
-
continue;
|
|
1041
|
-
const rec = cborDecode(recBytes);
|
|
1042
|
-
const primary = primaryFor(did, col, rec);
|
|
1043
|
-
if (!primary)
|
|
1044
|
-
continue;
|
|
1045
|
-
const uri = `at://${did}/${col}/${rkey}`;
|
|
1046
|
-
ops.push({ type: "put", key: primary, value: uri });
|
|
1047
|
-
ops.push({ type: "put", key: `${SEP}rk${SEP}${did}${SEP}${col}${SEP}${rkey}`, value: primary });
|
|
1048
|
-
if (col === C_ARTIST2)
|
|
1049
|
-
stats.artists++;
|
|
1050
|
-
else if (col === C_ALBUM2)
|
|
1051
|
-
stats.albums++;
|
|
1052
|
-
else if (col === C_SONG2)
|
|
1053
|
-
stats.songs++;
|
|
1054
|
-
else
|
|
1055
|
-
stats.scrobbles++;
|
|
1056
|
-
}
|
|
1057
|
-
if (commit.rev)
|
|
1058
|
-
ops.push({ type: "put", key: `${SEP}meta${SEP}rev${SEP}${did}`, value: commit.rev });
|
|
1059
|
-
await this.db.batch(ops);
|
|
1060
|
-
return stats;
|
|
1061
|
-
}
|
|
1062
|
-
async applyCommit(did, col, operation, rkey, record) {
|
|
1063
|
-
if (operation === "create" || operation === "update") {
|
|
1064
|
-
if (!record)
|
|
1065
|
-
return;
|
|
1066
|
-
const primary = primaryFor(did, col, record);
|
|
1067
|
-
if (!primary)
|
|
1068
|
-
return;
|
|
1069
|
-
await this.putPrimary(did, col, primary, `at://${did}/${col}/${rkey}`);
|
|
1070
|
-
} else if (operation === "delete") {
|
|
1071
|
-
const rk = `${SEP}rk${SEP}${did}${SEP}${col}${SEP}${rkey}`;
|
|
1072
|
-
const primary = await this.get(rk);
|
|
1073
|
-
if (primary) {
|
|
1074
|
-
await this.db.batch([
|
|
1075
|
-
{ type: "del", key: primary },
|
|
1076
|
-
{ type: "del", key: rk }
|
|
1077
|
-
]);
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
function* walkMst(blocks, cid) {
|
|
1083
|
-
const raw = blocks.get(cid);
|
|
1084
|
-
if (!raw)
|
|
1085
|
-
return;
|
|
1086
|
-
const node = cborDecode(raw);
|
|
1087
|
-
if (node.l && isCidLink(node.l))
|
|
1088
|
-
yield* walkMst(blocks, node.l.$link);
|
|
1089
|
-
let last = new Uint8Array(0);
|
|
1090
|
-
for (const e of node.e) {
|
|
1091
|
-
const suffix = isBytes(e.k) ? fromBytes(e.k) : e.k;
|
|
1092
|
-
const key = new Uint8Array(e.p + suffix.length);
|
|
1093
|
-
key.set(last.subarray(0, e.p), 0);
|
|
1094
|
-
key.set(suffix, e.p);
|
|
1095
|
-
yield [new TextDecoder().decode(key), e.v.$link];
|
|
1096
|
-
last = key;
|
|
1097
|
-
if (e.t && isCidLink(e.t))
|
|
1098
|
-
yield* walkMst(blocks, e.t.$link);
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
938
|
// src/remote-player.ts
|
|
1102
939
|
var DEFAULT_REMOTE_WS = "wss://api.rocksky.app/ws";
|
|
1103
940
|
|
|
@@ -1742,6 +1579,21 @@ var ScrobbleFields = {
|
|
|
1742
1579
|
artistName: "artist.name",
|
|
1743
1580
|
artistGenres: "artist.genres"
|
|
1744
1581
|
};
|
|
1582
|
+
// src/hash.ts
|
|
1583
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
1584
|
+
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
1585
|
+
function sha256Lower(s) {
|
|
1586
|
+
return bytesToHex(sha256(new TextEncoder().encode(s.toLowerCase())));
|
|
1587
|
+
}
|
|
1588
|
+
function songHash(title, artist, album) {
|
|
1589
|
+
return sha256Lower(`${title} - ${artist} - ${album}`);
|
|
1590
|
+
}
|
|
1591
|
+
function albumHash(album, albumArtist) {
|
|
1592
|
+
return sha256Lower(`${album} - ${albumArtist}`);
|
|
1593
|
+
}
|
|
1594
|
+
function artistHash(albumArtist) {
|
|
1595
|
+
return sha256Lower(albumArtist);
|
|
1596
|
+
}
|
|
1745
1597
|
|
|
1746
1598
|
// src/index.ts
|
|
1747
1599
|
init_errors();
|
|
@@ -1760,13 +1612,11 @@ export {
|
|
|
1760
1612
|
RemotePlayer,
|
|
1761
1613
|
RockskyClient,
|
|
1762
1614
|
RockskyError,
|
|
1763
|
-
RockskyIndex,
|
|
1764
1615
|
RockskyLibrary,
|
|
1765
1616
|
ScrobbleFields,
|
|
1766
1617
|
SongFields,
|
|
1767
1618
|
albumHash,
|
|
1768
1619
|
artistHash,
|
|
1769
1620
|
runJetstream,
|
|
1770
|
-
songHash
|
|
1771
|
-
totalIndexed
|
|
1621
|
+
songHash
|
|
1772
1622
|
};
|
package/dist/remote.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rocksky/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
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": {
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
"types": "./dist/remote.d.ts",
|
|
27
27
|
"import": "./dist/remote.js",
|
|
28
28
|
"default": "./dist/remote.js"
|
|
29
|
+
},
|
|
30
|
+
"./dedup": {
|
|
31
|
+
"types": "./dist/dedup.d.ts",
|
|
32
|
+
"import": "./dist/dedup.js",
|
|
33
|
+
"default": "./dist/dedup.js"
|
|
29
34
|
}
|
|
30
35
|
},
|
|
31
36
|
"files": [
|
|
@@ -34,7 +39,7 @@
|
|
|
34
39
|
"README.md"
|
|
35
40
|
],
|
|
36
41
|
"scripts": {
|
|
37
|
-
"build": "bun build ./src/index.ts ./src/remote.ts --outdir ./dist --target node --format esm --packages external && bun run build:types",
|
|
42
|
+
"build": "bun build ./src/index.ts ./src/remote.ts ./src/dedup.ts --outdir ./dist --target node --format esm --packages external && bun run build:types",
|
|
38
43
|
"build:types": "tsc -p tsconfig.build.json",
|
|
39
44
|
"typecheck": "tsc --noEmit",
|
|
40
45
|
"test": "bun test",
|
|
@@ -69,6 +74,7 @@
|
|
|
69
74
|
"@atcute/identity": "^2.0.2",
|
|
70
75
|
"@atcute/identity-resolver": "^2.0.1",
|
|
71
76
|
"@atcute/password-session": "^1.0.2",
|
|
77
|
+
"@noble/hashes": "^2.3.0",
|
|
72
78
|
"classic-level": "^3.0.0"
|
|
73
79
|
}
|
|
74
80
|
}
|
package/src/agent.ts
CHANGED
|
@@ -325,7 +325,7 @@ export class Agent {
|
|
|
325
325
|
const res = await this.rpc.post("com.atproto.repo.createRecord" as never, {
|
|
326
326
|
input: { repo: this.did, collection, record: { ...record, $type: collection } },
|
|
327
327
|
} as never);
|
|
328
|
-
if (!res.ok) throw new RockskyError(res.data);
|
|
328
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
329
329
|
return (res.data as { uri: string }).uri;
|
|
330
330
|
}
|
|
331
331
|
|
|
@@ -334,7 +334,7 @@ export class Agent {
|
|
|
334
334
|
const res = await this.rpc.post("com.atproto.repo.putRecord" as never, {
|
|
335
335
|
input: { repo: this.did, collection, rkey, record: { ...record, $type: collection } },
|
|
336
336
|
} as never);
|
|
337
|
-
if (!res.ok) throw new RockskyError(res.data);
|
|
337
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
338
338
|
return (res.data as { uri: string }).uri;
|
|
339
339
|
}
|
|
340
340
|
|
|
@@ -344,7 +344,7 @@ export class Agent {
|
|
|
344
344
|
const res = await this.rpc.post("com.atproto.repo.deleteRecord" as never, {
|
|
345
345
|
input: { repo: this.did, collection, rkey },
|
|
346
346
|
} as never);
|
|
347
|
-
if (!res.ok) throw new RockskyError(res.data);
|
|
347
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
/**
|
package/src/client.ts
CHANGED
|
@@ -11,6 +11,8 @@ import type {
|
|
|
11
11
|
ArtistViewBasic,
|
|
12
12
|
ArtistViewDetailed,
|
|
13
13
|
ChartsView,
|
|
14
|
+
CreateScrobbleInput,
|
|
15
|
+
FollowAccountOutput,
|
|
14
16
|
FeedGeneratorsView,
|
|
15
17
|
FeedRecommendationsView,
|
|
16
18
|
FeedRecommendedAlbumsView,
|
|
@@ -37,10 +39,13 @@ import type {
|
|
|
37
39
|
GetTrackShoutsOutput,
|
|
38
40
|
GetUnreadCountOutput,
|
|
39
41
|
ListNotificationsOutput,
|
|
42
|
+
MirrorSourceView,
|
|
40
43
|
PlayerCurrentlyPlayingViewDetailed,
|
|
41
44
|
PlayerPlaybackQueueViewDetailed,
|
|
42
45
|
PlaylistGetPlaylistsOutput,
|
|
43
46
|
PlaylistViewDetailed,
|
|
47
|
+
PutAudioSettingsInput,
|
|
48
|
+
PutMirrorSourceInput,
|
|
44
49
|
RockboxSettingsView,
|
|
45
50
|
ScrobbleViewBasic,
|
|
46
51
|
SongViewBasic,
|
|
@@ -48,6 +53,7 @@ import type {
|
|
|
48
53
|
StatsGlobalStatsView,
|
|
49
54
|
StatsView,
|
|
50
55
|
StatsWrappedView,
|
|
56
|
+
UnfollowAccountOutput,
|
|
51
57
|
UpdateSeenOutput,
|
|
52
58
|
} from "./generated/types.js";
|
|
53
59
|
|
|
@@ -136,7 +142,7 @@ export class RockskyClient {
|
|
|
136
142
|
if (v !== undefined && v !== "") clean[k] = v;
|
|
137
143
|
}
|
|
138
144
|
const res = await this.rpc.get(nsid as never, { params: clean } as never);
|
|
139
|
-
if (!res.ok) throw new RockskyError(res.data);
|
|
145
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
140
146
|
return res.data as T;
|
|
141
147
|
}
|
|
142
148
|
|
|
@@ -161,6 +167,24 @@ export class RockskyClient {
|
|
|
161
167
|
return this.query(nsid, params);
|
|
162
168
|
}
|
|
163
169
|
|
|
170
|
+
/** Call any AppView procedure by nsid. `params` ride the query string (some
|
|
171
|
+
* procedures take their arguments there), `body` is the JSON input — omitted
|
|
172
|
+
* entirely when `undefined`. Escape hatch for procedures without a wrapper. */
|
|
173
|
+
async post<T = unknown>(
|
|
174
|
+
nsid: string,
|
|
175
|
+
opts: { params?: Record<string, unknown>; body?: unknown } = {},
|
|
176
|
+
): Promise<T> {
|
|
177
|
+
const clean: Record<string, unknown> = {};
|
|
178
|
+
for (const [k, v] of Object.entries(opts.params ?? {})) {
|
|
179
|
+
if (v !== undefined && v !== "") clean[k] = v;
|
|
180
|
+
}
|
|
181
|
+
const call: Record<string, unknown> = { params: clean };
|
|
182
|
+
if (opts.body !== undefined) call.input = opts.body;
|
|
183
|
+
const res = await this.rpc.post(nsid as never, call as never);
|
|
184
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
185
|
+
return res.data as T;
|
|
186
|
+
}
|
|
187
|
+
|
|
164
188
|
/** An actor's most-played songs. */
|
|
165
189
|
async songs(actor: string, limit = 50, offset = 0): Promise<SongViewBasic[]> {
|
|
166
190
|
const out = await this.query<{ tracks?: SongViewBasic[] }>("app.rocksky.actor.getActorSongs", {
|
|
@@ -539,7 +563,34 @@ export class RockskyClient {
|
|
|
539
563
|
const res = await this.rpc.post("app.rocksky.notification.updateSeen" as never, {
|
|
540
564
|
input: (ids && ids.length ? { ids } : {}) as never,
|
|
541
565
|
} as never);
|
|
542
|
-
if (!res.ok) throw new RockskyError(res.data);
|
|
566
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
543
567
|
return res.data as UpdateSeenOutput;
|
|
544
568
|
}
|
|
569
|
+
|
|
570
|
+
/** Follow an account by DID or handle (`app.rocksky.graph.followAccount`). Auth required. */
|
|
571
|
+
followAccount(account: string): Promise<FollowAccountOutput> {
|
|
572
|
+
return this.post("app.rocksky.graph.followAccount", { params: { account } });
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/** Unfollow an account by DID or handle (`app.rocksky.graph.unfollowAccount`). Auth required. */
|
|
576
|
+
unfollowAccount(account: string): Promise<UnfollowAccountOutput> {
|
|
577
|
+
return this.post("app.rocksky.graph.unfollowAccount", { params: { account } });
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/** Submit a scrobble through the AppView (`app.rocksky.scrobble.createScrobble`).
|
|
581
|
+
* Auth required. For direct-to-PDS scrobbling use {@link Agent} instead. */
|
|
582
|
+
createScrobble(input: CreateScrobbleInput): Promise<ScrobbleViewBasic> {
|
|
583
|
+
return this.post("app.rocksky.scrobble.createScrobble", { body: input });
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** Create or update a mirror source (`app.rocksky.mirror.putMirrorSource`). Auth required. */
|
|
587
|
+
putMirrorSource(input: PutMirrorSourceInput): Promise<MirrorSourceView> {
|
|
588
|
+
return this.post("app.rocksky.mirror.putMirrorSource", { body: input });
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/** Patch the viewer's Rockbox audio settings (`app.rocksky.rockbox.putAudioSettings`).
|
|
592
|
+
* Auth required. */
|
|
593
|
+
putAudioSettings(input: PutAudioSettingsInput): Promise<RockboxSettingsView> {
|
|
594
|
+
return this.post("app.rocksky.rockbox.putAudioSettings", { body: input });
|
|
595
|
+
}
|
|
545
596
|
}
|
package/src/errors.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
/** Error thrown when a Rocksky XRPC call returns a non-2xx `{ error, message }`. */
|
|
2
1
|
export 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
|
-
|
|
5
|
+
/** The HTTP status of the failed response, when known. */
|
|
6
|
+
readonly status?: number;
|
|
7
|
+
|
|
8
|
+
constructor(payload: unknown, status?: number) {
|
|
5
9
|
const p = payload as { error?: string; message?: string } | undefined;
|
|
6
10
|
super(p?.message || p?.error || "rocksky request failed");
|
|
7
11
|
this.name = "RockskyError";
|
|
8
12
|
this.kind = p?.error;
|
|
13
|
+
this.status = status;
|
|
9
14
|
}
|
|
10
15
|
}
|
package/src/hash.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
+
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
2
3
|
|
|
3
4
|
// Lowercase-hex SHA-256 of s.toLowerCase() — the lowercasing is applied to the
|
|
4
5
|
// whole string (not per field), matching Rocksky's server and every other SDK.
|
|
6
|
+
// Pure-JS digest (@noble/hashes) so this module stays browser-safe.
|
|
5
7
|
function sha256Lower(s: string): string {
|
|
6
|
-
return
|
|
8
|
+
return bytesToHex(sha256(new TextEncoder().encode(s.toLowerCase())));
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
/** Identity hash of a song: sha256(lower("{title} - {artist} - {album}")). */
|
package/src/index.ts
CHANGED
|
@@ -23,7 +23,9 @@ export {
|
|
|
23
23
|
type RateLimitOptions,
|
|
24
24
|
type RateLimitState,
|
|
25
25
|
} from "./agent.js";
|
|
26
|
-
|
|
26
|
+
// The dedup index (classic-level, Node-only) lives on the `@rocksky/sdk/dedup`
|
|
27
|
+
// subpath so this root entry stays browser-safe.
|
|
28
|
+
export type { IndexStats, RockskyIndex } from "./dedup.js";
|
|
27
29
|
export { runJetstream, DEFAULT_JETSTREAM_SERVERS, type JetstreamOptions } from "./jetstream.js";
|
|
28
30
|
export {
|
|
29
31
|
RemotePlayer,
|
package/src/library.ts
CHANGED
|
@@ -20,7 +20,7 @@ export class RockskyLibrary {
|
|
|
20
20
|
if (v !== undefined && v !== "") clean[k] = v;
|
|
21
21
|
}
|
|
22
22
|
const res = await this.rpc.get(nsid as never, { params: clean } as never);
|
|
23
|
-
if (!res.ok) throw new RockskyError(res.data);
|
|
23
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
24
24
|
return res.data as T;
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -30,7 +30,7 @@ export class RockskyLibrary {
|
|
|
30
30
|
if (v !== undefined && v !== "") clean[k] = v;
|
|
31
31
|
}
|
|
32
32
|
const res = await this.rpc.post(nsid as never, { input: clean } as never);
|
|
33
|
-
if (!res.ok) throw new RockskyError(res.data);
|
|
33
|
+
if (!res.ok) throw new RockskyError(res.data, res.status);
|
|
34
34
|
return res.data as T;
|
|
35
35
|
}
|
|
36
36
|
|
package/src/remote.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Lightweight entry: the remote-control player + controller only.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// subpath (`@rocksky/sdk/remote`) is safe to import from a browser bundle.
|
|
3
|
+
// Since 0.14.0 the main entry (`@rocksky/sdk`) is browser-safe too — the
|
|
4
|
+
// dedup index (classic-level, Node-only) moved to `@rocksky/sdk/dedup`. This
|
|
5
|
+
// subpath remains for consumers that only need the remote player/controller.
|
|
7
6
|
|
|
8
7
|
export {
|
|
9
8
|
RemotePlayer,
|