import type { AuthProvider } from "@slices/client"; import { AtProtoClient } from "../generated_client.ts"; import { ConfigManager } from "../auth/config.ts"; import { checkUserWaitlistAccess, showWaitlistError } from "./waitlist.ts"; class DeviceAuthProvider implements AuthProvider { private config: ConfigManager; constructor(config: ConfigManager) { this.config = config; } async ensureValidToken(): Promise<{ accessToken: string; tokenType?: string }> { await this.config.load(); if (!this.config.isAuthenticated()) { throw new Error("Not authenticated. Run 'slices login' first."); } const authConfig = this.config.get().auth!; // Check if token is expired if (authConfig.expiresAt && authConfig.expiresAt <= Date.now()) { throw new Error("Access token has expired. Please re-authenticate using 'slices login'."); } return { accessToken: authConfig.accessToken, tokenType: "Bearer", }; } async refreshAccessToken(): Promise<{ accessToken: string; tokenType?: string }> { return await this.ensureValidToken(); } } export async function createAuthenticatedClient(sliceUri: string, apiUrl = "https://api.slices.network"): Promise { const config = new ConfigManager(); await config.load(); if (!config.isAuthenticated()) { throw new Error("Not authenticated. Run 'slices login' first."); } const authConfig = config.get().auth!; if (!authConfig.did) { throw new Error("Missing user DID in authentication config. Please re-authenticate using 'slices login'."); } // Only check waitlist access for production Slices network if (apiUrl === "https://api.slices.network") { const { hasAccess, isOnWaitlist } = await checkUserWaitlistAccess(authConfig.did, apiUrl); if (!hasAccess) { showWaitlistError(authConfig.did, isOnWaitlist); Deno.exit(1); } } // Create simple auth provider that uses stored device flow tokens const authProvider = new DeviceAuthProvider(config); return new AtProtoClient(apiUrl, sliceUri, authProvider); }