equipped 5.3.0-alpha.0 → 5.3.1

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.
Files changed (134) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/server/adapters/express/index.cjs +312 -4
  3. package/dist/cjs/server/adapters/express/index.cjs.map +1 -1
  4. package/dist/cjs/server/adapters/express/index.min.cjs +7 -7
  5. package/dist/cjs/server/adapters/express/index.min.cjs.map +1 -1
  6. package/dist/cjs/server/adapters/fastify/index.cjs +315 -4
  7. package/dist/cjs/server/adapters/fastify/index.cjs.map +1 -1
  8. package/dist/cjs/server/adapters/fastify/index.min.cjs +7 -7
  9. package/dist/cjs/server/adapters/fastify/index.min.cjs.map +1 -1
  10. package/dist/cjs/server/index.cjs +261 -4
  11. package/dist/cjs/server/index.cjs.map +1 -1
  12. package/dist/cjs/server/index.min.cjs +7 -7
  13. package/dist/cjs/server/index.min.cjs.map +1 -1
  14. package/dist/esm/cache/adapters/in-memory/index.min.mjs +1 -1
  15. package/dist/esm/cache/adapters/in-memory/index.mjs +2 -2
  16. package/dist/esm/cache/adapters/redis/index.min.mjs +1 -1
  17. package/dist/esm/cache/adapters/redis/index.mjs +3 -3
  18. package/dist/esm/cache/index.min.mjs +1 -1
  19. package/dist/esm/cache/index.mjs +2 -2
  20. package/dist/esm/{chunk-AUKXL4EA.min.mjs → chunk-2GGMLKRP.min.mjs} +2 -2
  21. package/dist/esm/{chunk-TWKHVLLT.mjs → chunk-3TP7NINX.mjs} +2 -2
  22. package/dist/esm/{chunk-RIRBNBTC.mjs → chunk-5PZACGPI.mjs} +3 -3
  23. package/dist/esm/{chunk-OXI6IKAM.min.mjs → chunk-676VIABN.min.mjs} +2 -2
  24. package/dist/esm/{chunk-I4BB436E.mjs → chunk-7CP7ZE2O.mjs} +2 -2
  25. package/dist/esm/{chunk-YTM6ZURZ.min.mjs → chunk-7NF7PV6S.min.mjs} +2 -2
  26. package/dist/esm/{chunk-WHIWTP2Z.min.mjs → chunk-7SQ5JQYR.min.mjs} +2 -2
  27. package/dist/esm/{chunk-2TCFNKRZ.mjs → chunk-A4P7P6BU.mjs} +262 -5
  28. package/dist/esm/chunk-A4P7P6BU.mjs.map +1 -0
  29. package/dist/esm/{chunk-KW3PBDFD.mjs → chunk-BWUFPMVG.mjs} +2 -2
  30. package/dist/esm/{chunk-YTHRK2PO.mjs → chunk-HXFNN6RI.mjs} +3 -3
  31. package/dist/esm/chunk-IN5YKIJ7.min.mjs +32 -0
  32. package/dist/esm/chunk-IN5YKIJ7.min.mjs.map +1 -0
  33. package/dist/esm/{chunk-ECBJ3NT3.min.mjs → chunk-IRYCN6PI.min.mjs} +2 -2
  34. package/dist/esm/{chunk-IEBC3OWN.mjs → chunk-LKS5ZE45.mjs} +2 -2
  35. package/dist/esm/{chunk-6DW4GW3R.min.mjs → chunk-MQXTTWPS.min.mjs} +2 -2
  36. package/dist/esm/{chunk-MYGAF2AC.min.mjs → chunk-P4PRHHIY.min.mjs} +2 -2
  37. package/dist/esm/{chunk-6SB5M4XH.mjs → chunk-TSVHZZE4.mjs} +3 -3
  38. package/dist/esm/dbs/adapters/mongodb/index.min.mjs +1 -1
  39. package/dist/esm/dbs/adapters/mongodb/index.mjs +3 -3
  40. package/dist/esm/dbs/index.min.mjs +1 -1
  41. package/dist/esm/dbs/index.mjs +3 -3
  42. package/dist/esm/errors/index.min.mjs +1 -1
  43. package/dist/esm/errors/index.mjs +1 -1
  44. package/dist/esm/events/adapters/kafka/index.min.mjs +1 -1
  45. package/dist/esm/events/adapters/kafka/index.mjs +2 -2
  46. package/dist/esm/events/adapters/rabbitmq/index.min.mjs +1 -1
  47. package/dist/esm/events/adapters/rabbitmq/index.mjs +1 -1
  48. package/dist/esm/index.min.mjs +1 -1
  49. package/dist/esm/index.mjs +1 -1
  50. package/dist/esm/instance/index.min.mjs +1 -1
  51. package/dist/esm/instance/index.mjs +1 -1
  52. package/dist/esm/introspection-THKMXV5V.min.mjs +2 -0
  53. package/dist/esm/{introspection-Y7EXSYPD.mjs → introspection-YJF3QAUK.mjs} +3 -3
  54. package/dist/esm/jobs/adapters/redis/index.min.mjs +1 -1
  55. package/dist/esm/jobs/adapters/redis/index.mjs +3 -3
  56. package/dist/esm/orm/adapters/in-memory/index.min.mjs +1 -1
  57. package/dist/esm/orm/adapters/in-memory/index.mjs +3 -3
  58. package/dist/esm/orm/adapters/json/index.min.mjs +1 -1
  59. package/dist/esm/orm/adapters/json/index.mjs +3 -3
  60. package/dist/esm/orm/adapters/mongodb/index.min.mjs +1 -1
  61. package/dist/esm/orm/adapters/mongodb/index.mjs +2 -2
  62. package/dist/esm/orm/adapters/postgresql/index.min.mjs +2 -2
  63. package/dist/esm/orm/adapters/postgresql/index.mjs +3 -3
  64. package/dist/esm/orm/index.min.mjs +1 -1
  65. package/dist/esm/orm/index.mjs +3 -3
  66. package/dist/esm/server/adapters/express/index.min.mjs +1 -1
  67. package/dist/esm/server/adapters/express/index.min.mjs.map +1 -1
  68. package/dist/esm/server/adapters/express/index.mjs +52 -1
  69. package/dist/esm/server/adapters/express/index.mjs.map +1 -1
  70. package/dist/esm/server/adapters/fastify/index.min.mjs +1 -1
  71. package/dist/esm/server/adapters/fastify/index.min.mjs.map +1 -1
  72. package/dist/esm/server/adapters/fastify/index.mjs +55 -1
  73. package/dist/esm/server/adapters/fastify/index.mjs.map +1 -1
  74. package/dist/esm/server/index.min.mjs +1 -1
  75. package/dist/esm/server/index.mjs +1 -1
  76. package/dist/esm/utilities/index.min.mjs +1 -1
  77. package/dist/esm/utilities/index.mjs +1 -1
  78. package/dist/esm/validations/index.min.mjs +1 -1
  79. package/dist/esm/validations/index.mjs +1 -1
  80. package/dist/types/{base-3PpBAx1K.d.ts → base-BDTBLZ9a.d.ts} +26 -2
  81. package/dist/types/cache/adapters/in-memory/index.js +2 -2
  82. package/dist/types/cache/adapters/redis/index.js +3 -3
  83. package/dist/types/cache/index.js +2 -2
  84. package/dist/types/{chunk-H6JBLKX5.js → chunk-4DH3POYM.js} +2 -2
  85. package/dist/types/{chunk-XOU2A2Y6.js → chunk-55CTVK7R.js} +1 -1
  86. package/dist/types/{chunk-A2MRYMCA.js → chunk-5Z26ZURE.js} +1 -1
  87. package/dist/types/{chunk-JZ2JTENY.js → chunk-IZDJDGOV.js} +2 -2
  88. package/dist/types/{chunk-IAHTILKJ.js → chunk-J3TGB5YQ.js} +1 -1
  89. package/dist/types/{chunk-LWUMIHL4.js → chunk-LPB5LS7A.js} +1 -1
  90. package/dist/types/{chunk-32DMHN3G.js → chunk-TT5EORDK.js} +261 -4
  91. package/dist/types/{chunk-4LRJJSGG.js → chunk-YLJNBL6J.js} +2 -2
  92. package/dist/types/dbs/adapters/mongodb/index.js +3 -3
  93. package/dist/types/dbs/index.js +3 -3
  94. package/dist/types/errors/index.js +1 -1
  95. package/dist/types/events/adapters/kafka/index.js +2 -2
  96. package/dist/types/events/adapters/rabbitmq/index.js +1 -1
  97. package/dist/types/index.js +1 -1
  98. package/dist/types/instance/index.js +1 -1
  99. package/dist/types/{introspection-ZQCAW254.js → introspection-EHGM4RMO.js} +2 -2
  100. package/dist/types/jobs/adapters/redis/index.js +3 -3
  101. package/dist/types/orm/adapters/in-memory/index.js +3 -3
  102. package/dist/types/orm/adapters/json/index.js +3 -3
  103. package/dist/types/orm/adapters/mongodb/index.js +2 -2
  104. package/dist/types/orm/adapters/postgresql/index.js +3 -3
  105. package/dist/types/orm/index.js +3 -3
  106. package/dist/types/server/adapters/express/index.d.ts +3 -1
  107. package/dist/types/server/adapters/express/index.js +52 -1
  108. package/dist/types/server/adapters/fastify/index.d.ts +3 -1
  109. package/dist/types/server/adapters/fastify/index.js +55 -1
  110. package/dist/types/server/index.d.ts +2 -2
  111. package/dist/types/server/index.js +1 -1
  112. package/dist/types/utilities/index.js +1 -1
  113. package/dist/types/validations/index.js +1 -1
  114. package/package.json +2 -4
  115. package/dist/esm/chunk-2TCFNKRZ.mjs.map +0 -1
  116. package/dist/esm/chunk-LTDVZJYJ.min.mjs +0 -32
  117. package/dist/esm/chunk-LTDVZJYJ.min.mjs.map +0 -1
  118. package/dist/esm/introspection-GP3G26B6.min.mjs +0 -2
  119. /package/dist/esm/{chunk-AUKXL4EA.min.mjs.map → chunk-2GGMLKRP.min.mjs.map} +0 -0
  120. /package/dist/esm/{chunk-TWKHVLLT.mjs.map → chunk-3TP7NINX.mjs.map} +0 -0
  121. /package/dist/esm/{chunk-RIRBNBTC.mjs.map → chunk-5PZACGPI.mjs.map} +0 -0
  122. /package/dist/esm/{chunk-OXI6IKAM.min.mjs.map → chunk-676VIABN.min.mjs.map} +0 -0
  123. /package/dist/esm/{chunk-I4BB436E.mjs.map → chunk-7CP7ZE2O.mjs.map} +0 -0
  124. /package/dist/esm/{chunk-YTM6ZURZ.min.mjs.map → chunk-7NF7PV6S.min.mjs.map} +0 -0
  125. /package/dist/esm/{chunk-WHIWTP2Z.min.mjs.map → chunk-7SQ5JQYR.min.mjs.map} +0 -0
  126. /package/dist/esm/{chunk-KW3PBDFD.mjs.map → chunk-BWUFPMVG.mjs.map} +0 -0
  127. /package/dist/esm/{chunk-YTHRK2PO.mjs.map → chunk-HXFNN6RI.mjs.map} +0 -0
  128. /package/dist/esm/{chunk-ECBJ3NT3.min.mjs.map → chunk-IRYCN6PI.min.mjs.map} +0 -0
  129. /package/dist/esm/{chunk-IEBC3OWN.mjs.map → chunk-LKS5ZE45.mjs.map} +0 -0
  130. /package/dist/esm/{chunk-6DW4GW3R.min.mjs.map → chunk-MQXTTWPS.min.mjs.map} +0 -0
  131. /package/dist/esm/{chunk-MYGAF2AC.min.mjs.map → chunk-P4PRHHIY.min.mjs.map} +0 -0
  132. /package/dist/esm/{chunk-6SB5M4XH.mjs.map → chunk-TSVHZZE4.mjs.map} +0 -0
  133. /package/dist/esm/{introspection-GP3G26B6.min.mjs.map → introspection-THKMXV5V.min.mjs.map} +0 -0
  134. /package/dist/esm/{introspection-Y7EXSYPD.mjs.map → introspection-YJF3QAUK.mjs.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [5.3.1](https://github.com/kevinand11/equipped/compare/v5.3.0...v5.3.1) (2026-06-19)
6
+
7
+
8
+ ### Features
9
+
10
+ * **server:** add before listen hook ([f72134c](https://github.com/kevinand11/equipped/commit/f72134c67273023a3e98351dd079fa6600b6a43d))
11
+
12
+ ## [5.3.0](https://github.com/kevinand11/equipped/compare/v5.3.0-alpha.0...v5.3.0) (2026-06-19)
13
+
14
+
15
+ ### Features
16
+
17
+ * **server:** add custom not found fallback ([6173b4f](https://github.com/kevinand11/equipped/commit/6173b4ffb7f14dd7f965507c972f9fb1434dc5d1))
18
+
5
19
  ## [5.3.0-alpha.0](https://github.com/kevinand11/equipped/compare/v5.2.9...v5.3.0-alpha.0) (2026-06-16)
6
20
 
7
21
 
@@ -68,6 +68,7 @@ var RequestError = class extends EquippedError {
68
68
  };
69
69
 
70
70
  // src/server/adapters/base.ts
71
+ var import_node_http = require("http");
71
72
  var import_cors = require("@fastify/cors");
72
73
  var import_cors2 = require("cors");
73
74
  var import_socket = require("socket.io");
@@ -839,6 +840,22 @@ var serverConfigPipe = () => import_valleyed6.v.object({
839
840
  ),
840
841
  socketsAuthMethods: import_valleyed6.v.defaults(import_valleyed6.v.array(import_valleyed6.v.instanceOf(BaseRequestAuthMethod)), [])
841
842
  });
843
+ var rawResponseHandledSymbol = /* @__PURE__ */ Symbol("rawResponseHandled");
844
+ var rawResponseHandled = Object.freeze({ [rawResponseHandledSymbol]: true });
845
+ var rawResponseNotStartedMessage = "Raw not-found handler did not start or complete a response";
846
+ function isRawResponseHandled(input) {
847
+ return Boolean(input && typeof input === "object" && rawResponseHandledSymbol in input);
848
+ }
849
+ function hasRawResponseStarted(response) {
850
+ return response.headersSent || response.writableEnded;
851
+ }
852
+ function writeRawHandlerError(response, error) {
853
+ if (hasRawResponseStarted(response)) return;
854
+ response.statusCode = StatusCodes.BadRequest;
855
+ response.setHeader("Content-Type", "application/json");
856
+ const message = error instanceof Error ? error.message : `${error}`;
857
+ response.end(JSON.stringify([{ message }]));
858
+ }
842
859
  var errorsSchemas = Object.entries(StatusCodes).filter(([, value]) => value > 399).map(([key, value]) => ({
843
860
  status: value,
844
861
  contentType: "application/json",
@@ -855,6 +872,9 @@ var Server = class {
855
872
  #serverConfig;
856
873
  #queue = [];
857
874
  #routesByKey = /* @__PURE__ */ new Set();
875
+ #started = false;
876
+ #beforeListenHandlers = [];
877
+ #notFoundHandler = null;
858
878
  setup(httpServer, config) {
859
879
  this.#httpServer = httpServer;
860
880
  this.#serverConfig = config;
@@ -904,10 +924,21 @@ var Server = class {
904
924
  });
905
925
  });
906
926
  }
927
+ setNotFoundHandler(handler) {
928
+ if (this.#started) throw new EquippedError("Cannot set not-found handler after server has started", {});
929
+ this.#notFoundHandler = handler;
930
+ return this;
931
+ }
932
+ onBeforeListen(handler) {
933
+ if (this.#started) throw new EquippedError("Cannot add before-listen handler after server has started", {});
934
+ this.#beforeListenHandlers.push(handler);
935
+ return this;
936
+ }
907
937
  test() {
908
938
  return (0, import_supertest.default)(this.#httpServer);
909
939
  }
910
940
  async start() {
941
+ this.#started = true;
911
942
  const config = this.#serverConfig;
912
943
  const instance = Instance.get();
913
944
  const { app } = instance.settings;
@@ -921,10 +952,7 @@ var Server = class {
921
952
  })
922
953
  });
923
954
  await Promise.all(this.#queue.map((cb) => cb()));
924
- this.registerNotFoundHandler(async (req) => {
925
- const request = await this.parseRequest(req);
926
- throw new NotFoundError(`Route ${request.path} not found`);
927
- });
955
+ this.registerNotFoundHandler(async (req, res) => await this.#handleNotFound(req, res));
928
956
  this.registerErrorHandler(async (error, _, res) => {
929
957
  if (!(error instanceof EquippedError)) Instance.get().log.error({ error }, "Uncaught error in route handler");
930
958
  const response = error instanceof RequestError ? new Response({
@@ -939,10 +967,36 @@ var Server = class {
939
967
  });
940
968
  return await this.handleResponse(res, response);
941
969
  });
970
+ for (const handler of this.#beforeListenHandlers) await handler({ httpServer: this.#httpServer, port: config.port });
942
971
  const started = await this.startServer(config.port);
943
972
  if (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${config.port}`);
944
973
  return started;
945
974
  }
975
+ createNodeRawResponder(input) {
976
+ return async (handler) => {
977
+ input.beforeHandle?.();
978
+ try {
979
+ await handler(input.request, input.response);
980
+ } catch (error) {
981
+ if (!hasRawResponseStarted(input.response)) {
982
+ writeRawHandlerError(input.response, error);
983
+ return rawResponseHandled;
984
+ }
985
+ throw error;
986
+ }
987
+ if (!hasRawResponseStarted(input.response))
988
+ writeRawHandlerError(input.response, new EquippedError(rawResponseNotStartedMessage, {}));
989
+ return rawResponseHandled;
990
+ };
991
+ }
992
+ async #handleNotFound(req, res) {
993
+ const request = await this.parseRequest(req);
994
+ if (!this.#notFoundHandler) throw new NotFoundError(`Route ${request.path} not found`);
995
+ const result = await this.#notFoundHandler({ request, respondWithRaw: this.createRawResponder(req, res) });
996
+ if (isRawResponseHandled(result)) return;
997
+ if (result instanceof Response) return await this.handleResponse(res, result);
998
+ throw new EquippedError("Not-found handler must return a Response or respondWithRaw(...)", {});
999
+ }
946
1000
  #resolveSchema(method, schema) {
947
1001
  const defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok;
948
1002
  const defaultContentType = schema?.defaultContentType ?? "application/json";
@@ -1033,6 +1087,209 @@ var Server = class {
1033
1087
  };
1034
1088
  }
1035
1089
  };
1090
+ if (void 0) {
1091
+ let ensureTestInstance = function() {
1092
+ const instance = Instance.maybeGet() ?? Instance.create({ app: { name: "equipped-test" }, log: { level: "silent" } });
1093
+ if (!testInstanceState.__equippedTestInstanceAliased) {
1094
+ instance.alias("equipped-test");
1095
+ testInstanceState.__equippedTestInstanceAliased = true;
1096
+ }
1097
+ }, createRawResponse = function() {
1098
+ const chunks = [];
1099
+ return {
1100
+ statusCode: 200,
1101
+ headersSent: false,
1102
+ writableEnded: false,
1103
+ headers: {},
1104
+ setHeader(key, value) {
1105
+ this.headers[key] = value;
1106
+ },
1107
+ end(chunk) {
1108
+ if (chunk !== void 0) chunks.push(Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk));
1109
+ this.headersSent = true;
1110
+ this.writableEnded = true;
1111
+ },
1112
+ body() {
1113
+ return chunks.join("");
1114
+ }
1115
+ };
1116
+ };
1117
+ ensureTestInstance2 = ensureTestInstance, createRawResponse2 = createRawResponse;
1118
+ const { describe, expect, test } = void 0;
1119
+ const testInstanceState = globalThis;
1120
+ class TestServer extends Server {
1121
+ handledResponse = null;
1122
+ startedPorts = [];
1123
+ notFoundHandler = null;
1124
+ constructor() {
1125
+ super();
1126
+ this.setup(http.createServer(), {
1127
+ port: 0,
1128
+ cors: void 0,
1129
+ eventBus: void 0,
1130
+ publicPath: void 0,
1131
+ healthPath: void 0,
1132
+ openapi: { docsVersion: "1.0.0", docsBaseUrl: ["/"], docsPath: "/__docs" },
1133
+ requests: {
1134
+ log: false,
1135
+ rateLimit: { enabled: false, periodInMs: 1, limit: 1 },
1136
+ slowdown: { enabled: false, periodInMs: 1, delayAfter: 1, delayInMs: 1 }
1137
+ },
1138
+ socketsAuthMethods: []
1139
+ });
1140
+ }
1141
+ async parseRequest(req) {
1142
+ return new Request2({
1143
+ ip: "127.0.0.1",
1144
+ body: {},
1145
+ cookies: {},
1146
+ params: {},
1147
+ query: {},
1148
+ method: Methods.get,
1149
+ path: req.path,
1150
+ headers: {},
1151
+ files: {}
1152
+ });
1153
+ }
1154
+ async handleResponse(_, response) {
1155
+ this.handledResponse = response;
1156
+ }
1157
+ createRawResponder(req, res) {
1158
+ return this.createNodeRawResponder({ request: req.rawRequest, response: res.rawResponse });
1159
+ }
1160
+ registerRoute() {
1161
+ }
1162
+ registerErrorHandler() {
1163
+ }
1164
+ registerNotFoundHandler(cb) {
1165
+ this.notFoundHandler = cb;
1166
+ }
1167
+ async startServer(port) {
1168
+ this.startedPorts.push(port);
1169
+ return true;
1170
+ }
1171
+ async dispatchNotFound(path) {
1172
+ if (!this.notFoundHandler) throw new Error("not-found handler was not registered");
1173
+ this.handledResponse = null;
1174
+ const rawResponse = createRawResponse();
1175
+ await this.notFoundHandler({ path, rawRequest: {} }, { rawResponse });
1176
+ return { handledResponse: this.handledResponse, rawResponse };
1177
+ }
1178
+ }
1179
+ describe("Server before-listen handlers", () => {
1180
+ test("runs before-listen handlers before adapter listen in registration order", async () => {
1181
+ ensureTestInstance();
1182
+ const server = new TestServer();
1183
+ const calls = [];
1184
+ let receivedServer = null;
1185
+ server.onBeforeListen(({ httpServer, port }) => {
1186
+ calls.push(`first:${port}`);
1187
+ receivedServer = httpServer;
1188
+ expect(server.startedPorts).toEqual([]);
1189
+ }).onBeforeListen(({ httpServer, port }) => {
1190
+ calls.push(`second:${port}`);
1191
+ expect(httpServer).toBe(receivedServer);
1192
+ expect(server.startedPorts).toEqual([]);
1193
+ });
1194
+ await server.start();
1195
+ expect(calls).toEqual(["first:0", "second:0"]);
1196
+ expect(receivedServer).toBeInstanceOf(http.Server);
1197
+ expect(server.startedPorts).toEqual([0]);
1198
+ });
1199
+ test("rejects startup when a before-listen handler fails before adapter listen", async () => {
1200
+ ensureTestInstance();
1201
+ const server = new TestServer();
1202
+ server.onBeforeListen(async () => {
1203
+ throw new Error("before-listen failed");
1204
+ });
1205
+ await expect(server.start()).rejects.toThrow("before-listen failed");
1206
+ expect(server.startedPorts).toEqual([]);
1207
+ });
1208
+ test("rejects adding before-listen handlers after server startup", async () => {
1209
+ ensureTestInstance();
1210
+ const server = new TestServer();
1211
+ await server.start();
1212
+ expect(() => server.onBeforeListen(() => {
1213
+ })).toThrow("Cannot add before-listen handler after server has started");
1214
+ });
1215
+ });
1216
+ describe("Server not-found handler", () => {
1217
+ test("throws the default Equipped not-found error when no custom handler is set", async () => {
1218
+ ensureTestInstance();
1219
+ const server = new TestServer();
1220
+ await server.start();
1221
+ await expect(server.dispatchNotFound("/missing")).rejects.toBeInstanceOf(NotFoundError);
1222
+ });
1223
+ test("allows a custom not-found handler to return an Equipped response", async () => {
1224
+ ensureTestInstance();
1225
+ const server = new TestServer();
1226
+ server.setNotFoundHandler(
1227
+ ({ request }) => new Response({
1228
+ body: [{ message: `No route for ${request.path}` }],
1229
+ status: StatusCodes.NotFound,
1230
+ headers: {},
1231
+ cookies: {},
1232
+ contentType: "application/json"
1233
+ })
1234
+ );
1235
+ await server.start();
1236
+ const result = await server.dispatchNotFound("/custom");
1237
+ expect(result.handledResponse?.status).toBe(StatusCodes.NotFound);
1238
+ expect(result.handledResponse?.body).toEqual([{ message: "No route for /custom" }]);
1239
+ });
1240
+ test("allows a custom not-found handler to complete the response through a raw Node listener", async () => {
1241
+ ensureTestInstance();
1242
+ const server = new TestServer();
1243
+ server.setNotFoundHandler(
1244
+ ({ respondWithRaw }) => respondWithRaw((_, response) => {
1245
+ response.statusCode = 203;
1246
+ response.end("raw fallback");
1247
+ })
1248
+ );
1249
+ await server.start();
1250
+ const result = await server.dispatchNotFound("/page");
1251
+ expect(result.handledResponse).toBeNull();
1252
+ expect(result.rawResponse.statusCode).toBe(203);
1253
+ expect(result.rawResponse.body()).toBe("raw fallback");
1254
+ });
1255
+ test("writes a clear raw error when a raw not-found handler does not start a response", async () => {
1256
+ ensureTestInstance();
1257
+ const server = new TestServer();
1258
+ server.setNotFoundHandler(({ respondWithRaw }) => respondWithRaw(() => {
1259
+ }));
1260
+ await server.start();
1261
+ const result = await server.dispatchNotFound("/page");
1262
+ expect(result.handledResponse).toBeNull();
1263
+ expect(result.rawResponse.statusCode).toBe(StatusCodes.BadRequest);
1264
+ expect(result.rawResponse.body()).toContain(rawResponseNotStartedMessage);
1265
+ });
1266
+ test("rejects a custom not-found handler result that is neither an Equipped response nor raw completion", async () => {
1267
+ ensureTestInstance();
1268
+ const server = new TestServer();
1269
+ server.setNotFoundHandler((() => void 0));
1270
+ await server.start();
1271
+ await expect(server.dispatchNotFound("/bad")).rejects.toThrow("Not-found handler must return a Response or respondWithRaw(...)");
1272
+ });
1273
+ test("rejects setting the custom not-found handler after server startup", async () => {
1274
+ ensureTestInstance();
1275
+ const server = new TestServer();
1276
+ await server.start();
1277
+ expect(
1278
+ () => server.setNotFoundHandler(
1279
+ () => new Response({
1280
+ body: null,
1281
+ status: StatusCodes.NotFound,
1282
+ headers: {},
1283
+ cookies: {},
1284
+ contentType: "application/json"
1285
+ })
1286
+ )
1287
+ ).toThrow("Cannot set not-found handler after server has started");
1288
+ });
1289
+ });
1290
+ }
1291
+ var ensureTestInstance2;
1292
+ var createRawResponse2;
1036
1293
 
1037
1294
  // src/errors/types/badRequestError.ts
1038
1295
  var BadRequestError = class extends RequestError {
@@ -1678,6 +1935,9 @@ var ExpressServer = class extends configurable(serverConfigPipe, Server) {
1678
1935
  response.body.pipe(res);
1679
1936
  }
1680
1937
  }
1938
+ createRawResponder(req, res) {
1939
+ return this.createNodeRawResponder({ request: req, response: res });
1940
+ }
1681
1941
  registerRoute(method, path, cb) {
1682
1942
  this.#app[method]?.(path, async (req, res) => cb(req, res));
1683
1943
  }
@@ -1698,6 +1958,54 @@ var ExpressServer = class extends configurable(serverConfigPipe, Server) {
1698
1958
  });
1699
1959
  }
1700
1960
  };
1961
+ if (void 0) {
1962
+ let ensureTestInstance = function() {
1963
+ const instance = Instance.maybeGet() ?? Instance.create({ app: { name: "equipped-test" }, log: { level: "silent" } });
1964
+ if (!testInstanceState.__equippedTestInstanceAliased) {
1965
+ instance.alias("equipped-test");
1966
+ testInstanceState.__equippedTestInstanceAliased = true;
1967
+ }
1968
+ }, createExpressResponse = function() {
1969
+ return {
1970
+ statusCode: 200,
1971
+ headersSent: false,
1972
+ writableEnded: false,
1973
+ setHeader: vi.fn(),
1974
+ end(chunk) {
1975
+ void chunk;
1976
+ this.headersSent = true;
1977
+ this.writableEnded = true;
1978
+ }
1979
+ };
1980
+ };
1981
+ ensureTestInstance2 = ensureTestInstance, createExpressResponse2 = createExpressResponse;
1982
+ const { describe, expect, test, vi } = void 0;
1983
+ const testInstanceState = globalThis;
1984
+ class TestExpressServer extends ExpressServer {
1985
+ exposeRawResponder(req, res) {
1986
+ return this.createRawResponder(req, res);
1987
+ }
1988
+ }
1989
+ describe("ExpressServer raw responder", () => {
1990
+ test("passes the Express request and response to the raw Node handler", async () => {
1991
+ ensureTestInstance();
1992
+ const server = TestExpressServer.create({ port: 0, requests: { log: false } });
1993
+ const req = { marker: "request" };
1994
+ const res = createExpressResponse();
1995
+ let received = null;
1996
+ await server.exposeRawResponder(
1997
+ req,
1998
+ res
1999
+ )(async (request, response) => {
2000
+ received = { request, response };
2001
+ response.end("ok");
2002
+ });
2003
+ expect(received).toEqual({ request: req, response: res });
2004
+ });
2005
+ });
2006
+ }
2007
+ var ensureTestInstance2;
2008
+ var createExpressResponse2;
1701
2009
  // Annotate the CommonJS export names for ESM import in node:
1702
2010
  0 && (module.exports = {
1703
2011
  ExpressServer