test ai-blog
This commit is contained in:
182
ai-conversation/src/services/oauth.js
Normal file
182
ai-conversation/src/services/oauth.js
Normal file
@@ -0,0 +1,182 @@
|
||||
import { BrowserOAuthClient } from '@atproto/oauth-client-browser'
|
||||
import { Agent } from '@atproto/api'
|
||||
import { env } from '../config/env.js'
|
||||
import { isSyuIsHandle } from '../utils/pds.js'
|
||||
|
||||
export class OAuthService {
|
||||
constructor() {
|
||||
this.clientId = env.oauth.clientId || this.getClientId()
|
||||
this.clients = { bsky: null, syu: null }
|
||||
this.agent = null
|
||||
this.sessionInfo = null
|
||||
this.initPromise = null
|
||||
}
|
||||
|
||||
getClientId() {
|
||||
const origin = window.location.origin
|
||||
return origin.includes('localhost') || origin.includes('127.0.0.1')
|
||||
? undefined // Loopback client
|
||||
: `${origin}/client-metadata.json`
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
if (this.initPromise) return this.initPromise
|
||||
|
||||
this.initPromise = this._initialize()
|
||||
return this.initPromise
|
||||
}
|
||||
|
||||
async _initialize() {
|
||||
try {
|
||||
// Initialize OAuth clients
|
||||
this.clients.bsky = await BrowserOAuthClient.load({
|
||||
clientId: this.clientId,
|
||||
handleResolver: 'https://bsky.social',
|
||||
plcDirectoryUrl: 'https://plc.directory',
|
||||
})
|
||||
|
||||
this.clients.syu = await BrowserOAuthClient.load({
|
||||
clientId: this.clientId,
|
||||
handleResolver: 'https://syu.is',
|
||||
plcDirectoryUrl: 'https://plc.syu.is',
|
||||
})
|
||||
|
||||
// Try to restore session
|
||||
return await this.restoreSession()
|
||||
} catch (error) {
|
||||
console.error('OAuth initialization failed:', error)
|
||||
this.initPromise = null
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async restoreSession() {
|
||||
// Try both clients
|
||||
for (const client of [this.clients.bsky, this.clients.syu]) {
|
||||
const result = await client.init()
|
||||
if (result?.session) {
|
||||
this.agent = new Agent(result.session)
|
||||
return this.processSession(result.session)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async processSession(session) {
|
||||
const did = session.sub || session.did
|
||||
let handle = session.handle || 'unknown'
|
||||
let displayName = null
|
||||
let avatar = null
|
||||
|
||||
// Create Agent directly with session (per official docs)
|
||||
try {
|
||||
this.agent = new Agent(session)
|
||||
} catch (err) {
|
||||
// Fallback to dpopFetch method
|
||||
this.agent = new Agent({
|
||||
service: session.server?.serviceEndpoint || 'https://bsky.social',
|
||||
fetch: session.dpopFetch
|
||||
})
|
||||
}
|
||||
|
||||
// Get profile information using authenticated agent
|
||||
// Skip test DIDs
|
||||
if (this.agent && did && !did.includes('test-')) {
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 300))
|
||||
const profile = await this.agent.getProfile({ actor: did })
|
||||
handle = profile.data.handle || handle
|
||||
displayName = profile.data.displayName || null
|
||||
avatar = profile.data.avatar || null
|
||||
|
||||
console.log('Profile fetched from session:', {
|
||||
did,
|
||||
handle,
|
||||
displayName,
|
||||
avatar: avatar ? 'present' : 'none'
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('Failed to get profile from session:', error)
|
||||
// Keep the basic info we have
|
||||
}
|
||||
} else if (did && did.includes('test-')) {
|
||||
console.log('Skipping profile fetch for test DID:', did)
|
||||
}
|
||||
|
||||
this.sessionInfo = {
|
||||
did,
|
||||
handle,
|
||||
displayName,
|
||||
avatar
|
||||
}
|
||||
|
||||
return {
|
||||
did,
|
||||
handle,
|
||||
displayName,
|
||||
avatar
|
||||
}
|
||||
}
|
||||
|
||||
async login(handle) {
|
||||
await this.initialize()
|
||||
|
||||
const client = isSyuIsHandle(handle) ? this.clients.syu : this.clients.bsky
|
||||
const authUrl = await client.authorize(handle, {
|
||||
scope: 'atproto transition:generic'
|
||||
})
|
||||
|
||||
window.location.href = authUrl.toString()
|
||||
}
|
||||
|
||||
async checkAuth() {
|
||||
try {
|
||||
await this.initialize()
|
||||
if (this.sessionInfo) {
|
||||
return {
|
||||
user: this.sessionInfo,
|
||||
agent: this.agent
|
||||
}
|
||||
}
|
||||
return null
|
||||
} catch (error) {
|
||||
console.error('Auth check failed:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async logout() {
|
||||
try {
|
||||
// Sign out from session
|
||||
if (this.clients.bsky) {
|
||||
const result = await this.clients.bsky.init()
|
||||
if (result?.session?.signOut) {
|
||||
await result.session.signOut()
|
||||
}
|
||||
}
|
||||
|
||||
// Clear state
|
||||
this.agent = null
|
||||
this.sessionInfo = null
|
||||
this.clients = { bsky: null, syu: null }
|
||||
this.initPromise = null
|
||||
|
||||
// Clear storage
|
||||
localStorage.clear()
|
||||
sessionStorage.clear()
|
||||
|
||||
// Reload page
|
||||
window.location.reload()
|
||||
} catch (error) {
|
||||
console.error('Logout failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
getAgent() {
|
||||
return this.agent
|
||||
}
|
||||
|
||||
getUser() {
|
||||
return this.sessionInfo
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user