diff --git a/bobbin/crates/resolver/src/identity.rs b/bobbin/crates/resolver/src/identity.rs index 3f35ccae..21837c01 100644 --- a/bobbin/crates/resolver/src/identity.rs +++ b/bobbin/crates/resolver/src/identity.rs @@ -36,7 +36,6 @@ enum WarmKind { type WarmItem = (Did, WarmKind); #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] pub struct MiniDoc { pub did: Did, pub handle: Handle, @@ -631,7 +630,7 @@ mod tests { }; let json = serde_json::to_value(&doc).unwrap(); - assert_eq!(json["signingKey"], serde_json::json!(encoded)); + assert_eq!(json["signing_key"], serde_json::json!(encoded)); assert_eq!(json["pds"], serde_json::json!("https://gaze.systems/")); assert_eq!(serde_json::from_value::(json).unwrap(), doc); } @@ -646,7 +645,7 @@ mod tests { }; let json = serde_json::to_value(&doc).unwrap(); - assert!(json.get("signingKey").is_none()); + assert!(json.get("signing_key").is_none()); assert!(json.get("pds").is_none()); assert_eq!(serde_json::from_value::(json).unwrap(), doc); } @@ -676,7 +675,7 @@ mod tests { async fn resolve_serves_a_hydrant_observed_entry_from_cache() { let server = MockServer::start().await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .respond_with(ResponseTemplate::new(500)) .expect(0) .mount(&server) @@ -729,7 +728,7 @@ mod tests { async fn warming_resolves_a_did_we_only_saw_on_a_record() { let server = MockServer::start().await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .and(query_param("identifier", "did:plc:dawn")) .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ "did": "did:plc:dawn", @@ -822,7 +821,7 @@ mod tests { .mount(&server) .await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .respond_with(ResponseTemplate::new(500)) .expect(0) .mount(&server) @@ -853,7 +852,7 @@ mod tests { .mount(&server) .await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .and(query_param("identifier", "did:plc:stranger")) .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ "did": "did:plc:stranger", @@ -885,7 +884,7 @@ mod tests { .mount(&server) .await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .and(query_param("identifier", "did:plc:dawn")) .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ "did": "did:plc:dawn", @@ -917,7 +916,7 @@ mod tests { .mount(&server) .await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .and(query_param("identifier", "did:plc:dawn")) .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ "did": "did:plc:dawn", @@ -956,7 +955,7 @@ mod tests { async fn a_failed_refresh_leaves_the_cached_handle_alone() { let server = MockServer::start().await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .respond_with(ResponseTemplate::new(500)) .mount(&server) .await; @@ -988,7 +987,7 @@ mod tests { .mount(&server) .await; Mock::given(method("GET")) - .and(path("/xrpc/com.bad-example.identity.resolveMiniDoc")) + .and(path("/xrpc/blue.microcosm.identity.resolveMiniDoc")) .respond_with(ResponseTemplate::new(500)) .expect(0) .mount(&server) diff --git a/bobbin/crates/slingshot-client/src/lib.rs b/bobbin/crates/slingshot-client/src/lib.rs index 5aa2526f..c6e4124b 100644 --- a/bobbin/crates/slingshot-client/src/lib.rs +++ b/bobbin/crates/slingshot-client/src/lib.rs @@ -22,7 +22,7 @@ const USER_AGENT: &str = concat!("bobbin/", env!("CARGO_PKG_VERSION")); const REQUEST_TIMEOUT: Duration = Duration::from_secs(10); const CONNECT_TIMEOUT: Duration = Duration::from_secs(5); const GET_RECORD_PATH: &str = "xrpc/com.atproto.repo.getRecord"; -const RESOLVE_MINI_DOC_PATH: &str = "xrpc/com.bad-example.identity.resolveMiniDoc"; +const RESOLVE_MINI_DOC_PATH: &str = "xrpc/blue.microcosm.identity.resolveMiniDoc"; pub const MAX_BODY_BYTES: u64 = 4 * 1024 * 1024; #[derive(Clone)] diff --git a/bobbin/crates/xrpc/src/enrich.rs b/bobbin/crates/xrpc/src/enrich.rs index ec0c0333..75ce1817 100644 --- a/bobbin/crates/xrpc/src/enrich.rs +++ b/bobbin/crates/xrpc/src/enrich.rs @@ -24,8 +24,8 @@ use crate::{AppState, SubjectShape, XrpcError, mirror_kind, subject_shape}; pub const TYPE_COUNT: &str = "sh.tangled.query.enrichResponse#count"; pub const TYPE_DISTINCT_AUTHORS: &str = "sh.tangled.query.enrichResponse#distinctAuthors"; pub const TYPE_VIEWER: &str = "sh.tangled.query.enrichResponse#viewer"; -/// vendored from upstream com.bad-example.identity.resolveMiniDoc's output -pub const TYPE_MINIDOC: &str = "com.bad-example.identity.miniDoc"; +/// output of upstream blue.microcosm.identity.resolveMiniDoc +pub const TYPE_MINIDOC: &str = "blue.microcosm.identity.resolveMiniDoc"; const KNOWN_TYPES: [&str; 4] = [TYPE_COUNT, TYPE_DISTINCT_AUTHORS, TYPE_VIEWER, TYPE_MINIDOC]; @@ -603,7 +603,7 @@ mod tests { assert!(LinkSource::parse("not an nsid:subject").is_err()); let ty = PayloadType::parse(TYPE_MINIDOC).unwrap(); - assert_eq!(ty.nsid.as_ref(), "com.bad-example.identity.miniDoc"); + assert_eq!(ty.nsid.as_ref(), "blue.microcosm.identity.resolveMiniDoc"); assert_eq!(ty.fragment.as_deref(), None); let ty = PayloadType::parse(TYPE_COUNT).unwrap(); assert_eq!(ty.nsid.as_ref(), "sh.tangled.query.enrichResponse"); diff --git a/bobbin/crates/xrpc/src/lib.rs b/bobbin/crates/xrpc/src/lib.rs index bd5fda85..9c6964ef 100644 --- a/bobbin/crates/xrpc/src/lib.rs +++ b/bobbin/crates/xrpc/src/lib.rs @@ -473,7 +473,7 @@ pub fn router(state: AppState) -> Router { ) .route("/xrpc/sh.tangled.bobbin.getCoverage", get(get_coverage)) .route( - "/xrpc/com.bad-example.identity.resolveMiniDoc", + "/xrpc/blue.microcosm.identity.resolveMiniDoc", get(resolve_mini_doc), ) .merge(knot_proxied_routes()) diff --git a/bobbin/crates/xrpc/tests/enrich.rs b/bobbin/crates/xrpc/tests/enrich.rs index fb05bd8c..1e41cad1 100644 --- a/bobbin/crates/xrpc/tests/enrich.rs +++ b/bobbin/crates/xrpc/tests/enrich.rs @@ -27,7 +27,7 @@ const CID: &str = "bafyreieqygohnz2zqyvtvktbjpvhutphobcmbsnt4q5lc36ri7vpcmoz4i"; const COUNT: &str = "sh.tangled.query.enrichResponse#count"; const DISTINCT_AUTHORS: &str = "sh.tangled.query.enrichResponse#distinctAuthors"; const VIEWER: &str = "sh.tangled.query.enrichResponse#viewer"; -const MINIDOC: &str = "com.bad-example.identity.miniDoc"; +const MINIDOC: &str = "blue.microcosm.identity.resolveMiniDoc"; fn at(s: &str) -> AtUri { AtUri::new_owned(s).unwrap() diff --git a/lexicons/com/bad-example/identity/miniDoc.json b/lexicons/com/bad-example/identity/miniDoc.json deleted file mode 100644 index c8dcab40..00000000 --- a/lexicons/com/bad-example/identity/miniDoc.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "lexicon": 1, - "id": "com.bad-example.identity.miniDoc", - "defs": { - "main": { - "type": "object", - "description": "Minimal identity document, as returned by com.bad-example.identity.resolveMiniDoc.", - "required": ["did", "handle"], - "properties": { - "did": { - "type": "string", - "format": "did", - "description": "DID of the identity." - }, - "handle": { - "type": "string", - "format": "handle", - "description": "Handle of the identity." - }, - "pds": { - "type": "string", - "description": "PDS endpoint, when known." - } - } - } - } -} diff --git a/lexicons/query/enrichResponse.json b/lexicons/query/enrichResponse.json index 6bed883b..3bc6bbc5 100644 --- a/lexicons/query/enrichResponse.json +++ b/lexicons/query/enrichResponse.json @@ -83,7 +83,7 @@ "sh.tangled.query.enrichResponse#count", "sh.tangled.query.enrichResponse#distinctAuthors", "sh.tangled.query.enrichResponse#viewer", - "com.bad-example.identity.miniDoc" + "blue.microcosm.identity.resolveMiniDoc" ], "description": "NSID of the payload type to produce, which also defines the payload's shape. Results land at data[ref][source][type]." }, diff --git a/web/package.json b/web/package.json index b44226ef..f49ab82d 100644 --- a/web/package.json +++ b/web/package.json @@ -78,6 +78,7 @@ "@atcute/client": "^5.1.1", "@atcute/identity-resolver": "^2.0.1", "@atcute/lexicons": "^2.0.2", + "@atcute/microcosm": "^2.0.2", "@atcute/oauth-browser-client": "^4.0.1", "@atcute/tid": "^1.1.4", "@mdit/plugin-alert": "^1.0.1", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 209bf142..2fa62341 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@atcute/lexicons': specifier: ^2.0.2 version: 2.0.2 + '@atcute/microcosm': + specifier: ^2.0.2 + version: 2.0.2(@atcute/lexicons@2.0.2) '@atcute/oauth-browser-client': specifier: ^4.0.1 version: 4.0.1(@atcute/identity-resolver@2.0.1(@atcute/identity@2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3) @@ -276,6 +279,11 @@ packages: '@atcute/lexicons@2.0.2': resolution: {integrity: sha512-ATBADJAy4KQ76NB86BjgYKrRdbDRUo76Cbqna4WIfQAgN105Rcy972MiNKs+BSmcOOM3WakilgTm0CXD4RC0iA==} + '@atcute/microcosm@2.0.2': + resolution: {integrity: sha512-cmE5UWM1sZKSQD5b0gBD3+9FF3HtWCp1aCpP1BCUACeHor2eUlkKW9/YDVzCSTK54wVt3hlRbihiHBIgn4g/Ig==} + peerDependencies: + '@atcute/lexicons': ^2.0.0 + '@atcute/mst@1.0.2': resolution: {integrity: sha512-fb98Ygs0PjVAOE4WmtMGqi+PS4Y0Jsip4CIkzWBxyIcbfix8kBGQUwZi54k4rKiGfT9qroCY2rlaPFzwkkAFzQ==} peerDependencies: @@ -3653,8 +3661,8 @@ snapshots: '@atcute/cid@2.4.2': dependencies: - '@atcute/multibase': 1.2.4 - '@atcute/uint8array': 1.1.4 + '@atcute/multibase': 1.2.5 + '@atcute/uint8array': 1.1.5 '@atcute/client@5.1.1(@atcute/lexicons@2.0.2)(typescript@6.0.3)': dependencies: @@ -3736,6 +3744,10 @@ snapshots: '@standard-schema/spec': 1.1.0 esm-env: 1.2.2 + '@atcute/microcosm@2.0.2(@atcute/lexicons@2.0.2)': + dependencies: + '@atcute/lexicons': 2.0.2 + '@atcute/mst@1.0.2(@atcute/cbor@2.3.6(@atcute/cid@2.4.2))(@atcute/cid@2.4.2)': dependencies: '@atcute/cbor': 2.3.6(@atcute/cid@2.4.2) diff --git a/web/src/lib/api/enrich.ts b/web/src/lib/api/enrich.ts index ced13631..afdd2ecf 100644 --- a/web/src/lib/api/enrich.ts +++ b/web/src/lib/api/enrich.ts @@ -7,7 +7,7 @@ import { jsonPost } from "./_request"; export const TYPE_COUNT = "sh.tangled.query.enrichResponse#count"; export const TYPE_DISTINCT_AUTHORS = "sh.tangled.query.enrichResponse#distinctAuthors"; export const TYPE_VIEWER = "sh.tangled.query.enrichResponse#viewer"; -export const TYPE_MINIDOC = "com.bad-example.identity.miniDoc"; +export const TYPE_MINIDOC = "blue.microcosm.identity.resolveMiniDoc"; export type RecordPath = string & {}; export type EnvelopePath = ".repo" | ".collection" | ".rkey" | "."; diff --git a/web/src/lib/api/identity.test.ts b/web/src/lib/api/identity.test.ts index 36268180..56453187 100644 --- a/web/src/lib/api/identity.test.ts +++ b/web/src/lib/api/identity.test.ts @@ -2,7 +2,12 @@ import { describe, expect, it, vi } from "vitest"; import { createBobbinClient, type BobbinContext } from "./client"; import { IdentityCache, type MiniDoc } from "./identity"; -const DOC: MiniDoc = { did: "did:plc:x", handle: "alice.test" }; +const DOC: MiniDoc = { + did: "did:plc:x", + handle: "alice.test", + pds: "https://pds.example", + signing_key: "zQ3shSiLsnqpyQ4SfDTT1D8qzFEoeYT8rSDXW6o8pVY7VcRBJ" +}; const docResponse = (doc: MiniDoc): Response => new Response(JSON.stringify(doc), { @@ -32,7 +37,9 @@ describe("IdentityCache.resolve", () => { expect(first).toEqual(DOC); expect(second).toEqual(DOC); expect(fetchMock).toHaveBeenCalledTimes(1); - expect((fetchMock.mock.calls[0][0] as URL).searchParams.get("identifier")).toBe("alice.test"); + expect((fetchMock.mock.calls[0][0] as URL).searchParams.get("identifier")).toBe( + "alice.test" + ); }); it("coalesces concurrent misses for the same key into one in-flight fetch", async () => { @@ -56,7 +63,14 @@ describe("IdentityCache.resolve", () => { const cache = new IdentityCache(makeCtx(fetchMock)); await cache.resolve("bob.test"); - fetchMock.mockResolvedValueOnce(docResponse({ did: "did:plc:y", handle: "carol.test" })); + fetchMock.mockResolvedValueOnce( + docResponse({ + did: "did:plc:y", + handle: "carol.test", + pds: "https://pds.example", + signing_key: "zQ3shSiLsnqpyQ4SfDTT1D8qzFEoeYT8rSDXW6o8pVY7VcRBJ" + }) + ); await cache.resolve("carol.test"); expect(fetchMock).toHaveBeenCalledTimes(2); }); @@ -92,9 +106,18 @@ describe("IdentityCache.prime & map selection", () => { expect(fetchMock).not.toHaveBeenCalled(); // unknown dids miss the handle map and fetch. - fetchMock.mockResolvedValueOnce(docResponse({ did: "did:plc:z", handle: "dan.test" })); + fetchMock.mockResolvedValueOnce( + docResponse({ + did: "did:plc:z", + handle: "dan.test", + pds: "https://pds.example", + signing_key: "zQ3shSiLsnqpyQ4SfDTT1D8qzFEoeYT8rSDXW6o8pVY7VcRBJ" + }) + ); await cache.resolve("did:plc:z"); expect(fetchMock).toHaveBeenCalledTimes(1); - expect((fetchMock.mock.calls[0][0] as URL).searchParams.get("identifier")).toBe("did:plc:z"); + expect((fetchMock.mock.calls[0][0] as URL).searchParams.get("identifier")).toBe( + "did:plc:z" + ); }); }); diff --git a/web/src/lib/api/identity.ts b/web/src/lib/api/identity.ts index 65a7b12b..eb93ffcc 100644 --- a/web/src/lib/api/identity.ts +++ b/web/src/lib/api/identity.ts @@ -1,11 +1,8 @@ +import type * as BlueMicrocosmIdentityResolveMiniDoc from "@atcute/microcosm/types/blue/microcosm/identity/resolveMiniDoc"; import type { BobbinContext, XrpcRequestInit } from "./client"; import { jsonGet } from "./_request"; -export interface MiniDoc { - did: string; - handle: string; - pds?: string; -} +export type MiniDoc = BlueMicrocosmIdentityResolveMiniDoc.$output; export const INVALID_HANDLE = "handle.invalid"; @@ -14,7 +11,7 @@ export const resolveMiniDoc = ( identifier: string, init?: XrpcRequestInit ): Promise => - jsonGet(ctx, "com.bad-example.identity.resolveMiniDoc", { identifier }, init); + jsonGet(ctx, "blue.microcosm.identity.resolveMiniDoc", { identifier }, init); // did/handle cache with in-flight de-dupe. export class IdentityCache { diff --git a/web/src/lib/api/lexicons/types/sh/tangled/query/enrichResponse.ts b/web/src/lib/api/lexicons/types/sh/tangled/query/enrichResponse.ts index 8624b761..c0be0672 100644 --- a/web/src/lib/api/lexicons/types/sh/tangled/query/enrichResponse.ts +++ b/web/src/lib/api/lexicons/types/sh/tangled/query/enrichResponse.ts @@ -20,7 +20,7 @@ const _linkDescriptorSchema = /*#__PURE__*/ v.object({ * NSID of the payload type to produce, which also defines the payload's shape. Results land at data[ref][source][type]. */ type: /*#__PURE__*/ v.string< - | "com.bad-example.identity.miniDoc" + | "blue.microcosm.identity.resolveMiniDoc" | "sh.tangled.query.enrichResponse#count" | "sh.tangled.query.enrichResponse#distinctAuthors" | "sh.tangled.query.enrichResponse#viewer" diff --git a/web/src/lib/api/repo.test.ts b/web/src/lib/api/repo.test.ts index 1f6af5b5..79d56a3f 100644 --- a/web/src/lib/api/repo.test.ts +++ b/web/src/lib/api/repo.test.ts @@ -309,7 +309,7 @@ describe("resolveForkRepoLabels", () => { data: { "did:plc:forkowner": { "sh.tangled.repo:.repo": { - "com.bad-example.identity.miniDoc": { handle: "fork.example" } + "blue.microcosm.identity.resolveMiniDoc": { handle: "fork.example" } } } } diff --git a/web/src/lib/auth.svelte.ts b/web/src/lib/auth.svelte.ts index cd4d3430..89152d8a 100644 --- a/web/src/lib/auth.svelte.ts +++ b/web/src/lib/auth.svelte.ts @@ -147,7 +147,7 @@ const resolveProfile = async ( bobbinUrl: string ): Promise => { try { - const url = new URL("/xrpc/com.bad-example.identity.resolveMiniDoc", bobbinUrl); + const url = new URL("/xrpc/blue.microcosm.identity.resolveMiniDoc", bobbinUrl); url.searchParams.set("identifier", identifier); const response = await fetch(url, { headers: { accept: "application/json" } }); if (response.ok) { diff --git a/web/src/lib/components/profile/pages.test.ts b/web/src/lib/components/profile/pages.test.ts index ae38bc4b..39ec787b 100644 --- a/web/src/lib/components/profile/pages.test.ts +++ b/web/src/lib/components/profile/pages.test.ts @@ -64,7 +64,7 @@ describe("fetchStarredPage", () => { }, { source: "sh.tangled.repo:.repo", - type: "com.bad-example.identity.miniDoc", + type: "blue.microcosm.identity.resolveMiniDoc", targets: ["items[].uri"] } ]); diff --git a/web/src/lib/components/settings/tabs/ProfileTab.svelte b/web/src/lib/components/settings/tabs/ProfileTab.svelte index eb061d95..cf9daeaa 100644 --- a/web/src/lib/components/settings/tabs/ProfileTab.svelte +++ b/web/src/lib/components/settings/tabs/ProfileTab.svelte @@ -26,7 +26,7 @@ const serviceUrl = auth.bobbinUrl; if (!did) return null; const ctx = createBobbinClient({ serviceUrl }); - return (await resolveMiniDoc(ctx, did)).pds ?? null; + return (await resolveMiniDoc(ctx, did)).pds; }); // everything below is mocked — nothing is persisted yet diff --git a/web/src/routes/[handle]/+layout.ts b/web/src/routes/[handle]/+layout.ts index bb115832..e722fcdd 100644 --- a/web/src/routes/[handle]/+layout.ts +++ b/web/src/routes/[handle]/+layout.ts @@ -45,7 +45,7 @@ export const load: LayoutLoad = async (event) => { const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, fetch: event.fetch }); const viewerDid = parent.auth?.did; const resolved = await enrich(ctx, { - xrpc: "com.bad-example.identity.resolveMiniDoc", + xrpc: "blue.microcosm.identity.resolveMiniDoc", params: { identifier }, enrich: [ ...COUNT_DESCRIPTORS.map((descriptor) => ({ ...descriptor, targets: ["did"] })), diff --git a/web/src/routes/[handle]/[repo]/pipelines/pipelines.test.ts b/web/src/routes/[handle]/[repo]/pipelines/pipelines.test.ts index 5612893a..b366f11c 100644 --- a/web/src/routes/[handle]/[repo]/pipelines/pipelines.test.ts +++ b/web/src/routes/[handle]/[repo]/pipelines/pipelines.test.ts @@ -168,7 +168,7 @@ describe("pipelines load", () => { data: { "did:plc:forkowner": { "sh.tangled.repo:.repo": { - "com.bad-example.identity.miniDoc": { handle: "fork.example" } + "blue.microcosm.identity.resolveMiniDoc": { handle: "fork.example" } } } }