constellation 🌌 #
A global atproto backlink index ✨
- Self hostable: handles the full write throughput of the global atproto firehose on a raspberry pi 4b + single SSD
- Storage efficient: less than 2GB/day disk consumption indexing all references in all lexicons and all non-atproto URLs
- Handles record deletion, account de/re-activation, and account deletion, ensuring accurate link counts and respecting users data choices
- Simple JSON API
All social interactions in atproto tend to be represented by links (or references) between PDS records. This index can answer questions like "how many likes does a bsky post have", "who follows an account", "what are all the comments on a frontpage post", and more.
- status: works! api is unstable and likely to change, and no known instances have a full network backfill yet.
- source: ./constellation/
- public instance: constellation.microcosm.blue
note: the public instance currently runs on a little raspberry pi in my house, feel free to use it! it comes with only with best-effort uptime, no commitment to not breaking the api for now, and possible rate-limiting. if you want to be nice you can put your project name and bsky username (or email) in your user-agent header for api requests.
API endpoints #
currently this is a bit out of date -- refer to the api docs hosted by the app itself for now. they also let you try out live requests.
terms as used here:
- "URI": a URI, AT-URI, or DID.
- "JSON path": a dot-separated (and dot-prefixed, for now) path to a field in an atproto record. Arrays are noted by
[]and cannot contain a specific index.
GET /links/count #
The number of backlinks to a URI from a specified collection + json path.
Required URL parameters #
target(required): the URI. must be URL-encoded.- example:
at%3A%2F%2Fdid%3Aplc%3A57vlzz2egy6eqr4nksacmbht%2Fapp.bsky.feed.post%2F3lg2pgq3gq22b
- example:
collection(required): the source NSID of referring documents to consider.- example:
app.bsky.feed.post
- example:
path(required): the JSON path in referring documents to consider.- example:
.subject.uri
- example:
Response #
A number (u64) in plain text format
cURL example: Get a count of all bluesky likes for a post #
curl '<HOST>/links/count?target=at%3A%2F%2Fdid%3Aplc%3A57vlzz2egy6eqr4nksacmbht%2Fapp.bsky.feed.post%2F3lg2pgq3gq22b&collection=app.bsky.feed.like&path=.subject.uri'
40
GET /links/all/count #
The number of backlinks to a URI from any source collection or json path
Required URL parameters #
target(required): the URI. must be URL-encoded.- example:
did:plc:vc7f4oafdgxsihk4cry2xpze
- example:
Response #
A JSON object {[NSID]: {[JSON path]: [N]}}
cURL example: Get reference counts to a DID from any collection at any path #
curl '<HOST>/links/all/count?target=did:plc:vc7f4oafdgxsihk4cry2xpze'
curl '<HOST>/links/all/count?target=did:plc:vc7f4oafdgxsihk4cry2xpze'
{
"app.bsky.graph.block": { ".subject": 13 },
"app.bsky.graph.follow": { ".subject": 159 },
"app.bsky.feed.post": { ".facets[].features[].did": 16 },
"app.bsky.graph.listitem": { ".subject": 6 },
"app.bsky.graph.starterpack":
{
".feeds[].creator.did": 1,
".feeds[].creator.labels[].src": 1
}
}
some todos
-
- instead of looking this up, should be able to listen for it to be published on the firehose.
- this should work, but without backfill it won't be accurate. targeted backfill might be an option.
- instead of looking this up, should be able to listen for it to be published on the firehose.
- [~] other useful endpoints for the api server
- [~] write this readme
- [?] fix it sometimes getting stuck
- seems to unstick in my possibly-different repro (letting laptop fall asleep) after a bit.
-
-
-
- [~] handle all the unwraps
-
-
- very close to 1GB with data model before adding rkeys to linkers + fixing paths
- [~] clean up the main readme
-
-
- [~] rocksdb metrics
-
cache
data fixes
-
- [~] pull
$type/typefrom object children of arrays (distinguish replies, quotes, etc)- just $type to start
-
-
- and it could be looked up from the linker's doc
- ^^ for now, look up from source doc to get cid. might revisit this later.
-
- [~] pull