+21
.github/workflows/build.yml
+21
.github/workflows/build.yml
···
···+run: cargo build --bin reflector --release && mv target/release/reflector target/release/reflector_amd64
+197
-177
Cargo.lock
+197
-177
Cargo.lock
··············································································································································································································································································
··············································································································································································································································································
+1
Cargo.toml
+1
Cargo.toml
+8
-1
Makefile
+8
-1
Makefile
···
+1
-1
constellation/Cargo.toml
+1
-1
constellation/Cargo.toml
+661
constellation/LICENSE
+661
constellation/LICENSE
···
···
+3
constellation/LICENSE.future
+3
constellation/LICENSE.future
+9
constellation/readme.md
+9
constellation/readme.md
···+Constellation's source code is currently available exclusively under the AGPL license (see [LICENSE](./LICENSE)).+In the future, its code MAY become available under the MIT and/or Apache2.0 licenses, at the sole discretion of the microcosm organization. Contributing implies acceptance with this possible future licensing change. The change has not happed yet and is not guaranteed.
+57
-14
constellation/src/bin/main.rs
+57
-14
constellation/src/bin/main.rs
······/// Jetstream server to connect to (exclusive with --fixture). Provide either a wss:// URL, or a shorhand value:·····················.set_bucket_count(NonZero::new(10).unwrap()) // count * duration = 5 mins. stuff doesn't happen that fast here.
······/// Jetstream server to connect to (exclusive with --fixture). Provide either a wss:// URL, or a shorhand value:·····················.set_bucket_count(NonZero::new(10).unwrap()) // count * duration = 5 mins. stuff doesn't happen that fast here.
+239
-238
constellation/src/bin/rocks-link-stats.rs
+239
-238
constellation/src/bin/rocks-link-stats.rs
···-struct SourceLink(Collection, RPath, LinkType, Option<Collection>); // last is target collection, if it's an at-uri link with a collection-// b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b12, b16, b32, b64, b128, b256, b512, b1024, b4096, b16384, b65535, b262144, bmax-// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16, 32, 64, 128, 256, 512, 1024, 4096, 16384, 65535, 262144, 1048576+
···+// struct SourceLink(Collection, RPath, LinkType, Option<Collection>); // last is target collection, if it's an at-uri link with a collection+// xxx// b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b12, b16, b32, b64, b128, b256, b512, b1024, b4096, b16384, b65535, b262144, bmax+// xxx// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16, 32, 64, 128, 256, 512, 1024, 4096, 16384, 65535, 262144, 1048576+
+2
constellation/src/bin/rocks-restore-from-backup.rs
+2
constellation/src/bin/rocks-restore-from-backup.rs
······
+13
-6
constellation/src/consumer/jetstream.rs
+13
-6
constellation/src/consumer/jetstream.rs
···
···+counter!("jetstream_read_fail", "url" => stream.clone(), "reason" => "dirty close").increment(1);
+8
-6
constellation/src/server/filters.rs
+8
-6
constellation/src/server/filters.rs
······
······
+332
-19
constellation/src/server/mod.rs
+332
-19
constellation/src/server/mod.rs
······························help: "open this URL in a web browser (or request with Accept: text/html) for information about this API.",···············
······························help: "open this URL in a web browser (or request with Accept: text/html) for information about this API.",···············
+93
-1
constellation/src/storage/mem_store.rs
+93
-1
constellation/src/storage/mem_store.rs
···············
···············
+484
-14
constellation/src/storage/mod.rs
+484
-14
constellation/src/storage/mod.rs
······/// estimate of how many accounts we've seen create links. the _subjects_ of any links are not represented here.···/// for LSM stores, deleted links don't decrement this, and updated records with any links will likely increment it.···················································
······/// estimate of how many accounts we've seen create links. the _subjects_ of any links are not represented here.···/// for LSM stores, deleted links don't decrement this, and updated records with any links will likely increment it.···················································
+361
-41
constellation/src/storage/rocks_store.rs
+361
-41
constellation/src/storage/rocks_store.rs
···············pub db: Arc<DBWithThreadMode<MultiThreaded>>, // TODO: mov seqs here (concat merge op will be fun)·········-impl<Orig: Clone, IdVal: IdTableValue, const WITH_REVERSE: bool> IdTable<Orig, IdVal, WITH_REVERSE>····································
···············pub db: Arc<DBWithThreadMode<MultiThreaded>>, // TODO: mov seqs here (concat merge op will be fun)······························+let current_max = grouped_counts.keys().next_back().unwrap(); // limit should be non-zero bleh+eprintln!("failed to look up did_value from did_id {did_id:?}: {did:?}: data consistency bug?");···············
+1
-1
constellation/templates/dids.html.j2
+1
-1
constellation/templates/dids.html.j2
···--> browse <a href="https://atproto-browser-plus-links.vercel.app/at/{{ did.0|urlencode }}">this DID record</a></pre>
···
+54
constellation/templates/get-backlinks.html.j2
+54
constellation/templates/get-backlinks.html.j2
···
···+{% block description %}All {{ query.source }} records with links to {{ query.subject }}{% endblock %}+<small style="font-weight: normal; font-size: 1rem"><a href="{{ browseable_uri }}">browse record</a></small>+<li>See distinct linking DIDs at <code>/links/distinct-dids</code>: <a href="/links/distinct-dids?target={{ query.subject|urlencode }}&collection={{ collection|urlencode }}&path={{ path|urlencode }}">/links/distinct-dids?target={{ query.subject }}&collection={{ collection }}&path={{ path }}</a></li>+<li>See all links to this target at <code>/links/all</code>: <a href="/links/all?target={{ query.subject|urlencode }}">/links/all?target={{ query.subject }}</a></li>+<pre style="display: block; margin: 1em 2em" class="code"><strong>DID</strong>: {{ record.did().0 }} (<a href="/links/all?target={{ record.did().0|urlencode }}">DID links</a>)+-> <a href="https://pdsls.dev/at://{{ record.did().0 }}/{{ record.collection }}/{{ record.rkey }}">browse record</a></pre>
+67
constellation/templates/get-many-to-many-counts.html.j2
+67
constellation/templates/get-many-to-many-counts.html.j2
···
···+{% block description %}Counts of many-to-many {{ query.source }} join records with links to {{ query.subject }} and a secondary target at {{ query.path_to_other }}{% endblock %}+Many-to-many links to <code>{{ query.subject }}</code> joining through <code>{{ query.path_to_other }}</code>+<small style="font-weight: normal; font-size: 1rem"><a href="{{ browseable_uri }}">browse record</a></small>+<p><strong>{% if cursor.is_some() || query.cursor.is_some() %}more than {% endif %}{{ counts_by_other_subject.len()|to_u64|human_number }} joins</strong> <code>{{ query.source }}โ{{ query.path_to_other }}</code></p>+<li>See direct backlinks at <code>/xrpc/blue.microcosm.links.getBacklinks</code>: <a href="/xrpc/blue.microcosm.links.getBacklinks?subject={{ query.subject|urlencode }}&source={{ query.source|urlencode }}">/xrpc/blue.microcosm.links.getBacklinks?subject={{ query.subject }}&source={{ query.source }}</a></li>+<li>See all links to this target at <code>/links/all</code>: <a href="/links/all?target={{ query.subject|urlencode }}">/links/all?target={{ query.subject }}</a></li>+<pre style="display: block; margin: 1em 2em" class="code"><strong>Joined subject</strong>: {{ counts.subject }}
+65
-7
constellation/templates/hello.html.j2
+65
-7
constellation/templates/hello.html.j2
···<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>-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/>-<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>-<li><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></li>-{% call try_it::links("at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r", "app.bsky.feed.like", ".subject.uri") %}
···<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>+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">+<p>You're welcome to use this public instance! Please do not build the torment nexus. If you want to be nice, put your project name and bsky username (or email) in your user-agent header for api requests.</p>+<li><p><code>subject</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li>+<li><p><code>source</code>: required. Example: <code>app.bsky.feed.like:subject.uri</code></p></li>+<li><p><code>did</code>: optional, filter links to those from specific users. Include multiple times to filter by multiple users. Example: <code>did=did:plc:vc7f4oafdgxsihk4cry2xpze&did=did:plc:vc7f4oafdgxsihk4cry2xpze</code></p></li>+<li><p><code>limit</code>: optional. Default: <code>16</code>. Maximum: <code>100</code></p></li>+{% call try_it::get_backlinks("at://did:plc:a4pqq234yw7fqbddawjo7y35/app.bsky.feed.post/3m237ilwc372e", "app.bsky.feed.like:subject.uri", [""], 16) %}+<li><p><code>subject</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li>+<li><p><code>source</code>: required. Example: <code>app.bsky.feed.like:subject.uri</code></p></li>+<li><p><code>pathToOther</code>: required. Path to the secondary link in the many-to-many record. Example: <code>otherThing.uri</code></p></li>+<li><p><code>did</code>: optional, filter links to those from specific users. Include multiple times to filter by multiple users. Example: <code>did=did:plc:vc7f4oafdgxsihk4cry2xpze&did=did:plc:vc7f4oafdgxsihk4cry2xpze</code></p></li>+<li><p><code>otherSubject</code>: optional, filter secondary links to specific subjects. Include multiple times to filter by multiple users. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li>+<li><p><code>limit</code>: optional. Default: <code>16</code>. Maximum: <code>100</code></p></li>+<p>[DEPRECATED]: use <code>GET /xrpc/blue.microcosm.links.getBacklinks</code>. New apps should avoid it, but this endpoint <strong>will</strong> remain supported for the forseeable future.</p>+<li><p><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li>+<li><p><code>path</code>: required, must url-encode. Example: <code>.subject.uri</code></p></li>+<li><p><code>did</code>: optional, filter links to those from specific users. Include multiple times to filter by multiple users. Example: <code>did=did:plc:vc7f4oafdgxsihk4cry2xpze&did=did:plc:vc7f4oafdgxsihk4cry2xpze</code></p></li>+<li><p><code>from_dids</code> [deprecated]: optional. Use <code>did</code> instead. Example: <code>from_dids=did:plc:vc7f4oafdgxsihk4cry2xpze,did:plc:vc7f4oafdgxsihk4cry2xpze</code></p></li>+<li><p><code>limit</code>: optional. Default: <code>16</code>. Maximum: <code>100</code></p></li>+{% call try_it::links("at://did:plc:a4pqq234yw7fqbddawjo7y35/app.bsky.feed.post/3m237ilwc372e", "app.bsky.feed.like", ".subject.uri", [""], 16) %}
+2
-2
constellation/templates/links.html.j2
+2
-2
constellation/templates/links.html.j2
······<pre style="display: block; margin: 1em 2em" class="code"><strong>DID</strong>: {{ record.did().0 }} (<a href="/links/all?target={{ record.did().0|urlencode }}">DID links</a>)--> <a href="https://atproto-browser-plus-links.vercel.app/at/{{ record.did().0|urlencode }}/{{ record.collection }}/{{ record.rkey }}">browse record</a></pre>
······<pre style="display: block; margin: 1em 2em" class="code"><strong>DID</strong>: {{ record.did().0 }} (<a href="/links/all?target={{ record.did().0|urlencode }}">DID links</a>)+-> <a href="https://pdsls.dev/at://{{ record.did().0 }}/{{ record.collection }}/{{ record.rkey }}">browse record</a></pre>
+88
-3
constellation/templates/try-it-macros.html.j2
+88
-3
constellation/templates/try-it-macros.html.j2
···&collection= <input type="text" name="collection" value="{{ collection }}" placeholder="collection" />-&path= <input type="text" name="path" value="{{ path }}" placeholder="path" /> <button type="submit">get links</button></pre>
···+?subject= <input type="text" name="subject" value="{{ subject }}" placeholder="at-uri, did, uri..." />+&source= <input type="text" name="source" value="{{ source }}" placeholder="app.bsky.feed.like:subject.uri" />+&did= <input type="text" name="did" value="{{ did }}" placeholder="did:plc:..." />{% endif %}{% endfor %}+&limit= <input type="number" name="limit" value="{{ limit }}" max="100" placeholder="100" /> <button type="submit">get links</button></pre>+?subject= <input type="text" name="subject" value="{{ subject }}" placeholder="at-uri, did, uri..." />+&source= <input type="text" name="source" value="{{ source }}" placeholder="app.bsky.feed.like:subject.uri" />+&pathToOther= <input type="text" name="pathToOther" value="{{ pathToOther }}" placeholder="otherThing.uri" />+&did= <input type="text" name="did" value="{{ did }}" placeholder="did:plc:..." />{% endif %}{% endfor %}+<span id="m2m-subject-placeholder"></span> <button id="m2m-add-subject">+ other subject filter</button>+&otherSubject= <input type="text" name="did" value="{{ otherSubject }}" placeholder="at-uri, did, uri..." />{% endif %}{% endfor %}+&limit= <input type="number" name="limit" value="{{ limit }}" max="100" placeholder="100" /> <button type="submit">get links</button></pre>&collection= <input type="text" name="collection" value="{{ collection }}" placeholder="collection" />+&did= <input type="text" name="did" value="{{ did }}" placeholder="did:plc:..." />{% endif %}{% endfor %}+&limit= <input type="number" name="limit" value="{{ limit }}" max="100" placeholder="100" /> <button type="submit">get links</button></pre>
+1
pocket/.gitignore
+1
pocket/.gitignore
···
···
+2
pocket/src/lib.rs
+2
pocket/src/lib.rs
+29
-3
pocket/src/main.rs
+29
-3
pocket/src/main.rs
···
+100
-37
pocket/src/server.rs
+100
-37
pocket/src/server.rs
·····················
·····················
+50
pocket/src/storage.rs
+50
pocket/src/storage.rs
···
···
+20
-10
pocket/src/token.rs
+20
-10
pocket/src/token.rs
······// danger! unfortunately we need to decode the DID from the jwt body before we have a public key to verify the jwt with······
······// danger! unfortunately we need to decode the DID from the jwt body before we have a public key to verify the jwt with······
+12
reflector/Cargo.toml
+12
reflector/Cargo.toml
···
···
+9
reflector/readme.md
+9
reflector/readme.md
···
···+receiving requests from multiple subdomains is left as a problem for the reverse proxy to solve, since acme wildcard certificates (ie. letsencrypt) require the most complicated and involved challenge type (DNS).+caddy [has good support for](https://caddyserver.com/docs/caddyfile/patterns#wildcard-certificates) configuring the wildcard DNS challenge with various DNS providers, and also supports [on-demand](https://caddyserver.com/docs/automatic-https#using-on-demand-tls) provisioning via the simpler methods.+if you only need a small fixed number of subdomains, you can also use certbot or otherwise individually configure them in your reverse proxy.
+112
reflector/src/main.rs
+112
reflector/src/main.rs
···
···
+4
-2
slingshot/src/firehose_cache.rs
+4
-2
slingshot/src/firehose_cache.rs
···.with_file_size(16 * 2_usize.pow(20)), // note: this does limit the max cached item size, warning jumbo records
···.with_file_size(16 * 2_usize.pow(20)), // note: this does limit the max cached item size, warning jumbo records
+26
-5
slingshot/src/main.rs
+26
-5
slingshot/src/main.rs
···············
···············
+19
-12
slingshot/src/server.rs
+19
-12
slingshot/src/server.rs
························
························
+5
-5
spacedust/src/subscriber.rs
+5
-5
spacedust/src/subscriber.rs
···
···
+4
-4
who-am-i/src/server.rs
+4
-4
who-am-i/src/server.rs
···