better-auth
Version:
The most comprehensive authentication framework for TypeScript.
59 lines (58 loc) • 2.79 kB
JavaScript
import { isDynamicBaseURLConfig, isRequestLike } from "../utils/url.mjs";
import { pickSource, resolveDynamicTrustedProxyHeaders, resolveRequestContext } from "../context/helpers.mjs";
import { dispatchAuthEndpoint, getOperationId } from "./dispatch.mjs";
import { hasRequestState, runWithRequestState } from "@better-auth/core/context";
import { APIError, BetterAuthError } from "@better-auth/core/error";
//#region src/api/to-auth-endpoints.ts
/**
* Resolves the per-call `AuthContext` for endpoints with a dynamic `baseURL`.
*
* - `rawCtx.baseURL` already set: HTTP handler rehydrated upstream; return as-is.
* - Direct `auth.api` call with a source or a configured `fallback`: resolve here.
* - Neither: throw `APIError` with a helpful message. Leaving `baseURL = ""`
* would let plugins build `new URL("")` and crash cryptically downstream.
*/
async function resolveDynamicContext(rawCtx, input) {
if (rawCtx.baseURL) return rawCtx;
const source = pickSource(input);
const config = rawCtx.options.baseURL;
const hasFallback = isDynamicBaseURLConfig(config) && Boolean(config.fallback);
if (source === void 0 && !hasFallback) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Dynamic baseURL could not be resolved for this direct auth.api call. Pass `headers: request.headers` (or `request`) to the call, or add `fallback` to your baseURL config." });
try {
return await resolveRequestContext(rawCtx, source, resolveDynamicTrustedProxyHeaders(rawCtx.options));
} catch (err) {
if (err instanceof BetterAuthError) throw new APIError("INTERNAL_SERVER_ERROR", { message: err.message });
throw err;
}
}
/**
* Wraps each raw endpoint so a router or `auth.api.*` call runs it through the
* configured hook pipeline. Per-call work that is specific to this entry point
* (dynamic `baseURL` resolution, request-state initialization) happens here;
* the hook pipeline itself lives in {@link dispatchAuthEndpoint}.
*/
function toAuthEndpoints(endpoints, ctx) {
const api = {};
for (const [key, endpoint] of Object.entries(endpoints)) {
api[key] = async (context) => {
const operationId = getOperationId(endpoint, key);
const run = async () => {
const rawContext = await ctx;
const authContext = isDynamicBaseURLConfig(rawContext.options.baseURL) ? await resolveDynamicContext(rawContext, context) : rawContext;
return dispatchAuthEndpoint(endpoint, {
...context,
context: authContext,
operationId,
asResponse: context?.asResponse ?? isRequestLike(context?.request)
});
};
if (await hasRequestState()) return run();
return runWithRequestState(/* @__PURE__ */ new WeakMap(), run);
};
api[key].path = endpoint.path;
api[key].options = endpoint.options;
}
return api;
}
//#endregion
export { toAuthEndpoints };