jeasx 2.1.0 → 2.2.0

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,5 +1,83 @@
1
1
  # Changelog
2
2
 
3
+ ## 2025-12-01 - Jeasx 2.2.0 released
4
+
5
+ 🎉 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.
6
+
7
+ **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.
8
+
9
+ 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:
10
+
11
+ - [`FASTIFY_SERVER_OPTIONS`](<https://fastify.dev/docs/latest/Reference/Server/>)
12
+ - [`FASTIFY_COOKIE_OPTIONS`](<https://github.com/fastify/fastify-cookie#options>)
13
+ - [`FASTIFY_FORMBODY_OPTIONS`](<https://github.com/fastify/fastify-formbody#options>)
14
+ - [`FASTIFY_MULTIPART_OPTIONS`](<https://github.com/fastify/fastify-multipart#options>)
15
+ - [`FASTIFY_STATIC_OPTIONS`](<https://github.com/fastify/fastify-static#options>)
16
+
17
+ To optimise the developer experience, it is highly recommended that you use the recently introduced `.env.js` file to provide these configuration options. Alternatively, you can also provide them via `.env` or your process environment. Jeasx comes with a minimal set of reasonable [Fastify defaults](https://github.com/jeasx/jeasx/blob/main/serverless.ts), but you can also overwrite them if necessary.
18
+
19
+ Some Fastify options, such as `rewriteUrl` or `setHeaders`, take a function as a parameter. Jeasx supports this use case by deserialising the stringified function code when the server starts up.
20
+
21
+ ### Example configuration
22
+
23
+ ```js
24
+ const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
25
+
26
+ export default {
27
+ /** @type import("fastify").FastifyServerOptions */
28
+ FASTIFY_SERVER_OPTIONS: {
29
+ disableRequestLogging: NODE_ENV_IS_DEVELOPMENT,
30
+ bodyLimit: 2 * 1024 * 1024,
31
+ rewriteUrl: (req) => String(req.url).replace(/^\/jeasx/, ""),
32
+ },
33
+
34
+ /** @type import("@fastify/static").FastifyStaticOptions */
35
+ FASTIFY_STATIC_OPTIONS: {
36
+ maxAge: NODE_ENV_IS_DEVELOPMENT ? 0 : "365d",
37
+ },
38
+
39
+ /** @type import("@fastify/cookie").FastifyCookieOptions */
40
+ // FASTIFY_COOKIE_OPTIONS: {},
41
+
42
+ /** @type import("@fastify/formbody").FastifyFormbodyOptions */
43
+ // FASTIFY_FORMBODY_OPTIONS: {},
44
+
45
+ /** @type import("@fastify/multipart").FastifyMultipartOptions */
46
+ // FASTIFY_MULTIPART_OPTIONS: {},
47
+ };
48
+ ```
49
+
50
+ Another improvement has been made by introducing an automatic approach to determine the maximum size of the internal route cache. Depending on the amount of free memory available at startup, the maximum number of cache entries is calculated. This approach strikes a balance, ensuring the cache is large enough for large-scale projects while keeping maximum memory consumption within reasonable limits given the available resources. This means that you no longer need to worry about providing ~~`JEASX_ROUTE_CACHE_LIMIT`~~ via the environment.
51
+
52
+ Dependency updates: `@types/node@24.10.1`
53
+
54
+ ## 2025-11-10 - Jeasx 2.1.1 released
55
+
56
+ 🎉 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:
57
+
58
+ ```js
59
+ import { promisify } from "node:util";
60
+ import { gzip } from "node:zlib";
61
+
62
+ export default function ({ request, reply }) {
63
+ this.responseHandler = (payload) => {
64
+ if (
65
+ typeof payload === "string" &&
66
+ request.headers["accept-encoding"]?.includes("gzip")
67
+ ) {
68
+ reply.header("content-encoding", "gzip");
69
+ return promisify(gzip)(payload);
70
+ } else {
71
+ return payload;
72
+ }
73
+ };
74
+ }
75
+ ```
76
+
77
+ Updated `moduleResolution` to `bundler` in `tsconfig.json`.
78
+
79
+ Dependency updates: `jsx-async-runtime@2.0.1`, `fastify@5.6.2`, `esbuild@0.27.0`, `@types/node@24.9.2`
80
+
3
81
  ## 2025-10-28 - Jeasx 2.1.0 released
4
82
 
5
83
  🎉 Environment vars can now be loaded from a JavaScript file (`.env.js`) additionally to existing .env-files. This allows enhanced environment setups depending on your workflows.
package/env.js CHANGED
@@ -30,23 +30,29 @@ export default async function env() {
30
30
  }
31
31
  try {
32
32
  const envFile = `file://${join(process.cwd(), ".env.js")}`;
33
- const envObject = (await import(envFile)).default;
34
- Object.entries(envObject).forEach(([key, value]) => {
35
- if (!(key in process.env)) {
36
- switch (typeof value) {
37
- case "string":
38
- process.env[key] = value;
39
- break;
40
- case "function":
41
- process.env[key] = value.toString();
42
- break;
43
- default:
44
- process.env[key] = JSON.stringify(value);
45
- break;
46
- }
47
- }
48
- });
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
+ });
49
40
  } catch (e) {
50
41
  // ERR_MODULE_NOT_FOUND
51
42
  }
52
43
  }
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jeasx",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Jeasx - the ease of JSX with the power of SSR",
5
5
  "keywords": [
6
6
  "jsx",
@@ -28,10 +28,10 @@
28
28
  "@fastify/formbody": "8.0.2",
29
29
  "@fastify/multipart": "9.3.0",
30
30
  "@fastify/static": "8.3.0",
31
- "@types/node": "24.9.1",
32
- "esbuild": "0.25.11",
33
- "fastify": "5.6.1",
34
- "jsx-async-runtime": "2.0.0"
31
+ "@types/node": "24.10.1",
32
+ "esbuild": "0.27.0",
33
+ "fastify": "5.6.2",
34
+ "jsx-async-runtime": "2.0.1"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "esbuild --platform=node --format=esm --sourcemap=linked --sources-content=false --outdir=. serverless.ts"
package/serverless.js CHANGED
@@ -5,41 +5,39 @@ import fastifyStatic from "@fastify/static";
5
5
  import Fastify from "fastify";
6
6
  import { jsxToString } from "jsx-async-runtime";
7
7
  import { stat } from "node:fs/promises";
8
+ import { freemem } from "node:os";
8
9
  import { join } from "node:path";
9
10
  import env from "./env.js";
10
11
  await env();
11
- const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
12
12
  const CWD = process.cwd();
13
- const FASTIFY_STATIC_HEADERS = process.env.FASTIFY_STATIC_HEADERS && JSON.parse(process.env.FASTIFY_STATIC_HEADERS);
14
- const JEASX_ROUTE_CACHE_LIMIT = process.env.JEASX_ROUTE_CACHE_LIMIT && JSON.parse(process.env.JEASX_ROUTE_CACHE_LIMIT);
13
+ const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
14
+ const JEASX_ROUTE_CACHE_LIMIT = Math.floor(freemem() / 1024 / 1024);
15
15
  var serverless_default = Fastify({
16
16
  logger: true,
17
- disableRequestLogging: JSON.parse(
18
- process.env.FASTIFY_DISABLE_REQUEST_LOGGING || "false"
19
- ),
20
- bodyLimit: Number(process.env.FASTIFY_BODY_LIMIT) || void 0,
21
- trustProxy: JSON.parse(process.env.FASTIFY_TRUST_PROXY || "false"),
22
- rewriteUrl: process.env.FASTIFY_REWRITE_URL && new Function(`return ${process.env.FASTIFY_REWRITE_URL}`)()
23
- }).register(fastifyCookie).register(fastifyFormbody).register(fastifyMultipart, {
24
- attachFieldsToBody: JSON.parse(
25
- process.env.FASTIFY_MULTIPART_ATTACH_FIELDS_TO_BODY || '"keyValues"'
17
+ ...jsonToOptions(
18
+ process.env.FASTIFY_SERVER_OPTIONS
19
+ )
20
+ }).register(fastifyCookie, {
21
+ ...jsonToOptions(
22
+ process.env.FASTIFY_COOKIE_OPTIONS
23
+ )
24
+ }).register(fastifyFormbody, {
25
+ ...jsonToOptions(
26
+ process.env.FASTIFY_FORMBODY_OPTIONS
27
+ )
28
+ }).register(fastifyMultipart, {
29
+ attachFieldsToBody: "keyValues",
30
+ ...jsonToOptions(
31
+ process.env.FASTIFY_MULTIPART_OPTIONS
26
32
  )
27
33
  }).register(fastifyStatic, {
28
34
  root: ["public", "dist/browser"].map((dir) => join(CWD, dir)),
29
35
  prefix: "/",
30
36
  wildcard: false,
31
- cacheControl: false,
32
- setHeaders: FASTIFY_STATIC_HEADERS ? (reply, path) => {
33
- for (const [suffix, headers] of Object.entries(
34
- FASTIFY_STATIC_HEADERS
35
- )) {
36
- if (path.endsWith(suffix)) {
37
- for (const [key, value] of Object.entries(headers)) {
38
- reply.setHeader(key, value);
39
- }
40
- }
41
- }
42
- } : void 0
37
+ preCompressed: true,
38
+ ...jsonToOptions(
39
+ process.env.FASTIFY_STATIC_OPTIONS
40
+ )
43
41
  }).decorateRequest("route", "").decorateRequest("path", "").addHook("onRequest", async (request, reply) => {
44
42
  reply.header("Content-Type", "text/html; charset=utf-8");
45
43
  const index = request.url.indexOf("?");
@@ -52,6 +50,19 @@ var serverless_default = Fastify({
52
50
  throw error;
53
51
  }
54
52
  });
53
+ function jsonToOptions(json) {
54
+ const options = JSON.parse(json || "{}");
55
+ for (const key in options) {
56
+ if (typeof options[key] === "string" && options[key].includes("=>")) {
57
+ try {
58
+ options[key] = new Function(`return ${options[key]}`)();
59
+ } catch (error) {
60
+ console.warn("\u26A0\uFE0F", error);
61
+ }
62
+ }
63
+ }
64
+ return options;
65
+ }
55
66
  const modules = /* @__PURE__ */ new Map();
56
67
  async function handler(request, reply) {
57
68
  let response;
@@ -85,7 +96,7 @@ async function handler(request, reply) {
85
96
  }
86
97
  continue;
87
98
  } finally {
88
- if (typeof JEASX_ROUTE_CACHE_LIMIT === "number" && modules.size > JEASX_ROUTE_CACHE_LIMIT) {
99
+ if (modules.size > JEASX_ROUTE_CACHE_LIMIT) {
89
100
  modules.delete(modules.keys().next().value);
90
101
  }
91
102
  }
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
@@ -1,25 +1,23 @@
1
- import fastifyCookie from "@fastify/cookie";
2
- import fastifyFormbody from "@fastify/formbody";
3
- import fastifyMultipart from "@fastify/multipart";
4
- import fastifyStatic from "@fastify/static";
5
- import Fastify, { FastifyReply, FastifyRequest } from "fastify";
1
+ import fastifyCookie, { FastifyCookieOptions } from "@fastify/cookie";
2
+ import fastifyFormbody, { FastifyFormbodyOptions } from "@fastify/formbody";
3
+ import fastifyMultipart, { FastifyMultipartOptions } from "@fastify/multipart";
4
+ import fastifyStatic, { FastifyStaticOptions } from "@fastify/static";
5
+ import Fastify, {
6
+ FastifyReply,
7
+ FastifyRequest,
8
+ FastifyServerOptions,
9
+ } from "fastify";
6
10
  import { jsxToString } from "jsx-async-runtime";
7
11
  import { stat } from "node:fs/promises";
12
+ import { freemem } from "node:os";
8
13
  import { join } from "node:path";
9
14
  import env from "./env.js";
10
15
 
11
16
  await env();
12
17
 
13
- const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
14
18
  const CWD = process.cwd();
15
-
16
- const FASTIFY_STATIC_HEADERS =
17
- process.env.FASTIFY_STATIC_HEADERS &&
18
- JSON.parse(process.env.FASTIFY_STATIC_HEADERS);
19
-
20
- const JEASX_ROUTE_CACHE_LIMIT =
21
- process.env.JEASX_ROUTE_CACHE_LIMIT &&
22
- JSON.parse(process.env.JEASX_ROUTE_CACHE_LIMIT);
19
+ const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
20
+ const JEASX_ROUTE_CACHE_LIMIT = Math.floor(freemem() / 1024 / 1024);
23
21
 
24
22
  declare module "fastify" {
25
23
  interface FastifyRequest {
@@ -31,40 +29,34 @@ declare module "fastify" {
31
29
  // Create and export a Fastify app instance
32
30
  export default Fastify({
33
31
  logger: true,
34
- disableRequestLogging: JSON.parse(
35
- process.env.FASTIFY_DISABLE_REQUEST_LOGGING || "false"
36
- ),
37
- bodyLimit: Number(process.env.FASTIFY_BODY_LIMIT) || undefined,
38
- trustProxy: JSON.parse(process.env.FASTIFY_TRUST_PROXY || "false"),
39
- rewriteUrl:
40
- process.env.FASTIFY_REWRITE_URL &&
41
- new Function(`return ${process.env.FASTIFY_REWRITE_URL}`)(),
32
+ ...(jsonToOptions(
33
+ process.env.FASTIFY_SERVER_OPTIONS
34
+ ) as FastifyServerOptions),
42
35
  })
43
- .register(fastifyCookie)
44
- .register(fastifyFormbody)
36
+ .register(fastifyCookie, {
37
+ ...(jsonToOptions(
38
+ process.env.FASTIFY_COOKIE_OPTIONS
39
+ ) as FastifyCookieOptions),
40
+ })
41
+ .register(fastifyFormbody, {
42
+ ...(jsonToOptions(
43
+ process.env.FASTIFY_FORMBODY_OPTIONS
44
+ ) as FastifyFormbodyOptions),
45
+ })
45
46
  .register(fastifyMultipart, {
46
- attachFieldsToBody: JSON.parse(
47
- process.env.FASTIFY_MULTIPART_ATTACH_FIELDS_TO_BODY || '"keyValues"'
48
- ),
47
+ attachFieldsToBody: "keyValues",
48
+ ...(jsonToOptions(
49
+ process.env.FASTIFY_MULTIPART_OPTIONS
50
+ ) as FastifyMultipartOptions),
49
51
  })
50
52
  .register(fastifyStatic, {
51
53
  root: ["public", "dist/browser"].map((dir) => join(CWD, dir)),
52
54
  prefix: "/",
53
55
  wildcard: false,
54
- cacheControl: false,
55
- setHeaders: FASTIFY_STATIC_HEADERS
56
- ? (reply, path) => {
57
- for (const [suffix, headers] of Object.entries(
58
- FASTIFY_STATIC_HEADERS
59
- )) {
60
- if (path.endsWith(suffix)) {
61
- for (const [key, value] of Object.entries(headers)) {
62
- reply.setHeader(key, value);
63
- }
64
- }
65
- }
66
- }
67
- : undefined,
56
+ preCompressed: true,
57
+ ...(jsonToOptions(
58
+ process.env.FASTIFY_STATIC_OPTIONS
59
+ ) as FastifyStaticOptions),
68
60
  })
69
61
  .decorateRequest("route", "")
70
62
  .decorateRequest("path", "")
@@ -84,6 +76,23 @@ export default Fastify({
84
76
  }
85
77
  });
86
78
 
79
+ /**
80
+ * Parses JSON and instantiates all stringified functions.
81
+ */
82
+ function jsonToOptions(json: string) {
83
+ const options = JSON.parse(json || "{}");
84
+ for (const key in options) {
85
+ if (typeof options[key] === "string" && options[key].includes("=>")) {
86
+ try {
87
+ options[key] = new Function(`return ${options[key]}`)();
88
+ } catch (error) {
89
+ console.warn("⚠️", error);
90
+ }
91
+ }
92
+ }
93
+ return options;
94
+ }
95
+
87
96
  // Cache for resolved route modules, 'null' means no module exists.
88
97
  const modules = new Map<string, { default: Function }>();
89
98
 
@@ -137,10 +146,7 @@ async function handler(request: FastifyRequest, reply: FastifyReply) {
137
146
  continue;
138
147
  } finally {
139
148
  // Remove oldest entry from cache if limit is reached
140
- if (
141
- typeof JEASX_ROUTE_CACHE_LIMIT === "number" &&
142
- modules.size > JEASX_ROUTE_CACHE_LIMIT
143
- ) {
149
+ if (modules.size > JEASX_ROUTE_CACHE_LIMIT) {
144
150
  modules.delete(modules.keys().next().value);
145
151
  }
146
152
  }
package/tsconfig.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "module": "ESNext",
4
- "moduleResolution": "Node",
5
- "target": "ESNext",
3
+ "module": "esnext",
4
+ "moduleResolution": "bundler",
5
+ "target": "esnext",
6
6
  "outDir": "../../dist",
7
7
  "allowJs": true,
8
8
  "checkJs": true,