+22
-2
slingshot/api-description.md
+22
-2
slingshot/api-description.md
···
16
16
17
17
### Current status
18
18
19
-
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.
19
+
> [!important]
20
+
> 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.
20
21
21
22
The core APIs will not change, since they are standard third-party `com.atproto` query APIs from ATProtocol.
22
23
···
54
55
_(work on this endpoint is in progress)_
55
56
56
57
58
+
## Service proxying
59
+
60
+
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.
61
+
62
+
Service-proxied requests can specify a Slingshot instance via the `atproto-proxy` header:
63
+
64
+
```http
65
+
GET /xrpc/com.bad-example.identity.resolveMiniDoc?identifier=bad-example.com
66
+
Host: <your pds>
67
+
atproto-proxy: did:web:<slingshot domain>#slingshot
68
+
```
69
+
70
+
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.
71
+
72
+
> [!tip]
73
+
> 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_)
74
+
75
+
57
76
## Ergonomic APIs
58
77
59
78
- 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.
···
70
89
- [🌌 Constellation](https://constellation.microcosm.blue/), a global backlink index (all social interactions in atproto are links!)
71
90
- [🎇 Spacedust](https://spacedust.microcosm.blue/), a firehose of all social interactions
72
91
73
-
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)!
92
+
> [!success]
93
+
> 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
+2
-2
slingshot/src/main.rs
···
30
30
/// - an HTTPS certs will be automatically configured with Acme/letsencrypt
31
31
/// - TODO: a rate-limiter will be installed
32
32
#[arg(long)]
33
-
host: Option<String>,
33
+
domain: Option<String>,
34
34
/// email address for letsencrypt contact
35
35
///
36
36
/// recommended in production, i guess?
···
104
104
server_cache_handle,
105
105
identity,
106
106
repo,
107
-
args.host,
107
+
args.domain,
108
108
args.acme_contact,
109
109
args.certs,
110
110
server_shutdown,
+33
-29
slingshot/src/server.rs
+33
-29
slingshot/src/server.rs
···
227
227
enum ApiTags {
228
228
/// Core ATProtocol-compatible APIs.
229
229
///
230
-
/// Upstream documentation is available at
231
-
/// https://docs.bsky.app/docs/category/http-reference
230
+
/// > [!tip]
231
+
/// > Upstream documentation is available at
232
+
/// > https://docs.bsky.app/docs/category/http-reference
232
233
///
233
234
/// These queries are usually executed directly against the PDS containing
234
235
/// the data being requested. Slingshot offers a caching view of the same
···
241
242
/// more convenient [request parameters](#tag/slingshot-specific-queries/GET/xrpc/com.bad-example.repo.getUriRecord)
242
243
/// or [response formats](#tag/slingshot-specific-queries/GET/xrpc/com.bad-example.identity.resolveMiniDoc).
243
244
///
244
-
/// At the moment, these are namespaced under the `com.bad-example.*` NSID
245
-
/// prefix, but as they stabilize they will likely be moved to either
246
-
/// `blue.microcosm.*` or a slingshot-instance-specific lexicon under its
247
-
/// `did:web` (ie., `blue.microcosm.slingshot.*`). Maybe one day they can
248
-
/// be promoted to the [Lexicon Community](https://discourse.lexicon.community/)
249
-
/// namespace.
245
+
/// > [!important]
246
+
/// > At the moment, these are namespaced under the `com.bad-example.*` NSID
247
+
/// > prefix, but as they stabilize they may be migrated to an org namespace
248
+
/// > like `blue.microcosm.*`. Support for asliasing to `com.bad-example.*`
249
+
/// > will be maintained as long as it's in use.
250
250
#[oai(rename = "slingshot-specific queries")]
251
251
Custom,
252
252
}
···
257
257
///
258
258
/// Get a single record from a repository. Does not require auth.
259
259
///
260
-
/// See also the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-repo-get-record)
261
-
/// that this endpoint aims to be compatible with.
260
+
/// > [!tip]
261
+
/// > See also the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-repo-get-record)
262
+
/// > that this endpoint aims to be compatible with.
262
263
#[oai(
263
264
path = "/com.atproto.repo.getRecord",
264
265
method = "get",
···
279
280
///
280
281
/// If not specified, then return the most recent version.
281
282
///
282
-
/// If specified and a newer version of the record exists, returns 404 not
283
-
/// found. That is: slingshot only retains the most recent version of a
284
-
/// record. (TODO: verify bsky behaviour for mismatched/old CID)
283
+
/// If a stale `CID` is specified and a newer version of the record
284
+
/// exists, Slingshot returns a `NotFound` error. That is: Slingshot
285
+
/// only retains the most recent version of a record.
285
286
Query(cid): Query<Option<String>>,
286
287
) -> GetRecordResponse {
287
288
self.get_record_impl(repo, collection, rkey, cid).await
···
308
309
///
309
310
/// If not specified, then return the most recent version.
310
311
///
311
-
/// If specified and a newer version of the record exists, returns 404 not
312
-
/// found. That is: slingshot only retains the most recent version of a
313
-
/// record.
312
+
/// > [!tip]
313
+
/// > If specified and a newer version of the record exists, returns 404 not
314
+
/// > found. That is: slingshot only retains the most recent version of a
315
+
/// > record.
314
316
Query(cid): Query<Option<String>>,
315
317
) -> GetRecordResponse {
316
318
let bad_at_uri = || {
···
354
356
/// Resolves an atproto [`handle`](https://atproto.com/guides/glossary#handle)
355
357
/// (hostname) to a [`DID`](https://atproto.com/guides/glossary#did-decentralized-id).
356
358
///
357
-
/// Compatibility note: **Slingshot will _always_ bi-directionally verify
358
-
/// against the DID document**, which is optional according to the
359
-
/// authoritative lexicon.
359
+
/// > [!tip]
360
+
/// > Compatibility note: Slingshot will **always bi-directionally verify
361
+
/// > against the DID document**, which is optional according to the
362
+
/// > authoritative lexicon.
360
363
///
361
-
/// See the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-identity-resolve-handle)
362
-
/// that this endpoint aims to be compatible with.
364
+
/// > [!tip]
365
+
/// > See the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-identity-resolve-handle)
366
+
/// > that this endpoint aims to be compatible with.
363
367
#[oai(
364
368
path = "/com.atproto.identity.resolveHandle",
365
369
method = "get",
···
662
666
///
663
667
/// - PDS proxying offers a level of client IP anonymity from slingshot
664
668
/// - slingshot *may* implement more generous per-user rate-limits for proxied requests in the future
665
-
fn get_did_doc(host: &str) -> impl Endpoint + use<> {
669
+
fn get_did_doc(domain: &str) -> impl Endpoint + use<> {
666
670
let doc = poem::web::Json(AppViewDoc {
667
-
id: format!("did:web:{host}"),
671
+
id: format!("did:web:{domain}"),
668
672
service: [AppViewService {
669
673
id: "#slingshot".to_string(),
670
674
r#type: "SlingshotRecordProxy".to_string(),
671
-
service_endpoint: format!("https://{host}"),
675
+
service_endpoint: format!("https://{domain}"),
672
676
}],
673
677
});
674
678
make_sync(move |_| doc.clone())
···
678
682
cache: HybridCache<String, CachedRecord>,
679
683
identity: Identity,
680
684
repo: Repo,
681
-
host: Option<String>,
685
+
domain: Option<String>,
682
686
acme_contact: Option<String>,
683
687
certs: Option<PathBuf>,
684
688
shutdown: CancellationToken,
···
693
697
"Slingshot",
694
698
env!("CARGO_PKG_VERSION"),
695
699
)
696
-
.server(if let Some(ref h) = host {
700
+
.server(if let Some(ref h) = domain {
697
701
format!("https://{h}")
698
702
} else {
699
703
"http://localhost:3000".to_string()
···
714
718
.nest("/openapi", api_service.spec_endpoint())
715
719
.nest("/xrpc/", api_service);
716
720
717
-
if let Some(host) = host {
721
+
if let Some(domain) = domain {
718
722
rustls::crypto::aws_lc_rs::default_provider()
719
723
.install_default()
720
724
.expect("alskfjalksdjf");
721
725
722
-
app = app.at("/.well-known/did.json", get_did_doc(&host));
726
+
app = app.at("/.well-known/did.json", get_did_doc(&domain));
723
727
724
728
let mut auto_cert = AutoCert::builder()
725
729
.directory_url(LETS_ENCRYPT_PRODUCTION)
726
-
.domain(&host);
730
+
.domain(&domain);
727
731
if let Some(contact) = acme_contact {
728
732
auto_cert = auto_cert.contact(contact);
729
733
}