@tanstack/solid-start
Version:
Modern and scalable routing for Solid applications
126 lines (125 loc) • 5.48 kB
JavaScript
import { getSolidStartServerFunctionCodec } from "./solid-rpc-codec.js";
import { collectSolidStartFlightData } from "./solid-rpc-flight-server.js";
import { redirect } from "@tanstack/solid-router";
import { FUNCTION_HEADER, configureServerFunctionsServer, createNoJSHandler, handleServerFunctionRequest } from "@solidjs/web/server-functions/server";
import { getServerFnById } from "#tanstack-start-server-fn-resolver";
import { provideRequestEvent } from "@solidjs/web/storage";
import { getStartContext, runWithStartContext } from "@tanstack/start-storage-context";
//#region src/server-functions-handler.ts
configureServerFunctionsServer({ provideEvent: provideRequestEvent });
var solidNoJSHandler = createNoJSHandler();
async function handleSolidServerFunctionRequest(request, options = {}) {
const serverFnId = getSolidServerFunctionId(request);
if (!serverFnId) throw new Error("Unable to resolve Solid server function id from request");
await getServerFnById(serverFnId, { origin: "client" });
const requestWithId = withSolidServerFunctionId(request, serverFnId);
const { startContext, ...solidOptions } = options;
const transformResult = solidOptions.transformResult;
const handleNoJS = solidOptions.handleNoJS;
const collectFlightData = solidOptions.collectFlightData;
const existingStartContext = getStartContext({ throwIfNotFound: false });
const handlerOptions = {
...solidOptions,
collectFlightData: collectFlightData ?? collectSolidStartFlightData,
transformResult: async (event, result, context) => {
return adaptTanStackResult(transformResult ? await transformResult(event, result, context) : result);
},
handleNoJS: async (result, currentRequest, args, thrown) => {
if (handleNoJS) return await handleNoJS(result, currentRequest, args, thrown);
return await handleSolidStartNoJS(result, currentRequest, args, thrown);
}
};
const handleRequest = () => handleServerFunctionRequest(requestWithId, {
codec: getSolidStartServerFunctionCodec(),
...handlerOptions
});
if (existingStartContext) return await handleRequest();
return await runWithStartContext({
getRouter: unavailableRouter,
request,
startOptions: {},
contextAfterGlobalMiddlewares: {},
executedRequestMiddlewares: /* @__PURE__ */ new Set(),
handlerType: "serverFn",
...startContext
}, handleRequest);
}
function getSolidServerFunctionId(request) {
const headerId = request.headers.get(FUNCTION_HEADER);
if (headerId) return headerId;
const url = new URL(request.url);
const queryId = url.searchParams.get("id");
if (queryId) return queryId;
const serverFnBase = process.env.TSS_SERVER_FN_BASE;
if (serverFnBase && url.pathname.startsWith(serverFnBase)) return url.pathname.slice(serverFnBase.length).split("/")[0];
}
function withSolidServerFunctionId(request, serverFnId) {
if (request.headers.has(FUNCTION_HEADER)) return request;
try {
request.headers.set(FUNCTION_HEADER, serverFnId);
return request;
} catch {
const clonedRequest = request.clone();
clonedRequest.headers.set(FUNCTION_HEADER, serverFnId);
return clonedRequest;
}
}
function serializeTanStackRedirect(result) {
if (!isObject(result) || !isTanStackRedirect(result.error)) return result;
const redirectResponse = result.error;
return {
...result,
error: {
...redirectResponse.options,
headers: Object.fromEntries(redirectResponse.headers),
isSerializedRedirect: true
}
};
}
function adaptTanStackResult(result) {
const serialized = serializeTanStackRedirect(result);
if (!isTanStackResultEnvelope(serialized)) return serialized;
return Object.fromEntries(Object.entries(serialized).filter(([, value]) => value !== void 0));
}
async function handleSolidStartNoJS(result, request, args, thrown) {
if (isObject(result) && isSerializedRedirect(result.error)) {
const startContext = getStartContext({ throwIfNotFound: false });
if (startContext) return (await startContext.getRouter()).resolveRedirect(redirect(result.error));
}
if (isObject(result)) {
const unwrapped = result.result ?? result.error;
if (isResponseLike(unwrapped)) return normalizeResponse(unwrapped);
if (typeof unwrapped === "string") return new Response(unwrapped);
if (unwrapped !== void 0) return Response.json(unwrapped);
}
return solidNoJSHandler(result, request, args, thrown);
}
function isTanStackRedirect(value) {
return isResponseLike(value) && isObject(value.options);
}
function isTanStackResultEnvelope(value) {
return isObject(value) && ("result" in value || "error" in value || "context" in value);
}
function isResponseLike(value) {
return isObject(value) && typeof value.status === "number" && isObject(value.headers) && typeof value.headers.forEach === "function" && ("body" in value || typeof value.text === "function");
}
function normalizeResponse(response) {
if (response instanceof Response) return response;
return new Response(response.body, {
headers: response.headers,
status: response.status,
statusText: response.statusText
});
}
function isSerializedRedirect(value) {
return isObject(value) && value.isSerializedRedirect === true;
}
function isObject(value) {
return !!value && typeof value === "object";
}
function unavailableRouter() {
throw new Error("Router context is not available in handleSolidServerFunctionRequest. Use it inside createStartHandler or pass startContext.getRouter.");
}
//#endregion
export { handleSolidServerFunctionRequest };
//# sourceMappingURL=server-functions-handler.js.map