A CLI for publishing standard.site documents to ATProto
sequoia.pub
standard
site
lexicon
cli
publishing
1import { JoseKey } from "@atproto/jwk-jose";
2import { OAuthClient } from "@atproto/oauth-client";
3import { AtprotoDohHandleResolver } from "@atproto-labs/handle-resolver";
4import { createStateStore, createSessionStore } from "./kv-stores";
5
6export const OAUTH_SCOPE =
7 "atproto repo:site.standard.graph.subscription?action=create&action=delete";
8
9export function createOAuthClient(kv: KVNamespace, clientUrl: string) {
10 const clientId = `${clientUrl}/oauth/client-metadata.json`;
11 const redirectUri = `${clientUrl}/oauth/callback`;
12
13 return new OAuthClient({
14 responseMode: "query",
15 handleResolver: new AtprotoDohHandleResolver({
16 dohEndpoint: "https://cloudflare-dns.com/dns-query",
17 }),
18 clientMetadata: {
19 client_id: clientId,
20 client_name: "Sequoia",
21 client_uri: clientUrl,
22 redirect_uris: [redirectUri],
23 grant_types: ["authorization_code", "refresh_token"],
24 response_types: ["code"],
25 scope: "atproto repo:site.standard.graph.subscription?action=create",
26 token_endpoint_auth_method: "none",
27 application_type: "web",
28 dpop_bound_access_tokens: true,
29 },
30 runtimeImplementation: {
31 createKey: (algs: string[]) => JoseKey.generate(algs),
32 getRandomValues: (length: number) =>
33 crypto.getRandomValues(new Uint8Array(length)),
34 digest: async (data: Uint8Array, { name }: { name: string }) => {
35 const buf = await crypto.subtle.digest(
36 name.replace("sha", "SHA-"),
37 new Uint8Array(data),
38 );
39 return new Uint8Array(buf);
40 },
41 requestLock: <T>(_name: string, fn: () => T | PromiseLike<T>) => fn(),
42 },
43 stateStore: createStateStore(kv),
44 sessionStore: createSessionStore(kv),
45 });
46}