@@ -27,7 +27,7 @@ This package provides a simple way to integrate [Fedify] with [Next.js].
27
27
Usage
28
28
-----
29
29
30
- ~~~~ typescript
30
+ ~~~~ typescript ignore
31
31
// --- middleware.ts ---
32
32
import { fedifyWith } from " @fedify/next" ;
33
33
import { federation } from " ./federation" ;
@@ -63,164 +63,3 @@ export const config = {
63
63
],
64
64
};
65
65
~~~~
66
-
67
- The integration code looks like this:
68
-
69
- ~~~~ typescript
70
- /**
71
- * Fedify with Next.js
72
- * ===================
73
- *
74
- * This module provides a [Next.js] middleware to integrate with the Fedify.
75
- *
76
- * [Next.js]: https://nextjs.org/
77
- *
78
- * @module
79
- * @since 1.9.0
80
- */
81
- import type { Federation , FederationFetchOptions } from " @fedify/fedify" ;
82
- import { notFound } from " next/navigation" ;
83
- import { NextResponse } from " next/server" ;
84
- import { getXForwardedRequest } from " x-forwarded-fetch" ;
85
-
86
- interface ContextDataFactory <TContextData > {
87
- (request : Request ):
88
- | TContextData
89
- | Promise < TContextData > ;
90
- }
91
- type ErrorHandlers = Omit <FederationFetchOptions <unknown >, " contextData" >;
92
-
93
- /**
94
- * Wrapper function for Next.js middleware to integrate with the
95
- * {@link Federation } object.
96
- *
97
- * @template TContextData A type of the context data for the
98
- * {@link Federation } object.
99
- * @param federation A {@link Federation } object to integrate with Next.js.
100
- * @param contextDataFactory A function to create a context data for the
101
- * {@link Federation } object.
102
- * @param errorHandlers A set of error handlers to handle errors during
103
- * the federation fetch.
104
- * @returns A Next.js middleware function to integrate with the
105
- * {@link Federation } object.
106
- *
107
- * @example
108
- * ```ts
109
- * import { fedifyWith } from "@fedify/next";
110
- * import { federation } from "./federation";
111
- *
112
- * export default fedifyWith(federation)(
113
- * function (request: Request) {
114
- * // You can add custom logic here for other requests
115
- * // except federation requests. If there is no custom logic,
116
- * // you can omit this function.
117
- * }
118
- * )
119
- *
120
- * // This config makes middleware process only requests with the
121
- * // "Accept" header matching the federation accept regex.
122
- * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional.
123
- * export const config = {
124
- * runtime: "nodejs",
125
- * matcher: [
126
- * {
127
- * source: "/:path*",
128
- * has: [
129
- * {
130
- * type: "header",
131
- * key: "Accept",
132
- * value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
133
- * },
134
- * ],
135
- * },
136
- * {
137
- * source: "/:path*",
138
- * has: [
139
- * {
140
- * type: "header",
141
- * key: "content-type",
142
- * value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
143
- * },
144
- * ],
145
- * },
146
- * { source: "/.well-known/nodeinfo" },
147
- * { source: "/.well-known/x-nodeinfo2" },
148
- * ],
149
- * };
150
- * ```
151
- */
152
- export const fedifyWith = <TContextData >(
153
- federation : Federation <TContextData >,
154
- contextDataFactory ? : ContextDataFactory <TContextData >,
155
- errorHandlers ? : Partial <ErrorHandlers >,
156
- ) =>
157
- (
158
- middleware : (request : Request ) => unknown =
159
- ((_ : Request ) => NextResponse .next ()),
160
- ): (request : Request ) => unknown =>
161
- async (request : Request ) => {
162
- if (hasFederationAcceptHeader (request )) {
163
- return await integrateFederation (
164
- federation ,
165
- contextDataFactory ,
166
- errorHandlers ,
167
- )(request );
168
- }
169
- return await middleware (request );
170
- };
171
-
172
- /**
173
- * Check if the request has the "Accept" header matching the federation
174
- * accept regex.
175
- *
176
- * @param {Request} request The request to check.
177
- * @returns {boolean} `true` if the request has the "Accept" header matching
178
- * the federation accept regex, `false` otherwise.
179
- */
180
- export const hasFederationAcceptHeader = (request : Request ): boolean => {
181
- const acceptHeader = request .headers .get (" Accept" );
182
- // Check if the Accept header matches the federation accept regex.
183
- // If the header is not present, return false.
184
- return acceptHeader ? FEDERATION_ACCEPT_REGEX .test (acceptHeader ) : false ;
185
- };
186
- const FEDERATION_ACCEPT_REGEX =
187
- / . * application\/ ((jrd| activity| ld)\+ json| xrd\+ xml). * / ;
188
-
189
- /**
190
- * Create a Next.js handler to integrate with the {@link Federation } object.
191
- *
192
- * @template TContextData A type of the context data for the
193
- * {@link Federation } object.
194
- * @param federation A {@link Federation } object to integrate with Next.js.
195
- * @param contextDataFactory A function to create a context data for the
196
- * {@link Federation } object.
197
- * @param errorHandlers A set of error handlers to handle errors during
198
- * the federation fetch.
199
- * @returns A Next.js handler.
200
- */
201
- export function integrateFederation<TContextData >(
202
- federation : Federation <TContextData >,
203
- contextDataFactory : ContextDataFactory <TContextData > = () =>
204
- undefined as TContextData ,
205
- errorHandlers ? : Partial <ErrorHandlers >,
206
- ) {
207
- return async (request : Request ) => {
208
- const forwardedRequest = await getXForwardedRequest (request );
209
- const contextData = await contextDataFactory (forwardedRequest );
210
- return await federation .fetch (
211
- forwardedRequest ,
212
- {
213
- contextData ,
214
- onNotFound: notFound ,
215
- onNotAcceptable ,
216
- ... errorHandlers ,
217
- },
218
- );
219
- };
220
- }
221
- const onNotAcceptable = () =>
222
- new Response (" Not acceptable" , {
223
- status: 406 ,
224
- headers: { " Content-Type" : " text/plain" , Vary: " Accept" },
225
- });
226
- ~~~~
0 commit comments