release: WRNexusJS 0.5.10
This commit is contained in:
@@ -10,7 +10,8 @@
|
||||
*/
|
||||
|
||||
import { spawn, type ChildProcess } from "node:child_process";
|
||||
import { join, resolve } from "node:path";
|
||||
import { existsSync } from "node:fs";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { RESTART_EXIT_CODE } from "./restart.ts";
|
||||
|
||||
@@ -150,11 +151,15 @@ export function stripInternalError(res: Response): Response {
|
||||
}
|
||||
|
||||
/** Preserve an intentional verifier redirect while keeping other failures opaque. */
|
||||
export function forwardAuthFailure(res: Response, verifierUrl: string): Response {
|
||||
export function forwardAuthFailure(
|
||||
res: Response,
|
||||
verifierUrl: string,
|
||||
verifierPublicOrigin = verifierUrl,
|
||||
): Response {
|
||||
const location = res.headers.get("location");
|
||||
if (res.status >= 300 && res.status < 400 && location) {
|
||||
try {
|
||||
const redirect = new URL(location, verifierUrl);
|
||||
const redirect = new URL(location, verifierPublicOrigin);
|
||||
if (redirect.protocol === "http:" || redirect.protocol === "https:") {
|
||||
return new Response(null, { status: res.status, headers: { location: redirect.href } });
|
||||
}
|
||||
@@ -197,6 +202,7 @@ async function checkAuth(
|
||||
req: Request,
|
||||
ip: string,
|
||||
internalOrigins: Readonly<Record<string, string>>,
|
||||
publicOrigins: Readonly<Record<string, string>>,
|
||||
publicOrigin?: string,
|
||||
): Promise<Response | null> {
|
||||
if (!auth) return null;
|
||||
@@ -226,6 +232,10 @@ async function checkAuth(
|
||||
|
||||
if (auth.forward) {
|
||||
const verifyUrl = resolveForwardAuthUrl(auth.forward, internalOrigins);
|
||||
const verifierPublicOrigin =
|
||||
typeof auth.forward.app === "string"
|
||||
? publicOrigins[auth.forward.app]
|
||||
: new URL(auth.forward.url).origin;
|
||||
|
||||
try {
|
||||
const res = await fetch(verifyUrl, {
|
||||
@@ -240,7 +250,7 @@ async function checkAuth(
|
||||
`[wrnexus] forward-auth verifier error: ${req.method} ${requestUrl.pathname} via ${verifyUrl} returned ${res.status}${diagnostic ? ` — ${diagnostic}` : ""}`,
|
||||
);
|
||||
}
|
||||
return forwardAuthFailure(res, verifyUrl);
|
||||
return forwardAuthFailure(res, verifyUrl, verifierPublicOrigin);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
@@ -351,11 +361,21 @@ export async function startGateway(opts: GatewayOptions): Promise<RunningGateway
|
||||
const hostname = opts.hostname ?? defaultGatewayHostname(mode);
|
||||
const environment = opts.environment ?? (mode === "production" ? "production" : "development");
|
||||
|
||||
const workspaceOrigins = Object.fromEntries(
|
||||
opts.apps.map((app) => [app.name, app.publicOrigin ?? `http://${app.domains[0]}:${port}`]),
|
||||
const workspaceOrigins: Readonly<Record<string, string>> = Object.freeze(
|
||||
Object.fromEntries(
|
||||
opts.apps.map((app) => [app.name, app.publicOrigin ?? `http://${app.domains[0]}:${port}`]),
|
||||
),
|
||||
);
|
||||
const displayHost = hostname === "0.0.0.0" || hostname === "::" ? "localhost" : hostname;
|
||||
const serveEntry = fileURLToPath(import.meta.resolve("@wrnexus/dev-server/serve-entry"));
|
||||
// When the CLI is executed directly from a framework checkout, keep child
|
||||
// apps on that same source tree. Resolving the package name from an external
|
||||
// workspace can otherwise select its older installed release on restart.
|
||||
const sourceServeEntry = fileURLToPath(new URL("./serve-entry.ts", import.meta.url));
|
||||
const usesSourceServeEntry = existsSync(sourceServeEntry);
|
||||
const serveEntry = usesSourceServeEntry
|
||||
? sourceServeEntry
|
||||
: fileURLToPath(import.meta.resolve("@wrnexus/dev-server/serve-entry"));
|
||||
const frameworkRoot = resolve(dirname(sourceServeEntry), "../../..");
|
||||
|
||||
let stopping = false;
|
||||
const targets: Target[] = opts.apps.map((app, i) => {
|
||||
@@ -397,6 +417,11 @@ export async function startGateway(opts: GatewayOptions): Promise<RunningGateway
|
||||
],
|
||||
{
|
||||
stdio: "inherit",
|
||||
// Bun can otherwise resolve bare @wrnexus imports against the
|
||||
// external application's node_modules after an HMR restart.
|
||||
// Keep source-checkout children anchored to the same framework
|
||||
// checkout as the gateway command.
|
||||
cwd: usesSourceServeEntry ? frameworkRoot : dir,
|
||||
env: {
|
||||
...process.env,
|
||||
WRNEXUS_ENV: environment,
|
||||
@@ -496,7 +521,14 @@ export async function startGateway(opts: GatewayOptions): Promise<RunningGateway
|
||||
}
|
||||
|
||||
// Per-app access control (basic auth / IP allowlist / forward-auth).
|
||||
const denied = await checkAuth(target.auth, req, ip, internalOrigins, target.publicOrigin);
|
||||
const denied = await checkAuth(
|
||||
target.auth,
|
||||
req,
|
||||
ip,
|
||||
internalOrigins,
|
||||
workspaceOrigins,
|
||||
target.publicOrigin,
|
||||
);
|
||||
if (denied) {
|
||||
if (sec.accessLog)
|
||||
console.log(
|
||||
|
||||
Reference in New Issue
Block a user