release: WRNexusJS 0.5.0

This commit is contained in:
2026-07-29 12:51:10 +05:30
parent 76c768099d
commit 6afe32f63f
456 changed files with 40879 additions and 8850 deletions
@@ -19,10 +19,14 @@ test("Captcha browser runtime is valid JavaScript and exposes the expected lifec
expect(source).toContain("captchaRandomizeStyle");
expect(source).toContain("captchaResolvedImageStyle");
expect(source).toContain("captchaShowListen");
expect(source).toContain("captchaResetOnError");
expect(source).toContain("normalizeSize");
expect(source).toContain("verifyNotRobot");
expect(source).toContain("stopImmediatePropagation");
expect(source).toContain('addEventListener("submit"');
expect(source).toContain('addEventListener("wire:error"');
expect(source).toContain("state.config.resetOnError || captchaFailed");
expect(source).toContain("Verified response tokens are single-use");
expect(source).toContain("MutationObserver");
expect(source).toContain("new CustomEvent(name");
});
@@ -42,6 +46,7 @@ test("Captcha component delegates native browser work to the packaged runtime",
expect(source).toContain("data-captcha-randomize-style");
expect(source).toContain("data-captcha-show-listen");
expect(source).toContain("data-captcha-not-robot-button");
expect(source).toContain("data-captcha-reset-on-error");
expect(source).not.toContain("lifecycle {");
expect(source).not.toContain("async function");
expect(source).not.toContain("await ");
+2
View File
@@ -26,6 +26,7 @@ test("Captcha.wrn parses and exposes the full public contract", async () => {
"color",
"class",
"showListen",
"resetOnError",
]) {
expect(source).toContain(`${prop} =`);
}
@@ -50,6 +51,7 @@ test("Captcha.wrn parses and exposes the full public contract", async () => {
expect(source).toContain("data-captcha-excluded-styles='{excludedStyles}'");
expect(source).toContain("data-captcha-randomize-style='{randomizeStyle}'");
expect(source).toContain("data-captcha-show-listen='{showListen}'");
expect(source).toContain("data-captcha-reset-on-error='{resetOnError}'");
expect(source).toContain("data-captcha-not-robot-button");
expect(source).toContain("data-[captcha-size=compact]");
expect(source).toContain("data-[captcha-size=compact]:max-w-xs");
+56 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test";
import { createContext, type Context } from "@wrnexus/core";
import { captchaPageGate } from "../src/middleware.ts";
import { captchaGuard, captchaPageGate } from "../src/middleware.ts";
import type { CaptchaEngine } from "../src/types.ts";
function fakeEngine(): CaptchaEngine {
@@ -54,6 +54,61 @@ function sessionFixture() {
};
}
describe("CAPTCHA request guard", () => {
test("reuses an action-bound verified session grant for retryable requests", async () => {
const session = sessionFixture();
const guard = captchaGuard({
action: "auth-login",
engine: fakeEngine(),
verifiedForMs: 5 * 60_000,
});
const firstRequest = new Request("https://example.test/api/auth/login", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ "wrn-captcha-response": "verified-token" }),
});
const firstContext: Context = {
...createContext(firstRequest, new URL(firstRequest.url)),
session,
ip: "127.0.0.1",
};
const first = await guard(
firstContext,
() => new Response("credentials-invalid", { status: 401 }),
);
expect(first.status).toBe(401);
const retryRequest = new Request("https://example.test/api/auth/login", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({}),
});
const retryContext: Context = {
...createContext(retryRequest, new URL(retryRequest.url)),
session,
ip: "127.0.0.1",
};
const retry = await guard(retryContext, () => new Response("retry-allowed"));
expect(await retry.text()).toBe("retry-allowed");
expect(retryContext.locals.captcha).toMatchObject({
success: true,
action: "auth-login",
});
expect(retryContext.locals.captchaVerified).toBe(true);
});
test("rejects invalid verified-session durations", () => {
expect(() =>
captchaGuard({
action: "auth-login",
engine: fakeEngine(),
verifiedForMs: Number.NaN,
}),
).toThrow("verifiedForMs");
});
});
describe("CAPTCHA page gate", () => {
test("accepts a verified form token and grants the protected route", async () => {
const session = sessionFixture();