jeasx 2.2.2 → 2.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.
package/CHANGELOG.md CHANGED
@@ -1,10 +1,71 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-02-04 - Jeasx 2.3.1 released
4
+
5
+ 🎉 Just a patch release to update Fastify to fix [CVE-2026-25224](https://github.com/fastify/fastify/security/advisories/GHSA-mrq3-vjjr-p77c).
6
+
7
+ Additionally, I performed minor refactorings identified by [oxlint](https://oxc.rs/docs/guide/usage/linter.html) and replaced `prettier` with [oxfmt](https://oxc.rs/docs/guide/usage/formatter), a high-performance formatter optimized for the JavaScript ecosystem.
8
+
9
+ Dependency updates: `fastify@5.7.4`, `@types/node@24.10.10`
10
+
11
+ ## 2026-01-30 - Jeasx 2.3.0 released
12
+
13
+ 🎉 This release introduces support for [MDX](https://mdxjs.com), enabling you to seamlessly embed JSX within Markdown content. Just create a route with a `.mdx` extension, and you’re all set to enhance your websites and blogs with Markdown enriched by dynamic JSX components.
14
+
15
+ ```jsx
16
+ import Layout from "./Layout"
17
+
18
+ <Layout title="MDX - Markdown for the component era">
19
+ # MDX as content companion alongside JSX
20
+
21
+ You can easily access existing `props` in MDX:
22
+
23
+ - Current url: {props.request.url}
24
+ </Layout>
25
+ ```
26
+
27
+ You can also create MDX-based components for use within JSX by importing them with their full `.mdx` file extension into your JSX routes or components.
28
+
29
+ Since MDX supports a variety of plugins - and Jeasx provides only the MDX core to stay focused on infrastructure while letting users handle customization - the overall configuration for Jeasx has been significantly improved. Now, the configuration object from an `.env.js` file is imported directly into both the build process and server runtime, allowing you to use package imports seamlessly. Previously, (de)serializing the configuration via `process.env` restricted this capability and limited advanced setups.
30
+
31
+ **Please note:** Variables loaded from `.env.js` now consistently overwrite any existing environment variables. This ensures predictable and consistent behavior across your configuration.
32
+
33
+ Here’s an example of how to configure the MDX engine: if you want to enable GitHub-flavored Markdown (`remark-gfm`), add syntax highlighting (`rehype-prism-plus`), and generate IDs for your headings (`rehype-slug`), you can install and configure these plugins accordingly in `.env.js`.
34
+
35
+ ```js
36
+ import rehypePrismPlus from "rehype-prism-plus";
37
+ import rehypeSlug from "rehype-slug";
38
+ import remarkGFM from "remark-gfm";
39
+
40
+ export default {
41
+ /** @type import("@mdx-js/esbuild").Options */
42
+ ESBUILD_MDX_OPTIONS: {
43
+ remarkPlugins: [[remarkGFM, { singleTilde: false }]],
44
+ rehypePlugins: [rehypePrismPlus, [rehypeSlug, { prefix: "jeasx-" }]]
45
+ }
46
+ //...
47
+ }
48
+ ```
49
+
50
+ For a full overview of available configuration options and plugins, check out the excellent documentation of [@mdx-js/esbuild](https://mdxjs.com/packages/esbuild).
51
+
52
+ **Please note:** The update to the Jeasx configuration introduced a minor change in how `ESBUILD_BROWSER_TARGET` is specified to ensure consistency across the configuration. Previously, a comma-separated string was accepted and parsed as customization. Going forward, you must provide a proper JSON array (or its stringified form when using traditional `.env` files or the process environment).
53
+
54
+ ```js
55
+ export default {
56
+ /** @type import("esbuild").BuildOptions["target"] */
57
+ ESBUILD_BROWSER_TARGET: ["chrome130", "edge130", "firefox130", "safari18"]
58
+ //...
59
+ }
60
+ ```
61
+
62
+ Dependency updates: `fastify@5.7.2`, `@fastify/multipart@9.4.0`
63
+
3
64
  ## 2026-01-17 - Jeasx 2.2.2 released
4
65
 
5
- 🎉 This release now preserves the original status code when a 404 page is accessed directly (previously defaulted to 200). This improvement makes it easier to use Jeasx as a static site generator and to fetch the 404 page with common tools for saving it to a file system. While Jeasx is fundamentally a server-side rendering framework, there are valid use cases where serving a static page alone is sufficient.
66
+ 🎉 This release now preserves the original status code when a 404 page is accessed directly (defaults to 200). This improvement makes it easier to use Jeasx as a static site generator and to fetch the 404 page with common tools for saving it to a file system.
6
67
 
7
- For example, you can use `wget` to download a Jeasx website to a www-directory with just a single line:
68
+ While Jeasx is fundamentally a server-side rendering framework, there are valid use cases where serving a static page alone is sufficient. For example, you can use `wget` to download a Jeasx website to a www-directory with just a single line:
8
69
 
9
70
  ```bash
10
71
  wget --mirror --page-requisites --no-host-directories --directory-prefix=www http://localhost:3000 http://localhost:3000/404
@@ -12,6 +73,8 @@ wget --mirror --page-requisites --no-host-directories --directory-prefix=www htt
12
73
 
13
74
  Have a look at the [Dockerfile](https://github.com/jeasx/jeasx-website/blob/main/Dockerfile) of the Jeasx website to see how things can be wired up for serving a static export with Caddy as web server.
14
75
 
76
+ If you want to restore the old behaviour (directly calling /404 resulting in status code 404), you can simple add `reply.status(404)` to your `/[404]` handler.
77
+
15
78
  Dependency updates: `fastify@5.7.1`, `@fastify/static@9.0.0`, `@types/node@24.10.9`
16
79
 
17
80
  ## 2025-12-21 - Jeasx 2.2.1 released
@@ -24,7 +87,7 @@ Dependency updates: `esbuild@0.27.2`, `jsx-async-runtime@2.0.2`, `@types/node@24
24
87
 
25
88
  🎉 This release introduces a more flexible configuration approach for the underlying Fastify server. You can now customize all Fastify options (including those for all used plugins) according to your needs, without having to use the formerly fixed and very restrictive set of environment variables. This change was made to eliminate the need for increasingly specific environment variables to customise the default behaviour of Jeasx.
26
89
 
27
- **Breaking change**: The previously supported environment variables (~~`FASTIFY_​BODY_​LIMIT, FASTIFY_​DISABLE_​REQUEST_​LOGGING, FASTIFY_​REWRITE_​URL, FASTIFY_​STATIC_​HEADERS, FASTIFY_​TRUST_​PROXY, FASTIFY_​MULTIPART_​ATTACH_​FIELDS_​TO_​BODY`~~) have been completely removed. While this may seem inconvenient for a minor release, the process of migrating your setup to the new configuration approach usually takes less than a minute. This streamlines the code base and documentation, as these features are presumably seldom used.
90
+ **Breaking change**: The previously supported environment variables (`FASTIFY_​BODY_​LIMIT, FASTIFY_​DISABLE_​REQUEST_​LOGGING, FASTIFY_​REWRITE_​URL, FASTIFY_​STATIC_​HEADERS, FASTIFY_​TRUST_​PROXY, FASTIFY_​MULTIPART_​ATTACH_​FIELDS_​TO_​BODY`) have been completely removed. While this may seem inconvenient for a minor release, the process of migrating your setup to the new configuration approach usually takes less than a minute. This streamlines the code base and documentation, as these features are presumably seldom used.
28
91
 
29
92
  To configure Fastify (or a specific plugin), you can now use simple JSON objects which mirror the corresponding Fastify options. Have a look at the linked Fastify documentation for a reference of all existing options:
30
93
 
@@ -73,7 +136,7 @@ Dependency updates: `@types/node@24.10.1`
73
136
 
74
137
  ## 2025-11-10 - Jeasx 2.1.1 released
75
138
 
76
- 🎉 Enhanced configuration for @fastify/static, so you can serve pre-compressed static files (see <https://github.com/fastify/fastify-static?tab=readme-ov-file#precompressed>) from `public` and `dist/browser`. Just run `gzip -rk public dist/browser` as post build for gzipping your static assets. This might be useful if you don't want to run a reverse proxy in front of your Jeasx application and serve compressed files nevertheless. Setting up compression for dynamic content can be wired up in userland via a root guard:
139
+ 🎉 Enhanced configuration for @fastify/static, so you can serve pre-compressed static files (see [fastify docs](https://github.com/fastify/fastify-static?tab=readme-ov-file#precompressed)) from `public` and `dist/browser`. Just run `gzip -rk public dist/browser` as post build for gzipping your static assets. This might be useful if you don't want to run a reverse proxy in front of your Jeasx application and serve compressed files nevertheless. Setting up compression for dynamic content can be wired up in userland via a root guard:
77
140
 
78
141
  ```js
79
142
  import { promisify } from "node:util";
package/cli.js CHANGED
@@ -23,9 +23,7 @@ switch (process.argv[2]) {
23
23
  break;
24
24
 
25
25
  default:
26
- console.info(
27
- `❌ Error: Unknown command '${process.argv[2]}'.\nUse 'jeasx help' for options.`
28
- );
26
+ console.info(`❌ Error: Unknown command '${process.argv[2]}'.\nUse 'jeasx help' for options.`);
29
27
  process.exit(1);
30
28
  }
31
29
 
package/env.js CHANGED
@@ -2,8 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
 
4
4
  /**
5
- * Load environment variables from .env* files
6
- * into process.env in the following order:
5
+ * Load environment variables from .env-files into process.env in the following order:
7
6
  *
8
7
  * 1. .env.<NODE_ENV>.local
9
8
  * 2. .env.<NODE_ENV>
@@ -12,8 +11,7 @@ import { join } from "node:path";
12
11
  * 5. .env.defaults
13
12
  * 6. .env.js
14
13
  *
15
- * If a variable already exists in a previous environment,
16
- * it will be not overwritten at a later stage.
14
+ * .env.js is imported as an ES module and will always overwrite existing variables.
17
15
  */
18
16
  export default async function env() {
19
17
  if (process.loadEnvFile) {
@@ -30,29 +28,18 @@ export default async function env() {
30
28
  }
31
29
  try {
32
30
  const envFile = `file://${join(process.cwd(), ".env.js")}`;
33
- const envObject = stringifyFunctions((await import(envFile)).default);
34
- Object.entries(envObject)
35
- .filter(([key]) => !(key in process.env))
36
- .forEach(([key, value]) => {
37
- process.env[key] =
38
- typeof value === "string" ? value : JSON.stringify(value);
39
- });
40
- } catch (e) {
31
+ const envObject = (await import(envFile)).default;
32
+ Object.entries(envObject).forEach(([key, value]) => {
33
+ try {
34
+ process.env[key] = typeof value === "string" ? value : JSON.stringify(value);
35
+ } catch (error) {
36
+ // JSON.stringify throws TypeError for circular references or BigInts.
37
+ console.error("❌", `"${key}" in .env.js throws`, error);
38
+ }
39
+ });
40
+ return { ...process.env, ...envObject };
41
+ } catch {
41
42
  // ERR_MODULE_NOT_FOUND
43
+ return { ...process.env };
42
44
  }
43
45
  }
44
-
45
- /**
46
- * Convert all functions recursively to strings.
47
- */
48
- function stringifyFunctions(obj) {
49
- for (const key in obj) {
50
- if (typeof obj[key] === "function") {
51
- obj[key] = obj[key].toString();
52
- }
53
- if (typeof obj[key] === "object" && obj[key] !== null) {
54
- stringifyFunctions(obj[key]);
55
- }
56
- }
57
- return obj;
58
- }
package/esbuild.config.js CHANGED
@@ -1,28 +1,40 @@
1
+ import mdx from "@mdx-js/esbuild";
1
2
  import * as esbuild from "esbuild";
2
3
  import env from "./env.js";
3
4
 
4
- await env();
5
+ const ENV = await env();
5
6
 
6
- const BUILD_TIME = `"${Date.now().toString(36)}"`;
7
+ const BUILD_TIME = `"${ENV.BUILD_TIME || Date.now().toString(36)}"`;
7
8
 
8
- const BROWSER_PUBLIC_ENV = Object.keys(process.env)
9
+ const BROWSER_PUBLIC_ENV = Object.keys(ENV)
9
10
  .filter((key) => key.startsWith("BROWSER_PUBLIC_"))
10
11
  .reduce(
11
12
  (env, key) => {
12
- env[`process.env.${key}`] = `"${process.env[key]}"`;
13
+ env[`process.env.${key}`] = `"${ENV[key]}"`;
13
14
  return env;
14
15
  },
15
- { "process.env.BROWSER_PUBLIC_BUILD_TIME": BUILD_TIME }
16
+ { "process.env.BROWSER_PUBLIC_BUILD_TIME": BUILD_TIME },
16
17
  );
17
18
 
18
- const ESBUILD_BROWSER_TARGET = process.env.ESBUILD_BROWSER_TARGET
19
- ? process.env.ESBUILD_BROWSER_TARGET.replace(/\s/g, "").split(",")
20
- : ["chrome130", "edge130", "firefox130", "safari18"];
19
+ const ESBUILD_BROWSER_TARGET = ENV.ESBUILD_BROWSER_TARGET || [
20
+ "chrome130",
21
+ "edge130",
22
+ "firefox130",
23
+ "safari18",
24
+ ];
25
+
26
+ const ESBUILD_MDX_PLUGIN = mdx({
27
+ development: process.env.NODE_ENV === "development",
28
+ jsxImportSource: "jsx-async-runtime",
29
+ elementAttributeNameCase: "html",
30
+ stylePropertyNameCase: "css",
31
+ ...ENV.ESBUILD_MDX_OPTIONS,
32
+ });
21
33
 
22
34
  /** @type esbuild.BuildOptions[] */
23
35
  const buildOptions = [
24
36
  {
25
- entryPoints: ["js", "ts", "jsx", "tsx"].map((ext) => `src/**/[*].${ext}`),
37
+ entryPoints: ["js", "ts", "jsx", "tsx", "mdx"].map((ext) => `src/**/[*].${ext}`),
26
38
  define: {
27
39
  "process.env.BUILD_TIME": BUILD_TIME,
28
40
  },
@@ -38,11 +50,10 @@ const buildOptions = [
38
50
  outdir: "dist/server",
39
51
  platform: "neutral",
40
52
  packages: "external",
53
+ plugins: [ESBUILD_MDX_PLUGIN],
41
54
  },
42
55
  {
43
- entryPoints: ["js", "ts", "jsx", "tsx", "css"].map(
44
- (ext) => `src/**/index.${ext}`
45
- ),
56
+ entryPoints: ["js", "ts", "jsx", "tsx", "css"].map((ext) => `src/**/index.${ext}`),
46
57
  define: BROWSER_PUBLIC_ENV,
47
58
  minify: process.env.NODE_ENV !== "development",
48
59
  logLevel: "info",
@@ -71,6 +82,7 @@ const buildOptions = [
71
82
  "*.woff",
72
83
  "*.woff2",
73
84
  ],
85
+ plugins: [ESBUILD_MDX_PLUGIN],
74
86
  },
75
87
  ];
76
88
 
package/package.json CHANGED
@@ -1,39 +1,40 @@
1
1
  {
2
2
  "name": "jeasx",
3
- "version": "2.2.2",
3
+ "version": "2.3.1",
4
4
  "description": "Jeasx - the ease of JSX with the power of SSR",
5
5
  "keywords": [
6
+ "fastify",
6
7
  "jsx",
7
- "ssr",
8
8
  "node",
9
- "fastify"
9
+ "ssr"
10
10
  ],
11
- "license": "MIT",
12
11
  "homepage": "https://www.jeasx.dev",
12
+ "license": "MIT",
13
+ "author": {
14
+ "name": "Maik Jablonski",
15
+ "email": "mail@jeasx.dev"
16
+ },
13
17
  "repository": {
14
18
  "type": "git",
15
19
  "url": "https://github.com/jeasx/jeasx.git"
16
20
  },
17
- "author": {
18
- "name": "Maik Jablonski",
19
- "email": "mail@jeasx.dev"
21
+ "bin": {
22
+ "jeasx": "cli.js"
20
23
  },
21
24
  "type": "module",
22
25
  "main": "server.js",
23
- "bin": {
24
- "jeasx": "cli.js"
26
+ "scripts": {
27
+ "build": "esbuild --platform=node --format=esm --sourcemap=linked --sources-content=false --outdir=. serverless.ts"
25
28
  },
26
29
  "dependencies": {
27
30
  "@fastify/cookie": "11.0.2",
28
31
  "@fastify/formbody": "8.0.2",
29
- "@fastify/multipart": "9.3.0",
32
+ "@fastify/multipart": "9.4.0",
30
33
  "@fastify/static": "9.0.0",
31
- "@types/node": "24.10.9",
34
+ "@mdx-js/esbuild": "3.1.1",
35
+ "@types/node": "24.10.10",
32
36
  "esbuild": "0.27.2",
33
- "fastify": "5.7.1",
37
+ "fastify": "5.7.4",
34
38
  "jsx-async-runtime": "2.0.2"
35
- },
36
- "scripts": {
37
- "build": "esbuild --platform=node --format=esm --sourcemap=linked --sources-content=false --outdir=. serverless.ts"
38
39
  }
39
40
  }
package/serverless.js CHANGED
@@ -8,34 +8,26 @@ import { stat } from "node:fs/promises";
8
8
  import { freemem } from "node:os";
9
9
  import { join } from "node:path";
10
10
  import env from "./env.js";
11
- await env();
11
+ const ENV = await env();
12
12
  const CWD = process.cwd();
13
13
  const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
14
14
  const JEASX_ROUTE_CACHE_LIMIT = Math.floor(freemem() / 1024 / 1024);
15
15
  var serverless_default = Fastify({
16
16
  logger: true,
17
- ...jsonToOptions(process.env.FASTIFY_SERVER_OPTIONS)
17
+ ...ENV.FASTIFY_SERVER_OPTIONS
18
18
  }).register(fastifyCookie, {
19
- ...jsonToOptions(
20
- process.env.FASTIFY_COOKIE_OPTIONS
21
- )
19
+ ...ENV.FASTIFY_COOKIE_OPTIONS
22
20
  }).register(fastifyFormbody, {
23
- ...jsonToOptions(
24
- process.env.FASTIFY_FORMBODY_OPTIONS
25
- )
21
+ ...ENV.FASTIFY_FORMBODY_OPTIONS
26
22
  }).register(fastifyMultipart, {
27
23
  attachFieldsToBody: "keyValues",
28
- ...jsonToOptions(
29
- process.env.FASTIFY_MULTIPART_OPTIONS
30
- )
24
+ ...ENV.FASTIFY_MULTIPART_OPTIONS
31
25
  }).register(fastifyStatic, {
32
26
  root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
33
27
  prefix: "/",
34
28
  wildcard: false,
35
29
  preCompressed: true,
36
- ...jsonToOptions(
37
- process.env.FASTIFY_STATIC_OPTIONS
38
- )
30
+ ...ENV.FASTIFY_STATIC_OPTIONS
39
31
  }).decorateRequest("route", "").decorateRequest("path", "").addHook("onRequest", async (request, reply) => {
40
32
  reply.header("Content-Type", "text/html; charset=utf-8");
41
33
  const index = request.url.indexOf("?");
@@ -48,19 +40,6 @@ var serverless_default = Fastify({
48
40
  throw error;
49
41
  }
50
42
  });
51
- function jsonToOptions(json) {
52
- const options = JSON.parse(json || "{}");
53
- for (const key in options) {
54
- if (typeof options[key] === "string" && options[key].includes("=>")) {
55
- try {
56
- options[key] = new Function(`return ${options[key]}`)();
57
- } catch (error) {
58
- console.warn("\u26A0\uFE0F", error);
59
- }
60
- }
61
- }
62
- return options;
63
- }
64
43
  const modules = /* @__PURE__ */ new Map();
65
44
  async function handler(request, reply) {
66
45
  let response;
@@ -154,9 +133,7 @@ function generateEdges(path) {
154
133
  const edges = [];
155
134
  if (path) {
156
135
  const lastSegment = path.lastIndexOf("/") + 1;
157
- edges.push(
158
- `${path.substring(0, lastSegment)}[${path.substring(lastSegment)}]`
159
- );
136
+ edges.push(`${path.substring(0, lastSegment)}[${path.substring(lastSegment)}]`);
160
137
  }
161
138
  edges.push(`${path}/[index]`);
162
139
  return edges;
package/serverless.js.map CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["serverless.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": []
6
6
  }
package/serverless.ts CHANGED
@@ -2,18 +2,14 @@ import fastifyCookie, { FastifyCookieOptions } from "@fastify/cookie";
2
2
  import fastifyFormbody, { FastifyFormbodyOptions } from "@fastify/formbody";
3
3
  import fastifyMultipart, { FastifyMultipartOptions } from "@fastify/multipart";
4
4
  import fastifyStatic, { FastifyStaticOptions } from "@fastify/static";
5
- import Fastify, {
6
- FastifyReply,
7
- FastifyRequest,
8
- FastifyServerOptions
9
- } from "fastify";
5
+ import Fastify, { FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
10
6
  import { jsxToString } from "jsx-async-runtime";
11
7
  import { stat } from "node:fs/promises";
12
8
  import { freemem } from "node:os";
13
9
  import { join } from "node:path";
14
10
  import env from "./env.js";
15
11
 
16
- await env();
12
+ const ENV = await env();
17
13
 
18
14
  const CWD = process.cwd();
19
15
  const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
@@ -29,32 +25,24 @@ declare module "fastify" {
29
25
  // Create and export a Fastify app instance
30
26
  export default Fastify({
31
27
  logger: true,
32
- ...(jsonToOptions(process.env.FASTIFY_SERVER_OPTIONS) as FastifyServerOptions)
28
+ ...(ENV.FASTIFY_SERVER_OPTIONS as FastifyServerOptions),
33
29
  })
34
30
  .register(fastifyCookie, {
35
- ...(jsonToOptions(
36
- process.env.FASTIFY_COOKIE_OPTIONS
37
- ) as FastifyCookieOptions)
31
+ ...(ENV.FASTIFY_COOKIE_OPTIONS as FastifyCookieOptions),
38
32
  })
39
33
  .register(fastifyFormbody, {
40
- ...(jsonToOptions(
41
- process.env.FASTIFY_FORMBODY_OPTIONS
42
- ) as FastifyFormbodyOptions)
34
+ ...(ENV.FASTIFY_FORMBODY_OPTIONS as FastifyFormbodyOptions),
43
35
  })
44
36
  .register(fastifyMultipart, {
45
37
  attachFieldsToBody: "keyValues",
46
- ...(jsonToOptions(
47
- process.env.FASTIFY_MULTIPART_OPTIONS
48
- ) as FastifyMultipartOptions)
38
+ ...(ENV.FASTIFY_MULTIPART_OPTIONS as FastifyMultipartOptions),
49
39
  })
50
40
  .register(fastifyStatic, {
51
41
  root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
52
42
  prefix: "/",
53
43
  wildcard: false,
54
44
  preCompressed: true,
55
- ...(jsonToOptions(
56
- process.env.FASTIFY_STATIC_OPTIONS
57
- ) as FastifyStaticOptions)
45
+ ...(ENV.FASTIFY_STATIC_OPTIONS as FastifyStaticOptions),
58
46
  })
59
47
  .decorateRequest("route", "")
60
48
  .decorateRequest("path", "")
@@ -74,23 +62,6 @@ export default Fastify({
74
62
  }
75
63
  });
76
64
 
77
- /**
78
- * Parses JSON and instantiates all stringified functions.
79
- */
80
- function jsonToOptions(json: string) {
81
- const options = JSON.parse(json || "{}");
82
- for (const key in options) {
83
- if (typeof options[key] === "string" && options[key].includes("=>")) {
84
- try {
85
- options[key] = new Function(`return ${options[key]}`)();
86
- } catch (error) {
87
- console.warn("⚠️", error);
88
- }
89
- }
90
- }
91
- return options;
92
- }
93
-
94
65
  // Cache for resolved route modules, 'null' means no module exists.
95
66
  const modules = new Map<string, { default: Function }>();
96
67
 
@@ -157,7 +128,7 @@ async function handler(request: FastifyRequest, reply: FastifyReply) {
157
128
  response = await module.default.call(context, {
158
129
  request,
159
130
  reply,
160
- ...(typeof response === "object" ? response : {})
131
+ ...(typeof response === "object" ? response : {}),
161
132
  });
162
133
 
163
134
  if (reply.sent) {
@@ -169,11 +140,7 @@ async function handler(request: FastifyRequest, reply: FastifyReply) {
169
140
  reply.status(404);
170
141
  }
171
142
  break;
172
- } else if (
173
- typeof response === "string" ||
174
- Buffer.isBuffer(response) ||
175
- isJSX(response)
176
- ) {
143
+ } else if (typeof response === "string" || Buffer.isBuffer(response) || isJSX(response)) {
177
144
  break;
178
145
  } else if (
179
146
  route.endsWith("/[...guard]") &&
@@ -215,7 +182,7 @@ function generateRoutes(path: string): string[] {
215
182
  .map((segment) => `${segment}/[...guard]`),
216
183
  ...edges.map((edge) => `${edge}`),
217
184
  ...segments.map((segment) => `${segment}/[...path]`),
218
- ...segments.map((segment) => `${segment}/[404]`)
185
+ ...segments.map((segment) => `${segment}/[404]`),
219
186
  ];
220
187
  }
221
188
 
@@ -247,9 +214,7 @@ function generateEdges(path: string): string[] {
247
214
  const edges = [];
248
215
  if (path) {
249
216
  const lastSegment = path.lastIndexOf("/") + 1;
250
- edges.push(
251
- `${path.substring(0, lastSegment)}[${path.substring(lastSegment)}]`
252
- );
217
+ edges.push(`${path.substring(0, lastSegment)}[${path.substring(lastSegment)}]`);
253
218
  }
254
219
  edges.push(`${path}/[index]`);
255
220
  return edges;
@@ -266,12 +231,11 @@ function isJSX(obj: unknown): boolean {
266
231
  * Renders JSX to string and applies optional response handler.
267
232
  */
268
233
  async function renderJSX(context: object, response: unknown) {
269
- const payload =
270
- isJSX(response) ? await jsxToString.call(context, response) : response;
234
+ const payload = isJSX(response) ? await jsxToString.call(context, response) : response;
271
235
 
272
236
  // Post-process the payload with an optional response handler
273
237
  const responseHandler = context["responseHandler"];
274
- return typeof responseHandler === "function" ?
275
- await responseHandler.call(context, payload)
238
+ return typeof responseHandler === "function"
239
+ ? await responseHandler.call(context, payload)
276
240
  : payload;
277
241
  }