tangled
alpha
login
or
join now
heaths.dev
/
sequoia
forked from
stevedylan.dev/sequoia
0
fork
atom
A CLI for publishing standard.site documents to ATProto
0
fork
atom
overview
issues
pulls
pipelines
Add cors support
Co-Authored-By: @stevedylan.dev
Heath Stewart
4 weeks ago
5877729a
ead0f9eb
+64
-3
4 changed files
expand all
collapse all
unified
split
docs
src
index.ts
lib
oauth-client.ts
path-redirect.ts
routes
auth.ts
+10
docs/src/index.ts
···
1
1
import { Hono } from "hono";
2
2
+
import { cors } from "hono/cors";
2
3
import auth from "./routes/auth";
3
4
import subscribe from "./routes/subscribe";
5
5
+
import "./lib/path-redirect";
4
6
5
7
type Bindings = {
6
8
ASSETS: Fetcher;
···
12
14
13
15
app.route("/oauth", auth);
14
16
app.route("/subscribe", subscribe);
17
17
+
app.use("/subscribe", cors({
18
18
+
origin: (origin) => origin,
19
19
+
credentials: true,
20
20
+
}));
21
21
+
app.use("/subscribe/*", cors({
22
22
+
origin: (origin) => origin,
23
23
+
credentials: true,
24
24
+
}));
15
25
16
26
app.get("/api/health", (c) => {
17
27
return c.json({ status: "ok" });
+1
-1
docs/src/lib/oauth-client.ts
···
19
19
redirect_uris: [redirectUri],
20
20
grant_types: ["authorization_code", "refresh_token"],
21
21
response_types: ["code"],
22
22
-
scope: "atproto transition:generic",
22
22
+
scope: "atproto site.standard.graph.subscription",
23
23
token_endpoint_auth_method: "none",
24
24
application_type: "web",
25
25
dpop_bound_access_tokens: true,
+51
docs/src/lib/path-redirect.ts
···
1
1
+
// Cloudflare Workers compatibility patches for @atproto libraries.
2
2
+
//
3
3
+
// 1. Workers don't support `redirect: 'error'` — simulate it with 'manual'.
4
4
+
// 2. Workers don't support the standard `cache` option in Request — strip it.
5
5
+
6
6
+
function sanitizeInit(init?: RequestInit): RequestInit | undefined {
7
7
+
if (!init) return init;
8
8
+
const { cache, redirect, ...rest } = init;
9
9
+
return {
10
10
+
...rest,
11
11
+
// Workers only support 'follow' and 'manual'
12
12
+
redirect: redirect === "error" ? "manual" : redirect,
13
13
+
// Workers don't support standard cache modes — omit entirely
14
14
+
...(cache ? {} : {}),
15
15
+
};
16
16
+
}
17
17
+
18
18
+
const errorRedirectRequests = new WeakSet<Request>();
19
19
+
const OriginalRequest = globalThis.Request;
20
20
+
21
21
+
globalThis.Request = class extends OriginalRequest {
22
22
+
constructor(
23
23
+
input: RequestInfo | URL,
24
24
+
init?: RequestInit,
25
25
+
) {
26
26
+
super(input, sanitizeInit(init));
27
27
+
if (init?.redirect === "error") {
28
28
+
errorRedirectRequests.add(this);
29
29
+
}
30
30
+
}
31
31
+
} as typeof Request;
32
32
+
33
33
+
const originalFetch = globalThis.fetch;
34
34
+
globalThis.fetch = (async (
35
35
+
input: RequestInfo | URL,
36
36
+
init?: RequestInit,
37
37
+
): Promise<Response> => {
38
38
+
const cleanInit = sanitizeInit(init);
39
39
+
const response = await originalFetch(input, cleanInit);
40
40
+
41
41
+
// Simulate redirect: 'error' — throw on 3xx
42
42
+
const wantsRedirectError =
43
43
+
init?.redirect === "error" ||
44
44
+
(input instanceof Request && errorRedirectRequests.has(input));
45
45
+
46
46
+
if (wantsRedirectError && response.status >= 300 && response.status < 400) {
47
47
+
throw new TypeError("unexpected redirect");
48
48
+
}
49
49
+
50
50
+
return response;
51
51
+
}) as typeof fetch;
+2
-2
docs/src/routes/auth.ts
···
27
27
redirect_uris: [redirectUri],
28
28
grant_types: ["authorization_code", "refresh_token"],
29
29
response_types: ["code"],
30
30
-
scope: "atproto transition:generic",
30
30
+
scope: "atproto site.standard.graph.subscription",
31
31
token_endpoint_auth_method: "none",
32
32
application_type: "web",
33
33
dpop_bound_access_tokens: true,
···
44
44
45
45
const client = createOAuthClient(c.env.SEQUOIA_SESSIONS, c.env.CLIENT_URL);
46
46
const authUrl = await client.authorize(handle, {
47
47
-
scope: "atproto transition:generic",
47
47
+
scope: "atproto site.standard.graph.subscription",
48
48
});
49
49
50
50
return c.redirect(authUrl.toString());