@fedify/nestjs 2.3.12-dev.2365 → 2.3.13

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/dist/index.cjs CHANGED
@@ -51,6 +51,7 @@ function integrateFederation(federation, contextDataFactory) {
51
51
  },
52
52
  onNotAcceptable: () => {
53
53
  notAcceptable = true;
54
+ installNotAcceptableFallback(req, res);
54
55
  next();
55
56
  return new Response("Not acceptable", {
56
57
  status: 406,
@@ -61,7 +62,7 @@ function integrateFederation(federation, contextDataFactory) {
61
62
  });
62
63
  }
63
64
  });
64
- if (notFound || notAcceptable && req.route != null) return;
65
+ if (notFound || notAcceptable) return;
65
66
  await setEResponse(res, response);
66
67
  next();
67
68
  }
@@ -99,6 +100,69 @@ function setEResponse(res, response) {
99
100
  });
100
101
  });
101
102
  }
103
+ /**
104
+ * Waits for downstream handling to finish before replacing an unsent 404.
105
+ * A matched route can still fall through, and next() does not wait for an
106
+ * asynchronous handler. Already committed responses belong to the application.
107
+ */
108
+ function installNotAcceptableFallback(req, res) {
109
+ const end = res.end;
110
+ const json = res.json;
111
+ let pending = true;
112
+ let defaultNotFound = false;
113
+ const wrappedJson = function(body) {
114
+ defaultNotFound = this.statusCode === 404 && isDefaultNotFound(req, body);
115
+ return json.call(this, body);
116
+ };
117
+ res.json = wrappedJson;
118
+ const wrapEnd = (end) => function(...args) {
119
+ if (pending) {
120
+ Object.defineProperty(this, "end", {
121
+ configurable: true,
122
+ enumerable: true,
123
+ writable: true,
124
+ value: end
125
+ });
126
+ if (this.json === wrappedJson) this.json = json;
127
+ }
128
+ if (!pending || !defaultNotFound || this.headersSent || this.statusCode !== 404) {
129
+ pending = false;
130
+ return end.apply(this, args);
131
+ }
132
+ pending = false;
133
+ const callback = args.find((arg) => typeof arg === "function");
134
+ const body = "Not acceptable";
135
+ this.statusCode = 406;
136
+ this.statusMessage = "Not Acceptable";
137
+ for (const header of [
138
+ "Content-Encoding",
139
+ "Content-Language",
140
+ "Content-Range",
141
+ "ETag",
142
+ "Last-Modified",
143
+ "Transfer-Encoding"
144
+ ]) this.removeHeader(header);
145
+ this.setHeader("Content-Type", "text/plain; charset=utf-8");
146
+ this.setHeader("Content-Length", node_buffer.Buffer.byteLength(body));
147
+ this.vary("Accept");
148
+ return end.call(this, req.method === "HEAD" ? void 0 : body, "utf8", callback);
149
+ };
150
+ let wrappedEnd = wrapEnd(end);
151
+ Object.defineProperty(res, "end", {
152
+ configurable: true,
153
+ enumerable: true,
154
+ get: () => wrappedEnd,
155
+ set: (value) => {
156
+ wrappedEnd = wrapEnd(value);
157
+ }
158
+ });
159
+ }
160
+ /** A custom response copying Nest's exact default 404 is indistinguishable. */
161
+ function isDefaultNotFound(req, body) {
162
+ if (body == null || typeof body !== "object" || Object.keys(body).length !== 3) return false;
163
+ const error = body;
164
+ return error.statusCode === 404 && error.error === "Not Found" && error.message === `Cannot ${req.method} ${req.originalUrl}`;
165
+ }
102
166
  //#endregion
103
167
  exports.FEDIFY_FEDERATION = FEDIFY_FEDERATION;
104
168
  Object.defineProperty(exports, "FedifyModule", {
package/dist/index.mjs CHANGED
@@ -50,6 +50,7 @@ function integrateFederation(federation, contextDataFactory) {
50
50
  },
51
51
  onNotAcceptable: () => {
52
52
  notAcceptable = true;
53
+ installNotAcceptableFallback(req, res);
53
54
  next();
54
55
  return new Response("Not acceptable", {
55
56
  status: 406,
@@ -60,7 +61,7 @@ function integrateFederation(federation, contextDataFactory) {
60
61
  });
61
62
  }
62
63
  });
63
- if (notFound || notAcceptable && req.route != null) return;
64
+ if (notFound || notAcceptable) return;
64
65
  await setEResponse(res, response);
65
66
  next();
66
67
  }
@@ -98,5 +99,68 @@ function setEResponse(res, response) {
98
99
  });
99
100
  });
100
101
  }
102
+ /**
103
+ * Waits for downstream handling to finish before replacing an unsent 404.
104
+ * A matched route can still fall through, and next() does not wait for an
105
+ * asynchronous handler. Already committed responses belong to the application.
106
+ */
107
+ function installNotAcceptableFallback(req, res) {
108
+ const end = res.end;
109
+ const json = res.json;
110
+ let pending = true;
111
+ let defaultNotFound = false;
112
+ const wrappedJson = function(body) {
113
+ defaultNotFound = this.statusCode === 404 && isDefaultNotFound(req, body);
114
+ return json.call(this, body);
115
+ };
116
+ res.json = wrappedJson;
117
+ const wrapEnd = (end) => function(...args) {
118
+ if (pending) {
119
+ Object.defineProperty(this, "end", {
120
+ configurable: true,
121
+ enumerable: true,
122
+ writable: true,
123
+ value: end
124
+ });
125
+ if (this.json === wrappedJson) this.json = json;
126
+ }
127
+ if (!pending || !defaultNotFound || this.headersSent || this.statusCode !== 404) {
128
+ pending = false;
129
+ return end.apply(this, args);
130
+ }
131
+ pending = false;
132
+ const callback = args.find((arg) => typeof arg === "function");
133
+ const body = "Not acceptable";
134
+ this.statusCode = 406;
135
+ this.statusMessage = "Not Acceptable";
136
+ for (const header of [
137
+ "Content-Encoding",
138
+ "Content-Language",
139
+ "Content-Range",
140
+ "ETag",
141
+ "Last-Modified",
142
+ "Transfer-Encoding"
143
+ ]) this.removeHeader(header);
144
+ this.setHeader("Content-Type", "text/plain; charset=utf-8");
145
+ this.setHeader("Content-Length", Buffer.byteLength(body));
146
+ this.vary("Accept");
147
+ return end.call(this, req.method === "HEAD" ? void 0 : body, "utf8", callback);
148
+ };
149
+ let wrappedEnd = wrapEnd(end);
150
+ Object.defineProperty(res, "end", {
151
+ configurable: true,
152
+ enumerable: true,
153
+ get: () => wrappedEnd,
154
+ set: (value) => {
155
+ wrappedEnd = wrapEnd(value);
156
+ }
157
+ });
158
+ }
159
+ /** A custom response copying Nest's exact default 404 is indistinguishable. */
160
+ function isDefaultNotFound(req, body) {
161
+ if (body == null || typeof body !== "object" || Object.keys(body).length !== 3) return false;
162
+ const error = body;
163
+ return error.statusCode === 404 && error.error === "Not Found" && error.message === `Cannot ${req.method} ${req.originalUrl}`;
164
+ }
101
165
  //#endregion
102
166
  export { FEDIFY_FEDERATION, FedifyModule, integrateFederation };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/nestjs",
3
- "version": "2.3.12-dev.2365+89254121",
3
+ "version": "2.3.13",
4
4
  "description": "Integrate Fedify with Nest.js",
5
5
  "keywords": [
6
6
  "Fedify",
@@ -49,17 +49,23 @@
49
49
  "peerDependencies": {
50
50
  "@nestjs/common": "^11.0.1",
51
51
  "express": "^4.0.0 || ^5.0.0",
52
- "@fedify/fedify": "^2.3.12-dev.2365+89254121"
52
+ "@fedify/fedify": "^2.3.13"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/express": "^4.0.0",
56
56
  "@types/node": "^22.17.0",
57
57
  "tsdown": "^0.22.0",
58
- "typescript": "^6.0.0"
58
+ "typescript": "^6.0.0",
59
+ "@nestjs/core": "11.1.4",
60
+ "@nestjs/platform-express": "11.1.4",
61
+ "reflect-metadata": "^0.2.2",
62
+ "@fedify/fixture": "2.0.0"
59
63
  },
60
64
  "scripts": {
61
65
  "build:self": "tsdown",
62
66
  "build": "pnpm --filter @fedify/nestjs... run build:self",
63
- "prepublish": "pnpm build"
67
+ "prepublish": "pnpm build",
68
+ "test": "pnpm build:self && node --experimental-transform-types --test",
69
+ "test:bun": "pnpm build:self && bun test"
64
70
  }
65
71
  }