From 88e907783a0efd6a797730e0ee703dc7d733d782 Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Mon, 13 Jul 2026 12:54:07 +0530 Subject: [PATCH] fix: stabilize workspace gateway and scaffolding --- .publish/ai/package.json | 2 +- .publish/authz/package.json | 2 +- .publish/cli/README.md | 5 + .publish/cli/package.json | 22 +- .publish/compiler/package.json | 2 +- .publish/core/package.json | 2 +- .publish/csr/package.json | 4 +- .publish/db/package.json | 2 +- .publish/dev-server/README.md | 7 +- .publish/dev-server/package.json | 26 +-- .publish/encryption/package.json | 2 +- .publish/i18n/package.json | 4 +- .publish/jwt/package.json | 2 +- .publish/mobile/package.json | 4 +- .publish/native/package.json | 2 +- .publish/oauth/package.json | 2 +- .publish/pubsub/package.json | 2 +- .publish/queue/package.json | 2 +- .publish/reactive/package.json | 2 +- .publish/router/package.json | 6 +- .publish/ssr/package.json | 4 +- .publish/styles/package.json | 4 +- .publish/test/package.json | 2 +- .publish/tracking/package.json | 2 +- .publish/ui/package.json | 4 +- .publish/uploader/package.json | 4 +- .publish/validation/package.json | 2 +- packages/ai/package.json | 2 +- packages/authz/package.json | 2 +- packages/cli/README.md | 5 + packages/cli/package.json | 2 +- packages/cli/src/ai-guide.ts | 4 +- packages/cli/src/create.ts | 43 +++- packages/cli/src/update.ts | 23 ++- packages/cli/src/workspace.ts | 19 +- packages/cli/test/create.test.ts | 26 +++ packages/cli/test/update.test.ts | 1 + packages/cli/test/workspace.test.ts | 15 ++ packages/compiler/package.json | 2 +- packages/core/package.json | 2 +- packages/csr/package.json | 2 +- packages/db/package.json | 2 +- packages/dev-server/README.md | 7 +- packages/dev-server/package.json | 2 +- packages/dev-server/src/gateway.ts | 250 ++++++++++++++--------- packages/dev-server/test/gateway.test.ts | 19 ++ packages/encryption/package.json | 2 +- packages/i18n/package.json | 2 +- packages/jwt/package.json | 2 +- packages/mobile/package.json | 2 +- packages/native/package.json | 2 +- packages/oauth/package.json | 2 +- packages/pubsub/package.json | 2 +- packages/queue/package.json | 2 +- packages/reactive/package.json | 2 +- packages/router/package.json | 2 +- packages/ssr/package.json | 2 +- packages/styles/package.json | 2 +- packages/test/package.json | 2 +- packages/tracking/package.json | 2 +- packages/ui/package.json | 2 +- packages/uploader/package.json | 2 +- packages/validation/package.json | 2 +- 63 files changed, 380 insertions(+), 206 deletions(-) create mode 100644 packages/cli/test/workspace.test.ts create mode 100644 packages/dev-server/test/gateway.test.ts diff --git a/.publish/ai/package.json b/.publish/ai/package.json index b87eb234..886cf6d9 100644 --- a/.publish/ai/package.json +++ b/.publish/ai/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ai", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.", "license": "MIT", diff --git a/.publish/authz/package.json b/.publish/authz/package.json index 35ba1931..4bc17d4e 100644 --- a/.publish/authz/package.json +++ b/.publish/authz/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/authz", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/authz — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/cli/README.md b/.publish/cli/README.md index 7b3e7f59..a28f6407 100644 --- a/.publish/cli/README.md +++ b/.publish/cli/README.md @@ -167,6 +167,11 @@ wrnexus workspace acme wrnexus gateway --port=3000 ``` +Development gateways bind to `127.0.0.1` by default for reliable access on Windows, +macOS, and Linux. Open the configured app domain on the gateway port (for example +`http://localhost:3000` or `http://admin.localhost:3000`), not the internal child ports +printed while apps start. Pass `--host=0.0.0.0` to accept connections from other devices. + ### `wrnexus test` Runs the app's tests with `bun test`. Defaults to the `test` profile (config + `.env.test`). Pass `--watch` to re-run on change; extra flags pass straight through to `bun test`. diff --git a/.publish/cli/package.json b/.publish/cli/package.json index ad32b272..e5718608 100644 --- a/.publish/cli/package.json +++ b/.publish/cli/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/cli", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/cli — part of the WrNexus framework.", "license": "MIT", @@ -28,16 +28,16 @@ "wrnexus": "./dist/index.js" }, "dependencies": { - "@wrnexus/core": "^0.2.15", - "@wrnexus/router": "^0.2.15", - "@wrnexus/csr": "^0.2.15", - "@wrnexus/compiler": "^0.2.15", - "@wrnexus/styles": "^0.2.15", - "@wrnexus/dev-server": "^0.2.15", - "@wrnexus/ui": "^0.2.15", - "@wrnexus/validation": "^0.2.15", - "@wrnexus/i18n": "^0.2.15", - "@wrnexus/db": "^0.2.15" + "@wrnexus/core": "^0.2.16", + "@wrnexus/router": "^0.2.16", + "@wrnexus/csr": "^0.2.16", + "@wrnexus/compiler": "^0.2.16", + "@wrnexus/styles": "^0.2.16", + "@wrnexus/dev-server": "^0.2.16", + "@wrnexus/ui": "^0.2.16", + "@wrnexus/validation": "^0.2.16", + "@wrnexus/i18n": "^0.2.16", + "@wrnexus/db": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/compiler/package.json b/.publish/compiler/package.json index 92f14e35..9da5719d 100644 --- a/.publish/compiler/package.json +++ b/.publish/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/compiler", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/compiler — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/core/package.json b/.publish/core/package.json index 93d9be28..abe6c683 100644 --- a/.publish/core/package.json +++ b/.publish/core/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/core", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/core — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/csr/package.json b/.publish/csr/package.json index cb8fa32a..3d25a8ba 100644 --- a/.publish/csr/package.json +++ b/.publish/csr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/csr", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/csr — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.2.15" + "@wrnexus/core": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/db/package.json b/.publish/db/package.json index 5027e4ee..669c5341 100644 --- a/.publish/db/package.json +++ b/.publish/db/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/db", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/db — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/dev-server/README.md b/.publish/dev-server/README.md index d9e6dc0e..cfe004d0 100644 --- a/.publish/dev-server/README.md +++ b/.publish/dev-server/README.md @@ -147,7 +147,7 @@ Serves several apps behind one port and routes each request to the right app by ```ts interface GatewayOptions { port?: number; // default 3000 - hostname?: string; // default "localhost" + hostname?: string; // dev: "127.0.0.1"; production: "0.0.0.0" mode?: "development" | "production"; apps: GatewayApp[]; security?: GatewaySecurity; @@ -176,7 +176,10 @@ interface GatewaySecurity { } ``` -The gateway exposes `/__gateway/health` (JSON list of routed apps) and returns a `RunningGateway` (`{ port, url, stop() }`). +Open the gateway URL (normally `http://127.0.0.1:3000`), not an app's internal +port. The gateway exposes `/__gateway/health` (JSON list of routed apps) and returns a +`RunningGateway` (`{ port, url, stop() }`). Use `--host=0.0.0.0` when other devices need +to reach a development gateway. ### `node:http` adapter (from `./adapters/node.ts`) diff --git a/.publish/dev-server/package.json b/.publish/dev-server/package.json index cb910d4a..c00d362d 100644 --- a/.publish/dev-server/package.json +++ b/.publish/dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/dev-server", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/dev-server — part of the WrNexus framework.", "license": "MIT", @@ -25,18 +25,18 @@ } }, "dependencies": { - "@wrnexus/core": "^0.2.15", - "@wrnexus/router": "^0.2.15", - "@wrnexus/ssr": "^0.2.15", - "@wrnexus/csr": "^0.2.15", - "@wrnexus/compiler": "^0.2.15", - "@wrnexus/styles": "^0.2.15", - "@wrnexus/ui": "^0.2.15", - "@wrnexus/validation": "^0.2.15", - "@wrnexus/i18n": "^0.2.15", - "@wrnexus/db": "^0.2.15", - "@wrnexus/pubsub": "^0.2.15", - "@wrnexus/uploader": "^0.2.15" + "@wrnexus/core": "^0.2.16", + "@wrnexus/router": "^0.2.16", + "@wrnexus/ssr": "^0.2.16", + "@wrnexus/csr": "^0.2.16", + "@wrnexus/compiler": "^0.2.16", + "@wrnexus/styles": "^0.2.16", + "@wrnexus/ui": "^0.2.16", + "@wrnexus/validation": "^0.2.16", + "@wrnexus/i18n": "^0.2.16", + "@wrnexus/db": "^0.2.16", + "@wrnexus/pubsub": "^0.2.16", + "@wrnexus/uploader": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/encryption/package.json b/.publish/encryption/package.json index 6e280b94..678299df 100644 --- a/.publish/encryption/package.json +++ b/.publish/encryption/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/encryption", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/encryption — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/i18n/package.json b/.publish/i18n/package.json index 0fe7498e..b43ac999 100644 --- a/.publish/i18n/package.json +++ b/.publish/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/i18n", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/i18n — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.2.15" + "@wrnexus/core": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/jwt/package.json b/.publish/jwt/package.json index b724c984..00659bc3 100644 --- a/.publish/jwt/package.json +++ b/.publish/jwt/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/jwt", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/jwt — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/mobile/package.json b/.publish/mobile/package.json index 8adffe27..e837a1de 100644 --- a/.publish/mobile/package.json +++ b/.publish/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/mobile", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/mobile — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/native": "^0.2.15" + "@wrnexus/native": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/native/package.json b/.publish/native/package.json index 74ad87ee..8b480a5a 100644 --- a/.publish/native/package.json +++ b/.publish/native/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/native", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/native — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/oauth/package.json b/.publish/oauth/package.json index d7a94e35..0a315895 100644 --- a/.publish/oauth/package.json +++ b/.publish/oauth/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/oauth", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/oauth — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/pubsub/package.json b/.publish/pubsub/package.json index 636ce286..252f9b37 100644 --- a/.publish/pubsub/package.json +++ b/.publish/pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/pubsub", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/pubsub — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/queue/package.json b/.publish/queue/package.json index fe16f90f..0ab7eafe 100644 --- a/.publish/queue/package.json +++ b/.publish/queue/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/queue", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/queue — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/reactive/package.json b/.publish/reactive/package.json index a60c3a66..a0e1978c 100644 --- a/.publish/reactive/package.json +++ b/.publish/reactive/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/reactive", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/reactive — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/router/package.json b/.publish/router/package.json index 7e311705..f2782c23 100644 --- a/.publish/router/package.json +++ b/.publish/router/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/router", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/router — part of the WrNexus framework.", "license": "MIT", @@ -21,8 +21,8 @@ } }, "dependencies": { - "@wrnexus/compiler": "^0.2.15", - "@wrnexus/core": "^0.2.15" + "@wrnexus/compiler": "^0.2.16", + "@wrnexus/core": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/ssr/package.json b/.publish/ssr/package.json index 2a7e29d8..6fcfaf71 100644 --- a/.publish/ssr/package.json +++ b/.publish/ssr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ssr", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/ssr — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.2.15" + "@wrnexus/core": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/styles/package.json b/.publish/styles/package.json index 7effda12..566680eb 100644 --- a/.publish/styles/package.json +++ b/.publish/styles/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/styles", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/styles — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/uploader": "^0.2.15" + "@wrnexus/uploader": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/test/package.json b/.publish/test/package.json index 126d4f8e..47ed475e 100644 --- a/.publish/test/package.json +++ b/.publish/test/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/test", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/test — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/tracking/package.json b/.publish/tracking/package.json index 877d77a1..3080fcc4 100644 --- a/.publish/tracking/package.json +++ b/.publish/tracking/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/tracking", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/tracking — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/ui/package.json b/.publish/ui/package.json index 538c19d6..2962a96c 100644 --- a/.publish/ui/package.json +++ b/.publish/ui/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ui", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/ui — part of the WrNexus framework.", "license": "MIT", @@ -22,7 +22,7 @@ "./ui.css": "./ui.css" }, "dependencies": { - "@wrnexus/core": "^0.2.15" + "@wrnexus/core": "^0.2.16" }, "files": [ "dist", diff --git a/.publish/uploader/package.json b/.publish/uploader/package.json index fd5fdb6e..1ea2cda7 100644 --- a/.publish/uploader/package.json +++ b/.publish/uploader/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/uploader", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/uploader — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.2.15" + "@wrnexus/core": "^0.2.16" }, "files": [ "dist" diff --git a/.publish/validation/package.json b/.publish/validation/package.json index 8542f77e..752fb34b 100644 --- a/.publish/validation/package.json +++ b/.publish/validation/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/validation", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "description": "@wrnexus/validation — part of the WrNexus framework.", "license": "MIT", diff --git a/packages/ai/package.json b/packages/ai/package.json index 0d03bf0e..cd6d5deb 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ai", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.", diff --git a/packages/authz/package.json b/packages/authz/package.json index 07844fde..034d7c76 100644 --- a/packages/authz/package.json +++ b/packages/authz/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/authz", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/cli/README.md b/packages/cli/README.md index 7b3e7f59..a28f6407 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -167,6 +167,11 @@ wrnexus workspace acme wrnexus gateway --port=3000 ``` +Development gateways bind to `127.0.0.1` by default for reliable access on Windows, +macOS, and Linux. Open the configured app domain on the gateway port (for example +`http://localhost:3000` or `http://admin.localhost:3000`), not the internal child ports +printed while apps start. Pass `--host=0.0.0.0` to accept connections from other devices. + ### `wrnexus test` Runs the app's tests with `bun test`. Defaults to the `test` profile (config + `.env.test`). Pass `--watch` to re-run on change; extra flags pass straight through to `bun test`. diff --git a/packages/cli/package.json b/packages/cli/package.json index aa5ec5db..772cb02f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/cli", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/cli/src/ai-guide.ts b/packages/cli/src/ai-guide.ts index 341b046a..26a79e83 100644 --- a/packages/cli/src/ai-guide.ts +++ b/packages/cli/src/ai-guide.ts @@ -1,10 +1,10 @@ /** - * Framework conventions shipped into scaffolded apps as CLAUDE.md and llms.txt so + * Framework conventions shipped into scaffolded apps as CLAUDE.md and public/llms.txt so * AI coding tools (Claude Code, Cursor, Copilot) generate correct WrNexus code. * Generated from the repo-root llms.txt - do not edit by hand. */ -/** The canonical WrNexus conventions reference (shipped as llms.txt). */ +/** The canonical WrNexus conventions reference (served as /llms.txt). */ export const AI_GUIDE = `# WrNexus > WrNexus is an SSR-first, **Bun-native** full-stack web framework. UI is written in diff --git a/packages/cli/src/create.ts b/packages/cli/src/create.ts index cc9614f8..9d8c379b 100644 --- a/packages/cli/src/create.ts +++ b/packages/cli/src/create.ts @@ -8,12 +8,15 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { AI_GUIDE, CLAUDE_MD } from "./ai-guide.ts"; +import { currentCliVersion } from "./update-notifier.ts"; + +const frameworkVersion = currentCliVersion(); /** Map of file (relative to app root) -> contents. */ const TEMPLATE: Record = { // AI/agent context: teaches Claude Code / Cursor / Copilot the WrNexus conventions. "CLAUDE.md": CLAUDE_MD, - "llms.txt": AI_GUIDE, + "public/llms.txt": AI_GUIDE, ".gitignore": `# Dependencies node_modules/ @@ -64,6 +67,9 @@ Thumbs.db "version": "0.1.0", "private": true, "type": "module", + "wrnexus": { + "version": "${frameworkVersion}" + }, "scripts": { "dev": "wrnexus dev .", "build": "wrnexus build .", @@ -76,14 +82,14 @@ Thumbs.db "check": "bun run lint && bun run format:check" }, "dependencies": { - "@wrnexus/ai": "^0.2.0", - "@wrnexus/core": "^0.2.0", - "@wrnexus/styles": "^0.2.0", - "@wrnexus/validation": "^0.2.0", - "@wrnexus/db": "^0.2.0" + "@wrnexus/ai": "${frameworkVersion}", + "@wrnexus/core": "${frameworkVersion}", + "@wrnexus/styles": "${frameworkVersion}", + "@wrnexus/validation": "${frameworkVersion}", + "@wrnexus/db": "${frameworkVersion}" }, "devDependencies": { - "@wrnexus/cli": "^0.2.0", + "@wrnexus/cli": "${frameworkVersion}", "@eslint/js": "^9.0.0", "@tailwindcss/cli": "^4.0.0", "@types/bun": "latest", @@ -306,7 +312,7 @@ page Home {
@@ -332,6 +338,27 @@ page Home { } } +`, + "app/pages/about.wrn": `page About { + seo { + title = "About" + description = "Learn how APP_NAME is built with WrNexus." + } + + view { +
+
+ ← Home +

WrNexus application

+

About APP_NAME

+

+ This page is server-rendered from app/pages/about.wrn. Add state, + events, components, APIs, and data without switching to another UI framework. +

+
+
+ } +} `, "app/components/counter.wrn": `// A reusable component. Route: none — mounted inside a page with //
. diff --git a/packages/cli/src/update.ts b/packages/cli/src/update.ts index 16aa37fe..5a9eae8a 100644 --- a/packages/cli/src/update.ts +++ b/packages/cli/src/update.ts @@ -4,7 +4,7 @@ * Upgrade an app (or every app in a workspace) to a WrNexus release: * 1. Bump every `@wrnexus/*` dependency to the target version. * 2. `bun install`. - * 3. Refresh framework-owned reference files (llms.txt) and apply any + * 3. Refresh framework-owned reference files (public/llms.txt) and apply any * versioned, idempotent migrations that newer releases introduce. * 4. Record the applied version in package.json (`"wrnexus": { version }`). * @@ -19,7 +19,7 @@ import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { spawnSync } from "node:child_process"; -import { join, resolve } from "node:path"; +import { dirname, join, resolve } from "node:path"; import { pathToFileURL } from "node:url"; import { AI_GUIDE, CLAUDE_MD } from "./ai-guide.ts"; import { inspectProject } from "./doctor.ts"; @@ -190,11 +190,14 @@ function appVersion(appRoot: string, pkg: Record): string { /** Refresh pure framework-owned reference files. Never touches user-edited CLAUDE.md. */ function refreshFrameworkFiles(appRoot: string, dryRun: boolean, log: (m: string) => void): void { - // llms.txt is a generated reference — always safe to overwrite. - const llms = join(appRoot, "llms.txt"); + // Public llms.txt is generated and web-visible, so it is safe to refresh. + const llms = join(appRoot, "public", "llms.txt"); if (!existsSync(llms) || readFileSync(llms, "utf8") !== AI_GUIDE) { - log("~ llms.txt refreshed"); - if (!dryRun) writeFileSync(llms, AI_GUIDE, "utf8"); + log("~ public/llms.txt refreshed"); + if (!dryRun) { + mkdirSync(join(appRoot, "public"), { recursive: true }); + writeFileSync(llms, AI_GUIDE, "utf8"); + } } // CLAUDE.md is often user-edited — only create it when absent. const claude = join(appRoot, "CLAUDE.md"); @@ -223,10 +226,14 @@ function backupProjectFiles(appRoot: string, from: string, target: string): stri "tsconfig.json", ".gitignore", "CLAUDE.md", - "llms.txt", + "public/llms.txt", ]) { const source = join(appRoot, name); - if (existsSync(source)) cpSync(source, join(backup, name)); + if (existsSync(source)) { + const destination = join(backup, name); + mkdirSync(dirname(destination), { recursive: true }); + cpSync(source, destination); + } } return backup; } diff --git a/packages/cli/src/workspace.ts b/packages/cli/src/workspace.ts index ee46cc76..1223cefe 100644 --- a/packages/cli/src/workspace.ts +++ b/packages/cli/src/workspace.ts @@ -13,8 +13,11 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { pathToFileURL } from "node:url"; import { scaffoldApp } from "./create.ts"; +import { currentCliVersion } from "./update-notifier.ts"; import type { GatewayAuth, GatewaySecurity } from "@wrnexus/dev-server"; +const frameworkVersion = currentCliVersion(); + export interface WorkspaceApp { name: string; dir: string; @@ -29,7 +32,7 @@ export interface WorkspaceConfig { security?: GatewaySecurity; } -const files = (name: string): Record => ({ +export const workspaceFiles = (name: string): Record => ({ "package.json": `{ "name": "${name}", "private": true, @@ -40,7 +43,7 @@ const files = (name: string): Record => ({ "gateway": "wrnexus gateway" }, "devDependencies": { - "@wrnexus/cli": "^0.2.0" + "@wrnexus/cli": "${frameworkVersion}" } } `, @@ -86,7 +89,7 @@ dist/ "main": "src/index.ts", "exports": { ".": "./src/index.ts" }, "dependencies": { - "@wrnexus/pubsub": "^0.2.0" + "@wrnexus/pubsub": "${frameworkVersion}" } } `, @@ -124,7 +127,7 @@ ${name}/ \`\`\`bash bun install -bun run dev # = wrnexus gateway → http://localhost:3000 +bun run dev # = wrnexus gateway → http://127.0.0.1:3000 \`\`\` Add the hosts to your machine (e.g. /etc/hosts): @@ -133,6 +136,10 @@ Add the hosts to your machine (e.g. /etc/hosts): 127.0.0.1 web.localhost admin.localhost \`\`\` +Open \`http://localhost:3000\` for the web app or +\`http://admin.localhost:3000\` for the admin app. The ports printed for individual +apps are internal gateway targets, not public workspace URLs. + ## Interconnect - **Shared code:** import \`@app/shared\` in any app. @@ -162,7 +169,7 @@ export function createWorkspace(name: string): void { process.exit(1); } - for (const [rel, contents] of Object.entries(files(name))) { + for (const [rel, contents] of Object.entries(workspaceFiles(name))) { const target = join(root, rel); mkdirSync(dirname(target), { recursive: true }); writeFileSync(target, contents, "utf8"); @@ -198,7 +205,7 @@ export async function runGateway(root: string, args: string[]): Promise { const portArg = args.find((a) => a.startsWith("--port=")); const hostArg = args.find((a) => a.startsWith("--host=")); const port = portArg ? Number(portArg.split("=")[1]) : 3000; - const hostname = hostArg?.split("=")[1] || "::"; + const hostname = hostArg?.split("=")[1]; const mode = args.includes("--prod") ? "production" : "development"; const { startGateway } = await import("@wrnexus/dev-server"); diff --git a/packages/cli/test/create.test.ts b/packages/cli/test/create.test.ts index 202448b0..3fe7f47d 100644 --- a/packages/cli/test/create.test.ts +++ b/packages/cli/test/create.test.ts @@ -3,6 +3,7 @@ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { scaffoldApp } from "../src/create.ts"; +import { currentCliVersion } from "../src/update-notifier.ts"; test("scaffoldApp creates a comprehensive .gitignore", () => { const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-")); @@ -49,3 +50,28 @@ test("scaffoldApp includes production build and start scripts", () => { rmSync(parent, { recursive: true, force: true }); } }); + +test("scaffoldApp pins the current framework and exposes llms.txt publicly", () => { + const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-")); + const root = join(parent, "current-app"); + + try { + scaffoldApp(root, "current-app"); + const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); + const version = currentCliVersion(); + + expect(pkg.wrnexus.version).toBe(version); + for (const dependency of Object.values(pkg.dependencies) as string[]) { + expect(dependency).toBe(version); + } + expect(pkg.devDependencies["@wrnexus/cli"]).toBe(version); + expect(existsSync(join(root, "public", "llms.txt"))).toBe(true); + expect(existsSync(join(root, "llms.txt"))).toBe(false); + expect(readFileSync(join(root, "app", "pages", "index.wrn"), "utf8")).toContain( + 'href="/api/hello"', + ); + expect(existsSync(join(root, "app", "pages", "about.wrn"))).toBe(true); + } finally { + rmSync(parent, { recursive: true, force: true }); + } +}); diff --git a/packages/cli/test/update.test.ts b/packages/cli/test/update.test.ts index 861562c1..d751cae5 100644 --- a/packages/cli/test/update.test.ts +++ b/packages/cli/test/update.test.ts @@ -31,6 +31,7 @@ test("updateApp migrates project files without marking an unverified update comp const gitignore = readFileSync(join(root, ".gitignore"), "utf8"); expect(gitignore).toContain("!.env.example"); expect(gitignore).toContain("mobile/android/"); + expect(readFileSync(join(root, "public", "llms.txt"), "utf8")).toContain("# WrNexus"); } finally { rmSync(root, { recursive: true, force: true }); } diff --git a/packages/cli/test/workspace.test.ts b/packages/cli/test/workspace.test.ts new file mode 100644 index 00000000..b8cfbc72 --- /dev/null +++ b/packages/cli/test/workspace.test.ts @@ -0,0 +1,15 @@ +import { expect, test } from "bun:test"; +import { currentCliVersion } from "../src/update-notifier.ts"; +import { workspaceFiles } from "../src/workspace.ts"; + +test("workspace templates pin the running framework release", () => { + const files = workspaceFiles("acme"); + const rootPackage = JSON.parse(files["package.json"]!); + const sharedPackage = JSON.parse(files["packages/shared/package.json"]!); + const version = currentCliVersion(); + + expect(rootPackage.devDependencies["@wrnexus/cli"]).toBe(version); + expect(sharedPackage.dependencies["@wrnexus/pubsub"]).toBe(version); + expect(files["README.md"]).toContain("http://127.0.0.1:3000"); + expect(files["README.md"]).toContain("internal gateway targets"); +}); diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 6a42ba71..3853cf0d 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/compiler", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/core/package.json b/packages/core/package.json index 0b106590..a72a3a30 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/core", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/csr/package.json b/packages/csr/package.json index e462ba7d..7d26c228 100644 --- a/packages/csr/package.json +++ b/packages/csr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/csr", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/db/package.json b/packages/db/package.json index 99828a7c..31c3019d 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/db", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/dev-server/README.md b/packages/dev-server/README.md index d9e6dc0e..cfe004d0 100644 --- a/packages/dev-server/README.md +++ b/packages/dev-server/README.md @@ -147,7 +147,7 @@ Serves several apps behind one port and routes each request to the right app by ```ts interface GatewayOptions { port?: number; // default 3000 - hostname?: string; // default "localhost" + hostname?: string; // dev: "127.0.0.1"; production: "0.0.0.0" mode?: "development" | "production"; apps: GatewayApp[]; security?: GatewaySecurity; @@ -176,7 +176,10 @@ interface GatewaySecurity { } ``` -The gateway exposes `/__gateway/health` (JSON list of routed apps) and returns a `RunningGateway` (`{ port, url, stop() }`). +Open the gateway URL (normally `http://127.0.0.1:3000`), not an app's internal +port. The gateway exposes `/__gateway/health` (JSON list of routed apps) and returns a +`RunningGateway` (`{ port, url, stop() }`). Use `--host=0.0.0.0` when other devices need +to reach a development gateway. ### `node:http` adapter (from `./adapters/node.ts`) diff --git a/packages/dev-server/package.json b/packages/dev-server/package.json index 5fe47234..9f019b79 100644 --- a/packages/dev-server/package.json +++ b/packages/dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/dev-server", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/dev-server/src/gateway.ts b/packages/dev-server/src/gateway.ts index 0f23d6dd..1bcb23c8 100644 --- a/packages/dev-server/src/gateway.ts +++ b/packages/dev-server/src/gateway.ts @@ -170,25 +170,56 @@ function applyEdgeHeaders(res: Response): Response { return new Response(res.body, { status: res.status, statusText: res.statusText, headers }); } -async function waitReady(origin: string, timeoutMs = 15000): Promise { +async function waitReady(target: Target, timeoutMs = 15000): Promise { const deadline = Date.now() + timeoutMs; for (;;) { + if (target.child.exitCode !== null) { + throw new Error( + `app '${target.name}' exited with code ${target.child.exitCode} during startup`, + ); + } try { - await fetch(origin + "/__wrnexus/health-probe", { method: "HEAD" }); + await fetch(target.origin + "/__wrnexus/health-probe", { method: "HEAD" }); return; // any HTTP response (incl. 404) means the server is up } catch { - if (Date.now() > deadline) throw new Error(`app at ${origin} did not start in time`); + if (Date.now() > deadline) { + throw new Error(`app '${target.name}' at ${target.origin} did not start in time`); + } await new Promise((r) => setTimeout(r, 150)); } } } +/** Platform-safe defaults: IPv4 loopback in dev, all IPv4 interfaces in production. */ +export function defaultGatewayHostname(mode: "development" | "production"): string { + return mode === "production" ? "0.0.0.0" : "127.0.0.1"; +} + +export function gatewayProxyHeaders( + req: Request, + url: URL, + ip: string, + forwardedHeaders: boolean, +): Headers { + const headers = new Headers(req.headers); + // Bun's internal fetch transparently decompresses response bodies but preserves + // Content-Encoding. Asking child apps for identity encoding prevents clients from + // trying to decompress an already-decoded proxied body. + headers.set("accept-encoding", "identity"); + if (forwardedHeaders) { + headers.set("x-forwarded-host", req.headers.get("host") ?? ""); + headers.set("x-forwarded-proto", url.protocol.replace(":", "")); + if (ip) headers.set("x-forwarded-for", ip); + } + return headers; +} + /** Boot every app as a child process, then route by Host on one gateway port. */ export async function startGateway(opts: GatewayOptions): Promise { const port = opts.port ?? 3000; - const hostname = opts.hostname ?? "::"; - const displayHost = hostname === "0.0.0.0" || hostname === "::" ? "localhost" : hostname; const mode = opts.mode ?? "development"; + const hostname = opts.hostname ?? defaultGatewayHostname(mode); + const displayHost = hostname === "0.0.0.0" || hostname === "::" ? "localhost" : hostname; const serveEntry = fileURLToPath(import.meta.resolve("@wrnexus/dev-server/serve-entry")); const targets: Target[] = opts.apps.map((app, i) => { @@ -207,10 +238,21 @@ export async function startGateway(opts: GatewayOptions): Promise waitReady(t.origin))); + const stopChildren = () => { + for (const target of targets) { + if (target.child.exitCode === null) target.child.kill(); + } + }; + + try { + await Promise.all(targets.map((target) => waitReady(target))); + } catch (error) { + stopChildren(); + throw error; + } const byHost = new Map(); for (const t of targets) for (const d of t.domains) byHost.set(d.toLowerCase(), t); @@ -224,107 +266,121 @@ export async function startGateway(opts: GatewayOptions): Promise Date.now(); - const server = Bun.serve({ - port, - hostname, - development: mode === "development", - maxRequestBodySize: 50 * 1024 * 1024, - async fetch(req, srv) { - const url = new URL(req.url); - const ip = srv.requestIP(req)?.address ?? ""; + const createGatewayServer = () => + Bun.serve({ + port, + hostname, + development: mode === "development", + maxRequestBodySize: 50 * 1024 * 1024, + async fetch(req, srv) { + const url = new URL(req.url); + const ip = srv.requestIP(req)?.address ?? ""; - // Health/status endpoint (not proxied). - if (url.pathname === "/__gateway/health") { - return Response.json({ - ok: true, - apps: targets.map((t) => ({ name: t.name, domains: t.domains, origin: t.origin })), - }); - } + // Health/status endpoint (not proxied). + if (url.pathname === "/__gateway/health") { + return Response.json({ + ok: true, + apps: targets.map((t) => ({ name: t.name, domains: t.domains, origin: t.origin })), + }); + } - // Edge rate limit (global, by client IP). - if (rateLimit && !rateLimit(ip, now())) { - return new Response("Too Many Requests", { status: 429, headers: { "retry-after": "60" } }); - } + // Edge rate limit (global, by client IP). + if (rateLimit && !rateLimit(ip, now())) { + return new Response("Too Many Requests", { + status: 429, + headers: { "retry-after": "60" }, + }); + } - // Route by Host. Unknown host → 404 when trustedHostsOnly, else first app. - const target = - pick(req.headers.get("host") ?? "") ?? (sec.trustedHostsOnly ? null : targets[0]!); - if (!target) { - return new Response("Unknown host", { status: 404 }); - } + // Route by Host. Unknown host → 404 when trustedHostsOnly, else first app. + const target = + pick(req.headers.get("host") ?? "") ?? (sec.trustedHostsOnly ? null : targets[0]!); + if (!target) { + return new Response("Unknown host", { status: 404 }); + } - // Per-app access control (basic auth / IP allowlist / forward-auth). - const denied = await checkAuth(target.auth, req, ip); - if (denied) { + // Per-app access control (basic auth / IP allowlist / forward-auth). + const denied = await checkAuth(target.auth, req, ip); + if (denied) { + if (sec.accessLog) + console.log( + ` ⛔ ${req.headers.get("host")} ${req.method} ${url.pathname} → ${denied.status} (${target.name})`, + ); + return denied; + } + + // WebSocket upgrade → proxy the socket to the app's realtime server. + if (req.headers.get("upgrade")?.toLowerCase() === "websocket") { + const ok = srv.upgrade(req, { + data: { origin: target.origin, path: url.pathname + url.search, queue: [] }, + }); + return ok ? undefined : new Response("WebSocket upgrade failed", { status: 400 }); + } + + // HTTP → reverse-proxy to the app, preserving method/headers/body. + const headers = gatewayProxyHeaders(req, url, ip, forwardedHeaders); + const body = + req.method === "GET" || req.method === "HEAD" ? undefined : await req.arrayBuffer(); + let res: Response; + try { + res = await fetch(target.origin + url.pathname + url.search, { + method: req.method, + headers, + body, + redirect: "manual", + }); + } catch { + res = new Response(`Gateway: app '${target.name}' is unavailable.`, { status: 502 }); + } + if (sec.headers) res = applyEdgeHeaders(res); if (sec.accessLog) console.log( - ` ⛔ ${req.headers.get("host")} ${req.method} ${url.pathname} → ${denied.status} (${target.name})`, + ` ${req.headers.get("host")} ${req.method} ${url.pathname} → ${res.status} (${target.name})`, ); - return denied; - } + return res; + }, + websocket: { + open(ws) { + const backendUrl = ws.data.origin.replace(/^http/, "ws") + ws.data.path; + const backend = new WebSocket(backendUrl); + ws.data.backend = backend; + backend.addEventListener("open", () => { + for (const m of ws.data.queue) backend.send(m); + ws.data.queue = []; + }); + backend.addEventListener("message", (e) => ws.send(e.data as string | ArrayBufferLike)); + backend.addEventListener("close", () => ws.close()); + backend.addEventListener("error", () => ws.close()); + }, + message(ws, message) { + const backend = ws.data.backend; + if (backend && backend.readyState === WebSocket.OPEN) backend.send(message); + else ws.data.queue.push(message); + }, + close(ws) { + ws.data.backend?.close(); + }, + }, + }); - // WebSocket upgrade → proxy the socket to the app's realtime server. - if (req.headers.get("upgrade")?.toLowerCase() === "websocket") { - const ok = srv.upgrade(req, { - data: { origin: target.origin, path: url.pathname + url.search, queue: [] }, - }); - return ok ? undefined : new Response("WebSocket upgrade failed", { status: 400 }); - } - - // HTTP → reverse-proxy to the app, preserving method/headers/body. - const headers = new Headers(req.headers); - if (forwardedHeaders) { - headers.set("x-forwarded-host", req.headers.get("host") ?? ""); - headers.set("x-forwarded-proto", url.protocol.replace(":", "")); - if (ip) headers.set("x-forwarded-for", ip); - } - const body = - req.method === "GET" || req.method === "HEAD" ? undefined : await req.arrayBuffer(); - let res: Response; - try { - res = await fetch(target.origin + url.pathname + url.search, { - method: req.method, - headers, - body, - redirect: "manual", - }); - } catch { - res = new Response(`Gateway: app '${target.name}' is unavailable.`, { status: 502 }); - } - if (sec.headers) res = applyEdgeHeaders(res); - if (sec.accessLog) - console.log( - ` ${req.headers.get("host")} ${req.method} ${url.pathname} → ${res.status} (${target.name})`, - ); - return res; - }, - websocket: { - open(ws) { - const backendUrl = ws.data.origin.replace(/^http/, "ws") + ws.data.path; - const backend = new WebSocket(backendUrl); - ws.data.backend = backend; - backend.addEventListener("open", () => { - for (const m of ws.data.queue) backend.send(m); - ws.data.queue = []; - }); - backend.addEventListener("message", (e) => ws.send(e.data as string | ArrayBufferLike)); - backend.addEventListener("close", () => ws.close()); - backend.addEventListener("error", () => ws.close()); - }, - message(ws, message) { - const backend = ws.data.backend; - if (backend && backend.readyState === WebSocket.OPEN) backend.send(message); - else ws.data.queue.push(message); - }, - close(ws) { - ws.data.backend?.close(); - }, - }, - }); + let server: ReturnType; + try { + server = createGatewayServer(); + } catch (error) { + stopChildren(); + if (error instanceof Error && "code" in error && error.code === "EADDRINUSE") { + throw new Error( + `Gateway cannot listen on ${hostname}:${port} because the port is already in use. ` + + `Stop the existing process or run \`wrnexus gateway --port=\`.`, + { cause: error }, + ); + } + throw error; + } const stop = () => { server.stop(); - for (const t of targets) t.child.kill(); + stopChildren(); }; process.on("SIGINT", stop); process.on("SIGTERM", stop); diff --git a/packages/dev-server/test/gateway.test.ts b/packages/dev-server/test/gateway.test.ts new file mode 100644 index 00000000..40e5d00c --- /dev/null +++ b/packages/dev-server/test/gateway.test.ts @@ -0,0 +1,19 @@ +import { expect, test } from "bun:test"; +import { defaultGatewayHostname, gatewayProxyHeaders } from "../src/gateway.ts"; + +test("gateway uses platform-safe hostname defaults", () => { + expect(defaultGatewayHostname("development")).toBe("127.0.0.1"); + expect(defaultGatewayHostname("production")).toBe("0.0.0.0"); +}); + +test("gateway disables compression for its internal proxy hop", () => { + const request = new Request("http://localhost:3000/path", { + headers: { host: "web.localhost:3000", "accept-encoding": "gzip, deflate" }, + }); + const headers = gatewayProxyHeaders(request, new URL(request.url), "127.0.0.1", true); + + expect(headers.get("accept-encoding")).toBe("identity"); + expect(headers.get("x-forwarded-host")).toBe("web.localhost:3000"); + expect(headers.get("x-forwarded-proto")).toBe("http"); + expect(headers.get("x-forwarded-for")).toBe("127.0.0.1"); +}); diff --git a/packages/encryption/package.json b/packages/encryption/package.json index 9c31833e..0a5681bf 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/encryption", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 36ea7a8a..ba4a2bd2 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/i18n", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/jwt/package.json b/packages/jwt/package.json index 42334757..e8df7950 100644 --- a/packages/jwt/package.json +++ b/packages/jwt/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/jwt", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 8f714751..edeb61e5 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/mobile", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/native/package.json b/packages/native/package.json index 8a03827b..18f721f6 100644 --- a/packages/native/package.json +++ b/packages/native/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/native", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/oauth/package.json b/packages/oauth/package.json index dd47488e..c18e2347 100644 --- a/packages/oauth/package.json +++ b/packages/oauth/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/oauth", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index 591b96cb..2dd25558 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/pubsub", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/queue/package.json b/packages/queue/package.json index e4d922c1..443a772e 100644 --- a/packages/queue/package.json +++ b/packages/queue/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/queue", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/reactive/package.json b/packages/reactive/package.json index 6240e633..ec2bc2d1 100644 --- a/packages/reactive/package.json +++ b/packages/reactive/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/reactive", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/router/package.json b/packages/router/package.json index 12fe977b..db1b98a2 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/router", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/ssr/package.json b/packages/ssr/package.json index 346f9de3..7ec46fb2 100644 --- a/packages/ssr/package.json +++ b/packages/ssr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ssr", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/styles/package.json b/packages/styles/package.json index 7c8874ec..7fde77ef 100644 --- a/packages/styles/package.json +++ b/packages/styles/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/styles", - "version": "0.2.15", + "version": "0.2.16", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/test/package.json b/packages/test/package.json index 3fafac1a..f6681e04 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/test", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/tracking/package.json b/packages/tracking/package.json index 259979fc..5351dc4a 100644 --- a/packages/tracking/package.json +++ b/packages/tracking/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/tracking", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 069500b7..fe45ea85 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ui", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/uploader/package.json b/packages/uploader/package.json index 8c4078d3..1a851e32 100644 --- a/packages/uploader/package.json +++ b/packages/uploader/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/uploader", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/validation/package.json b/packages/validation/package.json index 38446bbb..ce761b84 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/validation", - "version": "0.2.15", + "version": "0.2.16", "private": true, "type": "module", "main": "src/index.ts",