Add cors support
9f834bf6
Co-Authored-By: @stevedylan.dev
4 file(s) · +64 −3
Co-Authored-By: @stevedylan.dev
| 1 | 1 | import { Hono } from "hono"; |
|
| 2 | + | import { cors } from "hono/cors"; |
|
| 2 | 3 | import auth from "./routes/auth"; |
|
| 3 | 4 | import subscribe from "./routes/subscribe"; |
|
| 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 | + | app.use("/subscribe", cors({ |
|
| 18 | + | origin: (origin) => origin, |
|
| 19 | + | credentials: true, |
|
| 20 | + | })); |
|
| 21 | + | app.use("/subscribe/*", cors({ |
|
| 22 | + | origin: (origin) => origin, |
|
| 23 | + | credentials: true, |
|
| 24 | + | })); |
|
| 15 | 25 | ||
| 16 | 26 | app.get("/api/health", (c) => { |
|
| 17 | 27 | return c.json({ status: "ok" }); |
|
| 19 | 19 | redirect_uris: [redirectUri], |
|
| 20 | 20 | grant_types: ["authorization_code", "refresh_token"], |
|
| 21 | 21 | response_types: ["code"], |
|
| 22 | - | scope: "atproto transition:generic", |
|
| 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, |
| 1 | + | // Cloudflare Workers compatibility patches for @atproto libraries. |
|
| 2 | + | // |
|
| 3 | + | // 1. Workers don't support `redirect: 'error'` — simulate it with 'manual'. |
|
| 4 | + | // 2. Workers don't support the standard `cache` option in Request — strip it. |
|
| 5 | + | ||
| 6 | + | function sanitizeInit(init?: RequestInit): RequestInit | undefined { |
|
| 7 | + | if (!init) return init; |
|
| 8 | + | const { cache, redirect, ...rest } = init; |
|
| 9 | + | return { |
|
| 10 | + | ...rest, |
|
| 11 | + | // Workers only support 'follow' and 'manual' |
|
| 12 | + | redirect: redirect === "error" ? "manual" : redirect, |
|
| 13 | + | // Workers don't support standard cache modes — omit entirely |
|
| 14 | + | ...(cache ? {} : {}), |
|
| 15 | + | }; |
|
| 16 | + | } |
|
| 17 | + | ||
| 18 | + | const errorRedirectRequests = new WeakSet<Request>(); |
|
| 19 | + | const OriginalRequest = globalThis.Request; |
|
| 20 | + | ||
| 21 | + | globalThis.Request = class extends OriginalRequest { |
|
| 22 | + | constructor( |
|
| 23 | + | input: RequestInfo | URL, |
|
| 24 | + | init?: RequestInit, |
|
| 25 | + | ) { |
|
| 26 | + | super(input, sanitizeInit(init)); |
|
| 27 | + | if (init?.redirect === "error") { |
|
| 28 | + | errorRedirectRequests.add(this); |
|
| 29 | + | } |
|
| 30 | + | } |
|
| 31 | + | } as typeof Request; |
|
| 32 | + | ||
| 33 | + | const originalFetch = globalThis.fetch; |
|
| 34 | + | globalThis.fetch = (async ( |
|
| 35 | + | input: RequestInfo | URL, |
|
| 36 | + | init?: RequestInit, |
|
| 37 | + | ): Promise<Response> => { |
|
| 38 | + | const cleanInit = sanitizeInit(init); |
|
| 39 | + | const response = await originalFetch(input, cleanInit); |
|
| 40 | + | ||
| 41 | + | // Simulate redirect: 'error' — throw on 3xx |
|
| 42 | + | const wantsRedirectError = |
|
| 43 | + | init?.redirect === "error" || |
|
| 44 | + | (input instanceof Request && errorRedirectRequests.has(input)); |
|
| 45 | + | ||
| 46 | + | if (wantsRedirectError && response.status >= 300 && response.status < 400) { |
|
| 47 | + | throw new TypeError("unexpected redirect"); |
|
| 48 | + | } |
|
| 49 | + | ||
| 50 | + | return response; |
|
| 51 | + | }) as typeof fetch; |
| 27 | 27 | redirect_uris: [redirectUri], |
|
| 28 | 28 | grant_types: ["authorization_code", "refresh_token"], |
|
| 29 | 29 | response_types: ["code"], |
|
| 30 | - | scope: "atproto transition:generic", |
|
| 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 | - | scope: "atproto transition:generic", |
|
| 47 | + | scope: "atproto site.standard.graph.subscription", |
|
| 48 | 48 | }); |
|
| 49 | 49 | ||
| 50 | 50 | return c.redirect(authUrl.toString()); |
|