UNPKG

kitcn

Version:

kitcn - React Query integration and CLI tools for Convex

127 lines (125 loc) 4.29 kB
import { t as getToken } from "../../token-oA2EMtPA.js"; import { stripIndent } from "common-tags"; import { ConvexHttpClient } from "convex/browser"; import React from "react"; //#region src/auth-start/index.ts const fallbackCache = (fn) => fn; const cache = React.cache ?? fallbackCache; const TANSTACK_REACT_START_SERVER = "@tanstack/react-start/server"; const TRAILING_COLON_RE = /:$/; function setupClient(options) { const client = new ConvexHttpClient(options.convexUrl); if (options.token !== void 0) client.setAuth(options.token); client.setFetchOptions?.({ cache: "no-store" }); return client; } const parseConvexSiteUrl = (url) => { if (!url) throw new Error(stripIndent` CONVEX_SITE_URL is not set. This is automatically set in the Convex backend, but must be set in the TanStack Start environment. For local development, this can be set in the .env.local file. `); if (url.endsWith(".convex.cloud")) throw new Error(stripIndent` CONVEX_SITE_URL should be set to your Convex Site URL, which ends in .convex.site. Currently set to ${url}. `); return url; }; const appendSetCookieHeaders = (target, source) => { const getSetCookie = source.getSetCookie; if (typeof getSetCookie === "function") { const values = getSetCookie.call(source); for (const value of values) target.append("set-cookie", value); return; } const value = source.get("set-cookie"); if (value) target.append("set-cookie", value); }; const cloneAuthHandlerResponse = (response) => { const headers = new Headers(); for (const [key, value] of response.headers.entries()) { if (key.toLowerCase() === "set-cookie") continue; headers.append(key, value); } appendSetCookieHeaders(headers, response.headers); return new Response(response.body, { headers, status: response.status, statusText: response.statusText }); }; const handler = (request, opts) => { const requestUrl = new URL(request.url); const nextUrl = `${opts.convexSiteUrl}${requestUrl.pathname}${requestUrl.search}`; const headers = new Headers(request.headers); const proto = requestUrl.protocol.replace(TRAILING_COLON_RE, ""); headers.set("accept-encoding", "application/json"); headers.set("host", new URL(opts.convexSiteUrl).host); headers.set("x-forwarded-host", requestUrl.host); headers.set("x-forwarded-proto", proto); headers.set("x-better-auth-forwarded-host", requestUrl.host); headers.set("x-better-auth-forwarded-proto", proto); return fetch(nextUrl, { body: request.method !== "GET" && request.method !== "HEAD" ? request.body : void 0, duplex: "half", headers, method: request.method, redirect: "manual" }); }; const convexBetterAuthReactStart = (opts) => { const siteUrl = parseConvexSiteUrl(opts.convexSiteUrl); const cachedGetToken = cache(async (opts) => { const { getRequestHeaders } = await import(TANSTACK_REACT_START_SERVER); const headers = getRequestHeaders(); const mutableHeaders = new Headers(headers); mutableHeaders.delete("content-length"); mutableHeaders.delete("transfer-encoding"); mutableHeaders.set("accept-encoding", "identity"); return getToken(siteUrl, mutableHeaders, opts); }); const callWithToken = async (fn) => { const token = await cachedGetToken(opts) ?? {}; try { return await fn(token?.token); } catch (error) { if (!opts?.jwtCache?.enabled || token.isFresh || !opts.jwtCache?.isAuthError(error)) throw error; return await fn((await cachedGetToken({ ...opts, forceRefresh: true })).token); } }; return { getToken: async () => { return (await cachedGetToken(opts)).token; }, handler: async (request) => cloneAuthHandlerResponse(await handler(request, opts)), fetchAuthQuery: async (query, ...args) => { return callWithToken((token) => { return setupClient({ ...opts, token }).query(query, ...args); }); }, fetchAuthMutation: async (mutation, ...args) => { return callWithToken((token) => { return setupClient({ ...opts, token }).mutation(mutation, ...args); }); }, fetchAuthAction: async (action, ...args) => { return callWithToken((token) => { return setupClient({ ...opts, token }).action(action, ...args); }); } }; }; //#endregion export { convexBetterAuthReactStart };