Compare commits
No commits in common. "ceeb6fbdaf711c3d8e27b5c17a0b0a0fb1a00df7" and "cb5126c94740b2edf27699a844bc866270db4d68" have entirely different histories.
ceeb6fbdaf
...
cb5126c947
1
.gitignore
vendored
1
.gitignore
vendored
@ -182,4 +182,3 @@ __fixtures__
|
|||||||
/.dump
|
/.dump
|
||||||
/.vscode
|
/.vscode
|
||||||
/source.md
|
/source.md
|
||||||
SECURITY.md
|
|
||||||
12
dist/commands/start/index.js
vendored
12
dist/commands/start/index.js
vendored
@ -1,9 +1,6 @@
|
|||||||
import { Command } from "commander";
|
import { Command } from "commander";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import writeErrorFile from "../../functions/write-error-file";
|
import writeErrorFile from "../../functions/write-error-file";
|
||||||
let retries = 0;
|
|
||||||
let timeout;
|
|
||||||
const MAX_RETRIES = 5;
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return new Command("start")
|
return new Command("start")
|
||||||
.description("Start production server")
|
.description("Start production server")
|
||||||
@ -12,11 +9,6 @@ export default function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function start() {
|
async function start() {
|
||||||
clearTimeout(timeout);
|
|
||||||
if (retries >= MAX_RETRIES) {
|
|
||||||
console.error(`Production server crashed ${MAX_RETRIES} times. Exiting.`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
const dev_spawn_file = path.resolve(__dirname, "prod-spawn.ts");
|
const dev_spawn_file = path.resolve(__dirname, "prod-spawn.ts");
|
||||||
const spawn_options = {
|
const spawn_options = {
|
||||||
cmd: ["bun", dev_spawn_file],
|
cmd: ["bun", dev_spawn_file],
|
||||||
@ -30,10 +22,6 @@ async function start() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let dev_process = Bun.spawn(spawn_options);
|
let dev_process = Bun.spawn(spawn_options);
|
||||||
retries++;
|
|
||||||
timeout = setTimeout(() => {
|
|
||||||
retries = 0;
|
|
||||||
}, 10000);
|
|
||||||
const exited = await dev_process.exited;
|
const exited = await dev_process.exited;
|
||||||
if (exited) {
|
if (exited) {
|
||||||
return await start();
|
return await start();
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export default async function buildOnstartErrorHandler(params) {
|
|||||||
global.BUNDLER_CTX_DISPOSED = true;
|
global.BUNDLER_CTX_DISPOSED = true;
|
||||||
global.RECOMPILING = false;
|
global.RECOMPILING = false;
|
||||||
global.IS_SERVER_COMPONENT = false;
|
global.IS_SERVER_COMPONENT = false;
|
||||||
await Promise.all([
|
Promise.all([
|
||||||
global.SSR_BUNDLER_CTX?.dispose(),
|
global.SSR_BUNDLER_CTX?.dispose(),
|
||||||
global.BUNDLER_CTX?.dispose(),
|
global.BUNDLER_CTX?.dispose(),
|
||||||
]);
|
]);
|
||||||
|
|||||||
4
dist/functions/bunext-init.d.ts
vendored
4
dist/functions/bunext-init.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
import type { BundlerCTXMap, BunextConfig, GlobalHMRControllerObject, PageFiles } from "../types";
|
import type { BundlerCTXMap, BunextConfig, GlobalHMRControllerObject, PageFiles } from "../types";
|
||||||
import type { FileSystemRouter, Server } from "bun";
|
import type { FileSystemRouter, Server } from "bun";
|
||||||
import { type DirNames } from "../utils/grab-dir-names";
|
import grabDirNames from "../utils/grab-dir-names";
|
||||||
import { type FSWatcher } from "fs";
|
import { type FSWatcher } from "fs";
|
||||||
import type { BuildContext } from "esbuild";
|
import type { BuildContext } from "esbuild";
|
||||||
import grabConstants from "../utils/grab-constants";
|
import grabConstants from "../utils/grab-constants";
|
||||||
@ -31,7 +31,7 @@ declare global {
|
|||||||
var SKIPPED_BROWSER_MODULES: Set<string>;
|
var SKIPPED_BROWSER_MODULES: Set<string>;
|
||||||
var BUNDLER_CTX: BuildContext | undefined;
|
var BUNDLER_CTX: BuildContext | undefined;
|
||||||
var SSR_BUNDLER_CTX: BuildContext | undefined;
|
var SSR_BUNDLER_CTX: BuildContext | undefined;
|
||||||
var DIR_NAMES: DirNames;
|
var DIR_NAMES: ReturnType<typeof grabDirNames>;
|
||||||
var REACT_IMPORTS_MAP: {
|
var REACT_IMPORTS_MAP: {
|
||||||
imports: Record<string, string>;
|
imports: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|||||||
2
dist/functions/bunext-init.js
vendored
2
dist/functions/bunext-init.js
vendored
@ -1,4 +1,4 @@
|
|||||||
import grabDirNames, {} from "../utils/grab-dir-names";
|
import grabDirNames from "../utils/grab-dir-names";
|
||||||
import {} from "fs";
|
import {} from "fs";
|
||||||
import init from "./init";
|
import init from "./init";
|
||||||
import isDevelopment from "../utils/is-development";
|
import isDevelopment from "../utils/is-development";
|
||||||
|
|||||||
4
dist/functions/cache/trim-all-cache.js
vendored
4
dist/functions/cache/trim-all-cache.js
vendored
@ -13,10 +13,6 @@ export default async function trimAllCache() {
|
|||||||
const trim_key = await trimCacheKey({
|
const trim_key = await trimCacheKey({
|
||||||
key: cache_key,
|
key: cache_key,
|
||||||
});
|
});
|
||||||
if (trim_key.success) {
|
|
||||||
cached_items.splice(i, 1);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
|
|||||||
17
dist/functions/server/bunext-req-handler.js
vendored
17
dist/functions/server/bunext-req-handler.js
vendored
@ -8,8 +8,6 @@ import handleBunextPublicAssets from "./handle-bunext-public-assets";
|
|||||||
import checkExcludedPatterns from "../../utils/check-excluded-patterns";
|
import checkExcludedPatterns from "../../utils/check-excluded-patterns";
|
||||||
import { AppData } from "../../data/app-data";
|
import { AppData } from "../../data/app-data";
|
||||||
import fullRebuild from "./full-rebuild";
|
import fullRebuild from "./full-rebuild";
|
||||||
const HMR_RETRY_COOLDOWN_MS = 5000;
|
|
||||||
let lastHmrRetryTime = 0;
|
|
||||||
export default async function bunextRequestHandler({ req: initial_req, server, }) {
|
export default async function bunextRequestHandler({ req: initial_req, server, }) {
|
||||||
const is_dev = isDevelopment();
|
const is_dev = isDevelopment();
|
||||||
let req = initial_req.clone();
|
let req = initial_req.clone();
|
||||||
@ -32,11 +30,6 @@ export default async function bunextRequestHandler({ req: initial_req, server, }
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_dev && url.pathname == AppData["BunextHMRRetryRoute"]) {
|
if (is_dev && url.pathname == AppData["BunextHMRRetryRoute"]) {
|
||||||
const now = Date.now();
|
|
||||||
if (now - lastHmrRetryTime < HMR_RETRY_COOLDOWN_MS) {
|
|
||||||
return new Response("Too Many Requests", { status: 429 });
|
|
||||||
}
|
|
||||||
lastHmrRetryTime = now;
|
|
||||||
await fullRebuild({ msg: `HMR Retry Rebuild ...` });
|
await fullRebuild({ msg: `HMR Retry Rebuild ...` });
|
||||||
return new Response("Modules Rebuilt");
|
return new Response("Modules Rebuilt");
|
||||||
}
|
}
|
||||||
@ -67,12 +60,8 @@ export default async function bunextRequestHandler({ req: initial_req, server, }
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
if (is_dev) {
|
return new Response(`Server Error: ${error.message}`, {
|
||||||
return new Response(`Server Error: ${error.message}`, {
|
status: 500,
|
||||||
status: 500,
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
console.error(`Server Error: ${error.message}`, error);
|
|
||||||
return new Response("Internal Server Error", { status: 500 });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,14 +2,13 @@ import grabDirNames from "../../utils/grab-dir-names";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import isDevelopment from "../../utils/is-development";
|
import isDevelopment from "../../utils/is-development";
|
||||||
import { readFileResponse } from "./handle-public";
|
import { readFileResponse } from "./handle-public";
|
||||||
import isSafePath from "../../utils/is-safe-path";
|
|
||||||
const { BUNEXT_PUBLIC_DIR } = grabDirNames();
|
const { BUNEXT_PUBLIC_DIR } = grabDirNames();
|
||||||
export default async function ({ req }) {
|
export default async function ({ req }) {
|
||||||
try {
|
try {
|
||||||
const is_dev = isDevelopment();
|
const is_dev = isDevelopment();
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const file_path = path.join(BUNEXT_PUBLIC_DIR, url.pathname.replace(/\/\.bunext\/public\//, ""));
|
const file_path = path.join(BUNEXT_PUBLIC_DIR, url.pathname.replace(/\/\.bunext\/public\//, ""));
|
||||||
if (!isSafePath({ filePath: file_path, allowedDir: BUNEXT_PUBLIC_DIR })) {
|
if (!file_path.startsWith(BUNEXT_PUBLIC_DIR + path.sep)) {
|
||||||
return new Response("Forbidden", { status: 403 });
|
return new Response("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
return readFileResponse({
|
return readFileResponse({
|
||||||
|
|||||||
9
dist/functions/server/handle-files.js
vendored
9
dist/functions/server/handle-files.js
vendored
@ -2,14 +2,13 @@ import grabDirNames from "../../utils/grab-dir-names";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import isDevelopment from "../../utils/is-development";
|
import isDevelopment from "../../utils/is-development";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
import isSafePath from "../../utils/is-safe-path";
|
|
||||||
const { PUBLIC_DIR } = grabDirNames();
|
const { PUBLIC_DIR } = grabDirNames();
|
||||||
export default async function ({ req }) {
|
export default async function ({ req }) {
|
||||||
try {
|
try {
|
||||||
const is_dev = isDevelopment();
|
const is_dev = isDevelopment();
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const file_path = path.join(PUBLIC_DIR, url.pathname);
|
const file_path = path.join(PUBLIC_DIR, url.pathname);
|
||||||
if (!isSafePath({ filePath: file_path, allowedDir: PUBLIC_DIR })) {
|
if (!file_path.startsWith(PUBLIC_DIR + path.sep)) {
|
||||||
return new Response("Forbidden", { status: 403 });
|
return new Response("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
if (!existsSync(file_path)) {
|
if (!existsSync(file_path)) {
|
||||||
@ -18,11 +17,7 @@ export default async function ({ req }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const file = Bun.file(file_path);
|
const file = Bun.file(file_path);
|
||||||
const headers = new Headers();
|
return new Response(file);
|
||||||
if (!is_dev) {
|
|
||||||
headers.set("Cache-Control", "public, max-age=3600");
|
|
||||||
}
|
|
||||||
return new Response(file, { headers });
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
return new Response(`File Not Found`, {
|
return new Response(`File Not Found`, {
|
||||||
|
|||||||
25
dist/functions/server/handle-hmr.js
vendored
25
dist/functions/server/handle-hmr.js
vendored
@ -1,21 +1,5 @@
|
|||||||
function removeController(controller) {
|
|
||||||
const idx = global.HMR_CONTROLLERS.findIndex((c) => c.controller == controller);
|
|
||||||
if (typeof idx == "number" && idx >= 0) {
|
|
||||||
global.HMR_CONTROLLERS.splice(idx, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default async function ({ req }) {
|
export default async function ({ req }) {
|
||||||
const referer = req.headers.get("referer");
|
const referer_url = new URL(req.headers.get("referer") || "");
|
||||||
if (!referer) {
|
|
||||||
return new Response("Missing Referer Header", { status: 400 });
|
|
||||||
}
|
|
||||||
let referer_url;
|
|
||||||
try {
|
|
||||||
referer_url = new URL(referer);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return new Response("Invalid Referer Header", { status: 400 });
|
|
||||||
}
|
|
||||||
const match = global.ROUTER.match(referer_url.pathname);
|
const match = global.ROUTER.match(referer_url.pathname);
|
||||||
const target_map = match?.filePath
|
const target_map = match?.filePath
|
||||||
? global.BUNDLER_CTX_MAP?.[match.filePath]
|
? global.BUNDLER_CTX_MAP?.[match.filePath]
|
||||||
@ -36,13 +20,16 @@ export default async function ({ req }) {
|
|||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
clearInterval(heartbeat);
|
clearInterval(heartbeat);
|
||||||
removeController(controller);
|
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
},
|
},
|
||||||
cancel() {
|
cancel() {
|
||||||
clearInterval(heartbeat);
|
clearInterval(heartbeat);
|
||||||
removeController(controller);
|
const targetControllerIndex = global.HMR_CONTROLLERS.findIndex((c) => c.controller == controller);
|
||||||
|
if (typeof targetControllerIndex == "number" &&
|
||||||
|
targetControllerIndex >= 0) {
|
||||||
|
global.HMR_CONTROLLERS.splice(targetControllerIndex, 1);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return new Response(stream, {
|
return new Response(stream, {
|
||||||
|
|||||||
6
dist/functions/server/handle-public.js
vendored
6
dist/functions/server/handle-public.js
vendored
@ -2,14 +2,13 @@ import grabDirNames from "../../utils/grab-dir-names";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import isDevelopment from "../../utils/is-development";
|
import isDevelopment from "../../utils/is-development";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
import isSafePath from "../../utils/is-safe-path";
|
|
||||||
const { PUBLIC_DIR } = grabDirNames();
|
const { PUBLIC_DIR } = grabDirNames();
|
||||||
export default async function ({ req }) {
|
export default async function ({ req }) {
|
||||||
try {
|
try {
|
||||||
const is_dev = isDevelopment();
|
const is_dev = isDevelopment();
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const file_path = path.join(PUBLIC_DIR, url.pathname.replace(/^\/public/, ""));
|
const file_path = path.join(PUBLIC_DIR, url.pathname.replace(/^\/public/, ""));
|
||||||
if (!isSafePath({ filePath: file_path, allowedDir: PUBLIC_DIR })) {
|
if (!file_path.startsWith(PUBLIC_DIR + path.sep)) {
|
||||||
return new Response("Forbidden", { status: 403 });
|
return new Response("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
return readFileResponse({ file_path });
|
return readFileResponse({ file_path });
|
||||||
@ -34,9 +33,6 @@ export function readFileResponse({ file_path, cache }) {
|
|||||||
else if (cache?.duration) {
|
else if (cache?.duration) {
|
||||||
headers.set("Cache-Control", `public, max-age=${cache.duration}`);
|
headers.set("Cache-Control", `public, max-age=${cache.duration}`);
|
||||||
}
|
}
|
||||||
else if (!isDevelopment()) {
|
|
||||||
headers.set("Cache-Control", "public, max-age=3600");
|
|
||||||
}
|
|
||||||
return new Response(file, {
|
return new Response(file, {
|
||||||
headers,
|
headers,
|
||||||
});
|
});
|
||||||
|
|||||||
22
dist/functions/server/handle-routes.js
vendored
22
dist/functions/server/handle-routes.js
vendored
@ -41,13 +41,12 @@ export default async function ({ req }) {
|
|||||||
module = await import(import_path);
|
module = await import(import_path);
|
||||||
}
|
}
|
||||||
const config = module.config;
|
const config = module.config;
|
||||||
const maxBodyBytes = config?.max_request_body_mb
|
|
||||||
? config.max_request_body_mb * MBInBytes
|
|
||||||
: ServerDefaultRequestBodyLimitBytes;
|
|
||||||
const contentLength = req.headers.get("content-length");
|
const contentLength = req.headers.get("content-length");
|
||||||
if (contentLength) {
|
if (contentLength) {
|
||||||
const size = parseInt(contentLength, 10);
|
const size = parseInt(contentLength, 10);
|
||||||
if (size > maxBodyBytes) {
|
if ((config?.max_request_body_mb &&
|
||||||
|
size > config.max_request_body_mb * MBInBytes) ||
|
||||||
|
size > ServerDefaultRequestBodyLimitBytes) {
|
||||||
return Response.json({
|
return Response.json({
|
||||||
success: false,
|
success: false,
|
||||||
msg: "Request Body Too Large!",
|
msg: "Request Body Too Large!",
|
||||||
@ -59,21 +58,6 @@ export default async function ({ req }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (req.method !== "GET" && req.method !== "HEAD") {
|
|
||||||
const body = await req.arrayBuffer();
|
|
||||||
if (body.byteLength > maxBodyBytes) {
|
|
||||||
return Response.json({
|
|
||||||
success: false,
|
|
||||||
msg: "Request Body Too Large!",
|
|
||||||
}, {
|
|
||||||
status: 413,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
routeParams.body = JSON.parse(new TextDecoder().decode(body) || "{}");
|
|
||||||
}
|
|
||||||
const target_module = (module["default"] ||
|
const target_module = (module["default"] ||
|
||||||
module["handler"]);
|
module["handler"]);
|
||||||
const res = await target_module?.({
|
const res = await target_module?.({
|
||||||
|
|||||||
@ -30,8 +30,8 @@ export default async function serverPostBuildFn(params) {
|
|||||||
controller.controller.enqueue(reload_enqueue);
|
controller.controller.enqueue(reload_enqueue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const mock_req = target_artifact.req_url
|
const mock_req = target_artifact.req
|
||||||
? new Request(target_artifact.req_url)
|
? target_artifact.req.clone()
|
||||||
: new Request(controller.page_url);
|
: new Request(controller.page_url);
|
||||||
const page_component = global.IS_SERVER_COMPONENT
|
const page_component = global.IS_SERVER_COMPONENT
|
||||||
? await grabPageComponent({
|
? await grabPageComponent({
|
||||||
|
|||||||
@ -76,20 +76,15 @@ export default async function genWebHTML({ component: Main, pageProps, bundledMa
|
|||||||
console.error = () => { };
|
console.error = () => { };
|
||||||
console.info = () => { };
|
console.info = () => { };
|
||||||
console.debug = () => { };
|
console.debug = () => { };
|
||||||
let htmlBody;
|
const stream = await renderToReadableStream(final_component, {
|
||||||
try {
|
onError(error) {
|
||||||
const stream = await renderToReadableStream(final_component, {
|
if (error.message.includes('unique "key" prop'))
|
||||||
onError(error) {
|
return;
|
||||||
if (error.message.includes('unique "key" prop'))
|
originalConsole.error(error);
|
||||||
return;
|
},
|
||||||
originalConsole.error(error);
|
});
|
||||||
},
|
const htmlBody = await new Response(stream).text();
|
||||||
});
|
Object.assign(console, originalConsole);
|
||||||
htmlBody = await new Response(stream).text();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Object.assign(console, originalConsole);
|
|
||||||
}
|
|
||||||
html += htmlBody;
|
html += htmlBody;
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export default async function grabPageCombinedServerRes({ file_path, debug, url,
|
|||||||
const page_server_ctx = global.SSR_BUNDLER_CTX_MAP[server_file_path || ""];
|
const page_server_ctx = global.SSR_BUNDLER_CTX_MAP[server_file_path || ""];
|
||||||
const final_page_server_path = page_server_ctx?.local_path
|
const final_page_server_path = page_server_ctx?.local_path
|
||||||
? path.join(ROOT_DIR, page_server_ctx.path)
|
? path.join(ROOT_DIR, page_server_ctx.path)
|
||||||
: server_file_path;
|
: root_server_file_path;
|
||||||
const server_module = final_page_server_path
|
const server_module = final_page_server_path
|
||||||
? await import(`${final_page_server_path}?t=${now}`)
|
? await import(`${final_page_server_path}?t=${now}`)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|||||||
@ -72,7 +72,7 @@ export default async function grabPageComponent(params) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (req && !is_hydration) {
|
if (req && !is_hydration) {
|
||||||
global.BUNDLER_CTX_MAP[file_path].req_url = req.url;
|
global.BUNDLER_CTX_MAP[file_path].req = req;
|
||||||
}
|
}
|
||||||
if (debug) {
|
if (debug) {
|
||||||
log.info(`bundledMap:`, bundledMap);
|
log.info(`bundledMap:`, bundledMap);
|
||||||
|
|||||||
2
dist/types/index.d.ts
vendored
2
dist/types/index.d.ts
vendored
@ -306,7 +306,7 @@ export type BundlerCTXMap = {
|
|||||||
url_path: string;
|
url_path: string;
|
||||||
file_name: string;
|
file_name: string;
|
||||||
css_path?: string;
|
css_path?: string;
|
||||||
req_url?: string;
|
req?: Request;
|
||||||
};
|
};
|
||||||
export type GlobalHMRControllerObject = {
|
export type GlobalHMRControllerObject = {
|
||||||
controller: ReadableStreamDefaultController<string>;
|
controller: ReadableStreamDefaultController<string>;
|
||||||
|
|||||||
3
dist/utils/deserialize-query.d.ts
vendored
3
dist/utils/deserialize-query.d.ts
vendored
@ -1,3 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* # Convert Serialized Query back to object
|
||||||
|
*/
|
||||||
export default function deserializeQuery(query: string | {
|
export default function deserializeQuery(query: string | {
|
||||||
[s: string]: any;
|
[s: string]: any;
|
||||||
}): {
|
}): {
|
||||||
|
|||||||
25
dist/utils/deserialize-query.js
vendored
25
dist/utils/deserialize-query.js
vendored
@ -1,33 +1,18 @@
|
|||||||
import EJSON from "./ejson";
|
import EJSON from "./ejson";
|
||||||
const DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
/**
|
||||||
function sanitize(value) {
|
* # Convert Serialized Query back to object
|
||||||
if (value === null || typeof value !== "object")
|
*/
|
||||||
return value;
|
|
||||||
if (Array.isArray(value))
|
|
||||||
return value.map(sanitize);
|
|
||||||
const clean = Object.create(null);
|
|
||||||
for (const key of Object.keys(value)) {
|
|
||||||
if (DANGEROUS_KEYS.has(key))
|
|
||||||
continue;
|
|
||||||
clean[key] = sanitize(value[key]);
|
|
||||||
}
|
|
||||||
return clean;
|
|
||||||
}
|
|
||||||
export default function deserializeQuery(query) {
|
export default function deserializeQuery(query) {
|
||||||
let queryObject = typeof query == "object" ? query : Object(EJSON.parse(query));
|
let queryObject = typeof query == "object" ? query : Object(EJSON.parse(query));
|
||||||
const keys = Object.keys(queryObject);
|
const keys = Object.keys(queryObject);
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
const value = queryObject[key];
|
const value = queryObject[key];
|
||||||
if (DANGEROUS_KEYS.has(key)) {
|
|
||||||
delete queryObject[key];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (typeof value == "string") {
|
if (typeof value == "string") {
|
||||||
if (value.match(/^\{|^\[/)) {
|
if (value.match(/^\{|^\[/)) {
|
||||||
queryObject[key] = sanitize(EJSON.parse(value));
|
queryObject[key] = EJSON.parse(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sanitize(queryObject);
|
return queryObject;
|
||||||
}
|
}
|
||||||
|
|||||||
3
dist/utils/grab-dir-names.d.ts
vendored
3
dist/utils/grab-dir-names.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
export type DirNames = {
|
export default function grabDirNames(): {
|
||||||
ROOT_DIR: string;
|
ROOT_DIR: string;
|
||||||
SRC_DIR: string;
|
SRC_DIR: string;
|
||||||
PAGES_DIR: string;
|
PAGES_DIR: string;
|
||||||
@ -27,4 +27,3 @@ export type DirNames = {
|
|||||||
BUNX_ERROR_LOGS_DIR: string;
|
BUNX_ERROR_LOGS_DIR: string;
|
||||||
BUNX_LOGS_DIR: string;
|
BUNX_LOGS_DIR: string;
|
||||||
};
|
};
|
||||||
export default function grabDirNames(): DirNames;
|
|
||||||
|
|||||||
2
dist/utils/grab-dir-names.js
vendored
2
dist/utils/grab-dir-names.js
vendored
@ -1,7 +1,5 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
export default function grabDirNames() {
|
export default function grabDirNames() {
|
||||||
if (global.DIR_NAMES)
|
|
||||||
return global.DIR_NAMES;
|
|
||||||
const ROOT_DIR = process.cwd();
|
const ROOT_DIR = process.cwd();
|
||||||
const SRC_DIR = path.join(ROOT_DIR, "src");
|
const SRC_DIR = path.join(ROOT_DIR, "src");
|
||||||
const PAGES_DIR = path.join(SRC_DIR, "pages");
|
const PAGES_DIR = path.join(SRC_DIR, "pages");
|
||||||
|
|||||||
8
dist/utils/is-development.js
vendored
8
dist/utils/is-development.js
vendored
@ -1,6 +1,10 @@
|
|||||||
export default function isDevelopment() {
|
export default function isDevelopment() {
|
||||||
if (process.env.NODE_ENV === "production") {
|
const config = global.CONFIG;
|
||||||
|
if (process.env.NODE_ENV == "production") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Boolean(global.CONFIG?.development);
|
if (config.development) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
4
dist/utils/is-safe-path.d.ts
vendored
4
dist/utils/is-safe-path.d.ts
vendored
@ -1,4 +0,0 @@
|
|||||||
export default function isSafePath({ filePath, allowedDir, }: {
|
|
||||||
filePath: string;
|
|
||||||
allowedDir: string;
|
|
||||||
}): boolean;
|
|
||||||
15
dist/utils/is-safe-path.js
vendored
15
dist/utils/is-safe-path.js
vendored
@ -1,15 +0,0 @@
|
|||||||
import { realpathSync } from "fs";
|
|
||||||
import path from "path";
|
|
||||||
export default function isSafePath({ filePath, allowedDir, }) {
|
|
||||||
const resolved = path.resolve(filePath);
|
|
||||||
if (!resolved.startsWith(allowedDir + path.sep) && resolved !== allowedDir) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const real = realpathSync(resolved);
|
|
||||||
return (real.startsWith(allowedDir + path.sep) || real === allowedDir);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@moduletrace/bunext",
|
"name": "@moduletrace/bunext",
|
||||||
"version": "1.0.88",
|
"version": "1.0.86",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "index.ts",
|
"module": "index.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -3,10 +3,6 @@ import path from "path";
|
|||||||
import type { BunSpawnOptions } from "../../types";
|
import type { BunSpawnOptions } from "../../types";
|
||||||
import writeErrorFile from "../../functions/write-error-file";
|
import writeErrorFile from "../../functions/write-error-file";
|
||||||
|
|
||||||
let retries = 0;
|
|
||||||
let timeout: any;
|
|
||||||
const MAX_RETRIES = 5;
|
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return new Command("start")
|
return new Command("start")
|
||||||
.description("Start production server")
|
.description("Start production server")
|
||||||
@ -16,13 +12,6 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
clearTimeout(timeout);
|
|
||||||
|
|
||||||
if (retries >= MAX_RETRIES) {
|
|
||||||
console.error(`Production server crashed ${MAX_RETRIES} times. Exiting.`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const dev_spawn_file = path.resolve(__dirname, "prod-spawn.ts");
|
const dev_spawn_file = path.resolve(__dirname, "prod-spawn.ts");
|
||||||
|
|
||||||
const spawn_options: BunSpawnOptions = {
|
const spawn_options: BunSpawnOptions = {
|
||||||
@ -39,12 +28,6 @@ async function start() {
|
|||||||
|
|
||||||
let dev_process = Bun.spawn(spawn_options);
|
let dev_process = Bun.spawn(spawn_options);
|
||||||
|
|
||||||
retries++;
|
|
||||||
|
|
||||||
timeout = setTimeout(() => {
|
|
||||||
retries = 0;
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
const exited = await dev_process.exited;
|
const exited = await dev_process.exited;
|
||||||
|
|
||||||
if (exited) {
|
if (exited) {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export default async function buildOnstartErrorHandler(params?: Params) {
|
|||||||
global.RECOMPILING = false;
|
global.RECOMPILING = false;
|
||||||
global.IS_SERVER_COMPONENT = false;
|
global.IS_SERVER_COMPONENT = false;
|
||||||
|
|
||||||
await Promise.all([
|
Promise.all([
|
||||||
global.SSR_BUNDLER_CTX?.dispose(),
|
global.SSR_BUNDLER_CTX?.dispose(),
|
||||||
global.BUNDLER_CTX?.dispose(),
|
global.BUNDLER_CTX?.dispose(),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import type {
|
|||||||
PageFiles,
|
PageFiles,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import type { FileSystemRouter, Server } from "bun";
|
import type { FileSystemRouter, Server } from "bun";
|
||||||
import grabDirNames, { type DirNames } from "../utils/grab-dir-names";
|
import grabDirNames from "../utils/grab-dir-names";
|
||||||
import { type FSWatcher } from "fs";
|
import { type FSWatcher } from "fs";
|
||||||
import init from "./init";
|
import init from "./init";
|
||||||
import isDevelopment from "../utils/is-development";
|
import isDevelopment from "../utils/is-development";
|
||||||
@ -43,7 +43,7 @@ declare global {
|
|||||||
var BUNDLER_CTX: BuildContext | undefined;
|
var BUNDLER_CTX: BuildContext | undefined;
|
||||||
var SSR_BUNDLER_CTX: BuildContext | undefined;
|
var SSR_BUNDLER_CTX: BuildContext | undefined;
|
||||||
// var API_ROUTES_BUNDLER_CTX: BuildContext | undefined;
|
// var API_ROUTES_BUNDLER_CTX: BuildContext | undefined;
|
||||||
var DIR_NAMES: DirNames;
|
var DIR_NAMES: ReturnType<typeof grabDirNames>;
|
||||||
var REACT_IMPORTS_MAP: { imports: Record<string, string> };
|
var REACT_IMPORTS_MAP: { imports: Record<string, string> };
|
||||||
var REACT_DOM_SERVER: any;
|
var REACT_DOM_SERVER: any;
|
||||||
var REACT_DOM_MODULE_CACHE: Map<string, { main: any; css: string }>;
|
var REACT_DOM_MODULE_CACHE: Map<string, { main: any; css: string }>;
|
||||||
|
|||||||
5
src/functions/cache/trim-all-cache.ts
vendored
5
src/functions/cache/trim-all-cache.ts
vendored
@ -17,11 +17,6 @@ export default async function trimAllCache() {
|
|||||||
const trim_key = await trimCacheKey({
|
const trim_key = await trimCacheKey({
|
||||||
key: cache_key,
|
key: cache_key,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (trim_key.success) {
|
|
||||||
cached_items.splice(i, 1);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@ -8,10 +8,6 @@ import handleBunextPublicAssets from "./handle-bunext-public-assets";
|
|||||||
import checkExcludedPatterns from "../../utils/check-excluded-patterns";
|
import checkExcludedPatterns from "../../utils/check-excluded-patterns";
|
||||||
import { AppData } from "../../data/app-data";
|
import { AppData } from "../../data/app-data";
|
||||||
import fullRebuild from "./full-rebuild";
|
import fullRebuild from "./full-rebuild";
|
||||||
|
|
||||||
const HMR_RETRY_COOLDOWN_MS = 5000;
|
|
||||||
let lastHmrRetryTime = 0;
|
|
||||||
|
|
||||||
type Params = {
|
type Params = {
|
||||||
req: Request;
|
req: Request;
|
||||||
server: Bun.Server<any>;
|
server: Bun.Server<any>;
|
||||||
@ -49,11 +45,6 @@ export default async function bunextRequestHandler({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_dev && url.pathname == AppData["BunextHMRRetryRoute"]) {
|
if (is_dev && url.pathname == AppData["BunextHMRRetryRoute"]) {
|
||||||
const now = Date.now();
|
|
||||||
if (now - lastHmrRetryTime < HMR_RETRY_COOLDOWN_MS) {
|
|
||||||
return new Response("Too Many Requests", { status: 429 });
|
|
||||||
}
|
|
||||||
lastHmrRetryTime = now;
|
|
||||||
await fullRebuild({ msg: `HMR Retry Rebuild ...` });
|
await fullRebuild({ msg: `HMR Retry Rebuild ...` });
|
||||||
return new Response("Modules Rebuilt");
|
return new Response("Modules Rebuilt");
|
||||||
}
|
}
|
||||||
@ -85,12 +76,8 @@ export default async function bunextRequestHandler({
|
|||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (is_dev) {
|
return new Response(`Server Error: ${error.message}`, {
|
||||||
return new Response(`Server Error: ${error.message}`, {
|
status: 500,
|
||||||
status: 500,
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
console.error(`Server Error: ${error.message}`, error);
|
|
||||||
return new Response("Internal Server Error", { status: 500 });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import grabDirNames from "../../utils/grab-dir-names";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import isDevelopment from "../../utils/is-development";
|
import isDevelopment from "../../utils/is-development";
|
||||||
import { readFileResponse } from "./handle-public";
|
import { readFileResponse } from "./handle-public";
|
||||||
import isSafePath from "../../utils/is-safe-path";
|
|
||||||
|
|
||||||
const { BUNEXT_PUBLIC_DIR } = grabDirNames();
|
const { BUNEXT_PUBLIC_DIR } = grabDirNames();
|
||||||
|
|
||||||
@ -20,7 +19,7 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
url.pathname.replace(/\/\.bunext\/public\//, ""),
|
url.pathname.replace(/\/\.bunext\/public\//, ""),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isSafePath({ filePath: file_path, allowedDir: BUNEXT_PUBLIC_DIR })) {
|
if (!file_path.startsWith(BUNEXT_PUBLIC_DIR + path.sep)) {
|
||||||
return new Response("Forbidden", { status: 403 });
|
return new Response("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import grabDirNames from "../../utils/grab-dir-names";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import isDevelopment from "../../utils/is-development";
|
import isDevelopment from "../../utils/is-development";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
import isSafePath from "../../utils/is-safe-path";
|
|
||||||
|
|
||||||
const { PUBLIC_DIR } = grabDirNames();
|
const { PUBLIC_DIR } = grabDirNames();
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const file_path = path.join(PUBLIC_DIR, url.pathname);
|
const file_path = path.join(PUBLIC_DIR, url.pathname);
|
||||||
|
|
||||||
if (!isSafePath({ filePath: file_path, allowedDir: PUBLIC_DIR })) {
|
if (!file_path.startsWith(PUBLIC_DIR + path.sep)) {
|
||||||
return new Response("Forbidden", { status: 403 });
|
return new Response("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,13 +26,7 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const file = Bun.file(file_path);
|
const file = Bun.file(file_path);
|
||||||
const headers = new Headers();
|
return new Response(file);
|
||||||
|
|
||||||
if (!is_dev) {
|
|
||||||
headers.set("Cache-Control", "public, max-age=3600");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(file, { headers });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new Response(`File Not Found`, {
|
return new Response(`File Not Found`, {
|
||||||
status: 404,
|
status: 404,
|
||||||
|
|||||||
@ -2,28 +2,8 @@ type Params = {
|
|||||||
req: Request;
|
req: Request;
|
||||||
};
|
};
|
||||||
|
|
||||||
function removeController(controller: ReadableStreamDefaultController<string>) {
|
|
||||||
const idx = global.HMR_CONTROLLERS.findIndex(
|
|
||||||
(c) => c.controller == controller,
|
|
||||||
);
|
|
||||||
if (typeof idx == "number" && idx >= 0) {
|
|
||||||
global.HMR_CONTROLLERS.splice(idx, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function ({ req }: Params): Promise<Response> {
|
export default async function ({ req }: Params): Promise<Response> {
|
||||||
const referer = req.headers.get("referer");
|
const referer_url = new URL(req.headers.get("referer") || "");
|
||||||
if (!referer) {
|
|
||||||
return new Response("Missing Referer Header", { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
let referer_url: URL;
|
|
||||||
try {
|
|
||||||
referer_url = new URL(referer);
|
|
||||||
} catch {
|
|
||||||
return new Response("Invalid Referer Header", { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const match = global.ROUTER.match(referer_url.pathname);
|
const match = global.ROUTER.match(referer_url.pathname);
|
||||||
|
|
||||||
const target_map = match?.filePath
|
const target_map = match?.filePath
|
||||||
@ -45,13 +25,21 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
c.enqueue(": keep-alive\n\n");
|
c.enqueue(": keep-alive\n\n");
|
||||||
} catch {
|
} catch {
|
||||||
clearInterval(heartbeat);
|
clearInterval(heartbeat);
|
||||||
removeController(controller);
|
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
},
|
},
|
||||||
cancel() {
|
cancel() {
|
||||||
clearInterval(heartbeat);
|
clearInterval(heartbeat);
|
||||||
removeController(controller);
|
const targetControllerIndex = global.HMR_CONTROLLERS.findIndex(
|
||||||
|
(c) => c.controller == controller,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof targetControllerIndex == "number" &&
|
||||||
|
targetControllerIndex >= 0
|
||||||
|
) {
|
||||||
|
global.HMR_CONTROLLERS.splice(targetControllerIndex, 1);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import grabDirNames from "../../utils/grab-dir-names";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import isDevelopment from "../../utils/is-development";
|
import isDevelopment from "../../utils/is-development";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
import isSafePath from "../../utils/is-safe-path";
|
|
||||||
|
|
||||||
const { PUBLIC_DIR } = grabDirNames();
|
const { PUBLIC_DIR } = grabDirNames();
|
||||||
|
|
||||||
@ -20,7 +19,7 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
url.pathname.replace(/^\/public/, ""),
|
url.pathname.replace(/^\/public/, ""),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isSafePath({ filePath: file_path, allowedDir: PUBLIC_DIR })) {
|
if (!file_path.startsWith(PUBLIC_DIR + path.sep)) {
|
||||||
return new Response("Forbidden", { status: 403 });
|
return new Response("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,8 +53,6 @@ export function readFileResponse({ file_path, cache }: FileResponse) {
|
|||||||
headers.set("Cache-Control", "public, max-age=31536000, immutable");
|
headers.set("Cache-Control", "public, max-age=31536000, immutable");
|
||||||
} else if (cache?.duration) {
|
} else if (cache?.duration) {
|
||||||
headers.set("Cache-Control", `public, max-age=${cache.duration}`);
|
headers.set("Cache-Control", `public, max-age=${cache.duration}`);
|
||||||
} else if (!isDevelopment()) {
|
|
||||||
headers.set("Cache-Control", "public, max-age=3600");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(file, {
|
return new Response(file, {
|
||||||
|
|||||||
@ -68,16 +68,16 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
|
|
||||||
const config = module.config as BunextServerRouteConfig | undefined;
|
const config = module.config as BunextServerRouteConfig | undefined;
|
||||||
|
|
||||||
const maxBodyBytes = config?.max_request_body_mb
|
|
||||||
? config.max_request_body_mb * MBInBytes
|
|
||||||
: ServerDefaultRequestBodyLimitBytes;
|
|
||||||
|
|
||||||
const contentLength = req.headers.get("content-length");
|
const contentLength = req.headers.get("content-length");
|
||||||
|
|
||||||
if (contentLength) {
|
if (contentLength) {
|
||||||
const size = parseInt(contentLength, 10);
|
const size = parseInt(contentLength, 10);
|
||||||
|
|
||||||
if (size > maxBodyBytes) {
|
if (
|
||||||
|
(config?.max_request_body_mb &&
|
||||||
|
size > config.max_request_body_mb * MBInBytes) ||
|
||||||
|
size > ServerDefaultRequestBodyLimitBytes
|
||||||
|
) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
@ -91,26 +91,6 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (req.method !== "GET" && req.method !== "HEAD") {
|
|
||||||
const body = await req.arrayBuffer();
|
|
||||||
if (body.byteLength > maxBodyBytes) {
|
|
||||||
return Response.json(
|
|
||||||
{
|
|
||||||
success: false,
|
|
||||||
msg: "Request Body Too Large!",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: 413,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
routeParams.body = JSON.parse(
|
|
||||||
new TextDecoder().decode(body) || "{}",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const target_module = (module["default"] ||
|
const target_module = (module["default"] ||
|
||||||
|
|||||||
@ -45,8 +45,8 @@ export default async function serverPostBuildFn(params?: Params) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mock_req = target_artifact.req_url
|
const mock_req = target_artifact.req
|
||||||
? new Request(target_artifact.req_url)
|
? target_artifact.req.clone()
|
||||||
: new Request(controller.page_url);
|
: new Request(controller.page_url);
|
||||||
|
|
||||||
const page_component = global.IS_SERVER_COMPONENT
|
const page_component = global.IS_SERVER_COMPONENT
|
||||||
|
|||||||
@ -178,19 +178,16 @@ export default async function genWebHTML({
|
|||||||
console.info = () => {};
|
console.info = () => {};
|
||||||
console.debug = () => {};
|
console.debug = () => {};
|
||||||
|
|
||||||
let htmlBody: string;
|
const stream = await renderToReadableStream(final_component, {
|
||||||
try {
|
onError(error: any) {
|
||||||
const stream = await renderToReadableStream(final_component, {
|
if (error.message.includes('unique "key" prop')) return;
|
||||||
onError(error: any) {
|
originalConsole.error(error);
|
||||||
if (error.message.includes('unique "key" prop')) return;
|
},
|
||||||
originalConsole.error(error);
|
});
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
htmlBody = await new Response(stream).text();
|
const htmlBody = await new Response(stream).text();
|
||||||
} finally {
|
|
||||||
Object.assign(console, originalConsole);
|
Object.assign(console, originalConsole);
|
||||||
}
|
|
||||||
|
|
||||||
html += htmlBody;
|
html += htmlBody;
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,7 @@ export default async function grabPageCombinedServerRes({
|
|||||||
const page_server_ctx = global.SSR_BUNDLER_CTX_MAP[server_file_path || ""];
|
const page_server_ctx = global.SSR_BUNDLER_CTX_MAP[server_file_path || ""];
|
||||||
const final_page_server_path = page_server_ctx?.local_path
|
const final_page_server_path = page_server_ctx?.local_path
|
||||||
? path.join(ROOT_DIR, page_server_ctx.path)
|
? path.join(ROOT_DIR, page_server_ctx.path)
|
||||||
: server_file_path;
|
: root_server_file_path;
|
||||||
|
|
||||||
const server_module: BunextPageServerModule = final_page_server_path
|
const server_module: BunextPageServerModule = final_page_server_path
|
||||||
? await import(`${final_page_server_path}?t=${now}`)
|
? await import(`${final_page_server_path}?t=${now}`)
|
||||||
|
|||||||
@ -117,7 +117,7 @@ export default async function grabPageComponent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req && !is_hydration) {
|
if (req && !is_hydration) {
|
||||||
global.BUNDLER_CTX_MAP[file_path].req_url = req.url;
|
global.BUNDLER_CTX_MAP[file_path].req = req;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
|||||||
@ -344,7 +344,7 @@ export type BundlerCTXMap = {
|
|||||||
url_path: string;
|
url_path: string;
|
||||||
file_name: string;
|
file_name: string;
|
||||||
css_path?: string;
|
css_path?: string;
|
||||||
req_url?: string;
|
req?: Request;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GlobalHMRControllerObject = {
|
export type GlobalHMRControllerObject = {
|
||||||
|
|||||||
@ -1,18 +1,8 @@
|
|||||||
import EJSON from "./ejson";
|
import EJSON from "./ejson";
|
||||||
|
|
||||||
const DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
/**
|
||||||
|
* # Convert Serialized Query back to object
|
||||||
function sanitize<T>(value: T): T {
|
*/
|
||||||
if (value === null || typeof value !== "object") return value;
|
|
||||||
if (Array.isArray(value)) return value.map(sanitize) as T;
|
|
||||||
const clean: Record<string, any> = Object.create(null);
|
|
||||||
for (const key of Object.keys(value as Record<string, any>)) {
|
|
||||||
if (DANGEROUS_KEYS.has(key)) continue;
|
|
||||||
clean[key] = sanitize((value as Record<string, any>)[key]);
|
|
||||||
}
|
|
||||||
return clean as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function deserializeQuery(
|
export default function deserializeQuery(
|
||||||
query: string | { [s: string]: any }
|
query: string | { [s: string]: any }
|
||||||
): {
|
): {
|
||||||
@ -27,17 +17,12 @@ export default function deserializeQuery(
|
|||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
const value = queryObject[key];
|
const value = queryObject[key];
|
||||||
|
|
||||||
if (DANGEROUS_KEYS.has(key)) {
|
|
||||||
delete queryObject[key];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value == "string") {
|
if (typeof value == "string") {
|
||||||
if (value.match(/^\{|^\[/)) {
|
if (value.match(/^\{|^\[/)) {
|
||||||
queryObject[key] = sanitize(EJSON.parse(value));
|
queryObject[key] = EJSON.parse(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sanitize(queryObject);
|
return queryObject;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,38 +1,6 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
export type DirNames = {
|
export default function grabDirNames() {
|
||||||
ROOT_DIR: string;
|
|
||||||
SRC_DIR: string;
|
|
||||||
PAGES_DIR: string;
|
|
||||||
API_DIR: string;
|
|
||||||
PUBLIC_DIR: string;
|
|
||||||
HYDRATION_DST_DIR: string;
|
|
||||||
BUNX_CWD_DIR: string;
|
|
||||||
BUNX_ROOT_DIR: string;
|
|
||||||
CONFIG_FILE: string;
|
|
||||||
BUNX_TMP_DIR: string;
|
|
||||||
BUNX_HYDRATION_SRC_DIR: string;
|
|
||||||
BUNX_ROOT_SRC_DIR: string;
|
|
||||||
BUNX_ROOT_PRESETS_DIR: string;
|
|
||||||
BUNX_ROOT_500_PRESET_COMPONENT: string;
|
|
||||||
BUNX_ROOT_500_FILE_NAME: string;
|
|
||||||
BUNX_ROOT_404_PRESET_COMPONENT: string;
|
|
||||||
BUNX_ROOT_404_FILE_NAME: string;
|
|
||||||
HYDRATION_DST_DIR_MAP_JSON_FILE: string;
|
|
||||||
BUNEXT_CACHE_DIR: string;
|
|
||||||
BUNX_CWD_MODULE_CACHE_DIR: string;
|
|
||||||
BUNX_CWD_PAGES_REWRITE_DIR: string;
|
|
||||||
HYDRATION_DST_DIR_MAP_JSON_FILE_NAME: string;
|
|
||||||
BUNEXT_VENDOR_DIR: string;
|
|
||||||
BUNEXT_PUBLIC_DIR: string;
|
|
||||||
BUNX_BUNDLER_ERROR_EXIT_FILE: string;
|
|
||||||
BUNX_ERROR_LOGS_DIR: string;
|
|
||||||
BUNX_LOGS_DIR: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function grabDirNames(): DirNames {
|
|
||||||
if (global.DIR_NAMES) return global.DIR_NAMES;
|
|
||||||
|
|
||||||
const ROOT_DIR = process.cwd();
|
const ROOT_DIR = process.cwd();
|
||||||
const SRC_DIR = path.join(ROOT_DIR, "src");
|
const SRC_DIR = path.join(ROOT_DIR, "src");
|
||||||
const PAGES_DIR = path.join(SRC_DIR, "pages");
|
const PAGES_DIR = path.join(SRC_DIR, "pages");
|
||||||
|
|||||||
@ -1,7 +1,13 @@
|
|||||||
export default function isDevelopment() {
|
export default function isDevelopment() {
|
||||||
if (process.env.NODE_ENV === "production") {
|
const config = global.CONFIG;
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV == "production") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boolean(global.CONFIG?.development);
|
if (config.development) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import { realpathSync } from "fs";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
export default function isSafePath({
|
|
||||||
filePath,
|
|
||||||
allowedDir,
|
|
||||||
}: {
|
|
||||||
filePath: string;
|
|
||||||
allowedDir: string;
|
|
||||||
}): boolean {
|
|
||||||
const resolved = path.resolve(filePath);
|
|
||||||
if (!resolved.startsWith(allowedDir + path.sep) && resolved !== allowedDir) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const real = realpathSync(resolved);
|
|
||||||
return (
|
|
||||||
real.startsWith(allowedDir + path.sep) || real === allowedDir
|
|
||||||
);
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user