From 567fb4f746f6cd3d6eb3cd1b9a1faec9af3cc702 Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Mon, 23 Mar 2026 06:58:41 +0100 Subject: [PATCH] Fix errors, bugs and known vulerabilities --- bun.lock | 8 ++-- package.json | 2 +- src/commands/build/index.ts | 7 ++-- src/commands/dev/index.ts | 8 ++-- .../bundler/all-pages-bun-bundler.ts | 2 +- src/functions/init.ts | 31 ++++++++++++-- .../server/handle-bunext-public-assets.ts | 4 ++ src/functions/server/handle-files.ts | 4 ++ src/functions/server/handle-public.ts | 4 ++ src/functions/server/handle-routes.ts | 2 +- src/functions/server/server-post-build-fn.ts | 2 +- .../server/web-pages/generate-web-html.tsx | 8 ++-- .../web-pages/grab-page-error-component.tsx | 5 +-- .../server/web-pages/grab-web-meta-html.ts | 41 ++++++++++--------- src/utils/grab-all-pages.ts | 8 ++-- 15 files changed, 84 insertions(+), 52 deletions(-) diff --git a/bun.lock b/bun.lock index 22c7b53..da13cf9 100644 --- a/bun.lock +++ b/bun.lock @@ -19,7 +19,10 @@ "micromatch": "^4.0.8", "ora": "^9.0.0", "postcss": "^8.5.8", + "react": "^19.0.0", + "react-dom": "^19.0.0", "tailwindcss": "^4.2.2", + "typescript": "^5.0.0", }, "devDependencies": { "@testing-library/dom": "^10.4.1", @@ -27,11 +30,6 @@ "@types/micromatch": "^4.0.10", "happy-dom": "^20.8.4", }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0", - "typescript": "^5.0.0", - }, }, }, "packages": { diff --git a/package.json b/package.json index 6df4640..5a7a5a7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@moduletrace/bunext", "module": "index.ts", "type": "module", - "version": "1.0.17", + "version": "1.0.18", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { diff --git a/src/commands/build/index.ts b/src/commands/build/index.ts index c9fef32..eb1976d 100644 --- a/src/commands/build/index.ts +++ b/src/commands/build/index.ts @@ -1,11 +1,10 @@ import { Command } from "commander"; -import allPagesBundler from "../../functions/bundler/all-pages-bundler"; import { log } from "../../utils/log"; import init from "../../functions/init"; import rewritePagesModule from "../../utils/rewrite-pages-module"; import allPagesBunBundler from "../../functions/bundler/all-pages-bun-bundler"; -import { execSync } from "child_process"; import grabDirNames from "../../utils/grab-dir-names"; +import { rmSync } from "fs"; const { HYDRATION_DST_DIR, BUNX_CWD_PAGES_REWRITE_DIR } = grabDirNames(); @@ -17,8 +16,8 @@ export default function () { process.env.BUILD = "true"; try { - execSync(`rm -rf ${HYDRATION_DST_DIR}`); - execSync(`rm -rf ${BUNX_CWD_PAGES_REWRITE_DIR}`); + rmSync(HYDRATION_DST_DIR, { recursive: true }); + rmSync(BUNX_CWD_PAGES_REWRITE_DIR, { recursive: true }); } catch (error) {} await rewritePagesModule(); diff --git a/src/commands/dev/index.ts b/src/commands/dev/index.ts index ec98730..1f4f294 100644 --- a/src/commands/dev/index.ts +++ b/src/commands/dev/index.ts @@ -3,8 +3,8 @@ import startServer from "../../functions/server/start-server"; import { log } from "../../utils/log"; import bunextInit from "../../functions/bunext-init"; import rewritePagesModule from "../../utils/rewrite-pages-module"; -import { execSync } from "child_process"; import grabDirNames from "../../utils/grab-dir-names"; +import { rmSync } from "fs"; const { HYDRATION_DST_DIR, BUNX_CWD_PAGES_REWRITE_DIR } = grabDirNames(); @@ -12,13 +12,13 @@ export default function () { return new Command("dev") .description("Run development server") .action(async () => { - process.env.NODE_ENV == "development"; + process.env.NODE_ENV = "development"; log.info("Running development server ..."); try { - execSync(`rm -rf ${HYDRATION_DST_DIR}`); - execSync(`rm -rf ${BUNX_CWD_PAGES_REWRITE_DIR}`); + rmSync(HYDRATION_DST_DIR, { recursive: true }); + rmSync(BUNX_CWD_PAGES_REWRITE_DIR, { recursive: true }); } catch (error) {} await rewritePagesModule(); diff --git a/src/functions/bundler/all-pages-bun-bundler.ts b/src/functions/bundler/all-pages-bun-bundler.ts index ebe0c6d..3078b18 100644 --- a/src/functions/bundler/all-pages-bun-bundler.ts +++ b/src/functions/bundler/all-pages-bun-bundler.ts @@ -82,7 +82,7 @@ export default async function allPagesBunBundler(params?: Params) { ], }); - Bun.write( + await Bun.write( path.join(BUNX_TMP_DIR, "bundle.json"), JSON.stringify(result, null, 4), { createPath: true }, diff --git a/src/functions/init.ts b/src/functions/init.ts index 452e474..6cb51f4 100644 --- a/src/functions/init.ts +++ b/src/functions/init.ts @@ -1,6 +1,5 @@ -import { existsSync, mkdirSync, writeFileSync } from "fs"; +import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs"; import grabDirNames from "../utils/grab-dir-names"; -import { execSync } from "child_process"; import path from "path"; import grabConfig from "./grab-config"; import type { BunextConfig } from "../types"; @@ -9,8 +8,32 @@ export default async function () { const dirNames = grabDirNames(); const is_dev = !Boolean(process.env.NODE_ENV == "production"); - execSync(`rm -rf ${dirNames.BUNEXT_CACHE_DIR}`); - execSync(`rm -rf ${dirNames.BUNX_CWD_MODULE_CACHE_DIR}`); + rmSync(dirNames.BUNEXT_CACHE_DIR, { + recursive: true, + force: true, + }); + rmSync(dirNames.BUNX_CWD_MODULE_CACHE_DIR, { + recursive: true, + force: true, + }); + + try { + const react_package_dir = path.join( + dirNames.ROOT_DIR, + "node_modules", + "react", + ); + const react_dom_package_dir = path.join( + dirNames.ROOT_DIR, + "node_modules", + "react-dom", + ); + + if (dirNames.BUNX_ROOT_DIR !== dirNames.ROOT_DIR) { + rmSync(react_package_dir, { recursive: true }); + rmSync(react_dom_package_dir, { recursive: true }); + } + } catch (error) {} try { const package_json = await Bun.file( diff --git a/src/functions/server/handle-bunext-public-assets.ts b/src/functions/server/handle-bunext-public-assets.ts index 4856650..74c53e7 100644 --- a/src/functions/server/handle-bunext-public-assets.ts +++ b/src/functions/server/handle-bunext-public-assets.ts @@ -18,6 +18,10 @@ export default async function ({ req }: Params): Promise { url.pathname.replace(/\/\.bunext\/public\/pages\//, ""), ); + if (!file_path.startsWith(HYDRATION_DST_DIR + path.sep)) { + return new Response("Forbidden", { status: 403 }); + } + if (!existsSync(file_path)) { return new Response(`File Doesn't Exist`, { status: 404, diff --git a/src/functions/server/handle-files.ts b/src/functions/server/handle-files.ts index bed9707..cce9bed 100644 --- a/src/functions/server/handle-files.ts +++ b/src/functions/server/handle-files.ts @@ -15,6 +15,10 @@ export default async function ({ req }: Params): Promise { const url = new URL(req.url); const file_path = path.join(PUBLIC_DIR, url.pathname); + if (!file_path.startsWith(PUBLIC_DIR + path.sep)) { + return new Response("Forbidden", { status: 403 }); + } + if (!existsSync(file_path)) { return new Response(`File Doesn't Exist`, { status: 404, diff --git a/src/functions/server/handle-public.ts b/src/functions/server/handle-public.ts index 92afa7f..4bff2ea 100644 --- a/src/functions/server/handle-public.ts +++ b/src/functions/server/handle-public.ts @@ -19,6 +19,10 @@ export default async function ({ req }: Params): Promise { url.pathname.replace(/^\/public/, ""), ); + if (!file_path.startsWith(PUBLIC_DIR + path.sep)) { + return new Response("Forbidden", { status: 403 }); + } + if (!existsSync(file_path)) { return new Response(`Public File Doesn't Exist`, { status: 404, diff --git a/src/functions/server/handle-routes.ts b/src/functions/server/handle-routes.ts index 81b5779..f9d7b74 100644 --- a/src/functions/server/handle-routes.ts +++ b/src/functions/server/handle-routes.ts @@ -28,7 +28,7 @@ export default async function ({ req }: Params): Promise { msg: errMsg, }, { - status: 401, + status: 404, headers: { "Content-Type": "application/json", }, diff --git a/src/functions/server/server-post-build-fn.ts b/src/functions/server/server-post-build-fn.ts index aee98e0..ca3fbda 100644 --- a/src/functions/server/server-post-build-fn.ts +++ b/src/functions/server/server-post-build-fn.ts @@ -11,7 +11,7 @@ export default async function serverPostBuildFn() { return; } - for (let i = 0; i < global.HMR_CONTROLLERS.length; i++) { + for (let i = global.HMR_CONTROLLERS.length - 1; i >= 0; i--) { const controller = global.HMR_CONTROLLERS[i]; if (!controller.target_map?.local_path) { diff --git a/src/functions/server/web-pages/generate-web-html.tsx b/src/functions/server/web-pages/generate-web-html.tsx index 4f89b2d..eba911a 100644 --- a/src/functions/server/web-pages/generate-web-html.tsx +++ b/src/functions/server/web-pages/generate-web-html.tsx @@ -61,9 +61,11 @@ export default async function genWebHTML({ html += ` \n`; } - html += ` \n`; + const serializedProps = (EJSON.stringify(pageProps || {}) || "{}").replace( + /<\//g, + "<\\/", + ); + html += ` \n`; if (bundledMap?.path) { const dev = isDevelopment(); diff --git a/src/functions/server/web-pages/grab-page-error-component.tsx b/src/functions/server/web-pages/grab-page-error-component.tsx index b07f34e..a794e8e 100644 --- a/src/functions/server/web-pages/grab-page-error-component.tsx +++ b/src/functions/server/web-pages/grab-page-error-component.tsx @@ -1,7 +1,6 @@ import type { FC } from "react"; import grabDirNames from "../../../utils/grab-dir-names"; import type { - BundlerCTXMap, BunextPageModule, BunxRouteParams, GrabPageComponentRes, @@ -34,7 +33,7 @@ export default async function grabPageErrorComponent({ const bundledMap = match?.filePath ? global.BUNDLER_CTX_MAP?.[match.filePath] - : ({} as BundlerCTXMap); + : undefined; const module: BunextPageModule = await import(filePath); const Component = module.default as FC; @@ -72,7 +71,7 @@ export default async function grabPageErrorComponent({ component: , routeParams, module: { default: DefaultNotFound }, - bundledMap: {} as BundlerCTXMap, + bundledMap: undefined, serverRes: { responseOptions: { status: is404 ? 404 : 500, diff --git a/src/functions/server/web-pages/grab-web-meta-html.ts b/src/functions/server/web-pages/grab-web-meta-html.ts index ebb1176..6eae617 100644 --- a/src/functions/server/web-pages/grab-web-meta-html.ts +++ b/src/functions/server/web-pages/grab-web-meta-html.ts @@ -1,3 +1,4 @@ +import { escape } from "lodash"; import type { BunextPageModuleMeta } from "../../../types"; type Params = { @@ -8,68 +9,68 @@ export default function grabWebMetaHTML({ meta }: Params) { let html = ``; if (meta.title) { - html += ` ${meta.title}\n`; + html += ` ${escape(meta.title)}\n`; } if (meta.description) { - html += ` \n`; + html += ` \n`; } if (meta.keywords) { const keywords = Array.isArray(meta.keywords) ? meta.keywords.join(", ") : meta.keywords; - html += ` \n`; + html += ` \n`; } if (meta.author) { - html += ` \n`; + html += ` \n`; } if (meta.robots) { - html += ` \n`; + html += ` \n`; } if (meta.canonical) { - html += ` \n`; + html += ` \n`; } if (meta.themeColor) { - html += ` \n`; + html += ` \n`; } if (meta.og) { const { og } = meta; if (og.title) - html += ` \n`; + html += ` \n`; if (og.description) - html += ` \n`; + html += ` \n`; if (og.image) - html += ` \n`; + html += ` \n`; if (og.url) - html += ` \n`; + html += ` \n`; if (og.type) - html += ` \n`; + html += ` \n`; if (og.siteName) - html += ` \n`; + html += ` \n`; if (og.locale) - html += ` \n`; + html += ` \n`; } if (meta.twitter) { const { twitter } = meta; if (twitter.card) - html += ` \n`; + html += ` \n`; if (twitter.title) - html += ` \n`; + html += ` \n`; if (twitter.description) - html += ` \n`; + html += ` \n`; if (twitter.image) - html += ` \n`; + html += ` \n`; if (twitter.site) - html += ` \n`; + html += ` \n`; if (twitter.creator) - html += ` \n`; + html += ` \n`; } return html; diff --git a/src/utils/grab-all-pages.ts b/src/utils/grab-all-pages.ts index 39db52d..90def39 100644 --- a/src/utils/grab-all-pages.ts +++ b/src/utils/grab-all-pages.ts @@ -67,11 +67,9 @@ function grabPageDirRecursively({ page_dir }: { page_dir: string }) { } return pages_files.sort((a, b) => { - if (a.url_path == "/index") { - return -1; - } - - return 1; + if (a.url_path === "/index") return -1; + if (b.url_path === "/index") return 1; + return 0; }); }