···16161717### Current status
18181919-Slingshot is currently in a **v0, pre-release state**. There is one production instance and you can use it! Expect short downtimes for restarts as development progresses and lower cache hit-rates as the internal storage caches are adjusted and reset.
1919+> [!important]
2020+> Slingshot is currently in a **v0, pre-release state**. There is one production instance and you can use it! Expect short downtimes for restarts as development progresses and lower cache hit-rates as the internal storage caches are adjusted and reset.
20212122The core APIs will not change, since they are standard third-party `com.atproto` query APIs from ATProtocol.
2223···5455_(work on this endpoint is in progress)_
555656575858+## Service proxying
5959+6060+Clients can proxy atproto queries through their own PDS with [Service Proxying](https://atproto.com/specs/xrpc#service-proxying), and this is supported by Slingshot. The Slingshot instance must be started the `--domain` argument specified.
6161+6262+Service-proxied requests can specify a Slingshot instance via the `atproto-proxy` header:
6363+6464+```http
6565+GET /xrpc/com.bad-example.identity.resolveMiniDoc?identifier=bad-example.com
6666+Host: <your pds>
6767+atproto-proxy: did:web:<slingshot domain>#slingshot
6868+```
6969+7070+Where `<your pds>` is the user's own PDS host, and `<slingshot domain>` is the domain that the slingshot instance is deployed at (eg. `slingshot.microcosm.blue`). See the [Service Proxying](https://atproto.com/specs/xrpc#service-proxying) docs for more.
7171+7272+> [!tip]
7373+> Service proxying is supported but completely optional. All APIs are directly accessible over the public internet, and GeoDNS helps route users to the closest instance to them for the lowest possible latency. (_note: deploying multiple slingshot instances with GeoDNS is still TODO_)
7474+7575+5776## Ergonomic APIs
58775978- Slingshot also offers variants of the `getRecord` endpoints that accept a full `at-uri` as a parameter, to save clients from needing to parse and validate all parts of a record location.
···7089- [🌌 Constellation](https://constellation.microcosm.blue/), a global backlink index (all social interactions in atproto are links!)
7190- [🎇 Spacedust](https://spacedust.microcosm.blue/), a firehose of all social interactions
72917373-All microcosm projects are [open source](https://tangled.sh/@bad-example.com/microcosm-links). **You can help sustain Slingshot** and all of microcosm by becoming a [Github sponsor](https://github.com/sponsors/uniphil/) or a [Ko-fi supporter](https://ko-fi.com/bad_example)!
9292+> [!success]
9393+> All microcosm projects are [open source](https://tangled.sh/@bad-example.com/microcosm-links). **You can help sustain Slingshot** and all of microcosm by becoming a [Github sponsor](https://github.com/sponsors/uniphil/) or a [Ko-fi supporter](https://ko-fi.com/bad_example)!
+2-2
slingshot/src/main.rs
···3030 /// - an HTTPS certs will be automatically configured with Acme/letsencrypt
3131 /// - TODO: a rate-limiter will be installed
3232 #[arg(long)]
3333- host: Option<String>,
3333+ domain: Option<String>,
3434 /// email address for letsencrypt contact
3535 ///
3636 /// recommended in production, i guess?
···104104 server_cache_handle,
105105 identity,
106106 repo,
107107- args.host,
107107+ args.domain,
108108 args.acme_contact,
109109 args.certs,
110110 server_shutdown,
+33-29
slingshot/src/server.rs
···227227enum ApiTags {
228228 /// Core ATProtocol-compatible APIs.
229229 ///
230230- /// Upstream documentation is available at
231231- /// https://docs.bsky.app/docs/category/http-reference
230230+ /// > [!tip]
231231+ /// > Upstream documentation is available at
232232+ /// > https://docs.bsky.app/docs/category/http-reference
232233 ///
233234 /// These queries are usually executed directly against the PDS containing
234235 /// the data being requested. Slingshot offers a caching view of the same
···241242 /// more convenient [request parameters](#tag/slingshot-specific-queries/GET/xrpc/com.bad-example.repo.getUriRecord)
242243 /// or [response formats](#tag/slingshot-specific-queries/GET/xrpc/com.bad-example.identity.resolveMiniDoc).
243244 ///
244244- /// At the moment, these are namespaced under the `com.bad-example.*` NSID
245245- /// prefix, but as they stabilize they will likely be moved to either
246246- /// `blue.microcosm.*` or a slingshot-instance-specific lexicon under its
247247- /// `did:web` (ie., `blue.microcosm.slingshot.*`). Maybe one day they can
248248- /// be promoted to the [Lexicon Community](https://discourse.lexicon.community/)
249249- /// namespace.
245245+ /// > [!important]
246246+ /// > At the moment, these are namespaced under the `com.bad-example.*` NSID
247247+ /// > prefix, but as they stabilize they may be migrated to an org namespace
248248+ /// > like `blue.microcosm.*`. Support for asliasing to `com.bad-example.*`
249249+ /// > will be maintained as long as it's in use.
250250 #[oai(rename = "slingshot-specific queries")]
251251 Custom,
252252}
···257257 ///
258258 /// Get a single record from a repository. Does not require auth.
259259 ///
260260- /// See also the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-repo-get-record)
261261- /// that this endpoint aims to be compatible with.
260260+ /// > [!tip]
261261+ /// > See also the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-repo-get-record)
262262+ /// > that this endpoint aims to be compatible with.
262263 #[oai(
263264 path = "/com.atproto.repo.getRecord",
264265 method = "get",
···279280 ///
280281 /// If not specified, then return the most recent version.
281282 ///
282282- /// If specified and a newer version of the record exists, returns 404 not
283283- /// found. That is: slingshot only retains the most recent version of a
284284- /// record. (TODO: verify bsky behaviour for mismatched/old CID)
283283+ /// If a stale `CID` is specified and a newer version of the record
284284+ /// exists, Slingshot returns a `NotFound` error. That is: Slingshot
285285+ /// only retains the most recent version of a record.
285286 Query(cid): Query<Option<String>>,
286287 ) -> GetRecordResponse {
287288 self.get_record_impl(repo, collection, rkey, cid).await
···308309 ///
309310 /// If not specified, then return the most recent version.
310311 ///
311311- /// If specified and a newer version of the record exists, returns 404 not
312312- /// found. That is: slingshot only retains the most recent version of a
313313- /// record.
312312+ /// > [!tip]
313313+ /// > If specified and a newer version of the record exists, returns 404 not
314314+ /// > found. That is: slingshot only retains the most recent version of a
315315+ /// > record.
314316 Query(cid): Query<Option<String>>,
315317 ) -> GetRecordResponse {
316318 let bad_at_uri = || {
···354356 /// Resolves an atproto [`handle`](https://atproto.com/guides/glossary#handle)
355357 /// (hostname) to a [`DID`](https://atproto.com/guides/glossary#did-decentralized-id).
356358 ///
357357- /// Compatibility note: **Slingshot will _always_ bi-directionally verify
358358- /// against the DID document**, which is optional according to the
359359- /// authoritative lexicon.
359359+ /// > [!tip]
360360+ /// > Compatibility note: Slingshot will **always bi-directionally verify
361361+ /// > against the DID document**, which is optional according to the
362362+ /// > authoritative lexicon.
360363 ///
361361- /// See the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-identity-resolve-handle)
362362- /// that this endpoint aims to be compatible with.
364364+ /// > [!tip]
365365+ /// > See the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-identity-resolve-handle)
366366+ /// > that this endpoint aims to be compatible with.
363367 #[oai(
364368 path = "/com.atproto.identity.resolveHandle",
365369 method = "get",
···662666///
663667/// - PDS proxying offers a level of client IP anonymity from slingshot
664668/// - slingshot *may* implement more generous per-user rate-limits for proxied requests in the future
665665-fn get_did_doc(host: &str) -> impl Endpoint + use<> {
669669+fn get_did_doc(domain: &str) -> impl Endpoint + use<> {
666670 let doc = poem::web::Json(AppViewDoc {
667667- id: format!("did:web:{host}"),
671671+ id: format!("did:web:{domain}"),
668672 service: [AppViewService {
669673 id: "#slingshot".to_string(),
670674 r#type: "SlingshotRecordProxy".to_string(),
671671- service_endpoint: format!("https://{host}"),
675675+ service_endpoint: format!("https://{domain}"),
672676 }],
673677 });
674678 make_sync(move |_| doc.clone())
···678682 cache: HybridCache<String, CachedRecord>,
679683 identity: Identity,
680684 repo: Repo,
681681- host: Option<String>,
685685+ domain: Option<String>,
682686 acme_contact: Option<String>,
683687 certs: Option<PathBuf>,
684688 shutdown: CancellationToken,
···693697 "Slingshot",
694698 env!("CARGO_PKG_VERSION"),
695699 )
696696- .server(if let Some(ref h) = host {
700700+ .server(if let Some(ref h) = domain {
697701 format!("https://{h}")
698702 } else {
699703 "http://localhost:3000".to_string()
···714718 .nest("/openapi", api_service.spec_endpoint())
715719 .nest("/xrpc/", api_service);
716720717717- if let Some(host) = host {
721721+ if let Some(domain) = domain {
718722 rustls::crypto::aws_lc_rs::default_provider()
719723 .install_default()
720724 .expect("alskfjalksdjf");
721725722722- app = app.at("/.well-known/did.json", get_did_doc(&host));
726726+ app = app.at("/.well-known/did.json", get_did_doc(&domain));
723727724728 let mut auto_cert = AutoCert::builder()
725729 .directory_url(LETS_ENCRYPT_PRODUCTION)
726726- .domain(&host);
730730+ .domain(&domain);
727731 if let Some(contact) = acme_contact {
728732 auto_cert = auto_cert.contact(contact);
729733 }