Highly ambitious ATProtocol AppView service and sdks
1import type { AuthProvider } from "@slices/client";
2import { AtProtoClient } from "../generated_client.ts";
3import { ConfigManager } from "../auth/config.ts";
4import { checkUserWaitlistAccess, showWaitlistError } from "./waitlist.ts";
5
6class DeviceAuthProvider implements AuthProvider {
7 private config: ConfigManager;
8
9 constructor(config: ConfigManager) {
10 this.config = config;
11 }
12
13 async ensureValidToken(): Promise<{ accessToken: string; tokenType?: string }> {
14 await this.config.load();
15
16 if (!this.config.isAuthenticated()) {
17 throw new Error("Not authenticated. Run 'slices login' first.");
18 }
19
20 const authConfig = this.config.get().auth!;
21
22 // Check if token is expired
23 if (authConfig.expiresAt && authConfig.expiresAt <= Date.now()) {
24 throw new Error("Access token has expired. Please re-authenticate using 'slices login'.");
25 }
26
27 return {
28 accessToken: authConfig.accessToken,
29 tokenType: "Bearer",
30 };
31 }
32
33 async refreshAccessToken(): Promise<{ accessToken: string; tokenType?: string }> {
34 return await this.ensureValidToken();
35 }
36}
37
38export async function createAuthenticatedClient(sliceUri: string, apiUrl = "https://api.slices.network"): Promise<AtProtoClient> {
39 const config = new ConfigManager();
40 await config.load();
41
42 if (!config.isAuthenticated()) {
43 throw new Error("Not authenticated. Run 'slices login' first.");
44 }
45
46 const authConfig = config.get().auth!;
47
48 if (!authConfig.did) {
49 throw new Error("Missing user DID in authentication config. Please re-authenticate using 'slices login'.");
50 }
51
52 // Only check waitlist access for production Slices network
53 if (apiUrl === "https://api.slices.network") {
54 const { hasAccess, isOnWaitlist } = await checkUserWaitlistAccess(authConfig.did, apiUrl);
55
56 if (!hasAccess) {
57 showWaitlistError(authConfig.did, isOnWaitlist);
58 Deno.exit(1);
59 }
60 }
61
62 // Create simple auth provider that uses stored device flow tokens
63 const authProvider = new DeviceAuthProvider(config);
64
65 return new AtProtoClient(apiUrl, sliceUri, authProvider);
66}