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
@@ -64,6 +64,7 @@ var RequestError = class extends EquippedError {
64
64
  };
65
65
 
66
66
  // src/server/adapters/base.ts
67
+ var import_node_http = require("http");
67
68
  var import_cors = require("@fastify/cors");
68
69
  var import_cors2 = require("cors");
69
70
  var import_socket = require("socket.io");
@@ -1374,6 +1375,22 @@ var serverConfigPipe = () => import_valleyed8.v.object({
1374
1375
  ),
1375
1376
  socketsAuthMethods: import_valleyed8.v.defaults(import_valleyed8.v.array(import_valleyed8.v.instanceOf(BaseRequestAuthMethod)), [])
1376
1377
  });
1378
+ var rawResponseHandledSymbol = /* @__PURE__ */ Symbol("rawResponseHandled");
1379
+ var rawResponseHandled = Object.freeze({ [rawResponseHandledSymbol]: true });
1380
+ var rawResponseNotStartedMessage = "Raw not-found handler did not start or complete a response";
1381
+ function isRawResponseHandled(input) {
1382
+ return Boolean(input && typeof input === "object" && rawResponseHandledSymbol in input);
1383
+ }
1384
+ function hasRawResponseStarted(response) {
1385
+ return response.headersSent || response.writableEnded;
1386
+ }
1387
+ function writeRawHandlerError(response, error) {
1388
+ if (hasRawResponseStarted(response)) return;
1389
+ response.statusCode = StatusCodes.BadRequest;
1390
+ response.setHeader("Content-Type", "application/json");
1391
+ const message = error instanceof Error ? error.message : `${error}`;
1392
+ response.end(JSON.stringify([{ message }]));
1393
+ }
1377
1394
  var errorsSchemas = Object.entries(StatusCodes).filter(([, value]) => value > 399).map(([key, value]) => ({
1378
1395
  status: value,
1379
1396
  contentType: "application/json",
@@ -1390,6 +1407,9 @@ var Server = class {
1390
1407
  #serverConfig;
1391
1408
  #queue = [];
1392
1409
  #routesByKey = /* @__PURE__ */ new Set();
1410
+ #started = false;
1411
+ #beforeListenHandlers = [];
1412
+ #notFoundHandler = null;
1393
1413
  setup(httpServer, config) {
1394
1414
  this.#httpServer = httpServer;
1395
1415
  this.#serverConfig = config;
@@ -1439,10 +1459,21 @@ var Server = class {
1439
1459
  });
1440
1460
  });
1441
1461
  }
1462
+ setNotFoundHandler(handler) {
1463
+ if (this.#started) throw new EquippedError("Cannot set not-found handler after server has started", {});
1464
+ this.#notFoundHandler = handler;
1465
+ return this;
1466
+ }
1467
+ onBeforeListen(handler) {
1468
+ if (this.#started) throw new EquippedError("Cannot add before-listen handler after server has started", {});
1469
+ this.#beforeListenHandlers.push(handler);
1470
+ return this;
1471
+ }
1442
1472
  test() {
1443
1473
  return (0, import_supertest.default)(this.#httpServer);
1444
1474
  }
1445
1475
  async start() {
1476
+ this.#started = true;
1446
1477
  const config = this.#serverConfig;
1447
1478
  const instance = Instance.get();
1448
1479
  const { app } = instance.settings;
@@ -1456,10 +1487,7 @@ var Server = class {
1456
1487
  })
1457
1488
  });
1458
1489
  await Promise.all(this.#queue.map((cb) => cb()));
1459
- this.registerNotFoundHandler(async (req) => {
1460
- const request = await this.parseRequest(req);
1461
- throw new NotFoundError(`Route ${request.path} not found`);
1462
- });
1490
+ this.registerNotFoundHandler(async (req, res) => await this.#handleNotFound(req, res));
1463
1491
  this.registerErrorHandler(async (error, _, res) => {
1464
1492
  if (!(error instanceof EquippedError)) Instance.get().log.error({ error }, "Uncaught error in route handler");
1465
1493
  const response = error instanceof RequestError ? new Response({
@@ -1474,10 +1502,36 @@ var Server = class {
1474
1502
  });
1475
1503
  return await this.handleResponse(res, response);
1476
1504
  });
1505
+ for (const handler of this.#beforeListenHandlers) await handler({ httpServer: this.#httpServer, port: config.port });
1477
1506
  const started = await this.startServer(config.port);
1478
1507
  if (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${config.port}`);
1479
1508
  return started;
1480
1509
  }
1510
+ createNodeRawResponder(input) {
1511
+ return async (handler) => {
1512
+ input.beforeHandle?.();
1513
+ try {
1514
+ await handler(input.request, input.response);
1515
+ } catch (error) {
1516
+ if (!hasRawResponseStarted(input.response)) {
1517
+ writeRawHandlerError(input.response, error);
1518
+ return rawResponseHandled;
1519
+ }
1520
+ throw error;
1521
+ }
1522
+ if (!hasRawResponseStarted(input.response))
1523
+ writeRawHandlerError(input.response, new EquippedError(rawResponseNotStartedMessage, {}));
1524
+ return rawResponseHandled;
1525
+ };
1526
+ }
1527
+ async #handleNotFound(req, res) {
1528
+ const request = await this.parseRequest(req);
1529
+ if (!this.#notFoundHandler) throw new NotFoundError(`Route ${request.path} not found`);
1530
+ const result = await this.#notFoundHandler({ request, respondWithRaw: this.createRawResponder(req, res) });
1531
+ if (isRawResponseHandled(result)) return;
1532
+ if (result instanceof Response) return await this.handleResponse(res, result);
1533
+ throw new EquippedError("Not-found handler must return a Response or respondWithRaw(...)", {});
1534
+ }
1481
1535
  #resolveSchema(method, schema) {
1482
1536
  const defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok;
1483
1537
  const defaultContentType = schema?.defaultContentType ?? "application/json";
@@ -1568,6 +1622,209 @@ var Server = class {
1568
1622
  };
1569
1623
  }
1570
1624
  };
1625
+ if (void 0) {
1626
+ let ensureTestInstance = function() {
1627
+ const instance = Instance.maybeGet() ?? Instance.create({ app: { name: "equipped-test" }, log: { level: "silent" } });
1628
+ if (!testInstanceState.__equippedTestInstanceAliased) {
1629
+ instance.alias("equipped-test");
1630
+ testInstanceState.__equippedTestInstanceAliased = true;
1631
+ }
1632
+ }, createRawResponse = function() {
1633
+ const chunks = [];
1634
+ return {
1635
+ statusCode: 200,
1636
+ headersSent: false,
1637
+ writableEnded: false,
1638
+ headers: {},
1639
+ setHeader(key, value) {
1640
+ this.headers[key] = value;
1641
+ },
1642
+ end(chunk) {
1643
+ if (chunk !== void 0) chunks.push(Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk));
1644
+ this.headersSent = true;
1645
+ this.writableEnded = true;
1646
+ },
1647
+ body() {
1648
+ return chunks.join("");
1649
+ }
1650
+ };
1651
+ };
1652
+ ensureTestInstance2 = ensureTestInstance, createRawResponse2 = createRawResponse;
1653
+ const { describe, expect, test } = void 0;
1654
+ const testInstanceState = globalThis;
1655
+ class TestServer extends Server {
1656
+ handledResponse = null;
1657
+ startedPorts = [];
1658
+ notFoundHandler = null;
1659
+ constructor() {
1660
+ super();
1661
+ this.setup(http.createServer(), {
1662
+ port: 0,
1663
+ cors: void 0,
1664
+ eventBus: void 0,
1665
+ publicPath: void 0,
1666
+ healthPath: void 0,
1667
+ openapi: { docsVersion: "1.0.0", docsBaseUrl: ["/"], docsPath: "/__docs" },
1668
+ requests: {
1669
+ log: false,
1670
+ rateLimit: { enabled: false, periodInMs: 1, limit: 1 },
1671
+ slowdown: { enabled: false, periodInMs: 1, delayAfter: 1, delayInMs: 1 }
1672
+ },
1673
+ socketsAuthMethods: []
1674
+ });
1675
+ }
1676
+ async parseRequest(req) {
1677
+ return new Request2({
1678
+ ip: "127.0.0.1",
1679
+ body: {},
1680
+ cookies: {},
1681
+ params: {},
1682
+ query: {},
1683
+ method: Methods.get,
1684
+ path: req.path,
1685
+ headers: {},
1686
+ files: {}
1687
+ });
1688
+ }
1689
+ async handleResponse(_, response) {
1690
+ this.handledResponse = response;
1691
+ }
1692
+ createRawResponder(req, res) {
1693
+ return this.createNodeRawResponder({ request: req.rawRequest, response: res.rawResponse });
1694
+ }
1695
+ registerRoute() {
1696
+ }
1697
+ registerErrorHandler() {
1698
+ }
1699
+ registerNotFoundHandler(cb) {
1700
+ this.notFoundHandler = cb;
1701
+ }
1702
+ async startServer(port) {
1703
+ this.startedPorts.push(port);
1704
+ return true;
1705
+ }
1706
+ async dispatchNotFound(path) {
1707
+ if (!this.notFoundHandler) throw new Error("not-found handler was not registered");
1708
+ this.handledResponse = null;
1709
+ const rawResponse = createRawResponse();
1710
+ await this.notFoundHandler({ path, rawRequest: {} }, { rawResponse });
1711
+ return { handledResponse: this.handledResponse, rawResponse };
1712
+ }
1713
+ }
1714
+ describe("Server before-listen handlers", () => {
1715
+ test("runs before-listen handlers before adapter listen in registration order", async () => {
1716
+ ensureTestInstance();
1717
+ const server = new TestServer();
1718
+ const calls = [];
1719
+ let receivedServer = null;
1720
+ server.onBeforeListen(({ httpServer, port }) => {
1721
+ calls.push(`first:${port}`);
1722
+ receivedServer = httpServer;
1723
+ expect(server.startedPorts).toEqual([]);
1724
+ }).onBeforeListen(({ httpServer, port }) => {
1725
+ calls.push(`second:${port}`);
1726
+ expect(httpServer).toBe(receivedServer);
1727
+ expect(server.startedPorts).toEqual([]);
1728
+ });
1729
+ await server.start();
1730
+ expect(calls).toEqual(["first:0", "second:0"]);
1731
+ expect(receivedServer).toBeInstanceOf(http.Server);
1732
+ expect(server.startedPorts).toEqual([0]);
1733
+ });
1734
+ test("rejects startup when a before-listen handler fails before adapter listen", async () => {
1735
+ ensureTestInstance();
1736
+ const server = new TestServer();
1737
+ server.onBeforeListen(async () => {
1738
+ throw new Error("before-listen failed");
1739
+ });
1740
+ await expect(server.start()).rejects.toThrow("before-listen failed");
1741
+ expect(server.startedPorts).toEqual([]);
1742
+ });
1743
+ test("rejects adding before-listen handlers after server startup", async () => {
1744
+ ensureTestInstance();
1745
+ const server = new TestServer();
1746
+ await server.start();
1747
+ expect(() => server.onBeforeListen(() => {
1748
+ })).toThrow("Cannot add before-listen handler after server has started");
1749
+ });
1750
+ });
1751
+ describe("Server not-found handler", () => {
1752
+ test("throws the default Equipped not-found error when no custom handler is set", async () => {
1753
+ ensureTestInstance();
1754
+ const server = new TestServer();
1755
+ await server.start();
1756
+ await expect(server.dispatchNotFound("/missing")).rejects.toBeInstanceOf(NotFoundError);
1757
+ });
1758
+ test("allows a custom not-found handler to return an Equipped response", async () => {
1759
+ ensureTestInstance();
1760
+ const server = new TestServer();
1761
+ server.setNotFoundHandler(
1762
+ ({ request }) => new Response({
1763
+ body: [{ message: `No route for ${request.path}` }],
1764
+ status: StatusCodes.NotFound,
1765
+ headers: {},
1766
+ cookies: {},
1767
+ contentType: "application/json"
1768
+ })
1769
+ );
1770
+ await server.start();
1771
+ const result = await server.dispatchNotFound("/custom");
1772
+ expect(result.handledResponse?.status).toBe(StatusCodes.NotFound);
1773
+ expect(result.handledResponse?.body).toEqual([{ message: "No route for /custom" }]);
1774
+ });
1775
+ test("allows a custom not-found handler to complete the response through a raw Node listener", async () => {
1776
+ ensureTestInstance();
1777
+ const server = new TestServer();
1778
+ server.setNotFoundHandler(
1779
+ ({ respondWithRaw }) => respondWithRaw((_, response) => {
1780
+ response.statusCode = 203;
1781
+ response.end("raw fallback");
1782
+ })
1783
+ );
1784
+ await server.start();
1785
+ const result = await server.dispatchNotFound("/page");
1786
+ expect(result.handledResponse).toBeNull();
1787
+ expect(result.rawResponse.statusCode).toBe(203);
1788
+ expect(result.rawResponse.body()).toBe("raw fallback");
1789
+ });
1790
+ test("writes a clear raw error when a raw not-found handler does not start a response", async () => {
1791
+ ensureTestInstance();
1792
+ const server = new TestServer();
1793
+ server.setNotFoundHandler(({ respondWithRaw }) => respondWithRaw(() => {
1794
+ }));
1795
+ await server.start();
1796
+ const result = await server.dispatchNotFound("/page");
1797
+ expect(result.handledResponse).toBeNull();
1798
+ expect(result.rawResponse.statusCode).toBe(StatusCodes.BadRequest);
1799
+ expect(result.rawResponse.body()).toContain(rawResponseNotStartedMessage);
1800
+ });
1801
+ test("rejects a custom not-found handler result that is neither an Equipped response nor raw completion", async () => {
1802
+ ensureTestInstance();
1803
+ const server = new TestServer();
1804
+ server.setNotFoundHandler((() => void 0));
1805
+ await server.start();
1806
+ await expect(server.dispatchNotFound("/bad")).rejects.toThrow("Not-found handler must return a Response or respondWithRaw(...)");
1807
+ });
1808
+ test("rejects setting the custom not-found handler after server startup", async () => {
1809
+ ensureTestInstance();
1810
+ const server = new TestServer();
1811
+ await server.start();
1812
+ expect(
1813
+ () => server.setNotFoundHandler(
1814
+ () => new Response({
1815
+ body: null,
1816
+ status: StatusCodes.NotFound,
1817
+ headers: {},
1818
+ cookies: {},
1819
+ contentType: "application/json"
1820
+ })
1821
+ )
1822
+ ).toThrow("Cannot set not-found handler after server has started");
1823
+ });
1824
+ });
1825
+ }
1826
+ var ensureTestInstance2;
1827
+ var createRawResponse2;
1571
1828
 
1572
1829
  // src/errors/types/badRequestError.ts
1573
1830
  var BadRequestError = class extends RequestError {
@@ -1673,6 +1930,9 @@ var FastifyServer = class extends configurable(serverConfigPipe, Server) {
1673
1930
  for (const [key, { value, ...opts }] of Object.entries(response.cookies)) res = res.setCookie(key, value, opts);
1674
1931
  await res.status(response.status).headers(response.headers).send(response.body);
1675
1932
  }
1933
+ createRawResponder(req, res) {
1934
+ return this.createNodeRawResponder({ request: req.raw, response: res.raw, beforeHandle: () => res.hijack() });
1935
+ }
1676
1936
  registerRoute(method, path, cb) {
1677
1937
  this.#app.register(async (inst) => {
1678
1938
  inst.route({ url: path, method, handler: cb });
@@ -1702,6 +1962,57 @@ function excludeBufferKeys(body) {
1702
1962
  files: Object.fromEntries(fileEntries)
1703
1963
  };
1704
1964
  }
1965
+ if (void 0) {
1966
+ let ensureTestInstance = function() {
1967
+ const instance = Instance.maybeGet() ?? Instance.create({ app: { name: "equipped-test" }, log: { level: "silent" } });
1968
+ if (!testInstanceState.__equippedTestInstanceAliased) {
1969
+ instance.alias("equipped-test");
1970
+ testInstanceState.__equippedTestInstanceAliased = true;
1971
+ }
1972
+ }, createRawResponse = function() {
1973
+ return {
1974
+ statusCode: 200,
1975
+ headersSent: false,
1976
+ writableEnded: false,
1977
+ setHeader: vi.fn(),
1978
+ end(chunk) {
1979
+ void chunk;
1980
+ this.headersSent = true;
1981
+ this.writableEnded = true;
1982
+ }
1983
+ };
1984
+ };
1985
+ ensureTestInstance2 = ensureTestInstance, createRawResponse2 = createRawResponse;
1986
+ const { describe, expect, test, vi } = void 0;
1987
+ const testInstanceState = globalThis;
1988
+ class TestFastifyServer extends FastifyServer {
1989
+ exposeRawResponder(req, res) {
1990
+ return this.createRawResponder(req, res);
1991
+ }
1992
+ }
1993
+ describe("FastifyServer raw responder", () => {
1994
+ test("hijacks the Fastify reply before passing Node raw request and response to the handler", async () => {
1995
+ ensureTestInstance();
1996
+ const server = TestFastifyServer.create({ port: 0, requests: { log: false } });
1997
+ const rawRequest = { marker: "request" };
1998
+ const rawResponse = createRawResponse();
1999
+ const reply = { raw: rawResponse, hijack: vi.fn() };
2000
+ const request = { raw: rawRequest };
2001
+ let received = null;
2002
+ await server.exposeRawResponder(
2003
+ request,
2004
+ reply
2005
+ )(async (req, res) => {
2006
+ received = { request: req, response: res };
2007
+ res.end("ok");
2008
+ });
2009
+ expect(reply.hijack).toHaveBeenCalledOnce();
2010
+ expect(received).toEqual({ request: rawRequest, response: rawResponse });
2011
+ });
2012
+ });
2013
+ }
2014
+ var ensureTestInstance2;
2015
+ var createRawResponse2;
1705
2016
  // Annotate the CommonJS export names for ESM import in node:
1706
2017
  0 && (module.exports = {
1707
2018
  FastifyServer