Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
1{% extends "base.html.j2" %}
2{% import "try-it-macros.html.j2" as try_it %}
3
4{% block title %}Hello!{% endblock %}
5{% block body_classes %}home{% endblock %}
6
7{% block content %}
8
9 <p>Constellation is a self-hosted JSON API to an atproto-wide index of PDS record back-links, so you can query social interactions in real time. It can answer questions like:</p>
10
11 <ul>
12 <li><a href="/links/count/distinct-dids?target={{ "at://did:plc:44ybard66vv44zksje25o7dz/app.bsky.feed.post/3lhhz7k2yqk2h"|urlencode }}&collection=app.bsky.feed.like&path=.subject.uri">How many people liked a liked a bluesky post?</a></li>
13 <li><a href="/links/distinct-dids?target=did:plc:oky5czdrnfjpqslsw2a5iclo&collection=app.bsky.graph.follow&path=.subject">Who are all the bluesky followers of an identity?</a></li>
14 <li><a href="/links?target=at://did:plc:nlromb2qyyl6rszaluwhfy6j/fyi.unravel.frontpage.post/3lhd2ivyc422n&collection=fyi.unravel.frontpage.comment&path=.post.uri">What are all the replies to a Frontpage submission?</a></li>
15 <li><a href="/links/all?target=did:plc:vc7f4oafdgxsihk4cry2xpze">What are <em>all</em> the sources of links to an identity?</a></li>
16 <li>and more</li>
17 </ul>
18
19 <p>It works by recursively walking <em>all</em> records coming through the firehose, searching for anything that looks like a link. Links are indexed by the target they point at, the collection the record came from, and the JSON path to the link in that record.</p>
20
21 <p>
22 This server has indexed <span class="stat">{{ stats.linking_records|human_number }}</span> links between <span class="stat">{{ stats.targetables|human_number }}</span> targets and sources from <span class="stat">{{ stats.dids|human_number }}</span> identities over <span class="stat">{{ days_indexed|human_number }}</span> days.<br/>
23 <small>(indexing new records in real time, backfill still TODO)</small>
24 </p>
25
26 <p>The API is currently <strong>unstable</strong>. But feel free to use it! If you want to be nice, put your project name and bsky username (or email) in your user-agent header for api requests.</p>
27
28
29 <h2>API Endpoints</h2>
30
31 <h3 class="route"><code>GET /links</code></h3>
32
33 <p>A list of records linking to a target.</p>
34
35 <h4>Query parameters:</h4>
36
37 <ul>
38 <li><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></li>
39 <li><code>collection</code>: required. Example: <code>app.bsky.feed.like</code></li>
40 <li><code>path</code>: required, must url-encode. Example: <code>.subject.uri</code></li>
41 </ul>
42
43 <p style="margin-bottom: 0"><strong>Try it:</strong></p>
44 {% call try_it::links("at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r", "app.bsky.feed.like", ".subject.uri") %}
45
46
47 <h3 class="route"><code>GET /links/distinct-dids</code></h3>
48
49 <p>A list of distinct DIDs (identities) with links to a target.</p>
50
51 <h4>Query parameters:</h4>
52
53 <ul>
54 <li><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></li>
55 <li><code>collection</code>: required. Example: <code>app.bsky.feed.like</code></li>
56 <li><code>path</code>: required, must url-encode. Example: <code>.subject.uri</code></li>
57 </ul>
58
59 <p style="margin-bottom: 0"><strong>Try it:</strong></p>
60 {% call try_it::dids("at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r", "app.bsky.feed.like", ".subject.uri") %}
61
62
63 <h3 class="route"><code>GET /links/count</code></h3>
64
65 <p>The total number of links pointing at a given target.</p>
66
67 <h4>Query parameters:</h4>
68
69 <ul>
70 <li><code>target</code>: required, must url-encode. Example: <code>did:plc:vc7f4oafdgxsihk4cry2xpze</code></li>
71 <li><code>collection</code>: required. Example: <code>app.bsky.graph.block</code></li>
72 <li><code>path</code>: required, must url-encode. Example: <code>.subject</code></li>
73 <li><code>cursor</code>: optional, see Definitions.</li>
74 </ul>
75
76 <p style="margin-bottom: 0"><strong>Try it:</strong></p>
77 {% call try_it::links_count("did:plc:vc7f4oafdgxsihk4cry2xpze", "app.bsky.graph.block", ".subject") %}
78
79
80 <h3 class="route"><code>GET /links/count/distinct-dids</code></h3>
81
82 <p>The total number of DIDs (identities) with links to at a given target.</p>
83
84 <h4>Query parameters:</h4>
85
86 <ul>
87 <li><code>target</code>: required, must url-encode. Example: <code>did:plc:vc7f4oafdgxsihk4cry2xpze</code></li>
88 <li><code>collection</code>: required. Example: <code>app.bsky.graph.block</code></li>
89 <li><code>path</code>: required, must url-encode. Example: <code>.subject</code></li>
90 <li><code>cursor</code>: optional, see Definitions.</li>
91 </ul>
92
93 <p style="margin-bottom: 0"><strong>Try it:</strong></p>
94 {% call try_it::dids_count("did:plc:vc7f4oafdgxsihk4cry2xpze", "app.bsky.graph.block", ".subject") %}
95
96
97 <h3 class="route"><code>GET /links/all</code></h3>
98
99 <p>Show all sources with links to a target, including linking record counts and distinct linking DIDs</p>
100
101 <h4>Query parameters:</h4>
102
103 <ul>
104 <li><code>target</code>: required, must url-encode. Example: <code>did:plc:oky5czdrnfjpqslsw2a5iclo</code></li>
105 </ul>
106
107 <p style="margin-bottom: 0"><strong>Try it:</strong></p>
108 {% call try_it::explore_links("did:plc:oky5czdrnfjpqslsw2a5iclo") %}
109
110
111 <h3 class="route deprecated"><code>[deprecated] GET /links/all/count</code></h3>
112
113 <p>The total counts of all links pointing at a given target, by collection and path.</p>
114
115 <p>DEPRECATED: Use <code>GET /links/all</code> instead.</p>
116
117 <h4>Query parameters:</h4>
118
119 <ul>
120 <li><code>target</code>: required, must url-encode. Example: <code>did:plc:oky5czdrnfjpqslsw2a5iclo</code></li>
121 </ul>
122
123 <p style="margin-bottom: 0"><strong>Try it:</strong></p>
124 {% call try_it::links_all_count("did:plc:oky5czdrnfjpqslsw2a5iclo") %}
125
126
127 <h2>Definitions</h2>
128
129 <h3>Target</h3>
130
131 <p>A DID like <code>did:plc:hdhoaan3xa3jiuq4fg4mefid</code>, or an AT-URI like <code>at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3lgu4lg6j2k2v</code>, or a URI like <code>https://example.com</code>.</p>
132
133 <h3>Collection</h3>
134
135 <p>A record NSID like <code>app.bsky.feed.like</code>.</p>
136
137 <h3>Path</h3>
138
139 <p>A (currently-very-very-hacky) json-path-ish representation of the source of a link in a record. Records may contain multiple links with different meanings, so this specifies which specific link is of interest. Like <code>.subject.uri</code>.</p>
140
141 <h3>Cursor</h3>
142
143 <p>Paged responses include a <code>cursor</code> property. When it's <code>null</code>, no more data is available. If it's not null, you can repeat the request with <code>&cursor=<cursor></code> in the URL query to get the next set of responses.</p>
144
145
146{% endblock %}