release: WRNexusJS 0.8.0
Quality / quality (ubuntu-latest) (push) Failing after 21s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-02 23:18:51 +05:30
parent 87507edf59
commit 586a6db8ff
625 changed files with 243608 additions and 11210 deletions
+23 -7
View File
@@ -1,11 +1,27 @@
component AccountStatus {
props { status = "active" title = "Account status" activeMessage = "Your account is active and ready to use." pendingMessage = "Verify your contact details to activate your account." lockedMessage = "Your account is temporarily locked for security." disabledMessage = "Your account has been disabled." supportHref = "/support" color = "primary" size = "md" class = "" }
props {
status: string = "active"
title: string = "Account status"
activeMessage: string = "Your account is active and ready to use."
pendingMessage: string = "Verify your contact details to activate your account."
lockedMessage: string = "Your account is temporarily locked for security."
disabledMessage: string = "Your account has been disabled."
supportHref: string = "/support"
color: string = "primary"
size: string = "md"
class: string = ""
}
view {
<section {...attrs} data-status='{status}' class='w-full max-w-lg rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-center {class}'>
<span class='mx-auto flex size-14 items-center justify-center rounded-full bg-[var(--wire-color-surface-2)] text-[var(--wire-color-primary)] data-[status=locked]:text-[var(--wire-color-warning)] data-[status=disabled]:text-[var(--wire-color-danger)]'>{#if status == "active"}<span class="icon-[lucide--circle-check] size-7"></span>{:else if status == "pending"}<span class="icon-[lucide--clock-3] size-7"></span>{:else}<span class="icon-[lucide--shield-alert] size-7"></span>{/if}</span>
<h1 class="mb-0 mt-4 text-2xl font-semibold">{title}</h1>
<p class="mx-auto mt-2 max-w-md text-sm text-[var(--wire-color-muted)]">{status == "active" ? activeMessage : status == "pending" ? pendingMessage : status == "locked" ? lockedMessage : disabledMessage}</p>
{#if status != "active"}<a href='{supportHref}' class="mt-4 inline-flex h-10 items-center justify-center rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white">Contact support</a>{/if}
</section>
<Card {...attrs} title='{title}' color='{color}' size='{size}' align="center" class='w-full max-w-lg {class}'>
<div class="flex flex-col items-center text-center" data-status='{status}'>
<span class='flex size-14 items-center justify-center rounded-full bg-[var(--wire-color-surface-2)] text-[var(--wire-color-primary)]'>
{#if status == "active"}<span class="icon-[lucide--circle-check] size-7"></span>{:else if status == "pending"}<span class="icon-[lucide--clock-3] size-7"></span>{:else}<span class="icon-[lucide--shield-alert] size-7"></span>{/if}
</span>
<p class="mx-auto mt-3 max-w-md text-sm text-[var(--wire-color-muted)]">{status == "active" ? activeMessage : status == "pending" ? pendingMessage : status == "locked" ? lockedMessage : disabledMessage}</p>
<Badge label='{status}' color='{status == "active" ? "success" : status == "pending" ? "warning" : "danger"}' variant="soft" size="sm" />
{#if status != "active"}<Button href='{supportHref}' label="Contact support" color='{color}' size='{size}' class="mt-4" />{/if}
</div>
</Card>
}
}
@@ -0,0 +1,43 @@
component AuthProviderButtons {
outputs {
select(payload: { provider: string; href: string })
}
props {
providers: unknown[] = []
title: string = "Continue with"
dividerLabel: string = "or"
color: string = "primary"
size: string = "md"
class: string = ""
}
functions {
client function choose(provider) {
output.select({ provider: provider.id || provider.name || provider.label, href: provider.href || "" })
}
}
view {
<div {...attrs} class='space-y-3 {class}'>
{#if title}<p class="m-0 text-sm font-semibold text-[var(--wire-color-text)]">{title}</p>{/if}
<div class="grid gap-2 sm:grid-cols-2">
{#each providers as provider}
<Button
label='{provider.label || provider.name || "Continue"}'
href='{provider.href || ""}'
icon='{provider.icon || "icon-[lucide--log-in]"}'
variant='{provider.variant || "outline"}'
color='{provider.color || color}'
size='{size}'
fullWidth="true"
@click='choose(provider)'
/>
{/each}
</div>
{#if dividerLabel}
<div class="flex items-center gap-3 text-xs text-[var(--wire-color-muted)]"><span class="h-px flex-1 bg-[var(--wire-color-border)]"></span><span>{dividerLabel}</span><span class="h-px flex-1 bg-[var(--wire-color-border)]"></span></div>
{/if}
</div>
}
}
@@ -0,0 +1,22 @@
component AuthSecurityNotice {
props {
title: string = "Security notice"
description: string = "Your session and credentials are protected by WRNexusJS security controls."
color: string = "info"
size: string = "sm"
class: string = ""
}
view {
<Alert
{...attrs}
title='{title}'
description='{description}'
icon="icon-[lucide--shield-check]"
color='{color}'
size='{size}'
variant="soft"
class='text-[var(--wire-color-text)] {class}'
/>
}
}
+37
View File
@@ -0,0 +1,37 @@
component AuthShell {
props {
title: string = "Welcome"
description: string = ""
eyebrow: string = ""
icon: string = "icon-[lucide--shield-check]"
footer: string = ""
color: string = "primary"
size: string = "md"
maxWidth: string = "md"
class: string = ""
}
view {
<Card
{...attrs}
title='{title}'
description='{description}'
header='{eyebrow}'
footer='{footer}'
color='{color}'
size='{size}'
class='w-full {class}'
class:max-w-sm='maxWidth === "sm"'
class:max-w-md='maxWidth === "md"'
class:max-w-lg='maxWidth === "lg"'
class:max-w-xl='maxWidth === "xl"'
class:max-w-2xl='maxWidth === "2xl"'
class:max-w-none='maxWidth === "full"'
>
<div class="mb-5 flex size-12 items-center justify-center rounded-full bg-[color-mix(in_srgb,var(--wire-color-primary)_12%,transparent)] text-[var(--wire-color-primary)]">
<span class='{icon}' aria-hidden="true"></span>
</div>
<slot></slot>
</Card>
}
}
+18 -19
View File
@@ -1,40 +1,39 @@
component DeviceSessions {
props {
sessions = []
currentSessionId = ""
title = "Active sessions"
description = "Review devices signed in to your account."
revokeAction = "/api/auth/sessions/revoke"
revokeSchema = "auth-session-revoke"
revokeLabel = "Sign out"
successMessage = "Session revoked."
color = "primary"
size = "md"
class = ""
sessions: unknown[] = []
currentSessionId: string = ""
title: string = "Active sessions"
description: string = "Review devices signed in to your account."
revokeAction: string = "/api/auth/sessions/revoke"
revokeSchema: string = "auth-session-revoke"
revokeLabel: string = "Sign out"
successMessage: string = "Session revoked."
color: string = "primary"
size: string = "md"
class: string = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-2xl rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] {class}'>
<h2 class="m-0 text-xl font-semibold">{title}</h2>
<p class="mt-1 text-sm text-[var(--wire-color-muted)]">{description}</p>
<div class="mt-5 divide-y divide-[var(--wire-color-border)]">
<Card {...attrs} title='{title}' description='{description}' color='{color}' size='{size}' class='w-full max-w-2xl {class}'>
<div class="divide-y divide-[var(--wire-color-border)]">
{#each sessions as session}
<article class="flex items-center gap-3 py-4">
<span class="flex size-10 items-center justify-center rounded-full bg-[var(--wire-color-surface-2)]"><span class="icon-[lucide--monitor-smartphone] size-5"></span></span>
<Avatar fallback='{session.userAgent || "Device"}' icon="icon-[lucide--monitor-smartphone]" size="sm" color='{color}' />
<div class="min-w-0 flex-1"><p class="m-0 truncate text-sm font-semibold">{session.userAgent || "Unknown device"}</p><p class="m-0 mt-1 text-xs text-[var(--wire-color-muted)]">{session.ip || "Unknown IP"} · Last active {session.lastSeenAt}</p></div>
{#if session.id == currentSessionId}
<span class="rounded-full bg-[color-mix(in_srgb,var(--wire-color-success)_12%,transparent)] px-2 py-1 text-xs font-semibold text-[var(--wire-color-success)]">Current</span>
<Badge label="Current" color="success" variant="soft" size="sm" />
{:else}
<form method="post" action='{revokeAction}' data-schema='{revokeSchema}' novalidate>
<input type="hidden" name="sessionId" value='{session.id}' />
<p data-error="sessionId" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 text-xs text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="text-sm font-semibold text-[var(--wire-color-danger)] disabled:opacity-60">{revokeLabel}</button>
<Button type="submit" label='{revokeLabel}' color="danger" variant="ghost" size="sm" />
</form>
{/if}
</article>
{/each}
</div>
</section>
</Card>
}
}
@@ -1,22 +1,25 @@
component ImpersonationBanner {
props {
visible = true
targetName = "this user"
stopAction = "/api/auth/impersonation/stop"
stopSchema = "auth-empty"
redirect = "/account"
message = "You are viewing the application as"
stopLabel = "Stop impersonating"
color = "warning"
size = "md"
class = ""
visible: boolean = true
targetName: string = "this user"
stopAction: string = "/api/auth/impersonation/stop"
stopSchema: string = "auth-empty"
redirect: string = "/account"
message: string = "You are viewing the application as"
stopLabel: string = "Stop impersonating"
color: string = "warning"
size: string = "md"
class: string = ""
}
view {
{#if visible}
<aside {...attrs} data-wrnexus-runtime="auth" role="status" class='flex w-full flex-wrap items-center justify-between gap-3 border-b border-[var(--wire-color-warning)] bg-[color-mix(in_srgb,var(--wire-color-warning)_14%,var(--wire-color-surface))] px-4 py-2 text-sm text-[var(--wire-color-text)] {class}'>
<span class="flex items-center gap-2"><span class="icon-[lucide--scan-face] size-4 text-[var(--wire-color-warning)]"></span><span>{message} <strong>{targetName}</strong>.</span></span>
<form method="post" action='{stopAction}' data-schema='{stopSchema}' data-redirect='{redirect}' novalidate><p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p><button type="submit" class="inline-flex h-8 items-center rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-warning)] px-3 text-xs font-semibold text-black disabled:opacity-60">{stopLabel}</button></form>
</aside>
<Alert {...attrs} title='{message + " " + targetName}' icon="icon-[lucide--scan-face]" color='{color}' size='{size}' variant="soft" class='{class}'>
<form method="post" action='{stopAction}' data-schema='{stopSchema}' data-redirect='{redirect}' novalidate class="mt-2">
<p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p>
<Button type="submit" label='{stopLabel}' color='{color}' size="sm" />
</form>
</Alert>
{/if}
}
}
+35 -26
View File
@@ -1,33 +1,42 @@
component PasskeyButton {
props {
mode = "authenticate"
label = "Continue with a passkey"
registerLabel = "Add a passkey"
identifier = ""
rpId = ""
rpName = "WRNexusJS"
passkeyName = "Passkey"
optionsEndpoint = ""
verifyEndpoint = ""
redirect = ""
mfaHref = "/two-factor"
conditional = false
fullWidth = false
loadingMessage = "Waiting for your passkey…"
successMessage = "Passkey verified."
color = "primary"
size = "md"
class = ""
@event passkeyRegistered = function
@event passkeyAuthenticated = function
@event error = function
outputs {
passkeyRegistered(payload: { credentialId: string; response?: object })
passkeyAuthenticated(payload: { userId?: string; sessionId?: string; response?: object })
error(payload: { code: string; message: string })
}
props {
mode: string = "authenticate"
label: string = "Continue with a passkey"
registerLabel: string = "Add a passkey"
identifier: string = ""
rpId: string = ""
rpName: string = "WRNexusJS"
passkeyName: string = "Passkey"
optionsEndpoint: string = ""
verifyEndpoint: string = ""
redirect: string = ""
mfaHref: string = "/two-factor"
conditional: boolean = false
fullWidth: boolean = false
loadingMessage: string = "Waiting for your passkey…"
successMessage: string = "Passkey verified."
color: string = "primary"
size: string = "md"
class: string = ""
}
view {
<div {...attrs} data-wrnexus-runtime="auth" data-auth-passkey='{mode}' data-identifier='{identifier}' data-rp-id='{rpId}' data-rp-name='{rpName}' data-passkey-name='{passkeyName}' data-options-endpoint='{optionsEndpoint}' data-verify-endpoint='{verifyEndpoint}' data-redirect='{redirect}' data-mfa-href='{mfaHref}' data-conditional='{conditional}' data-loading-message='{loadingMessage}' data-success-message='{successMessage}' data-auth-state="idle" aria-busy="false" class='space-y-2 {class}'>
<button type="button" class='inline-flex h-11 items-center justify-center gap-2 rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] px-4 text-sm font-semibold text-[var(--wire-color-text)] hover:bg-[var(--wire-color-surface-2)] disabled:cursor-wait disabled:opacity-60 {fullWidth ? "w-full" : ""}'>
<span aria-hidden="true" class="icon-[lucide--key-round] size-4"></span>
{mode == "register" ? registerLabel : label}
</button>
<Button
type="button"
label='{mode == "register" ? registerLabel : label}'
icon="icon-[lucide--key-round]"
variant="outline"
color='{color}'
size='{size}'
fullWidth='{fullWidth}'
/>
<p data-auth-status hidden role="status" class="m-0 text-xs text-[var(--wire-color-muted)]"></p>
</div>
}
+22 -73
View File
@@ -1,86 +1,35 @@
component RecoveryCodes {
props {
codes = []
schema = "auth-recovery-codes"
title = "Recovery codes"
description = "Store these codes somewhere safe. Each code can be used once."
downloadLabel = "Download codes"
regenerateLabel = "Generate new codes"
regenerateAction = "/api/auth/recovery-codes"
successMessage = "New recovery codes generated. Previous unused codes are no longer valid."
count = 10
color = "primary"
size = "md"
class = ""
codes: unknown[] = []
schema: string = "auth-recovery-codes"
title: string = "Recovery codes"
description: string = "Store these codes somewhere safe. Each code can be used once."
downloadLabel: string = "Download codes"
regenerateLabel: string = "Generate new codes"
regenerateAction: string = "/api/auth/recovery-codes"
successMessage: string = "New recovery codes generated. Previous unused codes are no longer valid."
count: number = 10
color: string = "primary"
size: string = "md"
class: string = ""
}
view {
<section
{...attrs}
data-wrnexus-runtime="auth"
data-auth-recovery-codes
data-recovery-filename="wrnexus-recovery-codes.txt"
class='w-full max-w-xl rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 {class}'
>
<div class="flex items-start justify-between gap-4">
<div>
<h2 class="m-0 text-xl font-semibold">{title}</h2>
<p class="mt-1 text-sm text-[var(--wire-color-muted)]">{description}</p>
</div>
<span class="icon-[lucide--shield-keyhole] size-6 text-[var(--wire-color-primary)]"></span>
<Card {...attrs} title='{title}' description='{description}' color='{color}' size='{size}' class='w-full max-w-xl {class}' data-wrnexus-runtime="auth" data-auth-recovery-codes data-recovery-filename="wrnexus-recovery-codes.txt">
<Alert title="Keep these codes private" description="Anyone with a recovery code may be able to access your account." icon="icon-[lucide--shield-alert]" color="warning" variant="soft" size="sm" />
<div data-recovery-code-list class="mt-4 grid grid-cols-2 gap-2 rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-surface-2)] p-4 font-mono text-sm sm:grid-cols-3">
{#each codes as code}<code data-recovery-code class="rounded bg-[var(--wire-color-surface)] px-2 py-1.5 text-center">{code}</code>{/each}
</div>
<div
data-recovery-code-list
class="mt-5 grid grid-cols-2 gap-2 rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-surface-2)] p-4 font-mono text-sm sm:grid-cols-3"
>
{#each codes as code}
<code
data-recovery-code
class="rounded bg-[var(--wire-color-surface)] px-2 py-1.5 text-center"
>{code}</code>
{/each}
</div>
<div class="mt-4 flex flex-wrap gap-2">
<button
type="button"
data-recovery-download
class="h-10 rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] px-4 text-sm font-semibold"
>
{downloadLabel}
</button>
<form
method="post"
action='{regenerateAction}'
data-schema='{schema}'
novalidate
class="flex-1"
>
<Button type="button" label='{downloadLabel}' icon="icon-[lucide--download]" variant="outline" color='{color}' size='{size}' data-recovery-download />
<form method="post" action='{regenerateAction}' data-schema='{schema}' novalidate class="min-w-48 flex-1">
<input type="hidden" name="count" value='{count}' />
<p data-error="count" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p
data-error="_form"
role="alert"
class="m-0 hidden text-xs text-[var(--wire-color-danger)]"
></p>
<p
data-success='{successMessage}'
role="status"
hidden
class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-xs text-[var(--wire-color-success)]"
>
{successMessage}
</p>
<button
type="submit"
class="h-10 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] px-4 text-sm font-semibold disabled:cursor-wait disabled:opacity-60"
>
{regenerateLabel}
</button>
<p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 text-xs text-[var(--wire-color-success)]">{successMessage}</p>
<Button type="submit" label='{regenerateLabel}' icon="icon-[lucide--refresh-cw]" variant="outline" color='{color}' size='{size}' fullWidth="true" />
</form>
</div>
</section>
</Card>
}
}