this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 127 lines 3.1 kB view raw
1import { 2 buildAtprotoLoopbackClientMetadata, 3 JoseKey, 4 Keyset, 5 NodeOAuthClient, 6 NodeSavedSession, 7 NodeSavedState 8} from "@atproto/oauth-client-node"; 9import { getDB } from "../db"; 10 11declare global { 12 var _oauthClient: NodeOAuthClient | undefined; 13} 14 15const PRIVATE_KEY = process.env.PRIVATE_KEY; 16const PUBLIC_URL = process.env.PUBLIC_URL; 17 18export const SCOPE = 19 "atproto rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app#bsky_appview"; 20 21const getClientMetadata = () => { 22 if (PUBLIC_URL) { 23 return { 24 client_id: `${PUBLIC_URL}/oauth-client-metadata.json`, 25 client_name: "bambü", 26 client_uri: PUBLIC_URL, 27 dpop_bound_access_tokens: true, 28 grant_types: ["authorization_code", "refresh_token"], 29 jwks_uri: `${PUBLIC_URL}/.well-known/jwks.json`, 30 redirect_uris: [`${PUBLIC_URL}/oauth/callback`], 31 response_types: ["code"], 32 scope: SCOPE, 33 token_endpoint_auth_method: "private_key_jwt" as const, 34 token_endpoint_auth_signing_alg: "ES256" as const 35 }; 36 } 37 38 return buildAtprotoLoopbackClientMetadata({ 39 redirect_uris: ["http://127.0.0.1:3000/oauth/callback"], 40 scope: SCOPE 41 }); 42}; 43 44const getKeyset = async () => { 45 if (PUBLIC_URL && PRIVATE_KEY) { 46 return new Keyset([await JoseKey.fromJWK(JSON.parse(PRIVATE_KEY))]); 47 } 48 49 return undefined; 50}; 51 52export const getOAuthClient = async () => { 53 if (globalThis._oauthClient) { 54 return globalThis._oauthClient; 55 } 56 57 globalThis._oauthClient = new NodeOAuthClient({ 58 clientMetadata: getClientMetadata(), 59 keyset: await getKeyset(), 60 sessionStore: { 61 del: async (key: string) => { 62 const db = getDB(); 63 64 await db 65 ?.deleteFrom("auth_session") 66 .where("key", "=", key) 67 .execute(); 68 }, 69 get: async (key: string) => { 70 const db = getDB(); 71 const row = await db 72 ?.selectFrom("auth_session") 73 .select("value") 74 .where("key", "=", key) 75 .executeTakeFirst(); 76 77 return row ? JSON.parse(row.value) : undefined; 78 }, 79 set: async (key: string, value: NodeSavedSession) => { 80 const db = getDB(); 81 const valueJSON = JSON.stringify(value); 82 83 await db 84 ?.insertInto("auth_session") 85 .values({ key, value: valueJSON }) 86 .onConflict((oc) => 87 oc.column("key").doUpdateSet({ value: valueJSON }) 88 ) 89 .execute(); 90 } 91 }, 92 stateStore: { 93 del: async (key: string) => { 94 const db = getDB(); 95 96 await db 97 ?.deleteFrom("auth_state") 98 .where("key", "=", key) 99 .execute(); 100 }, 101 get: async (key: string) => { 102 const db = getDB(); 103 const row = await db 104 ?.selectFrom("auth_state") 105 .select("value") 106 .where("key", "=", key) 107 .executeTakeFirst(); 108 109 return row ? JSON.parse(row.value) : undefined; 110 }, 111 set: async (key: string, value: NodeSavedState) => { 112 const db = getDB(); 113 const valueJSON = JSON.stringify(value); 114 115 await db 116 ?.insertInto("auth_state") 117 .values({ key, value: valueJSON }) 118 .onConflict((oc) => 119 oc.column("key").doUpdateSet({ value: valueJSON }) 120 ) 121 .execute(); 122 } 123 } 124 }); 125 126 return globalThis._oauthClient; 127};