diff --git a/dist/__tests__/e2e/e2e.test.d.ts b/dist/__tests__/e2e/e2e.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/e2e/e2e.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/e2e/e2e.test.js b/dist/__tests__/e2e/e2e.test.js
deleted file mode 100644
index daeaec4..0000000
--- a/dist/__tests__/e2e/e2e.test.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { describe, expect, test, beforeAll, afterAll } from "bun:test";
-import startServer from "../../../src/functions/server/start-server";
-import bunextInit from "../../../src/functions/bunext-init";
-import path from "path";
-import fs from "fs";
-let originalCwd = process.cwd();
-describe("E2E Integration", () => {
- let server;
- beforeAll(async () => {
- // Change to the fixture directory to simulate actual user repo
- const fixtureDir = path.resolve(__dirname, "../__fixtures__/app");
- process.chdir(fixtureDir);
- // Mock grabAppPort to assign dynamically to avoid port conflicts
- global.CONFIG = { development: true };
- });
- afterAll(async () => {
- if (server) {
- server.stop(true);
- }
- process.chdir(originalCwd);
- // Ensure to remove the dummy generated .bunext folder
- const dotBunext = path.resolve(__dirname, "../__fixtures__/app/.bunext");
- if (fs.existsSync(dotBunext)) {
- fs.rmSync(dotBunext, { recursive: true, force: true });
- }
- const pubBunext = path.resolve(__dirname, "../__fixtures__/app/public/__bunext");
- if (fs.existsSync(pubBunext)) {
- fs.rmSync(pubBunext, { recursive: true, force: true });
- }
- });
- test("boots up the server and correctly routes to index.tsx page", async () => {
- // Mock to randomize port
- // Note: Bun test runs modules in isolation but startServer imports grab-app-port
- // If we can't easily mock we can set PORT env
- process.env.PORT = "0"; // Let Bun.serve pick port
- await bunextInit();
- server = await startServer();
- expect(server).toBeDefined();
- // Fetch the index page
- const response = await fetch(`http://localhost:${server.port}/`);
- expect(response.status).toBe(200);
- const html = await response.text();
- expect(html).toContain("Hello E2E");
- });
- test("returns 404 for unknown route", async () => {
- const response = await fetch(`http://localhost:${server.port}/unknown-foo-bar123`);
- expect(response.status).toBe(404);
- const text = await response.text();
- // Assume default 404 preset component is rendered
- expect(text).toContain("404");
- });
-});
diff --git a/dist/__tests__/functions/cache/grab-cache-names.test.d.ts b/dist/__tests__/functions/cache/grab-cache-names.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/functions/cache/grab-cache-names.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/functions/cache/grab-cache-names.test.js b/dist/__tests__/functions/cache/grab-cache-names.test.js
deleted file mode 100644
index 5b3e3ba..0000000
--- a/dist/__tests__/functions/cache/grab-cache-names.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import grabCacheNames from "../../../functions/cache/grab-cache-names";
-describe("grabCacheNames", () => {
- it("returns cache_name and cache_meta_name for a simple key", () => {
- const { cache_name, cache_meta_name } = grabCacheNames({ key: "home" });
- expect(cache_name).toBe("home.res.html");
- expect(cache_meta_name).toBe("home.meta.json");
- });
- it("defaults paradigm to html", () => {
- const { cache_name } = grabCacheNames({ key: "page" });
- expect(cache_name).toEndWith(".res.html");
- });
- it("uses json paradigm when specified", () => {
- const { cache_name } = grabCacheNames({ key: "api-data", paradigm: "json" });
- expect(cache_name).toBe("api-data.res.json");
- });
- it("URL-encodes the key", () => {
- const { cache_name, cache_meta_name } = grabCacheNames({
- key: "/blog/hello world",
- });
- const encoded = encodeURIComponent("/blog/hello world");
- expect(cache_name).toBe(`${encoded}.res.html`);
- expect(cache_meta_name).toBe(`${encoded}.meta.json`);
- });
- it("handles keys with special characters", () => {
- const key = "page?id=1&sort=asc";
- const { cache_name } = grabCacheNames({ key });
- expect(cache_name).toBe(`${encodeURIComponent(key)}.res.html`);
- });
- it("cache_meta_name always uses .meta.json regardless of paradigm", () => {
- const { cache_meta_name } = grabCacheNames({
- key: "test",
- paradigm: "json",
- });
- expect(cache_meta_name).toBe("test.meta.json");
- });
-});
diff --git a/dist/__tests__/functions/server/bunext-req-handler.test.d.ts b/dist/__tests__/functions/server/bunext-req-handler.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/functions/server/bunext-req-handler.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/functions/server/bunext-req-handler.test.js b/dist/__tests__/functions/server/bunext-req-handler.test.js
deleted file mode 100644
index 6269047..0000000
--- a/dist/__tests__/functions/server/bunext-req-handler.test.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import { describe, expect, test, mock, afterAll } from "bun:test";
-import bunextRequestHandler from "../../../../src/functions/server/bunext-req-handler";
-mock.module("../../../../src/utils/is-development", () => ({
- default: () => true
-}));
-mock.module("../../../../src/utils/grab-constants", () => ({
- default: () => ({
- config: {
- middleware: async ({ url }) => {
- if (url.pathname === "/blocked") {
- return new Response("Blocked by middleware", { status: 403 });
- }
- return undefined;
- }
- }
- })
-}));
-mock.module("../../../../src/functions/server/handle-routes", () => ({
- default: async () => new Response("api-routes")
-}));
-mock.module("../../../../src/functions/server/handle-public", () => ({
- default: async () => new Response("public")
-}));
-mock.module("../../../../src/functions/server/handle-files", () => ({
- default: async () => new Response("files")
-}));
-mock.module("../../../../src/functions/server/web-pages/handle-web-pages", () => ({
- default: async () => new Response("web-pages")
-}));
-/**
- * Tests for the `bunext-req-handler` module.
- * Ensures that requests are correctly routed to the proper subsystem.
- */
-describe("bunext-req-handler", () => {
- afterAll(() => {
- mock.restore();
- });
- test("middleware is caught", async () => {
- const req = new Request("http://localhost/blocked");
- const res = await bunextRequestHandler({ req });
- expect(res.status).toBe(403);
- expect(await res.text()).toBe("Blocked by middleware");
- });
- test("routes /__hmr to handleHmr in dev", async () => {
- global.ROUTER = { match: () => ({}) };
- global.HMR_CONTROLLERS = [];
- const req = new Request("http://localhost/__hmr", {
- headers: { referer: "http://localhost/" }
- });
- const res = await bunextRequestHandler({ req });
- expect(res.headers.get("Content-Type")).toBe("text/event-stream");
- });
- test("routes /api/ to handleRoutes", async () => {
- const req = new Request("http://localhost/api/users");
- const res = await bunextRequestHandler({ req });
- expect(await res.text()).toBe("api-routes");
- });
- test("routes /public/ to handlePublic", async () => {
- const req = new Request("http://localhost/public/image.png");
- const res = await bunextRequestHandler({ req });
- expect(await res.text()).toBe("public");
- });
- test("routes files like .js to handleFiles", async () => {
- const req = new Request("http://localhost/script.js");
- const res = await bunextRequestHandler({ req });
- expect(await res.text()).toBe("files");
- });
- test("routes anything else to handleWebPages", async () => {
- const req = new Request("http://localhost/about");
- const res = await bunextRequestHandler({ req });
- expect(await res.text()).toBe("web-pages");
- });
-});
diff --git a/dist/__tests__/functions/server/grab-web-meta-html.test.d.ts b/dist/__tests__/functions/server/grab-web-meta-html.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/functions/server/grab-web-meta-html.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/functions/server/grab-web-meta-html.test.js b/dist/__tests__/functions/server/grab-web-meta-html.test.js
deleted file mode 100644
index f5a8b67..0000000
--- a/dist/__tests__/functions/server/grab-web-meta-html.test.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import grabWebMetaHTML from "../../../functions/server/web-pages/grab-web-meta-html";
-describe("grabWebMetaHTML", () => {
- it("returns empty string for empty meta object", () => {
- expect(grabWebMetaHTML({ meta: {} })).toBe("");
- });
- it("generates a title tag", () => {
- const html = grabWebMetaHTML({ meta: { title: "My Page" } });
- expect(html).toContain("
My Page");
- });
- it("generates a description meta tag", () => {
- const html = grabWebMetaHTML({ meta: { description: "A description" } });
- expect(html).toContain(' {
- const html = grabWebMetaHTML({
- meta: { keywords: ["react", "bun", "ssr"] },
- });
- expect(html).toContain('content="react, bun, ssr"');
- });
- it("uses string keywords directly", () => {
- const html = grabWebMetaHTML({ meta: { keywords: "react, bun" } });
- expect(html).toContain('content="react, bun"');
- });
- it("generates author meta tag", () => {
- const html = grabWebMetaHTML({ meta: { author: "Alice" } });
- expect(html).toContain(' {
- const html = grabWebMetaHTML({ meta: { robots: "noindex" } });
- expect(html).toContain(' {
- const html = grabWebMetaHTML({
- meta: { canonical: "https://example.com/page" },
- });
- expect(html).toContain(' {
- const html = grabWebMetaHTML({ meta: { themeColor: "#ff0000" } });
- expect(html).toContain(' {
- const html = grabWebMetaHTML({
- meta: {
- og: {
- title: "OG Title",
- description: "OG Desc",
- image: "https://example.com/img.png",
- url: "https://example.com",
- type: "website",
- siteName: "Example",
- locale: "en_US",
- },
- },
- });
- expect(html).toContain(' {
- const html = grabWebMetaHTML({
- meta: {
- twitter: {
- card: "summary_large_image",
- title: "Tweet Title",
- description: "Tweet Desc",
- image: "https://example.com/tw.png",
- site: "@example",
- creator: "@alice",
- },
- },
- });
- expect(html).toContain(' {
- const html = grabWebMetaHTML({ meta: { og: { title: "Only Title" } } });
- expect(html).toContain("og:title");
- expect(html).not.toContain("og:description");
- expect(html).not.toContain("og:image");
- });
- it("does not emit tags for missing fields", () => {
- const html = grabWebMetaHTML({ meta: { title: "Hello" } });
- expect(html).not.toContain("description");
- expect(html).not.toContain("og:");
- expect(html).not.toContain("twitter:");
- });
-});
diff --git a/dist/__tests__/functions/server/handle-hmr.test.d.ts b/dist/__tests__/functions/server/handle-hmr.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/functions/server/handle-hmr.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/functions/server/handle-hmr.test.js b/dist/__tests__/functions/server/handle-hmr.test.js
deleted file mode 100644
index 5c6b60f..0000000
--- a/dist/__tests__/functions/server/handle-hmr.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { describe, expect, test, mock, beforeEach, afterEach } from "bun:test";
-import handleHmr from "../../../../src/functions/server/handle-hmr";
-describe("handle-hmr", () => {
- beforeEach(() => {
- global.ROUTER = {
- match: (path) => {
- if (path === "/test")
- return { filePath: "/test-file" };
- return null;
- }
- };
- global.HMR_CONTROLLERS = [];
- global.BUNDLER_CTX_MAP = [
- { local_path: "/test-file" }
- ];
- });
- afterEach(() => {
- global.ROUTER = undefined;
- global.HMR_CONTROLLERS = [];
- global.BUNDLER_CTX_MAP = undefined;
- });
- test("sets up SSE stream and pushes to HMR_CONTROLLERS", async () => {
- const req = new Request("http://localhost/hmr", {
- headers: {
- "referer": "http://localhost/test"
- }
- });
- const res = await handleHmr({ req });
- expect(res.status).toBe(200);
- expect(res.headers.get("Content-Type")).toBe("text/event-stream");
- expect(res.headers.get("Connection")).toBe("keep-alive");
- expect(global.HMR_CONTROLLERS.length).toBe(1);
- const controller = global.HMR_CONTROLLERS[0];
- expect(controller.page_url).toBe("http://localhost/test");
- expect(controller.target_map?.local_path).toBe("/test-file");
- });
-});
diff --git a/dist/__tests__/functions/server/handle-routes.test.d.ts b/dist/__tests__/functions/server/handle-routes.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/functions/server/handle-routes.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/functions/server/handle-routes.test.js b/dist/__tests__/functions/server/handle-routes.test.js
deleted file mode 100644
index 2bd7610..0000000
--- a/dist/__tests__/functions/server/handle-routes.test.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import { describe, expect, test, mock, afterAll } from "bun:test";
-import handleRoutes from "../../../../src/functions/server/handle-routes";
-mock.module("../../../../src/utils/is-development", () => ({
- default: () => false
-}));
-mock.module("../../../../src/utils/grab-constants", () => ({
- default: () => ({ MBInBytes: 1048576, ServerDefaultRequestBodyLimitBytes: 5242880 })
-}));
-mock.module("../../../../src/utils/grab-router", () => ({
- default: () => ({
- match: (path) => {
- if (path === "/api/test")
- return { filePath: "/test-path" };
- if (path === "/api/large")
- return { filePath: "/large-path" };
- return null;
- }
- })
-}));
-mock.module("../../../../src/utils/grab-route-params", () => ({
- default: async () => ({ params: {}, searchParams: {} })
-}));
-mock.module("/test-path", () => ({
- default: async () => new Response("OK", { status: 200 })
-}));
-mock.module("/large-path", () => ({
- default: async () => new Response("Large OK", { status: 200 }),
- config: { maxRequestBodyMB: 1 }
-}));
-/**
- * Tests for routing logic within `handle-routes`.
- */
-describe("handle-routes", () => {
- afterAll(() => {
- mock.restore();
- });
- test("returns 401 for unknown route", async () => {
- const req = new Request("http://localhost/api/unknown");
- const res = await handleRoutes({ req });
- expect(res.status).toBe(401);
- const json = await res.json();
- expect(json.success).toBe(false);
- expect(json.msg).toContain("not found");
- });
- test("calls matched module default export", async () => {
- const req = new Request("http://localhost/api/test");
- const res = await handleRoutes({ req });
- expect(res.status).toBe(200);
- expect(await res.text()).toBe("OK");
- });
- test("enforces request body size limits", async () => {
- // limit is 1MB from mock config
- const req = new Request("http://localhost/api/large", {
- method: "POST",
- headers: {
- "content-length": "2000000" // ~2MB
- },
- body: "x".repeat(10) // the actual body doesn't matter since handleRoutes only checks the header
- });
- const res = await handleRoutes({ req });
- expect(res.status).toBe(413);
- const json = await res.json();
- expect(json.success).toBe(false);
- });
-});
diff --git a/dist/__tests__/functions/server/start-server.test.d.ts b/dist/__tests__/functions/server/start-server.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/functions/server/start-server.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/functions/server/start-server.test.js b/dist/__tests__/functions/server/start-server.test.js
deleted file mode 100644
index fb359fb..0000000
--- a/dist/__tests__/functions/server/start-server.test.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { describe, expect, test, mock, afterEach } from "bun:test";
-import startServer from "../../../../src/functions/server/start-server";
-import { log } from "../../../../src/utils/log";
-// Mock log so we don't spam terminal during tests
-mock.module("../../../../src/utils/log", () => ({
- log: {
- server: mock((msg) => { }),
- info: mock((msg) => { }),
- error: mock((msg) => { }),
- }
-}));
-// Mock grabConfig so it doesn't try to look for bunext.config.ts and exit process
-mock.module("../../../../src/functions/grab-config", () => ({
- default: async () => ({})
-}));
-// Mock grabAppPort to return 0 so Bun.serve picks a random port
-mock.module("../../../../src/utils/grab-app-port", () => ({
- default: () => 0
-}));
-describe("startServer", () => {
- afterEach(() => {
- if (global.SERVER) {
- global.SERVER.stop(true);
- global.SERVER = undefined;
- }
- });
- test("starts the server and assigns to global.SERVER", async () => {
- global.CONFIG = { development: true };
- const server = await startServer();
- expect(server).toBeDefined();
- expect(server.port).toBeGreaterThan(0);
- expect(global.SERVER).toBe(server);
- expect(log.server).toHaveBeenCalled();
- server.stop(true);
- });
-});
diff --git a/dist/__tests__/hydration/hydration.test.d.ts b/dist/__tests__/hydration/hydration.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/hydration/hydration.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/hydration/hydration.test.js b/dist/__tests__/hydration/hydration.test.js
deleted file mode 100644
index 60b9b38..0000000
--- a/dist/__tests__/hydration/hydration.test.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
-import { describe, expect, test, beforeEach, afterEach } from "bun:test";
-import React, { useState } from "react";
-import { renderToString } from "react-dom/server";
-import { hydrateRoot } from "react-dom/client";
-import { GlobalWindow } from "happy-dom";
-// A mock application component to test hydration
-function App() {
- const [count, setCount] = useState(0);
- return (_jsxs("div", { id: "app-root", children: [_jsx("h1", { children: "Test Hydration" }), _jsxs("p", { "data-testid": "count", children: ["Count: ", count] }), _jsx("button", { "data-testid": "btn", onClick: () => setCount(c => c + 1), children: "Increment" })] }));
-}
-describe("React Hydration", () => {
- let window;
- let document;
- beforeEach(() => {
- window = new GlobalWindow();
- document = window.document;
- global.window = window;
- global.document = document;
- global.navigator = { userAgent: "node.js" };
- });
- afterEach(() => {
- // Clean up global mocks
- delete global.window;
- delete global.document;
- delete global.navigator;
- window.close();
- });
- test("hydrates a server-rendered component and binds events", async () => {
- // 1. Server-side render
- const html = renderToString(_jsx(App, {}));
- // 2. Setup DOM as it would be delivered to the client
- document.body.innerHTML = `${html}
`;
- const rootNode = document.getElementById("root");
- // 3. Hydrate
- let hydrateError = null;
- try {
- await new Promise((resolve) => {
- hydrateRoot(rootNode, _jsx(App, {}), {
- onRecoverableError: (err) => {
- hydrateError = err;
- }
- });
- setTimeout(resolve, 50); // let React finish hydration
- });
- }
- catch (e) {
- hydrateError = e;
- }
- // Verify no hydration errors
- expect(hydrateError).toBeNull();
- // 4. Verify client-side interactivity
- const button = document.querySelector('[data-testid="btn"]');
- const countText = document.querySelector('[data-testid="count"]');
- expect(countText.textContent).toBe("Count: 0");
- // Simulate click
- button.dispatchEvent(new window.Event("click", { bubbles: true }));
- // Let async state updates process
- await new Promise(r => setTimeout(r, 50));
- expect(countText.textContent).toBe("Count: 1");
- });
-});
diff --git a/dist/__tests__/utils/deserialize-query.test.d.ts b/dist/__tests__/utils/deserialize-query.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/deserialize-query.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/deserialize-query.test.js b/dist/__tests__/utils/deserialize-query.test.js
deleted file mode 100644
index f1bc5bd..0000000
--- a/dist/__tests__/utils/deserialize-query.test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import deserializeQuery from "../../utils/deserialize-query";
-describe("deserializeQuery", () => {
- it("passes through a plain object unchanged", () => {
- const input = { foo: "bar" };
- expect(deserializeQuery(input)).toEqual({ foo: "bar" });
- });
- it("parses a JSON string into an object", () => {
- const input = JSON.stringify({ a: 1, b: "hello" });
- expect(deserializeQuery(input)).toEqual({ a: 1, b: "hello" });
- });
- it("deep-parses string values that look like JSON objects", () => {
- const nested = { filter: JSON.stringify({ status: "active" }) };
- const result = deserializeQuery(nested);
- expect(result.filter).toEqual({ status: "active" });
- });
- it("deep-parses string values that look like JSON arrays", () => {
- const nested = { ids: JSON.stringify([1, 2, 3]) };
- const result = deserializeQuery(nested);
- expect(result.ids).toEqual([1, 2, 3]);
- });
- it("leaves plain string values alone", () => {
- const input = { name: "alice", age: "30" };
- expect(deserializeQuery(input)).toEqual({ name: "alice", age: "30" });
- });
- it("returns an empty object for an empty JSON string", () => {
- expect(deserializeQuery("{}")).toEqual({});
- });
- it("returns an empty object for an invalid JSON string", () => {
- // EJSON.parse returns undefined → Object(undefined) → {}
- expect(deserializeQuery("not-json")).toEqual({});
- });
-});
diff --git a/dist/__tests__/utils/ejson.test.d.ts b/dist/__tests__/utils/ejson.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/ejson.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/ejson.test.js b/dist/__tests__/utils/ejson.test.js
deleted file mode 100644
index 120908c..0000000
--- a/dist/__tests__/utils/ejson.test.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import EJSON from "../../utils/ejson";
-describe("EJSON.parse", () => {
- it("parses a valid JSON string", () => {
- expect(EJSON.parse('{"a":1}')).toEqual({ a: 1 });
- });
- it("parses a JSON array string", () => {
- expect(EJSON.parse('[1,2,3]')).toEqual([1, 2, 3]);
- });
- it("returns undefined for null input", () => {
- expect(EJSON.parse(null)).toBeUndefined();
- });
- it("returns undefined for empty string", () => {
- expect(EJSON.parse("")).toBeUndefined();
- });
- it("returns undefined for invalid JSON", () => {
- expect(EJSON.parse("{bad json")).toBeUndefined();
- });
- it("returns the object directly when passed an object (typeof object)", () => {
- const obj = { x: 1 };
- expect(EJSON.parse(obj)).toBe(obj);
- });
- it("returns undefined for a number input", () => {
- expect(EJSON.parse(42)).toBeUndefined();
- });
- it("applies a reviver function", () => {
- const result = EJSON.parse('{"a":"2"}', (key, value) => key === "a" ? Number(value) : value);
- expect(result).toEqual({ a: 2 });
- });
-});
-describe("EJSON.stringify", () => {
- it("stringifies an object", () => {
- expect(EJSON.stringify({ a: 1 })).toBe('{"a":1}');
- });
- it("stringifies an array", () => {
- expect(EJSON.stringify([1, 2, 3])).toBe("[1,2,3]");
- });
- it("applies spacing", () => {
- expect(EJSON.stringify({ a: 1 }, null, 2)).toBe('{\n "a": 1\n}');
- });
- it("returns undefined for circular references", () => {
- const obj = {};
- obj.self = obj;
- expect(EJSON.stringify(obj)).toBeUndefined();
- });
- it("stringifies null", () => {
- expect(EJSON.stringify(null)).toBe("null");
- });
- it("stringifies a number", () => {
- expect(EJSON.stringify(42)).toBe("42");
- });
-});
diff --git a/dist/__tests__/utils/grab-app-names.test.d.ts b/dist/__tests__/utils/grab-app-names.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/grab-app-names.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/grab-app-names.test.js b/dist/__tests__/utils/grab-app-names.test.js
deleted file mode 100644
index 3b971c4..0000000
--- a/dist/__tests__/utils/grab-app-names.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import AppNames from "../../utils/grab-app-names";
-describe("AppNames", () => {
- it("has a defaultPort of 7000", () => {
- expect(AppNames.defaultPort).toBe(7000);
- });
- it("has the correct defaultAssetPrefix", () => {
- expect(AppNames.defaultAssetPrefix).toBe("_bunext/static");
- });
- it("has name Bunext", () => {
- expect(AppNames.name).toBe("Bunext");
- });
- it("has a version string", () => {
- expect(typeof AppNames.version).toBe("string");
- expect(AppNames.version.length).toBeGreaterThan(0);
- });
- it("has defaultDistDir as .bunext", () => {
- expect(AppNames.defaultDistDir).toBe(".bunext");
- });
- it("has RootPagesComponentName as __root", () => {
- expect(AppNames.RootPagesComponentName).toBe("__root");
- });
-});
diff --git a/dist/__tests__/utils/grab-app-port.test.d.ts b/dist/__tests__/utils/grab-app-port.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/grab-app-port.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/grab-app-port.test.js b/dist/__tests__/utils/grab-app-port.test.js
deleted file mode 100644
index 02c6b91..0000000
--- a/dist/__tests__/utils/grab-app-port.test.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { describe, it, expect, beforeEach, afterEach } from "bun:test";
-import grabAppPort from "../../utils/grab-app-port";
-const originalEnv = process.env.PORT;
-beforeEach(() => {
- delete process.env.PORT;
- global.CONFIG = {};
-});
-afterEach(() => {
- if (originalEnv !== undefined) {
- process.env.PORT = originalEnv;
- }
- else {
- delete process.env.PORT;
- }
-});
-describe("grabAppPort", () => {
- it("returns the default port (7000) when no config or env set", () => {
- expect(grabAppPort()).toBe(7000);
- });
- it("uses PORT env variable when set", () => {
- process.env.PORT = "8080";
- expect(grabAppPort()).toBe(8080);
- });
- it("uses config.port when PORT env is not set", () => {
- global.CONFIG = { port: 3000 };
- expect(grabAppPort()).toBe(3000);
- });
- it("PORT env takes precedence over config.port", () => {
- process.env.PORT = "9000";
- global.CONFIG = { port: 3000 };
- expect(grabAppPort()).toBe(9000);
- });
- it("handles non-numeric PORT env gracefully via numberfy", () => {
- process.env.PORT = "abc";
- // numberfy strips non-numeric chars, "abc" → "" → 0
- expect(grabAppPort()).toBe(0);
- });
-});
diff --git a/dist/__tests__/utils/grab-constants.test.d.ts b/dist/__tests__/utils/grab-constants.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/grab-constants.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/grab-constants.test.js b/dist/__tests__/utils/grab-constants.test.js
deleted file mode 100644
index a8f0c6f..0000000
--- a/dist/__tests__/utils/grab-constants.test.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { describe, it, expect, beforeEach } from "bun:test";
-import grabConstants from "../../utils/grab-constants";
-beforeEach(() => {
- global.CONFIG = {};
-});
-describe("grabConstants", () => {
- it("has the correct ClientRootElementIDName", () => {
- expect(grabConstants().ClientRootElementIDName).toBe("__bunext");
- });
- it("has the correct ClientWindowPagePropsName", () => {
- expect(grabConstants().ClientWindowPagePropsName).toBe("__PAGE_PROPS__");
- });
- it("has the correct ClientRootComponentWindowName", () => {
- expect(grabConstants().ClientRootComponentWindowName).toBe("BUNEXT_ROOT");
- });
- it("calculates MBInBytes as 1024 * 1024", () => {
- expect(grabConstants().MBInBytes).toBe(1024 * 1024);
- });
- it("ServerDefaultRequestBodyLimitBytes is 10 MB", () => {
- expect(grabConstants().ServerDefaultRequestBodyLimitBytes).toBe(10 * 1024 * 1024);
- });
- it("MaxBundlerRebuilds is 5", () => {
- expect(grabConstants().MaxBundlerRebuilds).toBe(5);
- });
- it("returns the current global.CONFIG", () => {
- const cfg = { port: 9000 };
- global.CONFIG = cfg;
- expect(grabConstants().config).toBe(cfg);
- });
-});
diff --git a/dist/__tests__/utils/grab-dir-names.test.d.ts b/dist/__tests__/utils/grab-dir-names.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/grab-dir-names.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/grab-dir-names.test.js b/dist/__tests__/utils/grab-dir-names.test.js
deleted file mode 100644
index c76456d..0000000
--- a/dist/__tests__/utils/grab-dir-names.test.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import path from "path";
-import grabDirNames from "../../utils/grab-dir-names";
-describe("grabDirNames", () => {
- it("derives all paths from process.cwd()", () => {
- const cwd = process.cwd();
- const dirs = grabDirNames();
- expect(dirs.ROOT_DIR).toBe(cwd);
- expect(dirs.SRC_DIR).toBe(path.join(cwd, "src"));
- expect(dirs.PAGES_DIR).toBe(path.join(cwd, "src", "pages"));
- expect(dirs.API_DIR).toBe(path.join(cwd, "src", "pages", "api"));
- expect(dirs.PUBLIC_DIR).toBe(path.join(cwd, "public"));
- });
- it("nests HYDRATION_DST_DIR under public/__bunext/pages", () => {
- const dirs = grabDirNames();
- expect(dirs.HYDRATION_DST_DIR).toBe(path.join(dirs.PUBLIC_DIR, "__bunext", "pages"));
- });
- it("nests BUNEXT_CACHE_DIR under public/__bunext/cache", () => {
- const dirs = grabDirNames();
- expect(dirs.BUNEXT_CACHE_DIR).toBe(path.join(dirs.PUBLIC_DIR, "__bunext", "cache"));
- });
- it("places map JSON file inside HYDRATION_DST_DIR", () => {
- const dirs = grabDirNames();
- expect(dirs.HYDRATION_DST_DIR_MAP_JSON_FILE).toBe(path.join(dirs.HYDRATION_DST_DIR, "map.json"));
- });
- it("places CONFIG_FILE at root", () => {
- const dirs = grabDirNames();
- expect(dirs.CONFIG_FILE).toBe(path.join(dirs.ROOT_DIR, "bunext.config.ts"));
- });
- it("places BUNX_TMP_DIR inside .bunext", () => {
- const dirs = grabDirNames();
- expect(dirs.BUNX_TMP_DIR).toContain(".bunext");
- expect(dirs.BUNX_TMP_DIR).toEndWith(".tmp");
- });
- it("places BUNX_HYDRATION_SRC_DIR under client/hydration-src", () => {
- const dirs = grabDirNames();
- expect(dirs.BUNX_HYDRATION_SRC_DIR).toContain(path.join("client", "hydration-src"));
- });
- it("sets 404 file name to not-found", () => {
- const dirs = grabDirNames();
- expect(dirs.BUNX_ROOT_404_FILE_NAME).toBe("not-found");
- });
- it("sets 500 file name to server-error", () => {
- const dirs = grabDirNames();
- expect(dirs.BUNX_ROOT_500_FILE_NAME).toBe("server-error");
- });
- it("preset 404 component path ends with not-found.tsx", () => {
- const dirs = grabDirNames();
- expect(dirs.BUNX_ROOT_404_PRESET_COMPONENT).toEndWith("not-found.tsx");
- });
- it("preset 500 component path ends with server-error.tsx", () => {
- const dirs = grabDirNames();
- expect(dirs.BUNX_ROOT_500_PRESET_COMPONENT).toEndWith("server-error.tsx");
- });
-});
diff --git a/dist/__tests__/utils/grab-origin.test.d.ts b/dist/__tests__/utils/grab-origin.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/grab-origin.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/grab-origin.test.js b/dist/__tests__/utils/grab-origin.test.js
deleted file mode 100644
index 56f66b9..0000000
--- a/dist/__tests__/utils/grab-origin.test.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { describe, it, expect, beforeEach, afterEach } from "bun:test";
-import grabOrigin from "../../utils/grab-origin";
-const originalPort = process.env.PORT;
-beforeEach(() => {
- delete process.env.PORT;
- global.CONFIG = {};
-});
-afterEach(() => {
- if (originalPort !== undefined) {
- process.env.PORT = originalPort;
- }
- else {
- delete process.env.PORT;
- }
-});
-describe("grabOrigin", () => {
- it("returns config.origin when set", () => {
- global.CONFIG = { origin: "https://example.com" };
- expect(grabOrigin()).toBe("https://example.com");
- });
- it("falls back to http://localhost: using default port", () => {
- expect(grabOrigin()).toBe("http://localhost:7000");
- });
- it("falls back using PORT env variable", () => {
- process.env.PORT = "8080";
- expect(grabOrigin()).toBe("http://localhost:8080");
- });
- it("falls back using config.port", () => {
- global.CONFIG = { port: 3700 };
- expect(grabOrigin()).toBe("http://localhost:3700");
- });
-});
diff --git a/dist/__tests__/utils/grab-page-name.test.d.ts b/dist/__tests__/utils/grab-page-name.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/grab-page-name.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/grab-page-name.test.js b/dist/__tests__/utils/grab-page-name.test.js
deleted file mode 100644
index 97d4c4d..0000000
--- a/dist/__tests__/utils/grab-page-name.test.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import grabPageName from "../../utils/grab-page-name";
-describe("grabPageName", () => {
- it("returns the page name for a simple page path", () => {
- expect(grabPageName({ path: "/home/user/project/src/pages/about.tsx" }))
- .toBe("about");
- });
- it("returns 'index' for a root index file (no -index stripping at root)", () => {
- // -index suffix is only stripped when joined: e.g. "blog-index" → "blog"
- // A standalone "index" filename has no leading dash so stays as-is
- expect(grabPageName({ path: "/home/user/project/src/pages/index.tsx" }))
- .toBe("index");
- });
- it("handles nested page paths", () => {
- expect(grabPageName({ path: "/home/user/project/src/pages/blog/post.tsx" })).toBe("blog-post");
- });
- it("strips -index suffix from nested index files", () => {
- expect(grabPageName({ path: "/home/user/project/src/pages/blog/index.tsx" })).toBe("blog");
- });
- it("converts dynamic segments [slug] by replacing brackets", () => {
- const result = grabPageName({
- path: "/home/user/project/src/pages/blog/[slug].tsx",
- });
- // [ → - and ] is dropped (not a-z or -), so [slug] → -slug
- expect(result).toBe("blog--slug");
- });
- it("converts spread [...params] segments", () => {
- const result = grabPageName({
- path: "/home/user/project/src/pages/[...params].tsx",
- });
- // "[...params]" → remove ext → "[...params]"
- // [ → "-" → "-...params]"
- // "..." → "-" → "--params]"
- // strip non [a-z-] → "--params"
- expect(result).toBe("--params");
- });
- it("strips uppercase letters (only a-z and - are kept)", () => {
- // [^a-z\-] strips uppercase — 'A' is removed, 'bout' remains
- expect(grabPageName({ path: "/home/user/project/src/pages/About.tsx" })).toBe("bout");
- });
- it("handles deeply nested paths", () => {
- expect(grabPageName({
- path: "/home/user/project/src/pages/admin/users/list.tsx",
- })).toBe("admin-users-list");
- });
-});
diff --git a/dist/__tests__/utils/is-development.test.d.ts b/dist/__tests__/utils/is-development.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/is-development.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/is-development.test.js b/dist/__tests__/utils/is-development.test.js
deleted file mode 100644
index 6474a2d..0000000
--- a/dist/__tests__/utils/is-development.test.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { describe, it, expect, beforeEach, afterEach } from "bun:test";
-import isDevelopment from "../../utils/is-development";
-const originalEnv = process.env.NODE_ENV;
-beforeEach(() => {
- // Reset global config before each test
- global.CONFIG = {};
-});
-afterEach(() => {
- process.env.NODE_ENV = originalEnv;
-});
-describe("isDevelopment", () => {
- it("returns false when NODE_ENV is production", () => {
- process.env.NODE_ENV = "production";
- global.CONFIG = { development: true };
- expect(isDevelopment()).toBe(false);
- });
- it("returns true when config.development is true and NODE_ENV is not production", () => {
- process.env.NODE_ENV = "development";
- global.CONFIG = { development: true };
- expect(isDevelopment()).toBe(true);
- });
- it("returns false when config.development is false", () => {
- process.env.NODE_ENV = "development";
- global.CONFIG = { development: false };
- expect(isDevelopment()).toBe(false);
- });
- it("returns false when config.development is undefined", () => {
- process.env.NODE_ENV = "development";
- global.CONFIG = {};
- expect(isDevelopment()).toBe(false);
- });
-});
diff --git a/dist/__tests__/utils/numberfy.test.d.ts b/dist/__tests__/utils/numberfy.test.d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/dist/__tests__/utils/numberfy.test.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/__tests__/utils/numberfy.test.js b/dist/__tests__/utils/numberfy.test.js
deleted file mode 100644
index e8469ae..0000000
--- a/dist/__tests__/utils/numberfy.test.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { describe, it, expect } from "bun:test";
-import numberfy, { _n } from "../../utils/numberfy";
-describe("numberfy", () => {
- it("converts a plain integer string", () => {
- expect(numberfy("42")).toBe(42);
- });
- it("converts a float string preserving decimals", () => {
- expect(numberfy("3.14")).toBe(3.14);
- });
- it("strips non-numeric characters", () => {
- expect(numberfy("$1,234.56")).toBe(1234.56);
- });
- it("returns 0 for an empty string", () => {
- expect(numberfy("")).toBe(0);
- });
- it("returns 0 for undefined", () => {
- expect(numberfy(undefined)).toBe(0);
- });
- it("returns 0 for null", () => {
- expect(numberfy(null)).toBe(0);
- });
- it("passes through a number directly", () => {
- expect(numberfy(7)).toBe(7);
- });
- it("rounds when no decimals specified and no decimal in input", () => {
- expect(numberfy("5.0")).toBe(5);
- });
- it("respects decimals=0 by rounding", () => {
- expect(numberfy("3.7", 0)).toBe(4);
- });
- it("respects explicit decimals parameter", () => {
- expect(numberfy("3.14159", 2)).toBe(3.14);
- });
- it("preserves existing decimal places when no decimals arg given", () => {
- expect(numberfy("1.500")).toBe(1.5);
- });
- it("strips a trailing dot", () => {
- expect(numberfy("5.")).toBe(5);
- });
- it("_n alias works identically", () => {
- expect(_n("10")).toBe(10);
- });
-});
diff --git a/tsconfig.json b/tsconfig.json
index ca2fe1c..c41dd23 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -19,5 +19,11 @@
"declaration": true
},
"include": ["src"],
- "exclude": ["node_modules", "dist"]
+ "exclude": [
+ "node_modules",
+ "dist",
+ "src/__tests__",
+ "**/__tests__",
+ "__tests__"
+ ]
}