diff --git a/src/app.d.ts b/src/app.d.ts index 031435aaa..651f4f7c7 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -9,7 +9,12 @@ declare global { // interface Error {} // interface PageData {} // interface PageState {} - // interface Platform {} + interface Platform { + env: { + /** Secrets Store binding in deployed Workers; a plain string in local dev and prerender. */ + SERVER_API_TOKEN?: string | { get(): Promise }; + }; + } namespace Superforms { type Message = { type: "error" | "success"; text: string }; } diff --git a/src/lib/shared/api/mutator/custom-instance.ts b/src/lib/shared/api/mutator/custom-instance.ts index 1ce916c86..a3e76ed6e 100644 --- a/src/lib/shared/api/mutator/custom-instance.ts +++ b/src/lib/shared/api/mutator/custom-instance.ts @@ -3,7 +3,6 @@ import { env as envPrivate } from "$env/dynamic/private"; import { env as envPublic } from "$env/dynamic/public"; const { PUBLIC_SERVER_API_URL } = envPublic; -const { SERVER_API_TOKEN } = envPrivate; // NOTE: Supports cases where `content-type` is other than `json` const getBody = (c: Response | Request): Promise => { @@ -25,50 +24,32 @@ const getUrl = (contextUrl: string): string => { return requestUrl.toString(); }; -// NOTE: Add headers -const getHeaders = (headers?: HeadersInit): HeadersInit => { +// NOTE: Returns null when called outside of a request (e.g. at build time) +const tryGetRequestEvent = () => { try { - const { request } = getRequestEvent(); - - // Convert the request Headers object to a plain object - const requestHeadersObj: Record = {}; - request.headers.forEach((value, key) => { - requestHeadersObj[key] = value; - }); - - const mergedHeaders: HeadersInit = { - ...requestHeadersObj, - ...headers, - "X-API-Token": SERVER_API_TOKEN - }; - - return mergedHeaders; + return getRequestEvent(); } catch { - return { - ...headers, - "X-API-Token": SERVER_API_TOKEN - }; + return null; } }; export const customFetch = async (url: string, options: RequestInit): Promise => { - let fetchFunction = fetch; - try { - const event = getRequestEvent(); - fetchFunction = event.fetch; - } catch { - // Ignore this, we just won't have access to the request for this call - } + const event = tryGetRequestEvent(); - const requestUrl = getUrl(url); - const requestHeaders = getHeaders(options.headers); + // Deployed Workers get a Secrets Store binding; local dev and prerender get a plain string + const token = event?.platform?.env.SERVER_API_TOKEN ?? envPrivate.SERVER_API_TOKEN; + const serverApiToken = typeof token === "string" ? token : await token.get(); const requestInit: RequestInit = { ...options, - headers: requestHeaders + headers: { + ...(event ? Object.fromEntries(event.request.headers) : {}), + ...options.headers, + "X-API-Token": serverApiToken + } }; - const response = await fetchFunction(requestUrl, requestInit); + const response = await (event?.fetch ?? fetch)(getUrl(url), requestInit); const data = await getBody(response); return { status: response.status, data, headers: response.headers } as T; diff --git a/wrangler.jsonc b/wrangler.jsonc index 6e6f49c6f..3939b1eaf 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -47,7 +47,14 @@ "vars": { "PUBLIC_SERVER_API_URL": "https://sky.shiiyu.moe/api/", "PUBLIC_API_URL": "https://sky.shiiyu.moe/api/" - } + }, + "secrets_store_secrets": [ + { + "binding": "SERVER_API_TOKEN", + "store_id": "1a9462229b034bc78858f53bc58fb477", + "secret_name": "skycrypt-server-api-key" + } + ] }, "development": { "name": "skycrypt-embed", @@ -60,7 +67,14 @@ "vars": { "PUBLIC_SERVER_API_URL": "https://sky.shiiyu.moe/api/", "PUBLIC_API_URL": "https://sky.shiiyu.moe/api/" - } + }, + "secrets_store_secrets": [ + { + "binding": "SERVER_API_TOKEN", + "store_id": "739b83a68daf486ea3ec077b812048b4", + "secret_name": "skycrypt-server-api-key" + } + ] } } }