UNPKG

@fedify/next

Version:

Integrate Fedify with Next.js

121 lines (118 loc) 4.62 kB
//#region rolldown:runtime var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); //#endregion const next_navigation = __toESM(require("next/navigation")); const next_server = __toESM(require("next/server")); //#region src/index.ts /** * Wrapper function for Next.js middleware to integrate with the * {@link Federation} object. * * @template TContextData A type of the context data for the * {@link Federation} object. * @param federation A {@link Federation} object to integrate with Next.js. * @param contextDataFactory A function to create a context data for the * {@link Federation} object. * @param errorHandlers A set of error handlers to handle errors during * the federation fetch. * @returns A Next.js middleware function to integrate with the * {@link Federation} object. * * @example * ```ts ignore * import { fedifyWith } from "@fedify/next"; * import { federation } from "./federation"; * * export default fedifyWith(federation)( * function (request: Request) { * // You can add custom logic here for other requests * // except federation requests. If there is no custom logic, * // you can omit this function. * } * ) * * // This config makes middleware process only requests with the * // "Accept" header matching the federation accept regex. * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional. * export const config = { * runtime: "nodejs", * matcher: [{ * source: "/:path*", * has: [ * { * type: "header", * key: "Accept", * value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*", * }, * ], * }], * }; * ``` */ const fedifyWith = (federation, contextDataFactory, errorHandlers) => (middleware = (_) => next_server.NextResponse.next()) => async (request) => { if (hasFederationAcceptHeader(request)) return await integrateFederation(federation, contextDataFactory, errorHandlers)(request); return await middleware(request); }; /** * Check if the request has the "Accept" header matching the federation * accept regex. * * @param request The request to check. * @returns `true` if the request has the "Accept" header matching * the federation accept regex, `false` otherwise. */ const hasFederationAcceptHeader = (request) => { const acceptHeader = request.headers.get("Accept"); return acceptHeader ? FEDERATION_ACCEPT_REGEX.test(acceptHeader) : false; }; const FEDERATION_ACCEPT_REGEX = /.*application\/((jrd|activity|ld)\+json|xrd\+xml).*/; /** * Create a Next.js handler to integrate with the {@link Federation} object. * * @template TContextData A type of the context data for the * {@link Federation} object. * @param federation A {@link Federation} object to integrate with Next.js. * @param contextDataFactory A function to create a context data for the * {@link Federation} object. * @param errorHandlers A set of error handlers to handle errors during * the federation fetch. * @returns A Next.js handler. */ function integrateFederation(federation, contextDataFactory = () => void 0, errorHandlers) { return async (request) => await federation.fetch(request, { contextData: await contextDataFactory(request), onNotFound: next_navigation.notFound, onNotAcceptable, ...errorHandlers }); } const onNotAcceptable = () => new Response("Not acceptable", { status: 406, headers: { "Content-Type": "text/plain", Vary: "Accept" } }); //#endregion exports.fedifyWith = fedifyWith; exports.hasFederationAcceptHeader = hasFederationAcceptHeader; exports.integrateFederation = integrateFederation;