jeasx 2.3.2 β 2.4.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 +76 -0
- package/env.js +11 -1
- package/esbuild.config.js +5 -27
- package/package.json +2 -3
- package/serverless.js +39 -33
- package/serverless.js.map +2 -2
- package/serverless.ts +69 -45
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,81 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-03-02 - Jeasx 2.4.1 released
|
|
4
|
+
|
|
5
|
+
π This release introduces route prop inheritance from guards. Guards can return objects whose entries are used as additional props for your routes. Previously, only props from the closest guard were used. With this update, props from all guards along the route are collected and passed down. If multiple guards provide props with the same key, the value from the guard nearest to the route takes precedence and overwrites earlier ones.
|
|
6
|
+
|
|
7
|
+
Dependency updates: `@types/node@25.3.3`
|
|
8
|
+
|
|
9
|
+
## 2026-02-20 - Jeasx 2.4.0 released
|
|
10
|
+
|
|
11
|
+
π This release is both a step forward and a step back: the recently introduced support for MDX has been removed from the core project. Jeasx aims to keep its core as lean as possible, so this change aligns with the project's overall goals. Since MDX is not essential for every Jeasx website or application, it makes sense to move it out of the core.
|
|
12
|
+
|
|
13
|
+
Another key goal of Jeasx is to empower users to implement their own custom solutions in userland, providing the right tools to do so. In short, while MDX remains a fantastic technology for content-driven websites, Jeasx now lets you configure MDX support yourself through a much improved configuration system for its base technologies like esbuild and Fastify.
|
|
14
|
+
|
|
15
|
+
For esbuild, two new configuration options are available: `ESBUILD_SERVER_OPTIONS` and `ESBUILD_BROWSER_OPTIONS`. These can be defined as functions in `.env.js` that return additional configuration settings for esbuild.
|
|
16
|
+
|
|
17
|
+
Why use functions instead of plain objects for the configuration? Because using functions allows configurations to be created lazily - only when needed - which is especially helpful for more complex setups over time.
|
|
18
|
+
|
|
19
|
+
If you want to use MDX with Jeasx, simply run `npm install @mdx-js/esbuild` and add the configuration below to `ESBUILD_SERVER_OPTIONS` in `.env.js`.
|
|
20
|
+
|
|
21
|
+
If you've used `ESBUILD_BROWSER_TARGET` in the past, you have to move this configuration to `ESBUILD_BROWSER_OPTIONS` as shown below.
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
24
|
+
import mdx from "@mdx-js/esbuild";
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
/** @type {() => import("esbuild").BuildOptions} */
|
|
28
|
+
ESBUILD_SERVER_OPTIONS: () => ({
|
|
29
|
+
plugins: [
|
|
30
|
+
mdx({
|
|
31
|
+
development: process.env.NODE_ENV === "development",
|
|
32
|
+
jsxImportSource: "jsx-async-runtime",
|
|
33
|
+
elementAttributeNameCase: "html",
|
|
34
|
+
stylePropertyNameCase: "css"
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
}),
|
|
38
|
+
|
|
39
|
+
/** @type {() => import("esbuild").BuildOptions} */
|
|
40
|
+
ESBUILD_BROWSER_OPTIONS: () => ({
|
|
41
|
+
target: ["chrome130", "edge130", "firefox130", "safari18"]
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The existing configuration options for Fastify (such as `FASTIFY_SERVER_OPTIONS`, `FASTIFY_COOKIE_OPTIONS`, `FASTIFY_MULTIPART_OPTIONS`, `FASTIFY_STATIC_OPTIONS`) now require a minor change: they must be defined as functions instead of plain objects.
|
|
47
|
+
|
|
48
|
+
Additionally, you can now customize the fastify server instance using the optional `FASTIFY_SERVER` function. This function receives the created server instance and should return the modified version. This feature is especially useful when integrating existing Fastify plugins like `@fastify/compress`, as demonstrated below.
|
|
49
|
+
|
|
50
|
+
```jsx
|
|
51
|
+
import fastifyCompress from "@fastify/compress";
|
|
52
|
+
|
|
53
|
+
const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
|
|
54
|
+
|
|
55
|
+
export default {
|
|
56
|
+
/** @type {(fastify: import("fastify").FastifyInstance) => import("fastify").FastifyInstance} */
|
|
57
|
+
FASTIFY_SERVER: (fastify) => fastify.register(fastifyCompress),
|
|
58
|
+
|
|
59
|
+
/** @type {() => import("fastify").FastifyServerOptions} */
|
|
60
|
+
FASTIFY_SERVER_OPTIONS: () => ({
|
|
61
|
+
disableRequestLogging: NODE_ENV_IS_DEVELOPMENT,
|
|
62
|
+
bodyLimit: 1024 * 1024
|
|
63
|
+
}),
|
|
64
|
+
|
|
65
|
+
/** @type {() => import("@fastify/static").FastifyStaticOptions} */
|
|
66
|
+
FASTIFY_STATIC_OPTIONS: () => ({
|
|
67
|
+
immutable: !NODE_ENV_IS_DEVELOPMENT,
|
|
68
|
+
maxAge: NODE_ENV_IS_DEVELOPMENT ? 0 : "365d"
|
|
69
|
+
})
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Another notable change is that the fallback content-type (`text/html`) for routes is now set as late as possible. This means you can return plain JavaScript objects from routes, which will be automatically sent as `application/json` by default - without needing to explicitly specify the content-type in your code. This update brings Jeasx in line with Fastifyβs default behavior.
|
|
74
|
+
|
|
75
|
+
Additionally, you can now define routes directly from simple `*.json` or `*.txt` files - perfect for creating static endpoints like a health check or a `robots.txt` file right in your routes folder.
|
|
76
|
+
|
|
77
|
+
Dependency updates: `@types/node@25.3.0`
|
|
78
|
+
|
|
3
79
|
## 2026-02-12 - Jeasx 2.3.2 released
|
|
4
80
|
|
|
5
81
|
π Upgraded to @types/node@25, enabling seamless development with Node 25 while maintaining compatibility for Node 24 users.
|
package/env.js
CHANGED
|
@@ -31,7 +31,17 @@ export default async function env() {
|
|
|
31
31
|
const envObject = (await import(envFile)).default;
|
|
32
32
|
Object.entries(envObject).forEach(([key, value]) => {
|
|
33
33
|
try {
|
|
34
|
-
|
|
34
|
+
switch (typeof value) {
|
|
35
|
+
case "string":
|
|
36
|
+
process.env[key] = value;
|
|
37
|
+
break;
|
|
38
|
+
case "function":
|
|
39
|
+
process.env[key] = value.toString();
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
process.env[key] = JSON.stringify(value);
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
35
45
|
} catch (error) {
|
|
36
46
|
// JSON.stringify throws TypeError for circular references or BigInts.
|
|
37
47
|
console.error("β", `"${key}" in .env.js throws`, error);
|
package/esbuild.config.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import mdx from "@mdx-js/esbuild";
|
|
2
1
|
import * as esbuild from "esbuild";
|
|
3
2
|
import env from "./env.js";
|
|
4
3
|
|
|
@@ -16,33 +15,15 @@ const BROWSER_PUBLIC_ENV = Object.keys(ENV)
|
|
|
16
15
|
{ "process.env.BROWSER_PUBLIC_BUILD_TIME": BUILD_TIME },
|
|
17
16
|
);
|
|
18
17
|
|
|
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
|
-
});
|
|
33
|
-
|
|
34
18
|
/** @type esbuild.BuildOptions[] */
|
|
35
19
|
const buildOptions = [
|
|
36
20
|
{
|
|
37
|
-
entryPoints: ["
|
|
21
|
+
entryPoints: ["src/**/[*].*"],
|
|
38
22
|
define: {
|
|
39
23
|
"process.env.BUILD_TIME": BUILD_TIME,
|
|
40
24
|
},
|
|
41
25
|
minify: process.env.NODE_ENV !== "development",
|
|
42
26
|
logLevel: "info",
|
|
43
|
-
logOverride: {
|
|
44
|
-
"empty-glob": "silent",
|
|
45
|
-
},
|
|
46
27
|
color: true,
|
|
47
28
|
bundle: true,
|
|
48
29
|
sourcemap: process.sourceMapsEnabled,
|
|
@@ -50,16 +31,13 @@ const buildOptions = [
|
|
|
50
31
|
outdir: "dist/server",
|
|
51
32
|
platform: "neutral",
|
|
52
33
|
packages: "external",
|
|
53
|
-
|
|
34
|
+
...ENV.ESBUILD_SERVER_OPTIONS?.(),
|
|
54
35
|
},
|
|
55
36
|
{
|
|
56
|
-
entryPoints: ["
|
|
37
|
+
entryPoints: ["src/**/index.*"],
|
|
57
38
|
define: BROWSER_PUBLIC_ENV,
|
|
58
39
|
minify: process.env.NODE_ENV !== "development",
|
|
59
40
|
logLevel: "info",
|
|
60
|
-
logOverride: {
|
|
61
|
-
"empty-glob": "silent",
|
|
62
|
-
},
|
|
63
41
|
color: true,
|
|
64
42
|
bundle: true,
|
|
65
43
|
sourcemap: process.sourceMapsEnabled,
|
|
@@ -67,7 +45,7 @@ const buildOptions = [
|
|
|
67
45
|
outdir: "dist/browser",
|
|
68
46
|
platform: "browser",
|
|
69
47
|
format: "esm",
|
|
70
|
-
target:
|
|
48
|
+
target: ["chrome130", "edge130", "firefox130", "safari18"],
|
|
71
49
|
external: [
|
|
72
50
|
"*.avif",
|
|
73
51
|
"*.gif",
|
|
@@ -82,7 +60,7 @@ const buildOptions = [
|
|
|
82
60
|
"*.woff",
|
|
83
61
|
"*.woff2",
|
|
84
62
|
],
|
|
85
|
-
|
|
63
|
+
...ENV.ESBUILD_BROWSER_OPTIONS?.(),
|
|
86
64
|
},
|
|
87
65
|
];
|
|
88
66
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jeasx",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Jeasx - the ease of JSX with the power of SSR",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fastify",
|
|
@@ -31,8 +31,7 @@
|
|
|
31
31
|
"@fastify/formbody": "8.0.2",
|
|
32
32
|
"@fastify/multipart": "9.4.0",
|
|
33
33
|
"@fastify/static": "9.0.0",
|
|
34
|
-
"@
|
|
35
|
-
"@types/node": "25.2.3",
|
|
34
|
+
"@types/node": "25.3.3",
|
|
36
35
|
"esbuild": "0.27.3",
|
|
37
36
|
"fastify": "5.7.4",
|
|
38
37
|
"jsx-async-runtime": "2.0.2"
|
package/serverless.js
CHANGED
|
@@ -2,7 +2,7 @@ import fastifyCookie from "@fastify/cookie";
|
|
|
2
2
|
import fastifyFormbody from "@fastify/formbody";
|
|
3
3
|
import fastifyMultipart from "@fastify/multipart";
|
|
4
4
|
import fastifyStatic from "@fastify/static";
|
|
5
|
-
import
|
|
5
|
+
import fastify from "fastify";
|
|
6
6
|
import { jsxToString } from "jsx-async-runtime";
|
|
7
7
|
import { stat } from "node:fs/promises";
|
|
8
8
|
import { freemem } from "node:os";
|
|
@@ -12,38 +12,46 @@ 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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
15
|
+
const FASTIFY_SERVER = ENV.FASTIFY_SERVER ?? ((fastify2) => fastify2);
|
|
16
|
+
var serverless_default = FASTIFY_SERVER(
|
|
17
|
+
fastify({
|
|
18
|
+
logger: true,
|
|
19
|
+
...ENV.FASTIFY_SERVER_OPTIONS?.()
|
|
20
|
+
})
|
|
21
|
+
).register((fastify2) => {
|
|
22
|
+
fastify2.register(fastifyCookie, {
|
|
23
|
+
...ENV.FASTIFY_COOKIE_OPTIONS?.()
|
|
24
|
+
}).register(fastifyFormbody, {
|
|
25
|
+
...ENV.FASTIFY_FORMBODY_OPTIONS?.()
|
|
26
|
+
}).register(fastifyMultipart, {
|
|
27
|
+
attachFieldsToBody: "keyValues",
|
|
28
|
+
...ENV.FASTIFY_MULTIPART_OPTIONS?.()
|
|
29
|
+
}).register(fastifyStatic, {
|
|
30
|
+
root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
|
|
31
|
+
prefix: "/",
|
|
32
|
+
wildcard: false,
|
|
33
|
+
...ENV.FASTIFY_STATIC_OPTIONS?.()
|
|
34
|
+
}).decorateRequest("route", "").decorateRequest("path", "").addHook("onRequest", async (request) => {
|
|
35
|
+
const index = request.url.indexOf("?");
|
|
36
|
+
request.path = index === -1 ? request.url : request.url.slice(0, index);
|
|
37
|
+
}).all("*", async (request, reply) => {
|
|
38
|
+
try {
|
|
39
|
+
const payload = await handler(request, reply);
|
|
40
|
+
if (reply.getHeader("content-type") === void 0 && (typeof payload === "string" || Buffer.isBuffer(payload))) {
|
|
41
|
+
reply.type("text/html; charset=utf-8");
|
|
42
|
+
}
|
|
43
|
+
return payload;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("\u274C", error);
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
42
49
|
});
|
|
43
50
|
const modules = /* @__PURE__ */ new Map();
|
|
44
51
|
async function handler(request, reply) {
|
|
45
52
|
let response;
|
|
46
53
|
const context = {};
|
|
54
|
+
const props = { request, reply };
|
|
47
55
|
try {
|
|
48
56
|
for (const route of generateRoutes(request.path)) {
|
|
49
57
|
let module = modules.get(route);
|
|
@@ -79,11 +87,8 @@ async function handler(request, reply) {
|
|
|
79
87
|
}
|
|
80
88
|
}
|
|
81
89
|
request.route = route;
|
|
82
|
-
response =
|
|
83
|
-
|
|
84
|
-
reply,
|
|
85
|
-
...typeof response === "object" ? response : {}
|
|
86
|
-
});
|
|
90
|
+
response = // Call functions with 'this' context and props as parameters
|
|
91
|
+
typeof module.default === "function" ? await module.default.call(context, props) : module.default;
|
|
87
92
|
if (reply.sent) {
|
|
88
93
|
return;
|
|
89
94
|
} else if (route.endsWith("/[404]")) {
|
|
@@ -94,6 +99,7 @@ async function handler(request, reply) {
|
|
|
94
99
|
} else if (typeof response === "string" || Buffer.isBuffer(response) || isJSX(response)) {
|
|
95
100
|
break;
|
|
96
101
|
} else if (route.endsWith("/[...guard]") && (response === void 0 || typeof response === "object")) {
|
|
102
|
+
Object.assign(props, response);
|
|
97
103
|
continue;
|
|
98
104
|
} else if (reply.statusCode === 404) {
|
|
99
105
|
continue;
|
package/serverless.js.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["serverless.ts"],
|
|
4
|
-
"mappings": "AAAA,OAAO,mBAA6C;AACpD,OAAO,qBAAiD;AACxD,OAAO,sBAAmD;AAC1D,OAAO,mBAA6C;AACpD,OAAO,
|
|
5
|
-
"names": []
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["fastify"]
|
|
6
6
|
}
|
package/serverless.ts
CHANGED
|
@@ -2,7 +2,12 @@ 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
|
|
5
|
+
import fastify, {
|
|
6
|
+
FastifyInstance,
|
|
7
|
+
FastifyReply,
|
|
8
|
+
FastifyRequest,
|
|
9
|
+
FastifyServerOptions,
|
|
10
|
+
} from "fastify";
|
|
6
11
|
import { jsxToString } from "jsx-async-runtime";
|
|
7
12
|
import { stat } from "node:fs/promises";
|
|
8
13
|
import { freemem } from "node:os";
|
|
@@ -22,44 +27,59 @@ declare module "fastify" {
|
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
...(ENV.
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
30
|
+
// Enhance Fastify server from userland
|
|
31
|
+
const FASTIFY_SERVER = (ENV.FASTIFY_SERVER ?? ((fastify) => fastify)) as (
|
|
32
|
+
fastify: FastifyInstance,
|
|
33
|
+
) => FastifyInstance;
|
|
34
|
+
|
|
35
|
+
// Create and export a Fastify instance
|
|
36
|
+
export default FASTIFY_SERVER(
|
|
37
|
+
fastify({
|
|
38
|
+
logger: true,
|
|
39
|
+
...(ENV.FASTIFY_SERVER_OPTIONS?.() as FastifyServerOptions),
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
// Create encapsulation context
|
|
43
|
+
.register((fastify) => {
|
|
44
|
+
fastify
|
|
45
|
+
.register(fastifyCookie, {
|
|
46
|
+
...(ENV.FASTIFY_COOKIE_OPTIONS?.() as FastifyCookieOptions),
|
|
47
|
+
})
|
|
48
|
+
.register(fastifyFormbody, {
|
|
49
|
+
...(ENV.FASTIFY_FORMBODY_OPTIONS?.() as FastifyFormbodyOptions),
|
|
50
|
+
})
|
|
51
|
+
.register(fastifyMultipart, {
|
|
52
|
+
attachFieldsToBody: "keyValues",
|
|
53
|
+
...(ENV.FASTIFY_MULTIPART_OPTIONS?.() as FastifyMultipartOptions),
|
|
54
|
+
})
|
|
55
|
+
.register(fastifyStatic, {
|
|
56
|
+
root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
|
|
57
|
+
prefix: "/",
|
|
58
|
+
wildcard: false,
|
|
59
|
+
...(ENV.FASTIFY_STATIC_OPTIONS?.() as FastifyStaticOptions),
|
|
60
|
+
})
|
|
61
|
+
.decorateRequest("route", "")
|
|
62
|
+
.decorateRequest("path", "")
|
|
63
|
+
.addHook("onRequest", async (request) => {
|
|
64
|
+
// Extract path from url
|
|
65
|
+
const index = request.url.indexOf("?");
|
|
66
|
+
request.path = index === -1 ? request.url : request.url.slice(0, index);
|
|
67
|
+
})
|
|
68
|
+
.all("*", async (request: FastifyRequest, reply: FastifyReply) => {
|
|
69
|
+
try {
|
|
70
|
+
const payload = await handler(request, reply);
|
|
71
|
+
if (
|
|
72
|
+
reply.getHeader("content-type") === undefined &&
|
|
73
|
+
(typeof payload === "string" || Buffer.isBuffer(payload))
|
|
74
|
+
) {
|
|
75
|
+
reply.type("text/html; charset=utf-8");
|
|
76
|
+
}
|
|
77
|
+
return payload;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error("β", error);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
63
83
|
});
|
|
64
84
|
|
|
65
85
|
// Cache for resolved route modules, 'null' means no module exists.
|
|
@@ -74,6 +94,9 @@ async function handler(request: FastifyRequest, reply: FastifyReply) {
|
|
|
74
94
|
// Global context object for route handlers
|
|
75
95
|
const context = {};
|
|
76
96
|
|
|
97
|
+
// Default props for route handlers
|
|
98
|
+
const props = { request, reply };
|
|
99
|
+
|
|
77
100
|
try {
|
|
78
101
|
// Execute route handlers for current request
|
|
79
102
|
for (const route of generateRoutes(request.path)) {
|
|
@@ -124,12 +147,11 @@ async function handler(request: FastifyRequest, reply: FastifyReply) {
|
|
|
124
147
|
// Store current route in request
|
|
125
148
|
request.route = route;
|
|
126
149
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
});
|
|
150
|
+
response =
|
|
151
|
+
// Call functions with 'this' context and props as parameters
|
|
152
|
+
typeof module.default === "function"
|
|
153
|
+
? await module.default.call(context, props)
|
|
154
|
+
: module.default; // otherwise return default export
|
|
133
155
|
|
|
134
156
|
if (reply.sent) {
|
|
135
157
|
return;
|
|
@@ -146,6 +168,8 @@ async function handler(request: FastifyRequest, reply: FastifyReply) {
|
|
|
146
168
|
route.endsWith("/[...guard]") &&
|
|
147
169
|
(response === undefined || typeof response === "object")
|
|
148
170
|
) {
|
|
171
|
+
// Add object entries from guard to props
|
|
172
|
+
Object.assign(props, response);
|
|
149
173
|
continue;
|
|
150
174
|
} else if (reply.statusCode === 404) {
|
|
151
175
|
continue;
|