fix theme navigation and improve project scaffolding
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ai",
|
"name": "@wrnexus/ai",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/authz",
|
"name": "@wrnexus/authz",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -68,11 +68,13 @@ Before bundling, it regenerates typed queries for the default and every named da
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun dist/server.js # PORT env var optional
|
bun dist/server.js # PORT env var optional
|
||||||
|
# Generated apps also provide: npm start
|
||||||
|
# Build and start together: npm run production
|
||||||
```
|
```
|
||||||
|
|
||||||
### `wrnexus create`
|
### `wrnexus create`
|
||||||
|
|
||||||
Scaffolds a new app from an inline (dependency-free) template — `package.json`, config, and starter `app/` files. Run `wrnexus dev` in the new directory to start.
|
Scaffolds a new app from an inline (dependency-free) template — `package.json`, `.gitignore`, config, and starter `app/` files. Use `npm run dev` during development, `npm run build && npm start` for production, or `npm run production` to build and start in one command. The generated production server currently requires Bun even when npm is used to manage packages and scripts.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wrnexus create my-app
|
wrnexus create my-app
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/cli",
|
"name": "@wrnexus/cli",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ export const POST = async (ctx) => {
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
wrnexus dev . # dev server + HMR
|
wrnexus dev . # dev server + HMR
|
||||||
wrnexus build . # production build → dist/server.js
|
wrnexus build . # production build → dist/server.js
|
||||||
|
bun dist/server.js # run the production server (or npm start)
|
||||||
wrnexus create <name> # scaffold a new app
|
wrnexus create <name> # scaffold a new app
|
||||||
wrnexus generate page <Name> # scaffold a page (aliases: g p)
|
wrnexus generate page <Name> # scaffold a page (aliases: g p)
|
||||||
wrnexus generate component <name> | api <path> | schema <name>
|
wrnexus generate component <name> | api <path> | schema <name>
|
||||||
|
|||||||
@@ -14,6 +14,51 @@ const TEMPLATE: Record<string, string> = {
|
|||||||
// AI/agent context: teaches Claude Code / Cursor / Copilot the WrNexus conventions.
|
// AI/agent context: teaches Claude Code / Cursor / Copilot the WrNexus conventions.
|
||||||
"CLAUDE.md": CLAUDE_MD,
|
"CLAUDE.md": CLAUDE_MD,
|
||||||
"llms.txt": AI_GUIDE,
|
"llms.txt": AI_GUIDE,
|
||||||
|
".gitignore": `# Dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# WRNexusJS and production builds
|
||||||
|
dist/
|
||||||
|
.wrnexus/
|
||||||
|
**/.wrnexus/
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# Environment files and local secrets
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Logs and runtime files
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
*.pid
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Local databases
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
|
||||||
|
# Generated native projects
|
||||||
|
mobile/android/
|
||||||
|
mobile/ios/
|
||||||
|
mobile/.expo/
|
||||||
|
|
||||||
|
# Editors and operating systems
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# TypeScript and test caches
|
||||||
|
*.tsbuildinfo
|
||||||
|
.eslintcache
|
||||||
|
.nyc_output/
|
||||||
|
`,
|
||||||
"package.json": `{
|
"package.json": `{
|
||||||
"name": "APP_NAME",
|
"name": "APP_NAME",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@@ -22,6 +67,8 @@ const TEMPLATE: Record<string, string> = {
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "wrnexus dev .",
|
"dev": "wrnexus dev .",
|
||||||
"build": "wrnexus build .",
|
"build": "wrnexus build .",
|
||||||
|
"start": "bun dist/server.js",
|
||||||
|
"production": "bun run build && bun run start",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"format": "prettier . --write",
|
"format": "prettier . --write",
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { scaffoldApp } from "../src/create.ts";
|
||||||
|
|
||||||
|
test("scaffoldApp creates a comprehensive .gitignore", () => {
|
||||||
|
const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-"));
|
||||||
|
const root = join(parent, "demo-app");
|
||||||
|
|
||||||
|
try {
|
||||||
|
scaffoldApp(root, "demo-app");
|
||||||
|
|
||||||
|
const file = join(root, ".gitignore");
|
||||||
|
expect(existsSync(file)).toBe(true);
|
||||||
|
const contents = readFileSync(file, "utf8");
|
||||||
|
for (const entry of [
|
||||||
|
"node_modules/",
|
||||||
|
"dist/",
|
||||||
|
".wrnexus/",
|
||||||
|
".env.*",
|
||||||
|
"!.env.example",
|
||||||
|
"*.log",
|
||||||
|
"*.db",
|
||||||
|
"coverage/",
|
||||||
|
"mobile/android/",
|
||||||
|
".vscode/",
|
||||||
|
"*.tsbuildinfo",
|
||||||
|
]) {
|
||||||
|
expect(contents).toContain(entry);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
rmSync(parent, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("scaffoldApp includes production build and start scripts", () => {
|
||||||
|
const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-"));
|
||||||
|
const root = join(parent, "production-app");
|
||||||
|
|
||||||
|
try {
|
||||||
|
scaffoldApp(root, "production-app");
|
||||||
|
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
||||||
|
|
||||||
|
expect(pkg.scripts.build).toBe("wrnexus build .");
|
||||||
|
expect(pkg.scripts.start).toBe("bun dist/server.js");
|
||||||
|
expect(pkg.scripts.production).toBe("bun run build && bun run start");
|
||||||
|
} finally {
|
||||||
|
rmSync(parent, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/compiler",
|
"name": "@wrnexus/compiler",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/core",
|
"name": "@wrnexus/core",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/csr",
|
"name": "@wrnexus/csr",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export const NAV_RUNTIME = String.raw`
|
|||||||
try { if (window.__wrnexusHydrateScopes) window.__wrnexusHydrateScopes(document); } catch (e) {}
|
try { if (window.__wrnexusHydrateScopes) window.__wrnexusHydrateScopes(document); } catch (e) {}
|
||||||
try { if (window.__wrnexusHydrateCsrFetches) window.__wrnexusHydrateCsrFetches(document); } catch (e) {}
|
try { if (window.__wrnexusHydrateCsrFetches) window.__wrnexusHydrateCsrFetches(document); } catch (e) {}
|
||||||
try { if (window.__wireValidate) window.__wireValidate.init(document); } catch (e) {}
|
try { if (window.__wireValidate) window.__wireValidate.init(document); } catch (e) {}
|
||||||
|
try { if (window.wireTheme) window.wireTheme.bind(document); } catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function render(html, url, isPop) {
|
function render(html, url, isPop) {
|
||||||
|
|||||||
@@ -91,3 +91,16 @@ test("exposes programmatic navigation", async () => {
|
|||||||
expect(fetchCalls.length).toBe(1);
|
expect(fetchCalls.length).toBe(1);
|
||||||
expect(win.document.getElementById("app").innerHTML).toContain("Dashboard");
|
expect(win.document.getElementById("app").innerHTML).toContain("Dashboard");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("rebinds theme controls after swapping the page", async () => {
|
||||||
|
install(`<div id="app"><a href="/about" id="lnk">About</a></div>`);
|
||||||
|
let boundRoot: unknown;
|
||||||
|
win.wireTheme = { bind: (root: unknown) => (boundRoot = root) };
|
||||||
|
nextHtml = `<html><body><div id="app"><button data-wire-theme-toggle>Theme</button></div></body></html>`;
|
||||||
|
|
||||||
|
win.document.getElementById("lnk").click();
|
||||||
|
await flush();
|
||||||
|
|
||||||
|
expect(boundRoot).toBe(win.document);
|
||||||
|
expect(win.document.querySelector("[data-wire-theme-toggle]")).not.toBeNull();
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/db",
|
"name": "@wrnexus/db",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/dev-server",
|
"name": "@wrnexus/dev-server",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/encryption",
|
"name": "@wrnexus/encryption",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/i18n",
|
"name": "@wrnexus/i18n",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/jwt",
|
"name": "@wrnexus/jwt",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/mobile",
|
"name": "@wrnexus/mobile",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/native",
|
"name": "@wrnexus/native",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/oauth",
|
"name": "@wrnexus/oauth",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/pubsub",
|
"name": "@wrnexus/pubsub",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/queue",
|
"name": "@wrnexus/queue",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/reactive",
|
"name": "@wrnexus/reactive",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/router",
|
"name": "@wrnexus/router",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ssr",
|
"name": "@wrnexus/ssr",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/styles",
|
"name": "@wrnexus/styles",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ export function renderThemeRuntime(theme: ResolvedTheme): string {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.wireTheme={get:get,set:set,toggle:toggle,bind:bind,themes:THEMES};
|
window.wireTheme={get:get,set:set,toggle:toggle,bind:bind,themes:THEMES};
|
||||||
|
window.addEventListener("wrnexus:navigated",function(){bind(document);});
|
||||||
if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",function(){bind(document);});
|
if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",function(){bind(document);});
|
||||||
else bind(document);
|
else bind(document);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -39,4 +39,5 @@ test("renderThemeRuntime bakes the theme names for cycling", () => {
|
|||||||
const js = renderThemeRuntime(t);
|
const js = renderThemeRuntime(t);
|
||||||
expect(js).toContain("data-wire-theme-toggle");
|
expect(js).toContain("data-wire-theme-toggle");
|
||||||
expect(js).toContain(JSON.stringify(t.names));
|
expect(js).toContain(JSON.stringify(t.names));
|
||||||
|
expect(js).toContain('addEventListener("wrnexus:navigated"');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/test",
|
"name": "@wrnexus/test",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/tracking",
|
"name": "@wrnexus/tracking",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/uploader",
|
"name": "@wrnexus/uploader",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/validation",
|
"name": "@wrnexus/validation",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user