diff --git a/.publish/ai/README.md b/.publish/ai/README.md index bf3ca85f..05bd4c2e 100644 --- a/.publish/ai/README.md +++ b/.publish/ai/README.md @@ -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 diff --git a/.publish/ai/package.json b/.publish/ai/package.json index 44df6a2b..e38cc8ee 100644 --- a/.publish/ai/package.json +++ b/.publish/ai/package.json @@ -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", diff --git a/.publish/authz/package.json b/.publish/authz/package.json index b658d459..91a6ea2d 100644 --- a/.publish/authz/package.json +++ b/.publish/authz/package.json @@ -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", diff --git a/.publish/cli/README.md b/.publish/cli/README.md index f1db00b8..640b6200 100644 --- a/.publish/cli/README.md +++ b/.publish/cli/README.md @@ -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=` 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.`, `.env..local`) into `process.env`. diff --git a/.publish/cli/package.json b/.publish/cli/package.json index deeed02c..95e6360d 100644 --- a/.publish/cli/package.json +++ b/.publish/cli/package.json @@ -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" diff --git a/.publish/compiler/package.json b/.publish/compiler/package.json index df213ba9..34e1b3e1 100644 --- a/.publish/compiler/package.json +++ b/.publish/compiler/package.json @@ -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", diff --git a/.publish/core/package.json b/.publish/core/package.json index b67ec151..8cd0b04d 100644 --- a/.publish/core/package.json +++ b/.publish/core/package.json @@ -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", diff --git a/.publish/csr/package.json b/.publish/csr/package.json index 28876cb9..0ab80ea7 100644 --- a/.publish/csr/package.json +++ b/.publish/csr/package.json @@ -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" diff --git a/.publish/db/package.json b/.publish/db/package.json index 4235c75e..3a1e63a9 100644 --- a/.publish/db/package.json +++ b/.publish/db/package.json @@ -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", diff --git a/.publish/dev-server/package.json b/.publish/dev-server/package.json index 26a219ba..f973123d 100644 --- a/.publish/dev-server/package.json +++ b/.publish/dev-server/package.json @@ -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" diff --git a/.publish/encryption/package.json b/.publish/encryption/package.json index a7d6cfc9..4d3601b5 100644 --- a/.publish/encryption/package.json +++ b/.publish/encryption/package.json @@ -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", diff --git a/.publish/helpers/README.md b/.publish/helpers/README.md index f3bd2b41..7881480f 100644 --- a/.publish/helpers/README.md +++ b/.publish/helpers/README.md @@ -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 diff --git a/.publish/helpers/package.json b/.publish/helpers/package.json index dda71bc1..2cdd0b71 100644 --- a/.publish/helpers/package.json +++ b/.publish/helpers/package.json @@ -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" diff --git a/.publish/i18n/package.json b/.publish/i18n/package.json index 48f2aa57..db01d6f5 100644 --- a/.publish/i18n/package.json +++ b/.publish/i18n/package.json @@ -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" diff --git a/.publish/jwt/package.json b/.publish/jwt/package.json index fc3b9c64..e7089556 100644 --- a/.publish/jwt/package.json +++ b/.publish/jwt/package.json @@ -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", diff --git a/.publish/mobile/README.md b/.publish/mobile/README.md index 9e089485..58087db7 100644 --- a/.publish/mobile/README.md +++ b/.publish/mobile/README.md @@ -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("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. diff --git a/.publish/mobile/package.json b/.publish/mobile/package.json index b553992b..433abc89 100644 --- a/.publish/mobile/package.json +++ b/.publish/mobile/package.json @@ -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" diff --git a/.publish/native/README.md b/.publish/native/README.md index 3e9c8f54..3a2f5bc4 100644 --- a/.publish/native/README.md +++ b/.publish/native/README.md @@ -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. diff --git a/.publish/native/package.json b/.publish/native/package.json index f6350ff8..5ea90376 100644 --- a/.publish/native/package.json +++ b/.publish/native/package.json @@ -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", diff --git a/.publish/oauth/package.json b/.publish/oauth/package.json index 9c9ade66..23deae20 100644 --- a/.publish/oauth/package.json +++ b/.publish/oauth/package.json @@ -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", diff --git a/.publish/pubsub/package.json b/.publish/pubsub/package.json index 6409a231..fd3758ef 100644 --- a/.publish/pubsub/package.json +++ b/.publish/pubsub/package.json @@ -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", diff --git a/.publish/queue/package.json b/.publish/queue/package.json index ff3f3d63..11f21c14 100644 --- a/.publish/queue/package.json +++ b/.publish/queue/package.json @@ -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", diff --git a/.publish/reactive/package.json b/.publish/reactive/package.json index 184cc942..86659942 100644 --- a/.publish/reactive/package.json +++ b/.publish/reactive/package.json @@ -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", diff --git a/.publish/router/package.json b/.publish/router/package.json index bfcec654..9a72f089 100644 --- a/.publish/router/package.json +++ b/.publish/router/package.json @@ -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" diff --git a/.publish/ssr/README.md b/.publish/ssr/README.md index 5e732690..ba11ab53 100644 --- a/.publish/ssr/README.md +++ b/.publish/ssr/README.md @@ -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 `About Us — Acme`, the SEO/Open Graph/Twitter tags derived from the merged metadata, a `modulepreload` link and module ``, +}); + +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. diff --git a/.publish/ssr/package.json b/.publish/ssr/package.json index 15d58dcf..1abe3fe8 100644 --- a/.publish/ssr/package.json +++ b/.publish/ssr/package.json @@ -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" diff --git a/.publish/styles/package.json b/.publish/styles/package.json index 85028db7..ab4aadba 100644 --- a/.publish/styles/package.json +++ b/.publish/styles/package.json @@ -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" diff --git a/.publish/test/package.json b/.publish/test/package.json index a19e9e68..45493b3a 100644 --- a/.publish/test/package.json +++ b/.publish/test/package.json @@ -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", diff --git a/.publish/tracking/package.json b/.publish/tracking/package.json index b2dff52d..811c9c8b 100644 --- a/.publish/tracking/package.json +++ b/.publish/tracking/package.json @@ -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", diff --git a/.publish/ui/package.json b/.publish/ui/package.json index cf884a9c..a93ea421 100644 --- a/.publish/ui/package.json +++ b/.publish/ui/package.json @@ -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", diff --git a/.publish/uploader/README.md b/.publish/uploader/README.md index 48acd156..b89645b8 100644 --- a/.publish/uploader/README.md +++ b/.publish/uploader/README.md @@ -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//` (immutable cache). - **Public + S3** → `url` is the bucket/CDN URL directly. diff --git a/.publish/uploader/package.json b/.publish/uploader/package.json index f978e7a9..93fe50c1 100644 --- a/.publish/uploader/package.json +++ b/.publish/uploader/package.json @@ -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" diff --git a/.publish/validation/package.json b/.publish/validation/package.json index f547411a..af1fb9a6 100644 --- a/.publish/validation/package.json +++ b/.publish/validation/package.json @@ -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", diff --git a/packages/ai/README.md b/packages/ai/README.md index bf3ca85f..05bd4c2e 100644 --- a/packages/ai/README.md +++ b/packages/ai/README.md @@ -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 diff --git a/packages/ai/package.json b/packages/ai/package.json index 71ab35a0..4e5631d6 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -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.", diff --git a/packages/authz/package.json b/packages/authz/package.json index a303915a..43936963 100644 --- a/packages/authz/package.json +++ b/packages/authz/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/authz", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/cli/README.md b/packages/cli/README.md index f1db00b8..640b6200 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -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=` 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.`, `.env..local`) into `process.env`. diff --git a/packages/cli/package.json b/packages/cli/package.json index 83510e06..9acad155 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/cli", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/cli/src/update.ts b/packages/cli/src/update.ts index a8c82d3f..e670d5b5 100644 --- a/packages/cli/src/update.ts +++ b/packages/cli/src/update.ts @@ -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. */ diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 1935a9ac..b85f1a3a 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/compiler", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/core/package.json b/packages/core/package.json index e3300f59..7b5bcc0f 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/core", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/csr/package.json b/packages/csr/package.json index 385275e3..9b0a9b6a 100644 --- a/packages/csr/package.json +++ b/packages/csr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/csr", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/db/package.json b/packages/db/package.json index 04da56cc..0c156694 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/db", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/dev-server/package.json b/packages/dev-server/package.json index 0589f906..3405c997 100644 --- a/packages/dev-server/package.json +++ b/packages/dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/dev-server", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/encryption/package.json b/packages/encryption/package.json index fbb1087f..867b9bf8 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/encryption", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/helpers/README.md b/packages/helpers/README.md index f3bd2b41..7881480f 100644 --- a/packages/helpers/README.md +++ b/packages/helpers/README.md @@ -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 diff --git a/packages/helpers/package.json b/packages/helpers/package.json index c56fdcdc..b22e741f 100644 --- a/packages/helpers/package.json +++ b/packages/helpers/package.json @@ -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.", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 89146c2b..435d047c 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/i18n", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/jwt/package.json b/packages/jwt/package.json index 580ad28f..f55f0973 100644 --- a/packages/jwt/package.json +++ b/packages/jwt/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/jwt", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/mobile/README.md b/packages/mobile/README.md index 9e089485..58087db7 100644 --- a/packages/mobile/README.md +++ b/packages/mobile/README.md @@ -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("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. diff --git a/packages/mobile/package.json b/packages/mobile/package.json index d1084f8b..0f402791 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/mobile", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/native/README.md b/packages/native/README.md index 3e9c8f54..3a2f5bc4 100644 --- a/packages/native/README.md +++ b/packages/native/README.md @@ -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. diff --git a/packages/native/package.json b/packages/native/package.json index c62b5ff7..385707c5 100644 --- a/packages/native/package.json +++ b/packages/native/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/native", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/oauth/package.json b/packages/oauth/package.json index 24efef1e..381ae2a8 100644 --- a/packages/oauth/package.json +++ b/packages/oauth/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/oauth", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index d3709e6b..a004ac5e 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/pubsub", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/queue/package.json b/packages/queue/package.json index 6e4363d2..2489c641 100644 --- a/packages/queue/package.json +++ b/packages/queue/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/queue", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/reactive/package.json b/packages/reactive/package.json index ae0a13cd..7446761c 100644 --- a/packages/reactive/package.json +++ b/packages/reactive/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/reactive", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/router/package.json b/packages/router/package.json index 613595c3..4432ef9a 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/router", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/ssr/README.md b/packages/ssr/README.md index 5e732690..ba11ab53 100644 --- a/packages/ssr/README.md +++ b/packages/ssr/README.md @@ -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 `About Us — Acme`, the SEO/Open Graph/Twitter tags derived from the merged metadata, a `modulepreload` link and module ``, +}); + +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. diff --git a/packages/ssr/package.json b/packages/ssr/package.json index 969ecd5f..8f061ca9 100644 --- a/packages/ssr/package.json +++ b/packages/ssr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ssr", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/styles/package.json b/packages/styles/package.json index f45a3f30..05d66678 100644 --- a/packages/styles/package.json +++ b/packages/styles/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/styles", - "version": "0.2.23", + "version": "0.2.24", "type": "module", "main": "src/index.ts", "exports": { diff --git a/packages/test/package.json b/packages/test/package.json index a01f5fc2..1cd26e25 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/test", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/tracking/package.json b/packages/tracking/package.json index 5ed09626..eb03f5f9 100644 --- a/packages/tracking/package.json +++ b/packages/tracking/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/tracking", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 6918c40a..b1170355 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ui", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/uploader/README.md b/packages/uploader/README.md index 48acd156..b89645b8 100644 --- a/packages/uploader/README.md +++ b/packages/uploader/README.md @@ -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//` (immutable cache). - **Public + S3** → `url` is the bucket/CDN URL directly. diff --git a/packages/uploader/package.json b/packages/uploader/package.json index aee79d3b..a7eca1c9 100644 --- a/packages/uploader/package.json +++ b/packages/uploader/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/uploader", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts", diff --git a/packages/validation/package.json b/packages/validation/package.json index 3f75f28e..7394766f 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/validation", - "version": "0.2.23", + "version": "0.2.24", "private": true, "type": "module", "main": "src/index.ts",