feat: add helpers and improve workspace auth flows
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/authz — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -34,6 +34,7 @@ Every command accepts an optional `[app-dir]` (defaults to `.`). Commands that r
|
||||
| `wrnexus build [app-dir]` | Build a self-contained production server bundle + assets into `dist/`. |
|
||||
| `wrnexus create <app-name>` | Scaffold a new single app from an inline template. |
|
||||
| `wrnexus workspace <name>` | Scaffold a monorepo (`apps/*` + shared `packages/*`). |
|
||||
| `wrnexus workspace add <name>` | Add and register an app in the current workspace. |
|
||||
| `wrnexus gateway [--port=3000]` | Serve every workspace app behind one port, routed by domain. |
|
||||
| `wrnexus generate <type> <name>` | Scaffold a `page` \| `component` \| `api` \| `schema`. |
|
||||
| `wrnexus generate routes` | Regenerate the typed routes file (`app/routes.gen.ts`). |
|
||||
@@ -167,6 +168,13 @@ wrnexus workspace acme
|
||||
wrnexus gateway --port=3000
|
||||
```
|
||||
|
||||
From a workspace root, add and register another app in one command:
|
||||
|
||||
```bash
|
||||
wrnexus workspace add reports --domain=reports.localhost
|
||||
bun install
|
||||
```
|
||||
|
||||
Development gateways bind to `127.0.0.1` by default for reliable access on Windows,
|
||||
macOS, and Linux. Open the configured app domain on the gateway port (for example
|
||||
`http://localhost:3000` or `http://admin.localhost:3000`), not the internal child ports
|
||||
|
||||
+11
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"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.16",
|
||||
"@wrnexus/router": "^0.2.16",
|
||||
"@wrnexus/csr": "^0.2.16",
|
||||
"@wrnexus/compiler": "^0.2.16",
|
||||
"@wrnexus/styles": "^0.2.16",
|
||||
"@wrnexus/dev-server": "^0.2.16",
|
||||
"@wrnexus/ui": "^0.2.16",
|
||||
"@wrnexus/validation": "^0.2.16",
|
||||
"@wrnexus/i18n": "^0.2.16",
|
||||
"@wrnexus/db": "^0.2.16"
|
||||
"@wrnexus/core": "^0.2.17",
|
||||
"@wrnexus/router": "^0.2.17",
|
||||
"@wrnexus/csr": "^0.2.17",
|
||||
"@wrnexus/compiler": "^0.2.17",
|
||||
"@wrnexus/styles": "^0.2.17",
|
||||
"@wrnexus/dev-server": "^0.2.17",
|
||||
"@wrnexus/ui": "^0.2.17",
|
||||
"@wrnexus/validation": "^0.2.17",
|
||||
"@wrnexus/i18n": "^0.2.17",
|
||||
"@wrnexus/db": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/compiler — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/core — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/csr — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.16"
|
||||
"@wrnexus/core": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/db — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -176,6 +176,19 @@ interface GatewaySecurity {
|
||||
}
|
||||
```
|
||||
|
||||
Forward auth is a verification hook, not a login page. Configure `forward.url` with a
|
||||
dedicated endpoint such as `http://sso.localhost:3000/api/verify`. The gateway forwards
|
||||
the request's `Cookie` and `Authorization` headers plus `X-Forwarded-Host`,
|
||||
`X-Forwarded-Proto`, `X-Original-Method`, and `X-Original-Uri` (including its query
|
||||
string). The verifier must return 2xx only for an authenticated session and 401/403
|
||||
otherwise. Pointing forward auth at an SSO home page that always returns 200 allows
|
||||
every request and does not implement SSO.
|
||||
|
||||
For browser SSO, the verifier may return a `302`/`303`/`307`/`308` with a `Location`
|
||||
header pointing to its login page. The gateway passes that redirect to the browser. The
|
||||
login flow should validate a signed `returnTo` value before redirecting back; API clients
|
||||
should receive `401`/`403` instead of an HTML login redirect.
|
||||
|
||||
Open the gateway URL (normally `http://127.0.0.1:3000`), not an app's internal
|
||||
port. The gateway exposes `/__gateway/health` (JSON list of routed apps) and returns a
|
||||
`RunningGateway` (`{ port, url, stop() }`). Use `--host=0.0.0.0` when other devices need
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -25,18 +25,18 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.16",
|
||||
"@wrnexus/router": "^0.2.16",
|
||||
"@wrnexus/ssr": "^0.2.16",
|
||||
"@wrnexus/csr": "^0.2.16",
|
||||
"@wrnexus/compiler": "^0.2.16",
|
||||
"@wrnexus/styles": "^0.2.16",
|
||||
"@wrnexus/ui": "^0.2.16",
|
||||
"@wrnexus/validation": "^0.2.16",
|
||||
"@wrnexus/i18n": "^0.2.16",
|
||||
"@wrnexus/db": "^0.2.16",
|
||||
"@wrnexus/pubsub": "^0.2.16",
|
||||
"@wrnexus/uploader": "^0.2.16"
|
||||
"@wrnexus/core": "^0.2.17",
|
||||
"@wrnexus/router": "^0.2.17",
|
||||
"@wrnexus/ssr": "^0.2.17",
|
||||
"@wrnexus/csr": "^0.2.17",
|
||||
"@wrnexus/compiler": "^0.2.17",
|
||||
"@wrnexus/styles": "^0.2.17",
|
||||
"@wrnexus/ui": "^0.2.17",
|
||||
"@wrnexus/validation": "^0.2.17",
|
||||
"@wrnexus/i18n": "^0.2.17",
|
||||
"@wrnexus/db": "^0.2.17",
|
||||
"@wrnexus/pubsub": "^0.2.17",
|
||||
"@wrnexus/uploader": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/encryption — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# @wrnexus/helpers
|
||||
|
||||
Safe convenience helpers for common WrNexus application flows. The package uses
|
||||
standard `Context`, `URL`, and `Response` values and has no runtime dependency beyond
|
||||
`@wrnexus/core`.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bun add @wrnexus/helpers
|
||||
```
|
||||
|
||||
The package is private, so the machine must be authenticated to the `wrnexus` npm
|
||||
organization.
|
||||
|
||||
## Forward-auth login redirects
|
||||
|
||||
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
|
||||
in the login redirect:
|
||||
|
||||
```ts
|
||||
import type { Context } from "@wrnexus/core";
|
||||
import { redirectToLogin } from "@wrnexus/helpers";
|
||||
|
||||
export const GET = async (ctx: Context) => {
|
||||
if (await hasValidSession(ctx)) {
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
|
||||
return redirectToLogin(ctx, "/login", {
|
||||
allowedHosts: ["admin.localhost:3000", "reports.localhost:3000"],
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
This creates a response such as:
|
||||
|
||||
```text
|
||||
Location: http://sso.localhost:3000/login?returnTo=http%3A%2F%2Fadmin.localhost%3A3000%2F
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```ts
|
||||
allowedHosts: (host) => host.endsWith(".example.test");
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
- `getOriginalRequestUrl(ctx, options): URL` — reconstruct the gateway URL.
|
||||
- `getOriginalRequestOrigin(ctx, options): string` — return only its origin.
|
||||
- `getOriginalRequestPath(ctx): string` — return its path and query string.
|
||||
- `getOriginalRequestMethod(ctx): string` — return its HTTP method.
|
||||
- `redirectToLogin(ctx, loginUrl, options): Response` — create a login redirect with an
|
||||
encoded `returnTo` parameter.
|
||||
|
||||
For direct requests without gateway headers, URL helpers use `ctx.url`.
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"engines": {
|
||||
"bun": ">=1.1.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "restricted"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/i18n — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.16"
|
||||
"@wrnexus/core": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/jwt — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/mobile — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/native": "^0.2.16"
|
||||
"@wrnexus/native": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/native — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/oauth — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/queue — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/reactive — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/router — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,8 +21,8 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/compiler": "^0.2.16",
|
||||
"@wrnexus/core": "^0.2.16"
|
||||
"@wrnexus/compiler": "^0.2.17",
|
||||
"@wrnexus/core": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/ssr — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.16"
|
||||
"@wrnexus/core": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/styles — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/uploader": "^0.2.16"
|
||||
"@wrnexus/uploader": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/test — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/tracking — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"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.16"
|
||||
"@wrnexus/core": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/uploader — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.16"
|
||||
"@wrnexus/core": "^0.2.17"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.17",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/validation — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
Reference in New Issue
Block a user