docs: add verified package usage examples

This commit is contained in:
2026-07-13 20:51:04 +05:30
parent 7a1c6c0041
commit 4ce087b238
67 changed files with 592 additions and 136 deletions
+19
View File
@@ -122,6 +122,8 @@ try {
## Usage
### Return generated JSON from an API route
```ts
// app/api/summarize.ts — summarize posted text
import { createAI } from "@wrnexus/ai";
@@ -137,6 +139,23 @@ export const POST = async (ctx) => {
};
```
### Stream a chat response to the browser
```ts
// app/api/chat.ts
import { createAI } from "@wrnexus/ai";
const ai = createAI({ model: "claude-sonnet-5" });
export const POST = async (ctx) => {
const { messages } = await ctx.req.json();
return ai.streamResponse(messages, {
system: "Answer using concise Markdown.",
maxTokens: 1_500,
});
};
```
## Requirements / Notes
- **Bun-only.** Uses `fetch`, `ReadableStream`, `TextDecoder`/`TextEncoder`, and
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ai",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/authz",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/authz — part of the WrNexus framework.",
"license": "MIT",
+41
View File
@@ -188,6 +188,47 @@ Runs the app's tests with `bun test`. Defaults to the `test` profile (config + `
wrnexus test . --watch
```
## Usage
### Create and run a single application
```bash
bunx @wrnexus/cli create customer-portal
cd customer-portal
bun install
bun run dev
```
### Add routes and shared UI to an existing app
```bash
wrnexus generate page reports/monthly
wrnexus generate api reports/export
wrnexus generate component report-filter
wrnexus generate routes
```
### Create a multi-app workspace and add another app
```bash
wrnexus workspace company-suite
cd company-suite
wrnexus workspace add reports --domain=reports.localhost
bun install
wrnexus gateway --port=3000
```
Open `http://reports.localhost:3000`; the gateway selects `apps/reports` from the
request host.
### Upgrade with migrations and verification
```bash
wrnexus update --latest --dry-run
wrnexus update --latest
wrnexus doctor
```
## Profiles
Pass `--profile=<name>` to `dev`, `build`, `db` (or set `WRNEXUS_PROFILE`) to select a config profile. The CLI publishes `WRNEXUS_PROFILE` so config loaders and the dev child pick it up, and loads that profile's `.env` cascade (`.env`, `.env.local`, `.env.<profile>`, `.env.<profile>.local`) into `process.env`.
+11 -11
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/cli",
"version": "0.2.23",
"version": "0.2.24",
"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.23",
"@wrnexus/router": "^0.2.23",
"@wrnexus/csr": "^0.2.23",
"@wrnexus/compiler": "^0.2.23",
"@wrnexus/styles": "^0.2.23",
"@wrnexus/dev-server": "^0.2.23",
"@wrnexus/ui": "^0.2.23",
"@wrnexus/validation": "^0.2.23",
"@wrnexus/i18n": "^0.2.23",
"@wrnexus/db": "^0.2.23"
"@wrnexus/core": "^0.2.24",
"@wrnexus/router": "^0.2.24",
"@wrnexus/csr": "^0.2.24",
"@wrnexus/compiler": "^0.2.24",
"@wrnexus/styles": "^0.2.24",
"@wrnexus/dev-server": "^0.2.24",
"@wrnexus/ui": "^0.2.24",
"@wrnexus/validation": "^0.2.24",
"@wrnexus/i18n": "^0.2.24",
"@wrnexus/db": "^0.2.24"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/compiler",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/compiler — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/core",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/core — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/csr",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/csr — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.23"
"@wrnexus/core": "^0.2.24"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/db",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/db — part of the WrNexus framework.",
"license": "MIT",
+13 -13
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-server",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
"license": "MIT",
@@ -25,18 +25,18 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.23",
"@wrnexus/router": "^0.2.23",
"@wrnexus/ssr": "^0.2.23",
"@wrnexus/csr": "^0.2.23",
"@wrnexus/compiler": "^0.2.23",
"@wrnexus/styles": "^0.2.23",
"@wrnexus/ui": "^0.2.23",
"@wrnexus/validation": "^0.2.23",
"@wrnexus/i18n": "^0.2.23",
"@wrnexus/db": "^0.2.23",
"@wrnexus/pubsub": "^0.2.23",
"@wrnexus/uploader": "^0.2.23"
"@wrnexus/core": "^0.2.24",
"@wrnexus/router": "^0.2.24",
"@wrnexus/ssr": "^0.2.24",
"@wrnexus/csr": "^0.2.24",
"@wrnexus/compiler": "^0.2.24",
"@wrnexus/styles": "^0.2.24",
"@wrnexus/ui": "^0.2.24",
"@wrnexus/validation": "^0.2.24",
"@wrnexus/i18n": "^0.2.24",
"@wrnexus/db": "^0.2.24",
"@wrnexus/pubsub": "^0.2.24",
"@wrnexus/uploader": "^0.2.24"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/encryption",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/encryption — part of the WrNexus framework.",
"license": "MIT",
+19 -3
View File
@@ -13,7 +13,9 @@ bun add @wrnexus/helpers
The package is private, so the machine must be authenticated to the `wrnexus` npm
organization.
## Forward-auth login redirects
## Usage
### Redirect an unauthenticated forward-auth request
The gateway calls an SSO verifier on a different URL from the original application.
These helpers reconstruct the original URL from the gateway headers and safely place it
@@ -42,15 +44,29 @@ Location: http://sso.localhost:3000/login?returnTo=http%3A%2F%2Fadmin.localhost%
Always list the application hosts that are valid redirect destinations. Forwarded host
headers are rejected when `allowedHosts` is absent or does not match, preventing an open
redirect. A callback can support dynamic tenant domains:
redirect.
The SSO hostname is the login destination, not an `allowedHosts` entry. For example,
when protecting `admin.localhost:3000`, keep `admin.localhost:3000` in the allowlist even
though the verifier runs at `sso.localhost:3000`. WRNexus preserves both hosts across a
nested gateway request.
### Support dynamic tenant domains
```ts
allowedHosts: (host) => host.endsWith(".example.test");
import type { Context } from "@wrnexus/core";
import { getOriginalRequestOrigin, redirectToLogin } from "@wrnexus/helpers";
export const GET = async (ctx: Context) => {
const allowedHosts = (host: string) => host === "example.test" || host.endsWith(".example.test");
console.info("Authentication requested by", getOriginalRequestOrigin(ctx, { allowedHosts }));
return redirectToLogin(ctx, "https://auth.example.test/login", {
allowedHosts,
returnToParam: "continue",
status: 303,
});
};
```
## API
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/helpers",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.23"
"@wrnexus/core": "^0.2.24"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/i18n",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/i18n — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.23"
"@wrnexus/core": "^0.2.24"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/jwt",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/jwt — part of the WrNexus framework.",
"license": "MIT",
+70 -11
View File
@@ -1,24 +1,83 @@
# @wrnexus/mobile
SSR-safe access to Capacitor plugins from WrNexus browser code.
> SSR-safe access to Capacitor plugins from WRNexusJS browser code.
## Overview
`@wrnexus/mobile` keeps optional native imports out of server rendering while giving
browser-owned modules one consistent registry for Capacitor plugins. During SSR,
`mobile.isNative()` is `false` and `mobile.platform()` is `"web"`.
## Installation
Install a plugin through the WRNexusJS CLI so the web and native projects stay aligned:
```bash
wrnexus mobile add @capacitor/camera
wrnexus mobile add @capacitor/camera @capacitor/haptics
```
## Usage
### Register and invoke a Capacitor plugin
Import Capacitor packages only from browser-owned code, never from API routes or SSR
helpers.
```ts
import { Camera } from "@capacitor/camera";
import { Camera, CameraResultType } from "@capacitor/camera";
import { mobile } from "@wrnexus/mobile";
if (mobile.isNative()) {
mobile.registerPlugin("Camera", Camera);
const photo = await mobile.invoke("Camera", "getPhoto", { resultType: "uri" });
mobile.registerPlugin("Camera", Camera);
export async function takePhoto() {
if (!mobile.isNative()) return null;
return mobile.invoke("Camera", "getPhoto", {
quality: 85,
resultType: CameraResultType.Uri,
});
}
```
`isNative()` is false and `platform()` is `web` during SSR. `plugin()` returns
`undefined` when unavailable; `requirePlugin()` and `invoke()` throw an
actionable `MobileUnavailableError`.
### Provide a browser fallback
Import and register Capacitor packages only from browser-owned code. Do not
import them in server routes, SSR helpers, or other Bun-only modules.
`whenNative` runs the first callback only in a Capacitor WebView and can return a
web/SSR-safe fallback everywhere else.
```ts
import { Haptics, ImpactStyle } from "@capacitor/haptics";
import { mobile } from "@wrnexus/mobile";
mobile.registerPlugin("Haptics", Haptics);
export const confirmAction = () =>
mobile.whenNative(
() => mobile.invoke("Haptics", "impact", { style: ImpactStyle.Medium }),
() => navigator.vibrate?.(30),
);
```
### Read an optional plugin without throwing
```ts
import type { NetworkPlugin } from "@capacitor/network";
import { mobile } from "@wrnexus/mobile";
const network = mobile.plugin<NetworkPlugin>("Network");
const status = network ? await network.getStatus() : { connected: true, connectionType: "unknown" };
```
## API
- `registerPlugin(name, instance)` registers a browser-imported plugin.
- `plugin(name)` returns a plugin or `undefined`; `requirePlugin(name)` throws when absent.
- `invoke(plugin, method, options?)` calls a registered method and returns its result.
- `whenNative(native, fallback?)` selects native behavior without breaking SSR.
- `isNative()` and `platform()` report the current Capacitor environment.
Unavailable required plugins throw `MobileUnavailableError` with an actionable message.
## Requirements / Notes
- Capacitor plugin imports must remain in browser-owned modules.
- `@wrnexus/mobile` re-exports `native` from `@wrnexus/native` for applications that
prefer the higher-level cross-platform capability API.
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/mobile",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/mobile — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/native": "^0.2.23"
"@wrnexus/native": "^0.2.24"
},
"files": [
"dist"
+76 -8
View File
@@ -1,17 +1,85 @@
# @wrnexus/native
Cross-platform capabilities for browsers, Capacitor WebViews, and compiled native apps.
> Cross-platform capabilities for browsers, Capacitor WebViews, and compiled native apps.
## Overview
`@wrnexus/native` exposes capabilities by name so application code can ask what the
current platform supports before presenting an action. Browser capabilities use Web
APIs; mobile capabilities use installed Capacitor plugins. `platform()` returns
`"server"` during SSR, `"browser"` on the web, and the Capacitor platform in a native
WebView.
## Installation
```bash
bun add @wrnexus/native
```
## Usage
### Share a page when the platform supports it
```ts
import { native } from "@wrnexus/native";
if (native.supports("share")) await native.run("share", { title: "WrNexus", url: location.href });
export async function shareCurrentPage() {
if (!native.supports("share")) return false;
await native.run("share", {
title: document.title,
url: location.href,
});
return true;
}
```
Built-ins include `camera`, `clipboard.write`, `share`, `geolocation`, `network`,
`haptics`, storage, filesystem, notifications, and device information. Browser
capabilities use Web APIs; mobile capabilities use installed Capacitor plugins.
### Register an application-specific capability
`platform()` returns `server` during SSR, `browser` on the web, and the Capacitor
platform in a native WebView. Unsupported operations reject with
`NativeUnavailableError`; use `supports()` before presenting optional UI.
`register` returns an unregister function, which is useful for tests and temporary
feature modules.
```ts
import { native } from "@wrnexus/native";
const unregister = native.register("orders.scan", {
browser: {
supported: () => typeof window !== "undefined",
run: async ({ orderId }: { orderId: string }) => {
const code = window.prompt(`Scan code for order ${orderId}`);
return { code };
},
},
});
const result = await native.run<{ code: string | null }>("orders.scan", { orderId: "ord_42" });
unregister();
```
### Target browser or mobile behavior explicitly
```ts
import { native } from "@wrnexus/native";
const canUseMobileCamera = native.supports("camera", "mobile");
const position = await native.run(
"geolocation",
{ enableHighAccuracy: true },
{ target: "browser" },
);
```
## API
- `supports(name, target?)` checks availability without running the capability.
- `run(name, options?, runOptions?)` executes it or rejects with `NativeUnavailableError`.
- `register(name, capability)` adds or overrides a capability and returns cleanup.
- `registered()` lists capability names; `clearRegistry()` resets the registry.
- `isMobile()` and `platform()` report the current target safely during SSR.
Built-ins include `camera`, `clipboard.write`, `share`, `geolocation`, `network`,
`haptics`, storage, filesystem, notifications, and device information.
## Requirements / Notes
Use `supports()` before showing optional controls. Mobile capabilities require their
matching Capacitor plugins to be installed and registered by the application.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/native",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/native — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/oauth",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/oauth — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/pubsub",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/queue",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/queue — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/reactive",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/reactive — part of the WrNexus framework.",
"license": "MIT",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/router",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/router — part of the WrNexus framework.",
"license": "MIT",
@@ -21,8 +21,8 @@
}
},
"dependencies": {
"@wrnexus/compiler": "^0.2.23",
"@wrnexus/core": "^0.2.23"
"@wrnexus/compiler": "^0.2.24",
"@wrnexus/core": "^0.2.24"
},
"files": [
"dist"
+19
View File
@@ -71,6 +71,8 @@ type SeoConfig = {
## Usage
### Render an SEO-ready application page
```ts
import { renderDocument } from "@wrnexus/ssr";
@@ -98,6 +100,23 @@ return new Response(html, {
The produced document has `<title>About Us — Acme</title>`, the SEO/Open Graph/Twitter tags derived from the merged metadata, a `modulepreload` link and module `<script>` for each entry in `scripts`, and the body wrapped in `<div id="app">`.
### Add trusted framework assets and boot data
Use `extraHead` and `extraBody` only for HTML generated by your application or the
framework. User-provided values belong in `meta`, where they are escaped.
```ts
const html = renderDocument({
meta: { title: "Dashboard", robots: "noindex" },
body: dashboardHtml,
url: ctx.url,
extraHead: '<link rel="stylesheet" href="/_wrnexus/admin.css">',
extraBody: `<script type="application/json" id="boot">${JSON.stringify(bootData).replaceAll("<", "\\u003c")}</script>`,
});
return new Response(html, { headers: { "content-type": "text/html; charset=utf-8" } });
```
## Requirements / Notes
- **Server-only.** This module never imports or touches the DOM and is safe to keep out of client bundles.
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ssr",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/ssr — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.23"
"@wrnexus/core": "^0.2.24"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/styles",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/styles — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/uploader": "^0.2.23"
"@wrnexus/uploader": "^0.2.24"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/test",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/test — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/tracking",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/tracking — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ui",
"version": "0.2.23",
"version": "0.2.24",
"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.23"
"@wrnexus/core": "^0.2.24"
},
"files": [
"dist",
+6 -4
View File
@@ -6,7 +6,9 @@ with one function call, drop a drag-and-drop widget on a page, and serve files b
private. Zero external dependencies (S3 is signed with a built-in AWS SigV4 implementation, like the
rest of the framework).
## Configure
## Usage
### Configure local and S3 stores
```ts
// wrnexus.config.ts
@@ -40,7 +42,7 @@ const config: AppConfig = {
export default config;
```
## Upload (server)
### Upload from an API route or server function
```ts
// app/api/upload.ts — one-liner
@@ -60,7 +62,7 @@ Uploads are validated (size + type), stored under a random, collision-proof, pat
(the client filename is never used as a path), and — for public stores — returned with a servable
`url`.
## Widget (client)
### Add a client upload widget
Drop the element anywhere; the runtime (drag-and-drop, per-file progress, success/failed states) is
auto-injected on pages that contain `data-uploader`:
@@ -92,7 +94,7 @@ It dispatches bubbling events you can listen for:
- `wrnexus:upload``detail: { file, result: { key, url, name, size, type } }`
- `wrnexus:upload-error``detail: { file, error }`
## Serve files
### Serve private files behind application authentication
- **Public + local** → served automatically at `/__wrnexus/uploads/<store>/<key>` (immutable cache).
- **Public + S3** → `url` is the bucket/CDN URL directly.
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/uploader",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/uploader — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.23"
"@wrnexus/core": "^0.2.24"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/validation",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"description": "@wrnexus/validation — part of the WrNexus framework.",
"license": "MIT",
+19
View File
@@ -122,6 +122,8 @@ try {
## Usage
### Return generated JSON from an API route
```ts
// app/api/summarize.ts — summarize posted text
import { createAI } from "@wrnexus/ai";
@@ -137,6 +139,23 @@ export const POST = async (ctx) => {
};
```
### Stream a chat response to the browser
```ts
// app/api/chat.ts
import { createAI } from "@wrnexus/ai";
const ai = createAI({ model: "claude-sonnet-5" });
export const POST = async (ctx) => {
const { messages } = await ctx.req.json();
return ai.streamResponse(messages, {
system: "Answer using concise Markdown.",
maxTokens: 1_500,
});
};
```
## Requirements / Notes
- **Bun-only.** Uses `fetch`, `ReadableStream`, `TextDecoder`/`TextEncoder`, and
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ai",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/authz",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+41
View File
@@ -188,6 +188,47 @@ Runs the app's tests with `bun test`. Defaults to the `test` profile (config + `
wrnexus test . --watch
```
## Usage
### Create and run a single application
```bash
bunx @wrnexus/cli create customer-portal
cd customer-portal
bun install
bun run dev
```
### Add routes and shared UI to an existing app
```bash
wrnexus generate page reports/monthly
wrnexus generate api reports/export
wrnexus generate component report-filter
wrnexus generate routes
```
### Create a multi-app workspace and add another app
```bash
wrnexus workspace company-suite
cd company-suite
wrnexus workspace add reports --domain=reports.localhost
bun install
wrnexus gateway --port=3000
```
Open `http://reports.localhost:3000`; the gateway selects `apps/reports` from the
request host.
### Upgrade with migrations and verification
```bash
wrnexus update --latest --dry-run
wrnexus update --latest
wrnexus doctor
```
## Profiles
Pass `--profile=<name>` to `dev`, `build`, `db` (or set `WRNEXUS_PROFILE`) to select a config profile. The CLI publishes `WRNEXUS_PROFILE` so config loaders and the dev child pick it up, and loads that profile's `.env` cascade (`.env`, `.env.local`, `.env.<profile>`, `.env.<profile>.local`) into `process.env`.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/cli",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+8
View File
@@ -288,6 +288,14 @@ const MIGRATIONS: Migration[] = [
// Explicit no-op: updating @wrnexus/validation is sufficient.
},
},
{
version: "0.2.24",
id: "package-usage-documentation",
description: "No project-file changes; package usage documentation is expanded",
apply() {
// Explicit no-op: this release updates package and portal documentation only.
},
},
];
/** Release tooling uses this to require an explicit migration entry per version. */
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/compiler",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/core",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/csr",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/db",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-server",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/encryption",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+19 -3
View File
@@ -13,7 +13,9 @@ bun add @wrnexus/helpers
The package is private, so the machine must be authenticated to the `wrnexus` npm
organization.
## Forward-auth login redirects
## Usage
### Redirect an unauthenticated forward-auth request
The gateway calls an SSO verifier on a different URL from the original application.
These helpers reconstruct the original URL from the gateway headers and safely place it
@@ -42,15 +44,29 @@ Location: http://sso.localhost:3000/login?returnTo=http%3A%2F%2Fadmin.localhost%
Always list the application hosts that are valid redirect destinations. Forwarded host
headers are rejected when `allowedHosts` is absent or does not match, preventing an open
redirect. A callback can support dynamic tenant domains:
redirect.
The SSO hostname is the login destination, not an `allowedHosts` entry. For example,
when protecting `admin.localhost:3000`, keep `admin.localhost:3000` in the allowlist even
though the verifier runs at `sso.localhost:3000`. WRNexus preserves both hosts across a
nested gateway request.
### Support dynamic tenant domains
```ts
allowedHosts: (host) => host.endsWith(".example.test");
import type { Context } from "@wrnexus/core";
import { getOriginalRequestOrigin, redirectToLogin } from "@wrnexus/helpers";
export const GET = async (ctx: Context) => {
const allowedHosts = (host: string) => host === "example.test" || host.endsWith(".example.test");
console.info("Authentication requested by", getOriginalRequestOrigin(ctx, { allowedHosts }));
return redirectToLogin(ctx, "https://auth.example.test/login", {
allowedHosts,
returnToParam: "continue",
status: 303,
});
};
```
## API
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/helpers",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/i18n",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/jwt",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+70 -11
View File
@@ -1,24 +1,83 @@
# @wrnexus/mobile
SSR-safe access to Capacitor plugins from WrNexus browser code.
> SSR-safe access to Capacitor plugins from WRNexusJS browser code.
## Overview
`@wrnexus/mobile` keeps optional native imports out of server rendering while giving
browser-owned modules one consistent registry for Capacitor plugins. During SSR,
`mobile.isNative()` is `false` and `mobile.platform()` is `"web"`.
## Installation
Install a plugin through the WRNexusJS CLI so the web and native projects stay aligned:
```bash
wrnexus mobile add @capacitor/camera
wrnexus mobile add @capacitor/camera @capacitor/haptics
```
## Usage
### Register and invoke a Capacitor plugin
Import Capacitor packages only from browser-owned code, never from API routes or SSR
helpers.
```ts
import { Camera } from "@capacitor/camera";
import { Camera, CameraResultType } from "@capacitor/camera";
import { mobile } from "@wrnexus/mobile";
if (mobile.isNative()) {
mobile.registerPlugin("Camera", Camera);
const photo = await mobile.invoke("Camera", "getPhoto", { resultType: "uri" });
mobile.registerPlugin("Camera", Camera);
export async function takePhoto() {
if (!mobile.isNative()) return null;
return mobile.invoke("Camera", "getPhoto", {
quality: 85,
resultType: CameraResultType.Uri,
});
}
```
`isNative()` is false and `platform()` is `web` during SSR. `plugin()` returns
`undefined` when unavailable; `requirePlugin()` and `invoke()` throw an
actionable `MobileUnavailableError`.
### Provide a browser fallback
Import and register Capacitor packages only from browser-owned code. Do not
import them in server routes, SSR helpers, or other Bun-only modules.
`whenNative` runs the first callback only in a Capacitor WebView and can return a
web/SSR-safe fallback everywhere else.
```ts
import { Haptics, ImpactStyle } from "@capacitor/haptics";
import { mobile } from "@wrnexus/mobile";
mobile.registerPlugin("Haptics", Haptics);
export const confirmAction = () =>
mobile.whenNative(
() => mobile.invoke("Haptics", "impact", { style: ImpactStyle.Medium }),
() => navigator.vibrate?.(30),
);
```
### Read an optional plugin without throwing
```ts
import type { NetworkPlugin } from "@capacitor/network";
import { mobile } from "@wrnexus/mobile";
const network = mobile.plugin<NetworkPlugin>("Network");
const status = network ? await network.getStatus() : { connected: true, connectionType: "unknown" };
```
## API
- `registerPlugin(name, instance)` registers a browser-imported plugin.
- `plugin(name)` returns a plugin or `undefined`; `requirePlugin(name)` throws when absent.
- `invoke(plugin, method, options?)` calls a registered method and returns its result.
- `whenNative(native, fallback?)` selects native behavior without breaking SSR.
- `isNative()` and `platform()` report the current Capacitor environment.
Unavailable required plugins throw `MobileUnavailableError` with an actionable message.
## Requirements / Notes
- Capacitor plugin imports must remain in browser-owned modules.
- `@wrnexus/mobile` re-exports `native` from `@wrnexus/native` for applications that
prefer the higher-level cross-platform capability API.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/mobile",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+76 -8
View File
@@ -1,17 +1,85 @@
# @wrnexus/native
Cross-platform capabilities for browsers, Capacitor WebViews, and compiled native apps.
> Cross-platform capabilities for browsers, Capacitor WebViews, and compiled native apps.
## Overview
`@wrnexus/native` exposes capabilities by name so application code can ask what the
current platform supports before presenting an action. Browser capabilities use Web
APIs; mobile capabilities use installed Capacitor plugins. `platform()` returns
`"server"` during SSR, `"browser"` on the web, and the Capacitor platform in a native
WebView.
## Installation
```bash
bun add @wrnexus/native
```
## Usage
### Share a page when the platform supports it
```ts
import { native } from "@wrnexus/native";
if (native.supports("share")) await native.run("share", { title: "WrNexus", url: location.href });
export async function shareCurrentPage() {
if (!native.supports("share")) return false;
await native.run("share", {
title: document.title,
url: location.href,
});
return true;
}
```
Built-ins include `camera`, `clipboard.write`, `share`, `geolocation`, `network`,
`haptics`, storage, filesystem, notifications, and device information. Browser
capabilities use Web APIs; mobile capabilities use installed Capacitor plugins.
### Register an application-specific capability
`platform()` returns `server` during SSR, `browser` on the web, and the Capacitor
platform in a native WebView. Unsupported operations reject with
`NativeUnavailableError`; use `supports()` before presenting optional UI.
`register` returns an unregister function, which is useful for tests and temporary
feature modules.
```ts
import { native } from "@wrnexus/native";
const unregister = native.register("orders.scan", {
browser: {
supported: () => typeof window !== "undefined",
run: async ({ orderId }: { orderId: string }) => {
const code = window.prompt(`Scan code for order ${orderId}`);
return { code };
},
},
});
const result = await native.run<{ code: string | null }>("orders.scan", { orderId: "ord_42" });
unregister();
```
### Target browser or mobile behavior explicitly
```ts
import { native } from "@wrnexus/native";
const canUseMobileCamera = native.supports("camera", "mobile");
const position = await native.run(
"geolocation",
{ enableHighAccuracy: true },
{ target: "browser" },
);
```
## API
- `supports(name, target?)` checks availability without running the capability.
- `run(name, options?, runOptions?)` executes it or rejects with `NativeUnavailableError`.
- `register(name, capability)` adds or overrides a capability and returns cleanup.
- `registered()` lists capability names; `clearRegistry()` resets the registry.
- `isMobile()` and `platform()` report the current target safely during SSR.
Built-ins include `camera`, `clipboard.write`, `share`, `geolocation`, `network`,
`haptics`, storage, filesystem, notifications, and device information.
## Requirements / Notes
Use `supports()` before showing optional controls. Mobile capabilities require their
matching Capacitor plugins to be installed and registered by the application.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/native",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/oauth",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/pubsub",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/queue",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/reactive",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/router",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+19
View File
@@ -71,6 +71,8 @@ type SeoConfig = {
## Usage
### Render an SEO-ready application page
```ts
import { renderDocument } from "@wrnexus/ssr";
@@ -98,6 +100,23 @@ return new Response(html, {
The produced document has `<title>About Us — Acme</title>`, the SEO/Open Graph/Twitter tags derived from the merged metadata, a `modulepreload` link and module `<script>` for each entry in `scripts`, and the body wrapped in `<div id="app">`.
### Add trusted framework assets and boot data
Use `extraHead` and `extraBody` only for HTML generated by your application or the
framework. User-provided values belong in `meta`, where they are escaped.
```ts
const html = renderDocument({
meta: { title: "Dashboard", robots: "noindex" },
body: dashboardHtml,
url: ctx.url,
extraHead: '<link rel="stylesheet" href="/_wrnexus/admin.css">',
extraBody: `<script type="application/json" id="boot">${JSON.stringify(bootData).replaceAll("<", "\\u003c")}</script>`,
});
return new Response(html, { headers: { "content-type": "text/html; charset=utf-8" } });
```
## Requirements / Notes
- **Server-only.** This module never imports or touches the DOM and is safe to keep out of client bundles.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ssr",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/styles",
"version": "0.2.23",
"version": "0.2.24",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/test",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/tracking",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ui",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+6 -4
View File
@@ -6,7 +6,9 @@ with one function call, drop a drag-and-drop widget on a page, and serve files b
private. Zero external dependencies (S3 is signed with a built-in AWS SigV4 implementation, like the
rest of the framework).
## Configure
## Usage
### Configure local and S3 stores
```ts
// wrnexus.config.ts
@@ -40,7 +42,7 @@ const config: AppConfig = {
export default config;
```
## Upload (server)
### Upload from an API route or server function
```ts
// app/api/upload.ts — one-liner
@@ -60,7 +62,7 @@ Uploads are validated (size + type), stored under a random, collision-proof, pat
(the client filename is never used as a path), and — for public stores — returned with a servable
`url`.
## Widget (client)
### Add a client upload widget
Drop the element anywhere; the runtime (drag-and-drop, per-file progress, success/failed states) is
auto-injected on pages that contain `data-uploader`:
@@ -92,7 +94,7 @@ It dispatches bubbling events you can listen for:
- `wrnexus:upload``detail: { file, result: { key, url, name, size, type } }`
- `wrnexus:upload-error``detail: { file, error }`
## Serve files
### Serve private files behind application authentication
- **Public + local** → served automatically at `/__wrnexus/uploads/<store>/<key>` (immutable cache).
- **Public + S3** → `url` is the bucket/CDN URL directly.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/uploader",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/validation",
"version": "0.2.23",
"version": "0.2.24",
"private": true,
"type": "module",
"main": "src/index.ts",