/** * AT Protocol client wrapper for publishing Askimut records */ import { Client } from '@atproto/lex' import type { OAuthSession } from '@atproto/oauth-client-node' import { getOAuthClient } from './oauth' import { getCachedConfig, isPublishingEnabled } from './config' import * as lexicons from '../lexicons/index.js' import type { LexQuestion, LexAnswer, LexProfile } from './schema-bridge' /** * AT Protocol client for Askimut operations */ export class AskimutAtClient { private client: Client | null = null private session: OAuthSession | null = null constructor(session?: OAuthSession) { if (session) { this.session = session this.client = new Client(session, { validateRequest: getCachedConfig().atProtocol.strictValidation, validateResponse: true, strictResponseProcessing: getCachedConfig().atProtocol.strictValidation }) } } /** * Initialize client with OAuth session for a given DID */ static async fromDid(did: string): Promise { try { const oauthClient = await getOAuthClient() const session = await oauthClient.restore(did) return new AskimutAtClient(session) } catch (error) { console.error('Failed to restore AT Protocol session:', error) return new AskimutAtClient() } } /** * Check if the client is authenticated */ isAuthenticated(): boolean { return this.client !== null && this.session !== null } /** * Get the authenticated user's DID */ getDid(): string | null { return this.session?.did || null } /** * Publish a question to AT Protocol */ async publishQuestion(question: LexQuestion): Promise<{ uri: string; cid: string } | null> { if (!this.client || !isPublishingEnabled('question')) { return null } try { // Validate the question before publishing lexicons.question.$validate(question) // For now, we'll use a simplified approach until the Client API is more stable console.log('Would publish question to AT Protocol:', question) // Return a mock result for now return { uri: `at://${this.getDid()}/com.askimut.question/${Date.now()}`, cid: 'bafyrei' + Math.random().toString(36).substring(2) } } catch (error) { console.error('Failed to publish question to AT Protocol:', error) throw error } } /** * Publish an answer to AT Protocol */ async publishAnswer(answer: LexAnswer): Promise<{ uri: string; cid: string } | null> { if (!this.client || !isPublishingEnabled('answer')) { return null } try { // Validate the answer before publishing lexicons.answer.$validate(answer) // For now, we'll use a simplified approach until the Client API is more stable console.log('Would publish answer to AT Protocol:', answer) // Return a mock result for now return { uri: `at://${this.getDid()}/com.askimut.answer/${Date.now()}`, cid: 'bafyrei' + Math.random().toString(36).substring(2) } } catch (error) { console.error('Failed to publish answer to AT Protocol:', error) throw error } } /** * Publish/update a profile to AT Protocol */ async publishProfile(profile: LexProfile): Promise<{ uri: string; cid: string } | null> { if (!this.client || !isPublishingEnabled('profile')) { return null } try { // Validate the profile before publishing lexicons.profile.$validate(profile) // For now, we'll use a simplified approach until the Client API is more stable console.log('Would publish profile to AT Protocol:', profile) // Return a mock result for now return { uri: `at://${this.getDid()}/com.askimut.profile/self`, cid: 'bafyrei' + Math.random().toString(36).substring(2) } } catch (error) { console.error('Failed to publish profile to AT Protocol:', error) throw error } } // Note: Get, list, and delete methods are temporarily disabled // until the Client API type issues are resolved in a future update } /** * Create an AT Protocol client for a given session */ export async function createAtClient(session?: OAuthSession): Promise { return new AskimutAtClient(session) } /** * Create an AT Protocol client for a given DID */ export async function createAtClientForDid(did: string): Promise { return AskimutAtClient.fromDid(did) } /** * Utility function to extract record key (rkey) from AT-URI */ export function extractRkeyFromUri(atUri: string): string | null { try { const parts = atUri.split('/') return parts[parts.length - 1] || null } catch { return null } } /** * Utility function to construct AT-URI from DID and rkey */ export function constructAtUri(did: string, collection: string, rkey: string): string { return `at://${did}/${collection}/${rkey}` }