A CLI for publishing standard.site documents to ATProto sequoia.pub
standard site lexicon cli publishing
at main 76 lines 2.0 kB view raw
1import { JoseKey } from "@atproto/jwk-jose"; 2import type { 3 Key, 4 InternalStateData, 5 SessionStore, 6 StateStore, 7} from "@atproto/oauth-client"; 8 9type SerializedStateData = Omit<InternalStateData, "dpopKey"> & { 10 dpopJwk: Record<string, unknown>; 11}; 12 13type SerializedSession = Omit<Parameters<SessionStore["set"]>[1], "dpopKey"> & { 14 dpopJwk: Record<string, unknown>; 15}; 16 17function serializeKey(key: Key): Record<string, unknown> { 18 const jwk = key.privateJwk; 19 if (!jwk) throw new Error("Private DPoP JWK is missing"); 20 return jwk as Record<string, unknown>; 21} 22 23async function deserializeKey(jwk: Record<string, unknown>): Promise<Key> { 24 return JoseKey.fromJWK(jwk); 25} 26 27export function createStateStore(kv: KVNamespace, ttl = 600): StateStore { 28 return { 29 async set(key, { dpopKey, ...rest }) { 30 const data: SerializedStateData = { 31 ...rest, 32 dpopJwk: serializeKey(dpopKey), 33 }; 34 await kv.put(`oauth_state:${key}`, JSON.stringify(data), { 35 expirationTtl: ttl, 36 }); 37 }, 38 async get(key) { 39 const raw = await kv.get(`oauth_state:${key}`); 40 if (!raw) return undefined; 41 const { dpopJwk, ...rest }: SerializedStateData = JSON.parse(raw); 42 const dpopKey = await deserializeKey(dpopJwk); 43 return { ...rest, dpopKey }; 44 }, 45 async del(key) { 46 await kv.delete(`oauth_state:${key}`); 47 }, 48 }; 49} 50 51export function createSessionStore( 52 kv: KVNamespace, 53 ttl = 60 * 60 * 24 * 14, 54): SessionStore { 55 return { 56 async set(sub, { dpopKey, ...rest }) { 57 const data: SerializedSession = { 58 ...rest, 59 dpopJwk: serializeKey(dpopKey), 60 }; 61 await kv.put(`oauth_session:${sub}`, JSON.stringify(data), { 62 expirationTtl: ttl, 63 }); 64 }, 65 async get(sub) { 66 const raw = await kv.get(`oauth_session:${sub}`); 67 if (!raw) return undefined; 68 const { dpopJwk, ...rest }: SerializedSession = JSON.parse(raw); 69 const dpopKey = await deserializeKey(dpopJwk); 70 return { ...rest, dpopKey }; 71 }, 72 async del(sub) { 73 await kv.delete(`oauth_session:${sub}`); 74 }, 75 }; 76}