UNPKG

@trpc/server

Version:

The tRPC server library

165 lines (163 loc) • 6.77 kB
import { r as _defineProperty } from "../getErrorShape-B5jPKHJ3.mjs"; import { C as getTRPCErrorFromUnknown, x as TRPCError } from "../asyncGeneratorDelegate-JWx0LJUD.mjs"; import { formDataToObject } from "../unstable-core-do-not-import.mjs"; import * as nextNavigation from "next/navigation"; //#region src/adapters/next-app-dir/redirect.ts /** * The error `redirect()` returns, which `nextAppDirCaller` turns into a * Next.js redirect. * @internal */ var TRPCRedirectError = class extends TRPCError { constructor(url, redirectType) { super({ code: "UNPROCESSABLE_CONTENT", message: `Redirect error to "${url}" that will be handled by Next.js` }); _defineProperty(this, "args", void 0); this.args = [url.toString(), redirectType]; } }; /** * Like `redirect()` from `next/navigation`, for procedures called through * `nextAppDirCaller`. Return it from a resolver; the caller then * redirects. Its type is `undefined`, which matches what the client gets, * unlike Next.js's `never`. * @public */ const redirect = (url, redirectType) => { return new TRPCRedirectError(url, redirectType); }; //#endregion //#region src/adapters/next-app-dir/rethrowNextErrors.ts /** * @remarks The helpers from `next/dist/client/components/*` has been removed in Next.js 15. * Inlining them here instead... * @see https://github.com/vercel/next.js/blob/5ae286ffd664e5c76841ed64f6e2da85a0835922/packages/next/src/client/components/redirect.ts#L97-L123 */ const REDIRECT_ERROR_CODE = "NEXT_REDIRECT"; function isRedirectError(error) { if (typeof error !== "object" || error === null || !("digest" in error) || typeof error.digest !== "string") return false; const [errorCode, type, destination, status] = error.digest.split(";", 4); const statusCode = Number(status); return errorCode === REDIRECT_ERROR_CODE && (type === "replace" || type === "push") && typeof destination === "string" && !isNaN(statusCode); } /** * @remarks The helpers from `next/dist/client/components/*` has been removed in Next.js 15. * Inlining them here instead... * @see https://github.com/vercel/next.js/blob/5ae286ffd664e5c76841ed64f6e2da85a0835922/packages/next/src/client/components/not-found.ts#L33-L39 */ const NOT_FOUND_ERROR_CODE = "NEXT_NOT_FOUND"; function isNotFoundError(error) { if (typeof error !== "object" || error === null || !("digest" in error)) return false; return error.digest === NOT_FOUND_ERROR_CODE; } /** * Turns a caught `TRPCError` into the Next.js control-flow error it stands * for: a `NOT_FOUND` code calls `notFound()`, a `TRPCRedirectError` calls * `redirect()`, and a `notFound()` or `redirect()` error in `cause` is * rethrown. It only takes a `TRPCError`; rethrow Next.js's own errors, such * as those `nextAppDirCaller` throws, yourself. */ const rethrowNextErrors = (error) => { if (error.code === "NOT_FOUND") nextNavigation.notFound(); if (error instanceof TRPCRedirectError) nextNavigation.redirect(...error.args); const { cause } = error; if ("unstable_rethrow" in nextNavigation && typeof nextNavigation.unstable_rethrow === "function") nextNavigation.unstable_rethrow(cause); if (isRedirectError(cause) || isNotFoundError(cause)) throw cause; }; //#endregion //#region src/adapters/next-app-dir/nextAppDirCaller.ts /** * Makes procedures callable as Next.js server actions and from React * Server Components. Pass it to `.experimental_caller()`. * @see https://trpc.io/docs/client/nextjs/server-actions#1-define-a-base-procedure-with-experimental_caller */ function nextAppDirCaller(config) { const { normalizeFormData = true } = config; const createContext = async () => { var _config$createContext, _config$createContext2; return (_config$createContext = config === null || config === void 0 || (_config$createContext2 = config.createContext) === null || _config$createContext2 === void 0 ? void 0 : _config$createContext2.call(config)) !== null && _config$createContext !== void 0 ? _config$createContext : {}; }; return async (opts) => { var _config$pathExtractor, _config$pathExtractor2; const path = (_config$pathExtractor = (_config$pathExtractor2 = config.pathExtractor) === null || _config$pathExtractor2 === void 0 ? void 0 : _config$pathExtractor2.call(config, { meta: opts._def.meta })) !== null && _config$pathExtractor !== void 0 ? _config$pathExtractor : ""; const ctx = await createContext().catch((cause) => { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Failed to create context", cause }); }); const handleError = (cause) => { var _config$onError; const error = getTRPCErrorFromUnknown(cause); (_config$onError = config.onError) === null || _config$onError === void 0 || _config$onError.call(config, { ctx, error, input: opts.args[0], path, type: opts._def.type }); rethrowNextErrors(error); throw error; }; switch (opts._def.type) { case "mutation": { /** * When you wrap an action with useFormState, it gets an extra argument as its first argument. * The submitted form data is therefore its second argument instead of its first as it would usually be. * The new first argument that gets added is the current state of the form. * @see https://react.dev/reference/react-dom/hooks/useFormState#my-action-can-no-longer-read-the-submitted-form-data */ let input = opts.args.length === 1 ? opts.args[0] : opts.args[1]; if (normalizeFormData && input instanceof FormData) input = formDataToObject(input); return await opts.invoke({ type: opts._def.type, ctx, getRawInput: async () => input, path, input, signal: void 0, batchIndex: 0 }).then((data) => { if (data instanceof TRPCRedirectError) throw data; return data; }).catch(handleError); } case "query": { const input = opts.args[0]; return await opts.invoke({ type: opts._def.type, ctx, getRawInput: async () => input, path, input, signal: void 0, batchIndex: 0 }).then((data) => { if (data instanceof TRPCRedirectError) throw data; return data; }).catch(handleError); } default: throw new TRPCError({ code: "NOT_IMPLEMENTED", message: `Not implemented for type ${opts._def.type}` }); } }; } //#endregion //#region src/adapters/next-app-dir/notFound.ts /** * Like `notFound()` from `next/navigation`, but throws a `NOT_FOUND` * `TRPCError`, which `nextAppDirCaller` turns into Next.js's not-found * page. * @public */ const notFound = () => { throw new TRPCError({ code: "NOT_FOUND" }); }; //#endregion export { nextAppDirCaller as experimental_nextAppDirCaller, notFound as experimental_notFound, redirect as experimental_redirect, rethrowNextErrors }; //# sourceMappingURL=next-app-dir.mjs.map