@fedify/next 2.4.0-pr.936.41 → 2.5.0-dev.2271

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -63,6 +63,9 @@ export const config = {
63
63
  },
64
64
  { source: "/.well-known/nodeinfo" },
65
65
  { source: "/.well-known/x-nodeinfo2" },
66
+ // FEP-ef61 gateway requests such as hashlink media, which clients fetch
67
+ // without the federation media types, e.g., with "Accept: image/*":
68
+ { source: "/.well-known/apgateway/:path*" },
66
69
  ],
67
70
  };
68
71
  ~~~~
package/dist/index.cjs CHANGED
@@ -28,8 +28,12 @@ let next_server_js = require("next/server.js");
28
28
  * }
29
29
  * )
30
30
  *
31
- * // This config makes middleware process only requests with the
32
- * // "Accept" header matching the federation accept regex.
31
+ * // This config makes the middleware run only for requests that may be
32
+ * // federation requests: requests whose "Accept" or "Content-Type" header
33
+ * // has a federation media type, NodeInfo requests, and FEP-ef61 gateway
34
+ * // requests such as hashlink media, which clients fetch with, e.g.,
35
+ * // "Accept: image/*". fedifyWith() then decides which of them Fedify
36
+ * // handles.
33
37
  * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional.
34
38
  * export const config = {
35
39
  * runtime: "nodejs",
@@ -56,6 +60,7 @@ let next_server_js = require("next/server.js");
56
60
  * },
57
61
  * { source: "/.well-known/nodeinfo" },
58
62
  * { source: "/.well-known/x-nodeinfo2" },
63
+ * { source: "/.well-known/apgateway/:path*" },
59
64
  * ],
60
65
  * };
61
66
  * ```
@@ -64,10 +69,24 @@ const fedifyWith = (federation, contextDataFactory, errorHandlers) => (middlewar
64
69
  if (isFederationRequest(request)) return await integrateFederation(federation, contextDataFactory, errorHandlers)(request);
65
70
  return await middleware(request);
66
71
  };
72
+ /**
73
+ * Check if the request should be handled by the {@link Federation} object.
74
+ * A request is considered a federation request if any of the following
75
+ * conditions is met:
76
+ *
77
+ * - Its `Accept` or `Content-Type` header has an ActivityPub, JSON-LD, JRD,
78
+ * or XRD media type.
79
+ * - It is a NodeInfo request (see {@link isNodeInfoRequest}).
80
+ * - It is an FEP-ef61 hashlink media request
81
+ * (see {@link isHashlinkMediaRequest}).
82
+ * @param request The request to check.
83
+ * @returns `true` if the request is a federation request, `false` otherwise.
84
+ */
67
85
  const isFederationRequest = (request) => [
68
86
  hasFederationHeader("accept"),
69
87
  hasFederationHeader("content-type"),
70
- isNodeInfoRequest
88
+ isNodeInfoRequest,
89
+ isHashlinkMediaRequest
71
90
  ].some((f) => f(request));
72
91
  /**
73
92
  * Check if the request has the header matching the federation
@@ -86,6 +105,30 @@ const isNodeInfoRequest = (request) => {
86
105
  return NODEINFO_PATHS.some((path) => url.pathname.startsWith(path));
87
106
  };
88
107
  const NODEINFO_PATHS = ["/.well-known/nodeinfo", "/.well-known/x-nodeinfo2"];
108
+ /**
109
+ * Check if the request is an [FEP-ef61] gateway request for a resource
110
+ * addressed by a hashlink, e.g.,
111
+ * `GET /.well-known/apgateway/hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n`.
112
+ *
113
+ * Such requests need not carry a federation media type in their `Accept`
114
+ * header, as clients fetch media with, e.g., `Accept: image/*`, so they are
115
+ * recognized by their path alone. This only checks whether the path looks
116
+ * like a hashlink request; it does not check whether the hashlink is valid
117
+ * nor whether a hashlink media dispatcher is registered, which
118
+ * {@link Federation.fetch} takes care of.
119
+ *
120
+ * [FEP-ef61]: https://w3id.org/fep/ef61
121
+ * @param request The request to check.
122
+ * @returns `true` if the request is a hashlink media request,
123
+ * `false` otherwise.
124
+ * @since 2.4.0
125
+ */
126
+ const isHashlinkMediaRequest = (request) => {
127
+ const { pathname } = new URL(request.url);
128
+ return pathname.startsWith(GATEWAY_PATH_PREFIX) && HASHLINK_SCHEME_PATTERN.test(pathname.slice(GATEWAY_PATH_PREFIX.length));
129
+ };
130
+ const GATEWAY_PATH_PREFIX = "/.well-known/apgateway/";
131
+ const HASHLINK_SCHEME_PATTERN = /^hl(?::|%3A)/i;
89
132
  const FEDERATION_ACCEPT_REGEX = /.*application\/((jrd|activity|ld)\+json|xrd\+xml).*/;
90
133
  /**
91
134
  * Create a Next.js handler to integrate with the {@link Federation} object.
@@ -120,4 +163,5 @@ exports.fedifyWith = fedifyWith;
120
163
  exports.hasFederationHeader = hasFederationHeader;
121
164
  exports.integrateFederation = integrateFederation;
122
165
  exports.isFederationRequest = isFederationRequest;
166
+ exports.isHashlinkMediaRequest = isHashlinkMediaRequest;
123
167
  exports.isNodeInfoRequest = isNodeInfoRequest;
package/dist/index.d.cts CHANGED
@@ -32,8 +32,12 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
32
32
  * }
33
33
  * )
34
34
  *
35
- * // This config makes middleware process only requests with the
36
- * // "Accept" header matching the federation accept regex.
35
+ * // This config makes the middleware run only for requests that may be
36
+ * // federation requests: requests whose "Accept" or "Content-Type" header
37
+ * // has a federation media type, NodeInfo requests, and FEP-ef61 gateway
38
+ * // requests such as hashlink media, which clients fetch with, e.g.,
39
+ * // "Accept: image/*". fedifyWith() then decides which of them Fedify
40
+ * // handles.
37
41
  * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional.
38
42
  * export const config = {
39
43
  * runtime: "nodejs",
@@ -60,11 +64,25 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
60
64
  * },
61
65
  * { source: "/.well-known/nodeinfo" },
62
66
  * { source: "/.well-known/x-nodeinfo2" },
67
+ * { source: "/.well-known/apgateway/:path*" },
63
68
  * ],
64
69
  * };
65
70
  * ```
66
71
  */
67
72
  declare const fedifyWith: <TContextData>(federation: Federation<TContextData>, contextDataFactory?: ContextDataFactory<TContextData>, errorHandlers?: Partial<ErrorHandlers>) => (middleware?: (request: Request) => unknown) => (request: Request) => unknown;
73
+ /**
74
+ * Check if the request should be handled by the {@link Federation} object.
75
+ * A request is considered a federation request if any of the following
76
+ * conditions is met:
77
+ *
78
+ * - Its `Accept` or `Content-Type` header has an ActivityPub, JSON-LD, JRD,
79
+ * or XRD media type.
80
+ * - It is a NodeInfo request (see {@link isNodeInfoRequest}).
81
+ * - It is an FEP-ef61 hashlink media request
82
+ * (see {@link isHashlinkMediaRequest}).
83
+ * @param request The request to check.
84
+ * @returns `true` if the request is a federation request, `false` otherwise.
85
+ */
68
86
  declare const isFederationRequest: (request: Request) => boolean;
69
87
  /**
70
88
  * Check if the request has the header matching the federation
@@ -77,6 +95,25 @@ declare const isFederationRequest: (request: Request) => boolean;
77
95
  declare const hasFederationHeader: (key: string) => (request: Request) => boolean;
78
96
  declare const isNodeInfoRequest: (request: Request) => boolean;
79
97
  /**
98
+ * Check if the request is an [FEP-ef61] gateway request for a resource
99
+ * addressed by a hashlink, e.g.,
100
+ * `GET /.well-known/apgateway/hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n`.
101
+ *
102
+ * Such requests need not carry a federation media type in their `Accept`
103
+ * header, as clients fetch media with, e.g., `Accept: image/*`, so they are
104
+ * recognized by their path alone. This only checks whether the path looks
105
+ * like a hashlink request; it does not check whether the hashlink is valid
106
+ * nor whether a hashlink media dispatcher is registered, which
107
+ * {@link Federation.fetch} takes care of.
108
+ *
109
+ * [FEP-ef61]: https://w3id.org/fep/ef61
110
+ * @param request The request to check.
111
+ * @returns `true` if the request is a hashlink media request,
112
+ * `false` otherwise.
113
+ * @since 2.4.0
114
+ */
115
+ declare const isHashlinkMediaRequest: (request: Request) => boolean;
116
+ /**
80
117
  * Create a Next.js handler to integrate with the {@link Federation} object.
81
118
  *
82
119
  * @template TContextData A type of the context data for the
@@ -90,4 +127,4 @@ declare const isNodeInfoRequest: (request: Request) => boolean;
90
127
  */
91
128
  declare function integrateFederation<TContextData>(federation: Federation<TContextData>, contextDataFactory?: ContextDataFactory<TContextData>, errorHandlers?: Partial<ErrorHandlers>): (request: Request) => Promise<Response>;
92
129
  //#endregion
93
- export { fedifyWith, hasFederationHeader, integrateFederation, isFederationRequest, isNodeInfoRequest };
130
+ export { fedifyWith, hasFederationHeader, integrateFederation, isFederationRequest, isHashlinkMediaRequest, isNodeInfoRequest };
package/dist/index.d.ts CHANGED
@@ -32,8 +32,12 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
32
32
  * }
33
33
  * )
34
34
  *
35
- * // This config makes middleware process only requests with the
36
- * // "Accept" header matching the federation accept regex.
35
+ * // This config makes the middleware run only for requests that may be
36
+ * // federation requests: requests whose "Accept" or "Content-Type" header
37
+ * // has a federation media type, NodeInfo requests, and FEP-ef61 gateway
38
+ * // requests such as hashlink media, which clients fetch with, e.g.,
39
+ * // "Accept: image/*". fedifyWith() then decides which of them Fedify
40
+ * // handles.
37
41
  * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional.
38
42
  * export const config = {
39
43
  * runtime: "nodejs",
@@ -60,11 +64,25 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
60
64
  * },
61
65
  * { source: "/.well-known/nodeinfo" },
62
66
  * { source: "/.well-known/x-nodeinfo2" },
67
+ * { source: "/.well-known/apgateway/:path*" },
63
68
  * ],
64
69
  * };
65
70
  * ```
66
71
  */
67
72
  declare const fedifyWith: <TContextData>(federation: Federation<TContextData>, contextDataFactory?: ContextDataFactory<TContextData>, errorHandlers?: Partial<ErrorHandlers>) => (middleware?: (request: Request) => unknown) => (request: Request) => unknown;
73
+ /**
74
+ * Check if the request should be handled by the {@link Federation} object.
75
+ * A request is considered a federation request if any of the following
76
+ * conditions is met:
77
+ *
78
+ * - Its `Accept` or `Content-Type` header has an ActivityPub, JSON-LD, JRD,
79
+ * or XRD media type.
80
+ * - It is a NodeInfo request (see {@link isNodeInfoRequest}).
81
+ * - It is an FEP-ef61 hashlink media request
82
+ * (see {@link isHashlinkMediaRequest}).
83
+ * @param request The request to check.
84
+ * @returns `true` if the request is a federation request, `false` otherwise.
85
+ */
68
86
  declare const isFederationRequest: (request: Request) => boolean;
69
87
  /**
70
88
  * Check if the request has the header matching the federation
@@ -77,6 +95,25 @@ declare const isFederationRequest: (request: Request) => boolean;
77
95
  declare const hasFederationHeader: (key: string) => (request: Request) => boolean;
78
96
  declare const isNodeInfoRequest: (request: Request) => boolean;
79
97
  /**
98
+ * Check if the request is an [FEP-ef61] gateway request for a resource
99
+ * addressed by a hashlink, e.g.,
100
+ * `GET /.well-known/apgateway/hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n`.
101
+ *
102
+ * Such requests need not carry a federation media type in their `Accept`
103
+ * header, as clients fetch media with, e.g., `Accept: image/*`, so they are
104
+ * recognized by their path alone. This only checks whether the path looks
105
+ * like a hashlink request; it does not check whether the hashlink is valid
106
+ * nor whether a hashlink media dispatcher is registered, which
107
+ * {@link Federation.fetch} takes care of.
108
+ *
109
+ * [FEP-ef61]: https://w3id.org/fep/ef61
110
+ * @param request The request to check.
111
+ * @returns `true` if the request is a hashlink media request,
112
+ * `false` otherwise.
113
+ * @since 2.4.0
114
+ */
115
+ declare const isHashlinkMediaRequest: (request: Request) => boolean;
116
+ /**
80
117
  * Create a Next.js handler to integrate with the {@link Federation} object.
81
118
  *
82
119
  * @template TContextData A type of the context data for the
@@ -90,4 +127,4 @@ declare const isNodeInfoRequest: (request: Request) => boolean;
90
127
  */
91
128
  declare function integrateFederation<TContextData>(federation: Federation<TContextData>, contextDataFactory?: ContextDataFactory<TContextData>, errorHandlers?: Partial<ErrorHandlers>): (request: Request) => Promise<Response>;
92
129
  //#endregion
93
- export { fedifyWith, hasFederationHeader, integrateFederation, isFederationRequest, isNodeInfoRequest };
130
+ export { fedifyWith, hasFederationHeader, integrateFederation, isFederationRequest, isHashlinkMediaRequest, isNodeInfoRequest };
package/dist/index.js CHANGED
@@ -27,8 +27,12 @@ import { NextResponse } from "next/server.js";
27
27
  * }
28
28
  * )
29
29
  *
30
- * // This config makes middleware process only requests with the
31
- * // "Accept" header matching the federation accept regex.
30
+ * // This config makes the middleware run only for requests that may be
31
+ * // federation requests: requests whose "Accept" or "Content-Type" header
32
+ * // has a federation media type, NodeInfo requests, and FEP-ef61 gateway
33
+ * // requests such as hashlink media, which clients fetch with, e.g.,
34
+ * // "Accept: image/*". fedifyWith() then decides which of them Fedify
35
+ * // handles.
32
36
  * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional.
33
37
  * export const config = {
34
38
  * runtime: "nodejs",
@@ -55,6 +59,7 @@ import { NextResponse } from "next/server.js";
55
59
  * },
56
60
  * { source: "/.well-known/nodeinfo" },
57
61
  * { source: "/.well-known/x-nodeinfo2" },
62
+ * { source: "/.well-known/apgateway/:path*" },
58
63
  * ],
59
64
  * };
60
65
  * ```
@@ -63,10 +68,24 @@ const fedifyWith = (federation, contextDataFactory, errorHandlers) => (middlewar
63
68
  if (isFederationRequest(request)) return await integrateFederation(federation, contextDataFactory, errorHandlers)(request);
64
69
  return await middleware(request);
65
70
  };
71
+ /**
72
+ * Check if the request should be handled by the {@link Federation} object.
73
+ * A request is considered a federation request if any of the following
74
+ * conditions is met:
75
+ *
76
+ * - Its `Accept` or `Content-Type` header has an ActivityPub, JSON-LD, JRD,
77
+ * or XRD media type.
78
+ * - It is a NodeInfo request (see {@link isNodeInfoRequest}).
79
+ * - It is an FEP-ef61 hashlink media request
80
+ * (see {@link isHashlinkMediaRequest}).
81
+ * @param request The request to check.
82
+ * @returns `true` if the request is a federation request, `false` otherwise.
83
+ */
66
84
  const isFederationRequest = (request) => [
67
85
  hasFederationHeader("accept"),
68
86
  hasFederationHeader("content-type"),
69
- isNodeInfoRequest
87
+ isNodeInfoRequest,
88
+ isHashlinkMediaRequest
70
89
  ].some((f) => f(request));
71
90
  /**
72
91
  * Check if the request has the header matching the federation
@@ -85,6 +104,30 @@ const isNodeInfoRequest = (request) => {
85
104
  return NODEINFO_PATHS.some((path) => url.pathname.startsWith(path));
86
105
  };
87
106
  const NODEINFO_PATHS = ["/.well-known/nodeinfo", "/.well-known/x-nodeinfo2"];
107
+ /**
108
+ * Check if the request is an [FEP-ef61] gateway request for a resource
109
+ * addressed by a hashlink, e.g.,
110
+ * `GET /.well-known/apgateway/hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n`.
111
+ *
112
+ * Such requests need not carry a federation media type in their `Accept`
113
+ * header, as clients fetch media with, e.g., `Accept: image/*`, so they are
114
+ * recognized by their path alone. This only checks whether the path looks
115
+ * like a hashlink request; it does not check whether the hashlink is valid
116
+ * nor whether a hashlink media dispatcher is registered, which
117
+ * {@link Federation.fetch} takes care of.
118
+ *
119
+ * [FEP-ef61]: https://w3id.org/fep/ef61
120
+ * @param request The request to check.
121
+ * @returns `true` if the request is a hashlink media request,
122
+ * `false` otherwise.
123
+ * @since 2.4.0
124
+ */
125
+ const isHashlinkMediaRequest = (request) => {
126
+ const { pathname } = new URL(request.url);
127
+ return pathname.startsWith(GATEWAY_PATH_PREFIX) && HASHLINK_SCHEME_PATTERN.test(pathname.slice(GATEWAY_PATH_PREFIX.length));
128
+ };
129
+ const GATEWAY_PATH_PREFIX = "/.well-known/apgateway/";
130
+ const HASHLINK_SCHEME_PATTERN = /^hl(?::|%3A)/i;
88
131
  const FEDERATION_ACCEPT_REGEX = /.*application\/((jrd|activity|ld)\+json|xrd\+xml).*/;
89
132
  /**
90
133
  * Create a Next.js handler to integrate with the {@link Federation} object.
@@ -115,4 +158,4 @@ const onNotAcceptable = () => new Response("Not acceptable", {
115
158
  }
116
159
  });
117
160
  //#endregion
118
- export { fedifyWith, hasFederationHeader, integrateFederation, isFederationRequest, isNodeInfoRequest };
161
+ export { fedifyWith, hasFederationHeader, integrateFederation, isFederationRequest, isHashlinkMediaRequest, isNodeInfoRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/next",
3
- "version": "2.4.0-pr.936.41+59c7432c",
3
+ "version": "2.5.0-dev.2271+49d937e2",
4
4
  "description": "Integrate Fedify with Next.js",
5
5
  "keywords": [
6
6
  "Fedify",
@@ -48,15 +48,18 @@
48
48
  ],
49
49
  "peerDependencies": {
50
50
  "next": ">=15.4.6 <17",
51
- "@fedify/fedify": "^2.4.0-pr.936.41+59c7432c"
51
+ "@fedify/fedify": "^2.5.0-dev.2271+49d937e2"
52
52
  },
53
53
  "devDependencies": {
54
54
  "tsdown": "^0.22.0",
55
- "typescript": "^6.0.0"
55
+ "typescript": "^6.0.0",
56
+ "@fedify/fixture": "^2.0.0"
56
57
  },
57
58
  "scripts": {
58
59
  "build:self": "tsdown",
59
60
  "build": "pnpm --filter @fedify/next... run build:self",
60
- "prepublish": "pnpm build"
61
+ "prepublish": "pnpm build",
62
+ "test": "node --test dist/",
63
+ "test:bun": "bun test"
61
64
  }
62
65
  }