···226226 println!("jetstream closed the websocket cleanly.");
227227 break;
228228 }
229229- r => eprintln!("jetstream: close result after error: {r:?}"),
229229+ Err(_) => {
230230+ counter!("jetstream_read_fail", "url" => stream.clone(), "reason" => "dirty close").increment(1);
231231+ println!("jetstream failed to close the websocket cleanly.");
232232+ break;
233233+ }
234234+ Ok(r) => {
235235+ eprintln!("jetstream: close result after error: {r:?}");
236236+ counter!("jetstream_read_fail", "url" => stream.clone(), "reason" => "read error")
237237+ .increment(1);
238238+ // if we didn't immediately get ConnectionClosed, we should keep polling read
239239+ // until we get it.
240240+ continue;
241241+ }
230242 }
231231- counter!("jetstream_read_fail", "url" => stream.clone(), "reason" => "read error")
232232- .increment(1);
233233- // if we didn't immediately get ConnectionClosed, we should keep polling read
234234- // until we get it.
235235- continue;
236243 }
237244 };
238245
···11+{
22+ "lexicon": 1,
33+ "id": "com.bad-example.identity.resolveMiniDoc",
44+ "defs": {
55+ "main": {
66+ "type": "query",
77+ "description": "like com.atproto.identity.resolveIdentity but instead of the full didDoc it returns an atproto-relevant subset",
88+ "parameters": {
99+ "type": "params",
1010+ "required": [
1111+ "identifier"
1212+ ],
1313+ "properties": {
1414+ "identifier": {
1515+ "type": "string",
1616+ "format": "at-identifier",
1717+ "description": "handle or DID to resolve"
1818+ }
1919+ }
2020+ },
2121+ "output": {
2222+ "encoding": "application/json",
2323+ "schema": {
2424+ "type": "object",
2525+ "required": [
2626+ "did",
2727+ "handle",
2828+ "pds",
2929+ "signing_key"
3030+ ],
3131+ "properties": {
3232+ "did": {
3333+ "type": "string",
3434+ "format": "did",
3535+ "description": "DID, bi-directionally verified if a handle was provided in the query"
3636+ },
3737+ "handle": {
3838+ "type": "string",
3939+ "format": "handle",
4040+ "description": "the validated handle of the account or 'handle.invalid' if the handle did not bi-directionally match the DID document"
4141+ },
4242+ "pds": {
4343+ "type": "string",
4444+ "format": "uri",
4545+ "description": "the identity's PDS URL"
4646+ },
4747+ "signing_key": {
4848+ "type": "string",
4949+ "description": "the atproto signing key publicKeyMultibase"
5050+ }
5151+ }
5252+ }
5353+ }
5454+ }
5555+ }
5656+}
+54
lexicons/com.bad-example/repo/getUriRecord.json
···11+{
22+ "lexicon": 1,
33+ "id": "com.bad-example.repo.getUriRecord",
44+ "defs": {
55+ "main": {
66+ "type": "query",
77+ "description": "ergonomic complement to com.atproto.repo.getRecord which accepts an at-uri instead of individual repo/collection/rkey params",
88+ "parameters": {
99+ "type": "params",
1010+ "required": [
1111+ "at_uri"
1212+ ],
1313+ "properties": {
1414+ "at_uri": {
1515+ "type": "string",
1616+ "format": "at-uri",
1717+ "description": "the at-uri of the record (identifier can be a DID or handle)"
1818+ },
1919+ "cid": {
2020+ "type": "string",
2121+ "format": "cid",
2222+ "description": "optional CID of the version of the record. if not specified, return the most recent version. if specified and a newer version exists, returns 404."
2323+ }
2424+ }
2525+ },
2626+ "output": {
2727+ "encoding": "application/json",
2828+ "schema": {
2929+ "type": "object",
3030+ "required": [
3131+ "uri",
3232+ "value"
3333+ ],
3434+ "properties": {
3535+ "uri": {
3636+ "type": "string",
3737+ "format": "at-uri",
3838+ "description": "at-uri for this record"
3939+ },
4040+ "cid": {
4141+ "type": "string",
4242+ "format": "cid",
4343+ "description": "CID for this exact version of the record"
4444+ },
4545+ "value": {
4646+ "type": "unknown",
4747+ "description": "the record itself"
4848+ }
4949+ }
5050+ }
5151+ }
5252+ }
5353+ }
5454+}
+1-1
readme.md
···1010Tutorials, how-to guides, and client SDK libraries are all in the works for gentler on-ramps, but are not quite ready yet. But don't let that stop you! Hop in the [microcosm discord](https://discord.gg/tcDfe4PGVB), or post questions and tag [@bad-example.com](https://bsky.app/profile/bad-example.com) on Bluesky if you get stuck anywhere.
11111212> [!tip]
1313-> This repository's primary home is moving to tangled: [@microcosm.blue/microcosm-rs](https://tangled.sh/@microcosm.blue/microcosm-rs). It will continue to be mirrored on [github](https://github.com/at-microcosm/microcosm-rs) for the forseeable future, and it's fine to open issues or pulls in either place!
1313+> This repository's primary home is moving to tangled: [@microcosm.blue/microcosm-rs](https://tangled.org/microcosm.blue/microcosm-rs). It will continue to be mirrored on [github](https://github.com/at-microcosm/microcosm-rs) for the forseeable future, and it's fine to open issues or pulls in either place!
141415151616🌌 [Constellation](./constellation/)
+1-1
slingshot/api-description.md
···9090- [🎇 Spacedust](https://spacedust.microcosm.blue/), a firehose of all social interactions
91919292> [!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)!
9393+> All microcosm projects are [open source](https://tangled.org/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
spacedust/src/error.rs
···3030 TooManySourcesWanted,
3131 #[error("more wantedSubjectDids were requested than allowed (max 10,000)")]
3232 TooManyDidsWanted,
3333+ #[error("more wantedSubjectPrefixes were requested than allowed (max 100)")]
3434+ TooManySubjectPrefixesWanted,
3335 #[error("more wantedSubjects were requested than allowed (max 50,000)")]
3436 TooManySubjectsWanted,
3537}
+11-2
spacedust/src/server.rs
···228228 #[serde(default)]
229229 pub wanted_subjects: HashSet<String>,
230230 #[serde(default)]
231231+ pub wanted_subject_prefixes: HashSet<String>,
232232+ #[serde(default)]
231233 pub wanted_subject_dids: HashSet<String>,
232234 #[serde(default)]
233235 pub wanted_sources: HashSet<String>,
···242244 ///
243245 /// The at-uri must be url-encoded
244246 ///
245245- /// Pass this parameter multiple times to specify multiple collections, like
247247+ /// Pass this parameter multiple times to specify multiple subjects, like
246248 /// `wantedSubjects=[...]&wantedSubjects=[...]`
247249 pub wanted_subjects: String,
250250+ /// One or more at-uri, URI, or DID prefixes to receive links about
251251+ ///
252252+ /// The uri must be url-encoded
253253+ ///
254254+ /// Pass this parameter multiple times to specify multiple prefixes, like
255255+ /// `wantedSubjectPrefixes=[...]&wantedSubjectPrefixes=[...]`
256256+ pub wanted_subject_prefixes: String,
248257 /// One or more DIDs to receive links about
249258 ///
250250- /// Pass this parameter multiple times to specify multiple collections
259259+ /// Pass this parameter multiple times to specify multiple subjects
251260 pub wanted_subject_dids: String,
252261 /// One or more link sources to receive links about
253262 ///