diff --git a/bun.lock b/bun.lock index dd8c7b5..59c84b8 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "devDependencies": { "@atcute/client": "^2.0.9", "@atcute/identity": "^0.1.2", + "@atcute/identity-resolver": "^0.1.2", "@atcute/lex-cli": "^1.0.4", "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", @@ -44,8 +45,12 @@ "@atcute/identity": ["@atcute/identity@0.1.2", "", { "dependencies": { "@badrap/valita": "^0.4.2" } }, "sha512-YmRCXm/Z4lnJz4RItnr5e6NiTtQaCRb6xIEuaqRs/6wxKHMVEzFY8ROC24L7MO5qiAgIU6GsbWv67YmSo6Y2tQ=="], + "@atcute/identity-resolver": ["@atcute/identity-resolver@0.1.2", "", { "dependencies": { "@atcute/util-fetch": "^1.0.0", "@badrap/valita": "^0.4.2" }, "peerDependencies": { "@atcute/identity": "^0.1.0" } }, "sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg=="], + "@atcute/lex-cli": ["@atcute/lex-cli@1.0.4", "", { "dependencies": { "@badrap/valita": "^0.3.11", "@externdefs/collider": "^0.1.0", "picocolors": "^1.1.1", "prettier": "^3.3.3" }, "bin": { "lex-cli": "cli.mjs" } }, "sha512-8mRnjjK+b6Z4wmfFRUYYPswVZhT7PYZBHLMCFNiI1AdrZqaJ1CmoiExYjkVGQkixZURRIaxr49KGBV2iSMF/pQ=="], + "@atcute/util-fetch": ["@atcute/util-fetch@1.0.1", "", { "dependencies": { "@badrap/valita": "^0.4.2" } }, "sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow=="], + "@badrap/valita": ["@badrap/valita@0.4.3", "", {}, "sha512-C9iZSrVlTb610dxZ2oatK5LwefaHv0Q9eYfVDH3co846x7WinhCfc8jCDTE55yM8WxlmOfX2ckKmsSr7KzZ/gg=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ=="], diff --git a/package.json b/package.json index f6aaff9..993ccd6 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "devDependencies": { "@atcute/client": "^2.0.9", "@atcute/identity": "^0.1.2", + "@atcute/identity-resolver": "^0.1.2", "@atcute/lex-cli": "^1.0.4", "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", diff --git a/src/lib/util.ts b/src/lib/util.ts new file mode 100644 index 0000000..93a0a7d --- /dev/null +++ b/src/lib/util.ts @@ -0,0 +1,58 @@ +import { CredentialManager, XRPC } from '@atcute/client'; +import { getPdsEndpoint } from '@atcute/identity'; +import { + AtprotoWebDidDocumentResolver, + CompositeDidDocumentResolver, + PlcDidDocumentResolver, + XrpcHandleResolver +} from '@atcute/identity-resolver'; + +const didDocumentResolver = new CompositeDidDocumentResolver({ + methods: { + plc: new PlcDidDocumentResolver(), + web: new AtprotoWebDidDocumentResolver() + } +}); + +const handleResolver = new XrpcHandleResolver({ + serviceUrl: 'https://public.api.bsky.app' +}); + +async function resolvePDS(did: string) { + const doc = await didDocumentResolver.resolve(did as `did:plc:${string}` | `did:web:${string}`); + const pds = getPdsEndpoint(doc); + return pds; +} + +export async function resolveHandle(handle: string) { + if (!handle.includes('.')) { + throw new Error(`Invalid DID: ${handle}`); + } + return await handleResolver.resolve(handle as `${string}.${string}`); +} + +export async function createRPC(did: string) { + if (!did.startsWith('did:')) did = await resolveHandle(did); + + const pds = await resolvePDS(did); + if (!pds) { + throw new Error(`Failed to resolve PDS for DID: ${did}`); + } + + const manager = new CredentialManager({ service: pds }); + const rpc = new XRPC({ handler: manager }); + + return rpc; +} + +export async function getSessions(rpc: XRPC, did: string) { + const { + data: { records } + } = await rpc.get('com.atproto.repo.listRecords', { + params: { + repo: did, + collection: 'me.woach.feed.session' + } + }); + return records; +} diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index a02cfe3..ba58d86 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -1,14 +1,2 @@ -import { CredentialManager, XRPC } from '@atcute/client'; -import type { LayoutLoad } from './$types'; - export const prerender = true; export const trailingSlash = 'always'; - -export const load: LayoutLoad = async () => { - const manager = new CredentialManager({ service: 'https://bsky.social' }); - const rpc = new XRPC({ handler: manager }); - await manager.login({ identifier: 'm.woach.me', password: 'c5sj-oyqa-uxhx-ju45' }); - return { - rpc - }; -}; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 64d4d89..ffba1b5 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,7 +1,4 @@

Home Page

- - diff --git a/src/routes/user/[handle]/+page.svelte b/src/routes/user/[handle]/+page.svelte index c063380..7aea26f 100644 --- a/src/routes/user/[handle]/+page.svelte +++ b/src/routes/user/[handle]/+page.svelte @@ -3,12 +3,8 @@ import type { PageProps } from './$types'; let { data }: PageProps = $props(); - - -

{data.userData.handle}

-

{data.userData.did}

- - +

{data.handle}

+ diff --git a/src/routes/user/[handle]/+page.ts b/src/routes/user/[handle]/+page.ts index 7124945..154cfd6 100644 --- a/src/routes/user/[handle]/+page.ts +++ b/src/routes/user/[handle]/+page.ts @@ -1,33 +1,17 @@ -import type { ComAtprotoRepoListRecords, MeWoachFeedSession } from '@atcute/client/lexicons'; // Import the type +import { createRPC, getSessions, resolveHandle } from '$lib/util'; +import type { ComAtprotoRepoListRecords, MeWoachFeedSession } from '@atcute/client/lexicons'; import type { PageLoad } from './$types'; -export const load: PageLoad = async ({ parent, params }) => { - const { rpc } = await parent(); +export const load: PageLoad = async ({ params }) => { + const did = await resolveHandle(params.handle); + const rpc = await createRPC(did); - const { data: userData } = await rpc.get('com.atproto.identity.resolveHandle', { - params: { - handle: params.handle - } - }); - - const { - data: { records } - } = await rpc.get('com.atproto.repo.listRecords', { - params: { - repo: userData.did, - collection: 'me.woach.feed.session' - } - }); - - const sessionsValues: MeWoachFeedSession.Record[] = records.map( + const sessions: MeWoachFeedSession.Record[] = (await getSessions(rpc, did)).map( (record: ComAtprotoRepoListRecords.Record) => record.value as MeWoachFeedSession.Record ); return { - userData: { - handle: params.handle, - did: userData.did, - sessions: sessionsValues - } + handle: params.handle, + sessions: sessions }; };