@atproto-ui/core 0.13.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/dist/backlinks.d.ts +18 -0
- package/dist/backlinks.js +15 -0
- package/dist/blob-fetch.d.ts +42 -0
- package/dist/blob-fetch.js +53 -0
- package/dist/cache.d.ts +155 -0
- package/dist/cache.js +345 -0
- package/dist/client.d.ts +45 -0
- package/dist/client.js +118 -0
- package/dist/fetch-and-cache-handler.d.ts +84 -0
- package/dist/fetch-and-cache-handler.js +63 -0
- package/dist/grain.d.ts +22 -0
- package/dist/grain.js +30 -0
- package/dist/icons.d.ts +11 -0
- package/dist/icons.js +11 -0
- package/dist/identity.d.ts +28 -0
- package/dist/identity.js +55 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +22 -0
- package/dist/leaflet.d.ts +22 -0
- package/dist/leaflet.js +85 -0
- package/dist/music.d.ts +35 -0
- package/dist/music.js +88 -0
- package/dist/paginated.d.ts +61 -0
- package/dist/paginated.js +111 -0
- package/dist/records.d.ts +171 -0
- package/dist/records.js +321 -0
- package/dist/rpc.d.ts +21 -0
- package/dist/rpc.js +24 -0
- package/dist/styles.d.ts +40 -0
- package/dist/styles.js +1728 -0
- package/dist/tangled-fetch.d.ts +9 -0
- package/dist/tangled-fetch.js +15 -0
- package/dist/types/blob.d.ts +14 -0
- package/dist/types/bluesky.d.ts +4 -0
- package/dist/types/grain.d.ts +31 -0
- package/dist/types/leaflet.d.ts +173 -0
- package/dist/types/record.d.ts +28 -0
- package/dist/types/record.js +7 -0
- package/dist/types/tangled.d.ts +19 -0
- package/dist/types/teal.d.ts +36 -0
- package/dist/utils/at-uri.d.ts +10 -0
- package/dist/utils/at-uri.js +33 -0
- package/dist/utils/blob.d.ts +5 -0
- package/dist/utils/blob.js +26 -0
- package/dist/utils/profile.d.ts +2 -0
- package/dist/utils/profile.js +5 -0
- package/dist/utils/richtext.d.ts +28 -0
- package/dist/utils/richtext.js +95 -0
- package/dist/utils/time.d.ts +2 -0
- package/dist/utils/time.js +41 -0
- package/package.json +41 -0
package/dist/music.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const musicPlatforms = {
|
|
2
|
+
spotify: {
|
|
3
|
+
name: "Spotify",
|
|
4
|
+
svg: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 496 512\"><path fill=\"#1ed760\" d=\"M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8Z\"/><path d=\"M406.6 231.1c-5.2 0-8.4-1.3-12.9-3.9-71.2-42.5-198.5-52.7-280.9-29.7-3.6 1-8.1 2.6-12.9 2.6-13.2 0-23.3-10.3-23.3-23.6 0-13.6 8.4-21.3 17.4-23.9 35.2-10.3 74.6-15.2 117.5-15.2 73 0 149.5 15.2 205.4 47.8 7.8 4.5 12.9 10.7 12.9 22.6 0 13.6-11 23.3-23.2 23.3zm-31 76.2c-5.2 0-8.7-2.3-12.3-4.2-62.5-37-155.7-51.9-238.6-29.4-4.8 1.3-7.4 2.6-11.9 2.6-10.7 0-19.4-8.7-19.4-19.4s5.2-17.8 15.5-20.7c27.8-7.8 56.2-13.6 97.8-13.6 64.9 0 127.6 16.1 177 45.5 8.1 4.8 11.3 11 11.3 19.7-.1 10.8-8.5 19.5-19.4 19.5zm-26.9 65.6c-4.2 0-6.8-1.3-10.7-3.6-62.4-37.6-135-39.2-206.7-24.5-3.9 1-9 2.6-11.9 2.6-9.7 0-15.8-7.7-15.8-15.8 0-10.3 6.1-15.2 13.6-16.8 81.9-18.1 165.6-16.5 237 26.2 6.1 3.9 9.7 7.4 9.7 16.5s-7.1 15.4-15.2 15.4z\"/></svg>",
|
|
5
|
+
color: "#1DB954"
|
|
6
|
+
},
|
|
7
|
+
appleMusic: {
|
|
8
|
+
name: "Apple Music",
|
|
9
|
+
svg: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 361 361\"><defs><linearGradient id=\"apple-grad\" x1=\"180\" y1=\"358.6\" x2=\"180\" y2=\"7.76\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0\" style=\"stop-color:#FA233B\"/><stop offset=\"1\" style=\"stop-color:#FB5C74\"/></linearGradient></defs><path fill=\"url(#apple-grad)\" d=\"M360 112.61V247.39c0 4.3 0 8.6-.02 12.9-.02 3.62-.06 7.24-.16 10.86-.21 7.89-.68 15.84-2.08 23.64-1.42 7.92-3.75 15.29-7.41 22.49-3.6 7.07-8.3 13.53-13.91 19.14-5.61 5.61-12.08 10.31-19.15 13.91-7.19 3.66-14.56 5.98-22.47 7.41-7.8 1.4-15.76 1.87-23.65 2.08-3.62.1-7.24.14-10.86.16-4.3.03-8.6.02-12.9.02H112.61c-4.3 0-8.6 0-12.9-.02-3.62-.02-7.24-.06-10.86-.16-7.89-.21-15.85-.68-23.65-2.08-7.92-1.42-15.28-3.75-22.47-7.41-7.07-3.6-13.54-8.3-19.15-13.91-5.61-5.61-10.31-12.07-13.91-19.14-3.66-7.2-5.99-14.57-7.41-22.49-1.4-7.8-1.87-15.76-2.08-23.64-.1-3.62-.14-7.24-.16-10.86C0 255.99 0 251.69 0 247.39V112.61c0-4.3 0-8.6.02-12.9.02-3.62.06-7.24.16-10.86.21-7.89.68-15.84 2.08-23.64 1.42-7.92 3.75-15.29 7.41-22.49 3.6-7.07 8.3-13.53 13.91-19.14 5.61-5.61 12.08-10.31 19.15-13.91 7.19-3.66 14.56-5.98 22.47-7.41 7.8-1.4 15.76-1.87 23.65-2.08 3.62-.1 7.24-.14 10.86-.16C104.01 0 108.31 0 112.61 0h134.77c4.3 0 8.6 0 12.9.02 3.62.02 7.24.06 10.86.16 7.89.21 15.85.68 23.65 2.08 7.92 1.42 15.28 3.75 22.47 7.41 7.07 3.6 13.54 8.3 19.15 13.91 5.61 5.61 10.31 12.07 13.91 19.14 3.66 7.2 5.99 14.57 7.41 22.49 1.4 7.8 1.87 15.76 2.08 23.64.1 3.62.14 7.24.16 10.86.03 4.3.02 8.6.02 12.9z\"/><path fill=\"#FFF\" d=\"M254.5 55c-.87.08-8.6 1.45-9.53 1.64l-107 21.59-.04.01c-2.79.59-4.98 1.58-6.67 3-2.04 1.71-3.17 4.13-3.6 6.95-.09.6-.24 1.82-.24 3.62v133.92c0 3.13-.25 6.17-2.37 8.76-2.12 2.59-4.74 3.37-7.81 3.99-2.33.47-4.66.94-6.99 1.41-8.84 1.78-14.59 2.99-19.8 5.01-4.98 1.93-8.71 4.39-11.68 7.51-5.89 6.17-8.28 14.54-7.46 22.38.7 6.69 3.71 13.09 8.88 17.82 3.49 3.2 7.85 5.63 12.99 6.66 5.33 1.07 11.01.7 19.31-.98 4.42-.89 8.56-2.28 12.5-4.61 3.9-2.3 7.24-5.37 9.85-9.11 2.62-3.75 4.31-7.92 5.24-12.35.96-4.57 1.19-8.7 1.19-13.26V128.82c0-6.22 1.76-7.86 6.78-9.08l93.09-18.75c5.79-1.11 8.52.54 8.52 6.61v79.29c0 3.14-.03 6.32-2.17 8.92-2.12 2.59-4.74 3.37-7.81 3.99-2.33.47-4.66.94-6.99 1.41-8.84 1.78-14.59 2.99-19.8 5.01-4.98 1.93-8.71 4.39-11.68 7.51-5.89 6.17-8.49 14.54-7.67 22.38.7 6.69 3.92 13.09 9.09 17.82 3.49 3.2 7.85 5.56 12.99 6.6 5.33 1.07 11.01.69 19.31-.98 4.42-.89 8.56-2.22 12.5-4.55 3.9-2.3 7.24-5.37 9.85-9.11 2.62-3.75 4.31-7.92 5.24-12.35.96-4.57 1-8.7 1-13.26V64.46c0-6.16-3.25-9.96-9.04-9.46z\"/></svg>",
|
|
10
|
+
color: "#FA243C"
|
|
11
|
+
},
|
|
12
|
+
youtube: {
|
|
13
|
+
name: "YouTube",
|
|
14
|
+
svg: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 300 300\"><g transform=\"scale(.75)\"><path fill=\"red\" d=\"M199.917 105.63s-84.292 0-105.448 5.497c-11.328 3.165-20.655 12.493-23.82 23.987-5.498 21.156-5.498 64.969-5.498 64.969s0 43.979 5.497 64.802c3.165 11.494 12.326 20.655 23.82 23.82 21.323 5.664 105.448 5.664 105.448 5.664s84.459 0 105.615-5.497c11.494-3.165 20.655-12.16 23.654-23.82 5.664-20.99 5.664-64.803 5.664-64.803s.166-43.98-5.664-65.135c-2.999-11.494-12.16-20.655-23.654-23.654-21.156-5.83-105.615-5.83-105.615-5.83zm-26.82 53.974 70.133 40.479-70.133 40.312v-80.79z\"/><path fill=\"#fff\" d=\"m173.097 159.604 70.133 40.479-70.133 40.312v-80.79z\"/></g></svg>",
|
|
15
|
+
color: "#FF0000"
|
|
16
|
+
},
|
|
17
|
+
youtubeMusic: {
|
|
18
|
+
name: "YouTube Music",
|
|
19
|
+
svg: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 176 176\"><circle fill=\"#FF0000\" cx=\"88\" cy=\"88\" r=\"88\"/><path fill=\"#FFF\" d=\"M88 46c23.1 0 42 18.8 42 42s-18.8 42-42 42-42-18.8-42-42 18.8-42 42-42m0-4c-25.4 0-46 20.6-46 46s20.6 46 46 46 46-20.6 46-46-20.6-46-46-46z\"/><path fill=\"#FFF\" d=\"m72 111 39-24-39-22z\"/></svg>",
|
|
20
|
+
color: "#FF0000"
|
|
21
|
+
},
|
|
22
|
+
tidal: {
|
|
23
|
+
name: "Tidal",
|
|
24
|
+
svg: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0c141.385 0 256 114.615 256 256S397.385 512 256 512 0 397.385 0 256 114.615 0 256 0zm50.384 219.459-50.372 50.383 50.379 50.391-50.382 50.393-50.395-50.393 50.393-50.389-50.393-50.39 50.395-50.372 50.38 50.369 50.389-50.375 50.382 50.382-50.382 50.392-50.394-50.391zm-100.767-.001-50.392 50.392-50.385-50.392 50.385-50.382 50.392 50.382z\"/></svg>",
|
|
25
|
+
color: "#000000"
|
|
26
|
+
},
|
|
27
|
+
bandcamp: {
|
|
28
|
+
name: "Bandcamp",
|
|
29
|
+
svg: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path fill=\"#1DA0C3\" d=\"M0 156v200h172l84-200z\"/></svg>",
|
|
30
|
+
color: "#1DA0C3"
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function availableMusicPlatforms(t) {
|
|
34
|
+
return t ? Object.keys(musicPlatforms).filter((e) => t.linksByPlatform[e]) : [];
|
|
35
|
+
}
|
|
36
|
+
async function fetchTrackArtwork(e, t) {
|
|
37
|
+
let n = e.artists[0]?.artistName, r = e.trackName;
|
|
38
|
+
if (!n || !r) return {};
|
|
39
|
+
let i = {}, a = () => t?.aborted;
|
|
40
|
+
if (e.isrc) try {
|
|
41
|
+
let n = await fetch(`https://api.song.link/v1-alpha.1/links?platform=isrc&type=song&id=${encodeURIComponent(e.isrc)}&songIfSingle=true`, { signal: t });
|
|
42
|
+
if (a()) return i;
|
|
43
|
+
if (n.ok) {
|
|
44
|
+
let e = await n.json();
|
|
45
|
+
i.songlink = e;
|
|
46
|
+
let t = e.entitiesByUniqueId?.[e.entityUniqueId ?? ""];
|
|
47
|
+
if (t?.thumbnailUrl && (i.albumArt = t.thumbnailUrl), i.albumArt) return i;
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
if (a()) return i;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
let e = await fetch(`https://itunes.apple.com/search?term=${encodeURIComponent(`${r} ${n}`)}&media=music&entity=song&limit=1`, { signal: t });
|
|
54
|
+
if (a()) return i;
|
|
55
|
+
if (e.ok) {
|
|
56
|
+
let n = (await e.json()).results?.[0];
|
|
57
|
+
if (n) {
|
|
58
|
+
let e = n.artworkUrl100?.replace("100x100", "600x600") ?? n.artworkUrl100;
|
|
59
|
+
e && !i.albumArt && (i.albumArt = e);
|
|
60
|
+
try {
|
|
61
|
+
let e = await fetch(`https://api.song.link/v1-alpha.1/links?platform=itunes&type=song&id=${n.trackId}&songIfSingle=true`, { signal: t });
|
|
62
|
+
if (a()) return i;
|
|
63
|
+
if (e.ok) return i.songlink = await e.json(), i;
|
|
64
|
+
} catch {
|
|
65
|
+
if (a()) return i;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
if (a()) return i;
|
|
71
|
+
}
|
|
72
|
+
let o = e.originUrl;
|
|
73
|
+
if (o && /spotify\.com|apple\.com|youtube\.com|tidal\.com/.test(o)) try {
|
|
74
|
+
let e = await fetch(`https://api.song.link/v1-alpha.1/links?url=${encodeURIComponent(o)}&songIfSingle=true`, { signal: t });
|
|
75
|
+
if (a()) return i;
|
|
76
|
+
if (e.ok) {
|
|
77
|
+
let t = await e.json();
|
|
78
|
+
if (i.songlink = t, !i.albumArt) {
|
|
79
|
+
let e = t.entitiesByUniqueId?.[t.entityUniqueId ?? ""];
|
|
80
|
+
e?.thumbnailUrl && (i.albumArt = e.thumbnailUrl);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
if (a()) return i;
|
|
85
|
+
}
|
|
86
|
+
return i;
|
|
87
|
+
}
|
|
88
|
+
export { availableMusicPlatforms, fetchTrackArtwork, musicPlatforms };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ServiceResolver } from "./client";
|
|
2
|
+
import type { DidCache, PaginatedRecordsCache, RecordCache } from "./cache";
|
|
3
|
+
import { type AuthorFeedFilter, type PaginatedRecord } from "./records";
|
|
4
|
+
export interface PaginatedRecordsSnapshot<T> {
|
|
5
|
+
records: PaginatedRecord<T>[];
|
|
6
|
+
loading: boolean;
|
|
7
|
+
error?: Error;
|
|
8
|
+
hasNext: boolean;
|
|
9
|
+
hasPrev: boolean;
|
|
10
|
+
pageIndex: number;
|
|
11
|
+
pagesCount: number;
|
|
12
|
+
}
|
|
13
|
+
export interface PaginatedRecordsControllerOptions {
|
|
14
|
+
handleOrDid: string;
|
|
15
|
+
collection: string;
|
|
16
|
+
limit?: number;
|
|
17
|
+
preferAuthorFeed?: boolean;
|
|
18
|
+
authorFeedFilter?: AuthorFeedFilter;
|
|
19
|
+
authorFeedIncludePins?: boolean;
|
|
20
|
+
authorFeedService?: string;
|
|
21
|
+
authorFeedActor?: string;
|
|
22
|
+
appviewService: string;
|
|
23
|
+
resolver: ServiceResolver;
|
|
24
|
+
didCache: DidCache;
|
|
25
|
+
recordCache: RecordCache;
|
|
26
|
+
pageCache: PaginatedRecordsCache;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Framework-agnostic cursor pagination engine. Owns DID/PDS resolution, page
|
|
30
|
+
* fetching, prefetch of the next page, request sequencing and dedup, and the
|
|
31
|
+
* author-feed→PDS fallback. Framework hooks subscribe and mirror getSnapshot();
|
|
32
|
+
* they hold no pagination logic themselves.
|
|
33
|
+
*/
|
|
34
|
+
export declare class PaginatedRecordsController<T = unknown> {
|
|
35
|
+
private options;
|
|
36
|
+
private pages;
|
|
37
|
+
private pageIndex;
|
|
38
|
+
private loading;
|
|
39
|
+
private error?;
|
|
40
|
+
private feedDisabled;
|
|
41
|
+
private inFlight;
|
|
42
|
+
private seq;
|
|
43
|
+
private subscribers;
|
|
44
|
+
private snapshot;
|
|
45
|
+
private did?;
|
|
46
|
+
private endpoint?;
|
|
47
|
+
private destroyed;
|
|
48
|
+
constructor(options: PaginatedRecordsControllerOptions);
|
|
49
|
+
subscribe: (cb: () => void) => (() => void);
|
|
50
|
+
getSnapshot: () => PaginatedRecordsSnapshot<T>;
|
|
51
|
+
loadNext: () => void;
|
|
52
|
+
loadPrev: () => void;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
private emit;
|
|
55
|
+
private buildSnapshot;
|
|
56
|
+
private start;
|
|
57
|
+
private fetchPage;
|
|
58
|
+
private maybePrefetch;
|
|
59
|
+
}
|
|
60
|
+
/** Stable key for an option set, so a hook re-creates the controller only on real input changes. */
|
|
61
|
+
export declare function paginatedControllerKey(options: Omit<PaginatedRecordsControllerOptions, "resolver" | "didCache" | "recordCache" | "pageCache">): string;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { fetchPaginatedRecordsPage } from "./records.js";
|
|
2
|
+
var EMPTY = [], PaginatedRecordsController = class {
|
|
3
|
+
constructor(e) {
|
|
4
|
+
this.options = e, this.pages = [], this.pageIndex = 0, this.loading = !1, this.feedDisabled = !1, this.inFlight = /* @__PURE__ */ new Set(), this.seq = 0, this.subscribers = /* @__PURE__ */ new Set(), this.destroyed = !1, this.subscribe = (e) => (this.subscribers.add(e), () => {
|
|
5
|
+
this.subscribers.delete(e);
|
|
6
|
+
}), this.getSnapshot = () => this.snapshot, this.loadNext = () => {
|
|
7
|
+
if (this.pages[this.pageIndex + 1]) {
|
|
8
|
+
this.pageIndex += 1, this.emit(), this.maybePrefetch();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
let e = this.pages[this.pageIndex]?.cursor;
|
|
12
|
+
e && this.fetchPage(e, this.pageIndex + 1, "active");
|
|
13
|
+
}, this.loadPrev = () => {
|
|
14
|
+
this.pageIndex > 0 && (--this.pageIndex, this.emit());
|
|
15
|
+
}, this.snapshot = this.buildSnapshot(), this.start();
|
|
16
|
+
}
|
|
17
|
+
destroy() {
|
|
18
|
+
this.destroyed = !0, this.seq += 1, this.subscribers.clear();
|
|
19
|
+
}
|
|
20
|
+
emit() {
|
|
21
|
+
this.snapshot = this.buildSnapshot();
|
|
22
|
+
for (let e of this.subscribers) e();
|
|
23
|
+
}
|
|
24
|
+
buildSnapshot() {
|
|
25
|
+
let e = this.pages[this.pageIndex];
|
|
26
|
+
return {
|
|
27
|
+
records: e?.records ?? EMPTY,
|
|
28
|
+
loading: this.loading,
|
|
29
|
+
error: this.error,
|
|
30
|
+
hasNext: !!(e?.cursor || this.pages[this.pageIndex + 1]),
|
|
31
|
+
hasPrev: this.pageIndex > 0,
|
|
32
|
+
pageIndex: this.pageIndex,
|
|
33
|
+
pagesCount: this.pages.length
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async start() {
|
|
37
|
+
this.loading = !0, this.emit();
|
|
38
|
+
try {
|
|
39
|
+
let e = this.options.handleOrDid.trim(), t = e.startsWith("did:") ? e : await this.options.resolver.resolveHandle(e);
|
|
40
|
+
e.startsWith("did:") || this.options.didCache.memoize({
|
|
41
|
+
did: t,
|
|
42
|
+
handle: e.toLowerCase()
|
|
43
|
+
});
|
|
44
|
+
let n = await this.options.resolver.pdsEndpointForDid(t);
|
|
45
|
+
if (this.destroyed) return;
|
|
46
|
+
this.did = t, this.endpoint = n, await this.fetchPage(void 0, 0, "active");
|
|
47
|
+
} catch (e) {
|
|
48
|
+
if (this.destroyed) return;
|
|
49
|
+
this.error = e instanceof Error ? e : Error(String(e)), this.loading = !1, this.emit();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async fetchPage(t, n, r) {
|
|
53
|
+
if (!this.did || !this.endpoint) return;
|
|
54
|
+
if (this.pages[n]) {
|
|
55
|
+
r === "active" && (this.pageIndex = n, this.loading = !1, this.emit(), this.maybePrefetch());
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let i = `${n}:${t ?? "start"}`;
|
|
59
|
+
if (this.inFlight.has(i)) return;
|
|
60
|
+
this.inFlight.add(i);
|
|
61
|
+
let a = this.seq;
|
|
62
|
+
r === "active" && (this.loading = !0, this.error = void 0, this.emit());
|
|
63
|
+
try {
|
|
64
|
+
let i = await fetchPaginatedRecordsPage({
|
|
65
|
+
did: this.did,
|
|
66
|
+
pdsEndpoint: this.endpoint,
|
|
67
|
+
collection: this.options.collection,
|
|
68
|
+
limit: this.options.limit ?? 5,
|
|
69
|
+
cursor: t,
|
|
70
|
+
preferAuthorFeed: !!this.options.preferAuthorFeed && !this.feedDisabled,
|
|
71
|
+
authorFeedActor: this.options.authorFeedActor ?? this.did,
|
|
72
|
+
authorFeedService: this.options.authorFeedService ?? this.options.appviewService,
|
|
73
|
+
authorFeedFilter: this.options.authorFeedFilter,
|
|
74
|
+
authorFeedIncludePins: this.options.authorFeedIncludePins,
|
|
75
|
+
pageCache: this.options.pageCache,
|
|
76
|
+
didCache: this.options.didCache,
|
|
77
|
+
recordCache: this.options.recordCache
|
|
78
|
+
});
|
|
79
|
+
if (this.destroyed || a !== this.seq) return;
|
|
80
|
+
this.options.preferAuthorFeed && this.options.collection === "app.bsky.feed.post" && !i.usedAuthorFeed && (this.feedDisabled = !0);
|
|
81
|
+
let o = [...this.pages];
|
|
82
|
+
o[n] = {
|
|
83
|
+
records: i.records,
|
|
84
|
+
cursor: i.cursor
|
|
85
|
+
}, this.pages = o, r === "active" && (this.pageIndex = n, this.loading = !1), this.emit(), r === "active" && this.maybePrefetch();
|
|
86
|
+
} catch (e) {
|
|
87
|
+
if (this.destroyed || a !== this.seq) return;
|
|
88
|
+
r === "active" && (this.error = e instanceof Error ? e : Error(String(e)), this.loading = !1, this.emit());
|
|
89
|
+
} finally {
|
|
90
|
+
this.inFlight.delete(i);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
maybePrefetch() {
|
|
94
|
+
let e = this.pages[this.pageIndex]?.cursor;
|
|
95
|
+
!e || this.pages[this.pageIndex + 1] || this.fetchPage(e, this.pageIndex + 1, "prefetch");
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
function paginatedControllerKey(e) {
|
|
99
|
+
return JSON.stringify({
|
|
100
|
+
handleOrDid: e.handleOrDid,
|
|
101
|
+
collection: e.collection,
|
|
102
|
+
limit: e.limit ?? 5,
|
|
103
|
+
preferAuthorFeed: !!e.preferAuthorFeed,
|
|
104
|
+
authorFeedFilter: e.authorFeedFilter ?? "",
|
|
105
|
+
authorFeedIncludePins: !!e.authorFeedIncludePins,
|
|
106
|
+
authorFeedService: e.authorFeedService ?? "",
|
|
107
|
+
authorFeedActor: e.authorFeedActor ?? "",
|
|
108
|
+
appviewService: e.appviewService
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
export { PaginatedRecordsController, paginatedControllerKey };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { DidCache, PaginatedRecordsCache, RecordCache } from "./cache";
|
|
2
|
+
import type { ServiceResolver } from "./client";
|
|
3
|
+
export type RecordSource = "appview" | "slingshot" | "pds";
|
|
4
|
+
export interface CachedRecordResult<T> {
|
|
5
|
+
record: T;
|
|
6
|
+
source?: RecordSource;
|
|
7
|
+
}
|
|
8
|
+
export type AuthorFeedFilter = "posts_with_replies" | "posts_no_replies" | "posts_with_media" | "posts_and_author_threads" | "posts_with_video";
|
|
9
|
+
export interface AuthorFeedReason {
|
|
10
|
+
$type?: string;
|
|
11
|
+
by?: {
|
|
12
|
+
handle?: string;
|
|
13
|
+
did?: string;
|
|
14
|
+
};
|
|
15
|
+
indexedAt?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ReplyParentInfo {
|
|
18
|
+
uri?: string;
|
|
19
|
+
author?: {
|
|
20
|
+
handle?: string;
|
|
21
|
+
did?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface FeedAuthorInfo {
|
|
25
|
+
did?: string;
|
|
26
|
+
handle?: string;
|
|
27
|
+
displayName?: string;
|
|
28
|
+
avatar?: string;
|
|
29
|
+
createdAt?: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
pronouns?: string;
|
|
32
|
+
website?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface PaginatedRecord<T> {
|
|
35
|
+
uri: string;
|
|
36
|
+
rkey: string;
|
|
37
|
+
value: T;
|
|
38
|
+
author?: FeedAuthorInfo;
|
|
39
|
+
reason?: AuthorFeedReason;
|
|
40
|
+
replyParent?: ReplyParentInfo;
|
|
41
|
+
}
|
|
42
|
+
export interface PaginatedRecordsPage<T> {
|
|
43
|
+
records: PaginatedRecord<T>[];
|
|
44
|
+
cursor?: string;
|
|
45
|
+
usedAuthorFeed: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface FetchPaginatedRecordsPageOptions {
|
|
48
|
+
did: string;
|
|
49
|
+
pdsEndpoint: string;
|
|
50
|
+
collection: string;
|
|
51
|
+
limit: number;
|
|
52
|
+
cursor?: string;
|
|
53
|
+
preferAuthorFeed?: boolean;
|
|
54
|
+
authorFeedActor?: string;
|
|
55
|
+
authorFeedService: string;
|
|
56
|
+
authorFeedFilter?: AuthorFeedFilter;
|
|
57
|
+
authorFeedIncludePins?: boolean;
|
|
58
|
+
pageCache?: PaginatedRecordsCache;
|
|
59
|
+
didCache?: DidCache;
|
|
60
|
+
recordCache?: RecordCache;
|
|
61
|
+
}
|
|
62
|
+
export interface LatestRecordResult<T = unknown> {
|
|
63
|
+
record?: T;
|
|
64
|
+
rkey?: string;
|
|
65
|
+
empty: boolean;
|
|
66
|
+
}
|
|
67
|
+
export interface BlueskyFeedCachePrimeOptions {
|
|
68
|
+
feed: ReadonlyArray<{
|
|
69
|
+
post?: {
|
|
70
|
+
uri?: string;
|
|
71
|
+
record?: unknown;
|
|
72
|
+
author?: FeedAuthorInfo;
|
|
73
|
+
reply?: {
|
|
74
|
+
parent?: ReplyParentInfo;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
reason?: AuthorFeedReason;
|
|
78
|
+
}>;
|
|
79
|
+
didCache?: DidCache;
|
|
80
|
+
recordCache?: RecordCache;
|
|
81
|
+
}
|
|
82
|
+
export interface BlueskyFeedCachePrimeResult {
|
|
83
|
+
dids: number;
|
|
84
|
+
profiles: number;
|
|
85
|
+
records: number;
|
|
86
|
+
}
|
|
87
|
+
export interface BlueskyProfileCachePrimeOptions {
|
|
88
|
+
profile: FeedAuthorInfo;
|
|
89
|
+
didCache?: DidCache;
|
|
90
|
+
recordCache?: RecordCache;
|
|
91
|
+
}
|
|
92
|
+
export declare function ensureCachedRecord<T>(cache: RecordCache, options: {
|
|
93
|
+
did: string;
|
|
94
|
+
collection: string;
|
|
95
|
+
rkey: string;
|
|
96
|
+
bypassCache?: boolean;
|
|
97
|
+
loader: () => Promise<T>;
|
|
98
|
+
}): {
|
|
99
|
+
promise: Promise<T>;
|
|
100
|
+
release: () => void;
|
|
101
|
+
};
|
|
102
|
+
export declare function fetchRepositoryRecord<T>(options: {
|
|
103
|
+
service: string;
|
|
104
|
+
did: string;
|
|
105
|
+
collection: string;
|
|
106
|
+
rkey: string;
|
|
107
|
+
recordCache?: RecordCache;
|
|
108
|
+
bypassCache?: boolean;
|
|
109
|
+
}): {
|
|
110
|
+
promise: Promise<T>;
|
|
111
|
+
release: () => void;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Library entry point for a single Bluesky record. Resolves the handle→DID,
|
|
115
|
+
* runs the appview → slingshot → PDS fallback (resolving the PDS endpoint lazily
|
|
116
|
+
* only if needed), and deduplicates/caches by resolved DID. Framework hooks
|
|
117
|
+
* should call this and apply the result; they must not orchestrate DID/PDS
|
|
118
|
+
* resolution themselves.
|
|
119
|
+
*/
|
|
120
|
+
export declare function getBlueskyRecord<T>(options: {
|
|
121
|
+
handleOrDid: string;
|
|
122
|
+
collection: string;
|
|
123
|
+
rkey: string;
|
|
124
|
+
appviewService: string;
|
|
125
|
+
resolver: ServiceResolver;
|
|
126
|
+
recordCache: RecordCache;
|
|
127
|
+
skipAppview?: boolean;
|
|
128
|
+
}): {
|
|
129
|
+
promise: Promise<CachedRecordResult<T>>;
|
|
130
|
+
release: () => void;
|
|
131
|
+
};
|
|
132
|
+
export declare function fetchBlueskyRecord<T>(options: {
|
|
133
|
+
did: string;
|
|
134
|
+
collection: string;
|
|
135
|
+
rkey: string;
|
|
136
|
+
pdsEndpoint?: string;
|
|
137
|
+
appviewService: string;
|
|
138
|
+
resolver: ServiceResolver;
|
|
139
|
+
recordCache: RecordCache;
|
|
140
|
+
skipAppview?: boolean;
|
|
141
|
+
}): {
|
|
142
|
+
promise: Promise<CachedRecordResult<T>>;
|
|
143
|
+
release: () => void;
|
|
144
|
+
};
|
|
145
|
+
export declare function fetchBlueskyRecordUncached<T>(options: {
|
|
146
|
+
did: string;
|
|
147
|
+
collection: string;
|
|
148
|
+
rkey: string;
|
|
149
|
+
/** Optional PDS endpoint. When omitted, it is resolved lazily before the PDS fallback. */
|
|
150
|
+
pdsEndpoint?: string;
|
|
151
|
+
appviewService: string;
|
|
152
|
+
resolver: ServiceResolver;
|
|
153
|
+
skipAppview?: boolean;
|
|
154
|
+
}): Promise<CachedRecordResult<T>>;
|
|
155
|
+
export declare function fetchLatestRecord<T>(options: {
|
|
156
|
+
service: string;
|
|
157
|
+
did: string;
|
|
158
|
+
collection: string;
|
|
159
|
+
limit?: number;
|
|
160
|
+
}): Promise<LatestRecordResult<T>>;
|
|
161
|
+
export declare function fetchPaginatedRecordsPage<T>(options: FetchPaginatedRecordsPageOptions): Promise<PaginatedRecordsPage<T>>;
|
|
162
|
+
/**
|
|
163
|
+
* Primes atproto-ui's framework-agnostic caches from an appview author feed
|
|
164
|
+
* response. This is useful when an app fetches a feed directly with atcute and
|
|
165
|
+
* then passes each record into atproto-ui renderers: post/profile/DID data that
|
|
166
|
+
* appview already returned can be consumed immediately instead of refetched.
|
|
167
|
+
*/
|
|
168
|
+
export declare function primeBlueskyFeedCache(options: BlueskyFeedCachePrimeOptions): BlueskyFeedCachePrimeResult;
|
|
169
|
+
export declare function primeBlueskyProfileCache(options: BlueskyProfileCachePrimeOptions): BlueskyFeedCachePrimeResult;
|
|
170
|
+
export declare function extractRkey(uri: string): string;
|
|
171
|
+
export declare function isValidTimestamp(record: unknown): boolean;
|