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 ## Usage
### Return generated JSON from an API route
```ts ```ts
// app/api/summarize.ts — summarize posted text // app/api/summarize.ts — summarize posted text
import { createAI } from "@wrnexus/ai"; 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 ## Requirements / Notes
- **Bun-only.** Uses `fetch`, `ReadableStream`, `TextDecoder`/`TextEncoder`, and - **Bun-only.** Uses `fetch`, `ReadableStream`, `TextDecoder`/`TextEncoder`, and
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ai", "name": "@wrnexus/ai",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.", "description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/authz", "name": "@wrnexus/authz",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/authz — part of the WrNexus framework.", "description": "@wrnexus/authz — part of the WrNexus framework.",
"license": "MIT", "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 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 ## 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`. 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", "name": "@wrnexus/cli",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/cli — part of the WrNexus framework.", "description": "@wrnexus/cli — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -28,16 +28,16 @@
"wrnexus": "./dist/index.js" "wrnexus": "./dist/index.js"
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23", "@wrnexus/core": "^0.2.24",
"@wrnexus/router": "^0.2.23", "@wrnexus/router": "^0.2.24",
"@wrnexus/csr": "^0.2.23", "@wrnexus/csr": "^0.2.24",
"@wrnexus/compiler": "^0.2.23", "@wrnexus/compiler": "^0.2.24",
"@wrnexus/styles": "^0.2.23", "@wrnexus/styles": "^0.2.24",
"@wrnexus/dev-server": "^0.2.23", "@wrnexus/dev-server": "^0.2.24",
"@wrnexus/ui": "^0.2.23", "@wrnexus/ui": "^0.2.24",
"@wrnexus/validation": "^0.2.23", "@wrnexus/validation": "^0.2.24",
"@wrnexus/i18n": "^0.2.23", "@wrnexus/i18n": "^0.2.24",
"@wrnexus/db": "^0.2.23" "@wrnexus/db": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/compiler", "name": "@wrnexus/compiler",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/compiler — part of the WrNexus framework.", "description": "@wrnexus/compiler — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/core", "name": "@wrnexus/core",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/core — part of the WrNexus framework.", "description": "@wrnexus/core — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/csr", "name": "@wrnexus/csr",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/csr — part of the WrNexus framework.", "description": "@wrnexus/csr — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23" "@wrnexus/core": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/db", "name": "@wrnexus/db",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/db — part of the WrNexus framework.", "description": "@wrnexus/db — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+13 -13
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/dev-server", "name": "@wrnexus/dev-server",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/dev-server — part of the WrNexus framework.", "description": "@wrnexus/dev-server — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -25,18 +25,18 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23", "@wrnexus/core": "^0.2.24",
"@wrnexus/router": "^0.2.23", "@wrnexus/router": "^0.2.24",
"@wrnexus/ssr": "^0.2.23", "@wrnexus/ssr": "^0.2.24",
"@wrnexus/csr": "^0.2.23", "@wrnexus/csr": "^0.2.24",
"@wrnexus/compiler": "^0.2.23", "@wrnexus/compiler": "^0.2.24",
"@wrnexus/styles": "^0.2.23", "@wrnexus/styles": "^0.2.24",
"@wrnexus/ui": "^0.2.23", "@wrnexus/ui": "^0.2.24",
"@wrnexus/validation": "^0.2.23", "@wrnexus/validation": "^0.2.24",
"@wrnexus/i18n": "^0.2.23", "@wrnexus/i18n": "^0.2.24",
"@wrnexus/db": "^0.2.23", "@wrnexus/db": "^0.2.24",
"@wrnexus/pubsub": "^0.2.23", "@wrnexus/pubsub": "^0.2.24",
"@wrnexus/uploader": "^0.2.23" "@wrnexus/uploader": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/encryption", "name": "@wrnexus/encryption",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/encryption — part of the WrNexus framework.", "description": "@wrnexus/encryption — part of the WrNexus framework.",
"license": "MIT", "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 The package is private, so the machine must be authenticated to the `wrnexus` npm
organization. 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. 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 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 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 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, 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 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 though the verifier runs at `sso.localhost:3000`. WRNexus preserves both hosts across a
nested gateway request. nested gateway request.
### Support dynamic tenant domains
```ts ```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 ## API
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/helpers", "name": "@wrnexus/helpers",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.", "description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23" "@wrnexus/core": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/i18n", "name": "@wrnexus/i18n",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/i18n — part of the WrNexus framework.", "description": "@wrnexus/i18n — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23" "@wrnexus/core": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/jwt", "name": "@wrnexus/jwt",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/jwt — part of the WrNexus framework.", "description": "@wrnexus/jwt — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+70 -11
View File
@@ -1,24 +1,83 @@
# @wrnexus/mobile # @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 ```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 ```ts
import { Camera } from "@capacitor/camera"; import { Camera, CameraResultType } from "@capacitor/camera";
import { mobile } from "@wrnexus/mobile"; import { mobile } from "@wrnexus/mobile";
if (mobile.isNative()) { mobile.registerPlugin("Camera", Camera);
mobile.registerPlugin("Camera", Camera);
const photo = await mobile.invoke("Camera", "getPhoto", { resultType: "uri" }); 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 ### Provide a browser fallback
`undefined` when unavailable; `requirePlugin()` and `invoke()` throw an
actionable `MobileUnavailableError`.
Import and register Capacitor packages only from browser-owned code. Do not `whenNative` runs the first callback only in a Capacitor WebView and can return a
import them in server routes, SSR helpers, or other Bun-only modules. 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", "name": "@wrnexus/mobile",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/mobile — part of the WrNexus framework.", "description": "@wrnexus/mobile — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/native": "^0.2.23" "@wrnexus/native": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+76 -8
View File
@@ -1,17 +1,85 @@
# @wrnexus/native # @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 ```ts
import { native } from "@wrnexus/native"; 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`, ### Register an application-specific capability
`haptics`, storage, filesystem, notifications, and device information. Browser
capabilities use Web APIs; mobile capabilities use installed Capacitor plugins.
`platform()` returns `server` during SSR, `browser` on the web, and the Capacitor `register` returns an unregister function, which is useful for tests and temporary
platform in a native WebView. Unsupported operations reject with feature modules.
`NativeUnavailableError`; use `supports()` before presenting optional UI.
```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", "name": "@wrnexus/native",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/native — part of the WrNexus framework.", "description": "@wrnexus/native — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/oauth", "name": "@wrnexus/oauth",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/oauth — part of the WrNexus framework.", "description": "@wrnexus/oauth — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/pubsub", "name": "@wrnexus/pubsub",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/pubsub — part of the WrNexus framework.", "description": "@wrnexus/pubsub — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/queue", "name": "@wrnexus/queue",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/queue — part of the WrNexus framework.", "description": "@wrnexus/queue — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/reactive", "name": "@wrnexus/reactive",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/reactive — part of the WrNexus framework.", "description": "@wrnexus/reactive — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/router", "name": "@wrnexus/router",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/router — part of the WrNexus framework.", "description": "@wrnexus/router — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,8 +21,8 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/compiler": "^0.2.23", "@wrnexus/compiler": "^0.2.24",
"@wrnexus/core": "^0.2.23" "@wrnexus/core": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+19
View File
@@ -71,6 +71,8 @@ type SeoConfig = {
## Usage ## Usage
### Render an SEO-ready application page
```ts ```ts
import { renderDocument } from "@wrnexus/ssr"; 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">`. 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 ## Requirements / Notes
- **Server-only.** This module never imports or touches the DOM and is safe to keep out of client bundles. - **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", "name": "@wrnexus/ssr",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/ssr — part of the WrNexus framework.", "description": "@wrnexus/ssr — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23" "@wrnexus/core": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/styles", "name": "@wrnexus/styles",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/styles — part of the WrNexus framework.", "description": "@wrnexus/styles — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/uploader": "^0.2.23" "@wrnexus/uploader": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/test", "name": "@wrnexus/test",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/test — part of the WrNexus framework.", "description": "@wrnexus/test — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/tracking", "name": "@wrnexus/tracking",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/tracking — part of the WrNexus framework.", "description": "@wrnexus/tracking — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ui", "name": "@wrnexus/ui",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/ui — part of the WrNexus framework.", "description": "@wrnexus/ui — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -22,7 +22,7 @@
"./ui.css": "./ui.css" "./ui.css": "./ui.css"
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23" "@wrnexus/core": "^0.2.24"
}, },
"files": [ "files": [
"dist", "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 private. Zero external dependencies (S3 is signed with a built-in AWS SigV4 implementation, like the
rest of the framework). rest of the framework).
## Configure ## Usage
### Configure local and S3 stores
```ts ```ts
// wrnexus.config.ts // wrnexus.config.ts
@@ -40,7 +42,7 @@ const config: AppConfig = {
export default config; export default config;
``` ```
## Upload (server) ### Upload from an API route or server function
```ts ```ts
// app/api/upload.ts — one-liner // 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 (the client filename is never used as a path), and — for public stores — returned with a servable
`url`. `url`.
## Widget (client) ### Add a client upload widget
Drop the element anywhere; the runtime (drag-and-drop, per-file progress, success/failed states) is Drop the element anywhere; the runtime (drag-and-drop, per-file progress, success/failed states) is
auto-injected on pages that contain `data-uploader`: 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``detail: { file, result: { key, url, name, size, type } }`
- `wrnexus:upload-error``detail: { file, error }` - `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 + local** → served automatically at `/__wrnexus/uploads/<store>/<key>` (immutable cache).
- **Public + S3** → `url` is the bucket/CDN URL directly. - **Public + S3** → `url` is the bucket/CDN URL directly.
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/uploader", "name": "@wrnexus/uploader",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/uploader — part of the WrNexus framework.", "description": "@wrnexus/uploader — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.2.23" "@wrnexus/core": "^0.2.24"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/validation", "name": "@wrnexus/validation",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"description": "@wrnexus/validation — part of the WrNexus framework.", "description": "@wrnexus/validation — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+19
View File
@@ -122,6 +122,8 @@ try {
## Usage ## Usage
### Return generated JSON from an API route
```ts ```ts
// app/api/summarize.ts — summarize posted text // app/api/summarize.ts — summarize posted text
import { createAI } from "@wrnexus/ai"; 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 ## Requirements / Notes
- **Bun-only.** Uses `fetch`, `ReadableStream`, `TextDecoder`/`TextEncoder`, and - **Bun-only.** Uses `fetch`, `ReadableStream`, `TextDecoder`/`TextEncoder`, and
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ai", "name": "@wrnexus/ai",
"version": "0.2.23", "version": "0.2.24",
"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 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/authz", "name": "@wrnexus/authz",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "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 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 ## 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`. 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", "name": "@wrnexus/cli",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+8
View File
@@ -288,6 +288,14 @@ const MIGRATIONS: Migration[] = [
// Explicit no-op: updating @wrnexus/validation is sufficient. // 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. */ /** Release tooling uses this to require an explicit migration entry per version. */
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/compiler", "name": "@wrnexus/compiler",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/core", "name": "@wrnexus/core",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/csr", "name": "@wrnexus/csr",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/db", "name": "@wrnexus/db",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/dev-server", "name": "@wrnexus/dev-server",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/encryption", "name": "@wrnexus/encryption",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "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 The package is private, so the machine must be authenticated to the `wrnexus` npm
organization. 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. 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 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 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 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, 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 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 though the verifier runs at `sso.localhost:3000`. WRNexus preserves both hosts across a
nested gateway request. nested gateway request.
### Support dynamic tenant domains
```ts ```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 ## API
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/helpers", "name": "@wrnexus/helpers",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.", "description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/i18n", "name": "@wrnexus/i18n",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/jwt", "name": "@wrnexus/jwt",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+70 -11
View File
@@ -1,24 +1,83 @@
# @wrnexus/mobile # @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 ```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 ```ts
import { Camera } from "@capacitor/camera"; import { Camera, CameraResultType } from "@capacitor/camera";
import { mobile } from "@wrnexus/mobile"; import { mobile } from "@wrnexus/mobile";
if (mobile.isNative()) { mobile.registerPlugin("Camera", Camera);
mobile.registerPlugin("Camera", Camera);
const photo = await mobile.invoke("Camera", "getPhoto", { resultType: "uri" }); 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 ### Provide a browser fallback
`undefined` when unavailable; `requirePlugin()` and `invoke()` throw an
actionable `MobileUnavailableError`.
Import and register Capacitor packages only from browser-owned code. Do not `whenNative` runs the first callback only in a Capacitor WebView and can return a
import them in server routes, SSR helpers, or other Bun-only modules. 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", "name": "@wrnexus/mobile",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+76 -8
View File
@@ -1,17 +1,85 @@
# @wrnexus/native # @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 ```ts
import { native } from "@wrnexus/native"; 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`, ### Register an application-specific capability
`haptics`, storage, filesystem, notifications, and device information. Browser
capabilities use Web APIs; mobile capabilities use installed Capacitor plugins.
`platform()` returns `server` during SSR, `browser` on the web, and the Capacitor `register` returns an unregister function, which is useful for tests and temporary
platform in a native WebView. Unsupported operations reject with feature modules.
`NativeUnavailableError`; use `supports()` before presenting optional UI.
```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", "name": "@wrnexus/native",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/oauth", "name": "@wrnexus/oauth",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/pubsub", "name": "@wrnexus/pubsub",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/queue", "name": "@wrnexus/queue",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/reactive", "name": "@wrnexus/reactive",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/router", "name": "@wrnexus/router",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+19
View File
@@ -71,6 +71,8 @@ type SeoConfig = {
## Usage ## Usage
### Render an SEO-ready application page
```ts ```ts
import { renderDocument } from "@wrnexus/ssr"; 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">`. 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 ## Requirements / Notes
- **Server-only.** This module never imports or touches the DOM and is safe to keep out of client bundles. - **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", "name": "@wrnexus/ssr",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/styles", "name": "@wrnexus/styles",
"version": "0.2.23", "version": "0.2.24",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/test", "name": "@wrnexus/test",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/tracking", "name": "@wrnexus/tracking",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ui", "name": "@wrnexus/ui",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "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 private. Zero external dependencies (S3 is signed with a built-in AWS SigV4 implementation, like the
rest of the framework). rest of the framework).
## Configure ## Usage
### Configure local and S3 stores
```ts ```ts
// wrnexus.config.ts // wrnexus.config.ts
@@ -40,7 +42,7 @@ const config: AppConfig = {
export default config; export default config;
``` ```
## Upload (server) ### Upload from an API route or server function
```ts ```ts
// app/api/upload.ts — one-liner // 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 (the client filename is never used as a path), and — for public stores — returned with a servable
`url`. `url`.
## Widget (client) ### Add a client upload widget
Drop the element anywhere; the runtime (drag-and-drop, per-file progress, success/failed states) is Drop the element anywhere; the runtime (drag-and-drop, per-file progress, success/failed states) is
auto-injected on pages that contain `data-uploader`: 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``detail: { file, result: { key, url, name, size, type } }`
- `wrnexus:upload-error``detail: { file, error }` - `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 + local** → served automatically at `/__wrnexus/uploads/<store>/<key>` (immutable cache).
- **Public + S3** → `url` is the bucket/CDN URL directly. - **Public + S3** → `url` is the bucket/CDN URL directly.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/uploader", "name": "@wrnexus/uploader",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/validation", "name": "@wrnexus/validation",
"version": "0.2.23", "version": "0.2.24",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",