Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9eb712d
feat(api): restore commands/languages proxies to api.wolfstar.rocks
cursoragent Jul 17, 2026
1716048
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 17, 2026
e210b2c
feat(api): proxy full guild API surface to api.wolfstar.rocks
cursoragent Jul 17, 2026
48e7dbc
refactor(api): use $api for bot API instead of per-route proxies
cursoragent Jul 18, 2026
d49bcac
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 18, 2026
d7e5254
fix(api): correct bot BFF rateLimit window option
cursoragent Jul 18, 2026
9145a7e
refactor(api): call bot API directly via $api like legacy
cursoragent Jul 18, 2026
8c1f73b
refactor(api): move bot-api helpers and types into shared
cursoragent Jul 18, 2026
f370a57
refactor(api): rename bot-api modules to botApi
cursoragent Jul 18, 2026
04d7033
refactor(api): use NUXT_OAUTH_DISCORD_CLIENT_SECRET for botApi auth
cursoragent Jul 18, 2026
2818ed0
perf(nuxt): cache rendered payloads for ISR routes
cursoragent Jul 18, 2026
38e17e1
refactor(api): use FlattenedCommand instead of BotApiCommand
cursoragent Jul 18, 2026
76bd0eb
fix(api): scope fetch-cache keys and fix commands accordion HTML
cursoragent Jul 18, 2026
8555c77
fix(api): avoid reading private discord config on the client
cursoragent Jul 18, 2026
a84309f
Merge remote-tracking branch 'origin/main' into cursor/backport-struc…
cursoragent Jul 18, 2026
7bfbb0d
fix(api): keep botApi crypto helpers server-only
cursoragent Jul 18, 2026
bcb6411
refactor(db): remove Prisma; rely on bot API for guild data
cursoragent Jul 22, 2026
3ccab73
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 22, 2026
dc72482
Merge remote-tracking branch 'origin/main' into cursor/backport-struc…
cursoragent Jul 22, 2026
bce1a21
Merge branch 'cursor/backport-structure-api-88be' of https://github.c…
cursoragent Jul 22, 2026
92044cc
chore(deps): drop stale Prisma allowBuilds placeholders
cursoragent Jul 22, 2026
be17245
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 22, 2026
27c1f4e
chore: remove dead code left after Prisma removal
cursoragent Jul 22, 2026
a5ea7d9
Merge branch 'cursor/backport-structure-api-88be' of https://github.c…
cursoragent Jul 22, 2026
73a623a
chore(deps): pin Prisma allowBuilds to false
cursoragent Jul 22, 2026
578622f
feat(profile): load user/guilds from bot GET /users/@me
cursoragent Jul 22, 2026
5a49332
test(mocks): point bot API mockups at localhost:8282
cursoragent Jul 22, 2026
62df0f6
fix(api): restore /api/bot BFF for client sapphire auth
cursoragent Jul 22, 2026
ff608d1
refactor(api): proxy bot via /api catch-all; keep only auth routes
cursoragent Jul 22, 2026
241b0f3
chore: drop unrelated .cursor skill files from api refactor commit
cursoragent Jul 22, 2026
73757e4
fix(auth): establish SAPPHIRE_AUTH via bot /oauth/callback
cursoragent Jul 22, 2026
4129642
test(auth): parse bot Discord authorize URL with URLSearchParams
cursoragent Jul 22, 2026
9bf7c9d
refactor(auth): replace useBotOauth composable with utils
cursoragent Jul 22, 2026
eec3285
chore: drop unrelated .cursor skill symlinks from auth utils commit
cursoragent Jul 22, 2026
2692ca1
refactor(auth): remove unused import from refresh session handler
RedStar071 Jul 22, 2026
17e6d59
fix(auth): force Discord consent prompt on Better Auth login
RedStar071 Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 102 additions & 93 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
# ===================================
# Authentication (Required)
# ===================================
# Required for the admin dashboard for server
# Create a Discord OAuth app at: https://discord.dev/
# Callback URL: http://localhost:3000/api/auth/callback/discord (adjust for your domain)
# discord OAuth Application Client ID
NUXT_OAUTH_DISCORD_CLIENT_ID=
# discord OAuth Application Client Secret
NUXT_OAUTH_DISCORD_CLIENT_SECRET=
# Discord OAuth Application Redirect URL
NUXT_OAUTH_DISCORD_REDIRECT_URL=
# Discord Token useful for fetching data; Guild, User, Roles, etc.
NUXT_OAUTH_DISCORD_BOT_TOKEN=
# Better Auth session/cookie encryption secret — 32+ characters (generate a
# secure random string). You can use: openssl rand -base64 32
NUXT_BETTER_AUTH_SECRET=
# Session cookie name — MUST differ per deployment to prevent cookie bleed across subdomains
# Production (wolfstar.rocks): leave blank (defaults to wolfstar-session)
# Beta/staging (beta.wolfstar.rocks): wolfstar-session-beta

# ===================================
# Authentication (Required)
# ===================================
# Required for the admin dashboard for server
# Create a Discord OAuth app at: https://discord.dev/
# Callback URL: http://localhost:3000/api/auth/callback/discord (adjust for your domain)

# discord OAuth Application Client ID
NUXT_OAUTH_DISCORD_CLIENT_ID=

# discord OAuth Application Client Secret
NUXT_OAUTH_DISCORD_CLIENT_SECRET=

# Discord OAuth Application Redirect URL
NUXT_OAUTH_DISCORD_REDIRECT_URL=

# Discord Token useful for fetching data; Guild, User, Roles, etc.
NUXT_OAUTH_DISCORD_BOT_TOKEN=

# Better Auth session/cookie encryption secret — 32+ characters (generate a
# secure random string). You can use: openssl rand -base64 32
NUXT_BETTER_AUTH_SECRET=

# Session cookie name — MUST differ per deployment to prevent cookie bleed across subdomains
# Production (wolfstar.rocks): leave blank (defaults to wolfstar-session)
# Beta/staging (beta.wolfstar.rocks): wolfstar-session-beta
NUXT_SESSION_COOKIE_NAME=

# Nuxt Studio GitHub OAuth credentials (local development only)
Expand All @@ -34,69 +34,78 @@ NUXT_STUDIO_AUTH_GITHUB_CLIENT_ID=
NUXT_STUDIO_AUTH_GITHUB_CLIENT_SECRET=

# Secret for generating OG images (generate a secure random string)
# You can use: openssl rand -base64 32
NUXT_IMAGE_PROXY_SECRET=
# ===================================
# Storage Configuration (Required)
# ===================================

# Production only
NUXT_CLOUDFLARE_ACCOUNT_ID=
NUXT_CLOUDFLARE_NAMESPACE_ID=
NUXT_CLOUDFLARE_API_TOKEN=

# ===================================
# Website Environment (Required)
# API base url:
NUXT_PUBLIC_API_BASE_URL=http://localhost:8282

# Site URL (e.g., https://wolfstar.rocks)
NUXT_PUBLIC_SITE_URL=
# ===================================

# Enable PWA in development mode (true or false)
VITE_DEV_PWA=false

# ===================================
# Sentry (Optional)
# ===================================

# Sentry config for Auth Token
SENTRY_AUTH_TOKEN=

# Sentry config for Project Name
SENTRY_PROJECT=

# Sentry config for organization
SENTRY_ORG=

# Sentry DSN for error tracking:
SENTRY_DSN=

# Sentry trace sampling rate: a number from 0 to 1 (0 = no traces, 1 = all).
# Defaults to 0.2 when unset; invalid values fall back to the default.
NUXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE=

# ===================================
# Port and Hostname (Optional)
# ===================================

# uncomment this if you want change port or hostname
# PORT=8281
# HOSTNAME="localhost"

# ===================================
# Database (Required)
# ===================================
# This was inserted by `prisma init`:
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/wolfstar?schema=public"

# ===================================
# Audit log (dev only)
# ===================================
# No configuration required. When NODE_ENV=development, audit events are written
# to .audit/ via evlog/signed + FS drain (hash-chain, local inspection only).
# Run `pnpm audit:verify` to validate chain integrity offline.
# In production, audit events go to the AuditEvent Postgres table instead.
# You can use: openssl rand -base64 32
NUXT_IMAGE_PROXY_SECRET=
# ===================================
# Storage Configuration (Required)
# ===================================

# Production only
NUXT_CLOUDFLARE_ACCOUNT_ID=
NUXT_CLOUDFLARE_NAMESPACE_ID=
NUXT_CLOUDFLARE_API_TOKEN=

# ===================================
# Website Environment (Required)
# WolfStar bot API origin used by `$api` (legacy-style direct calls with
# credentials:include). After Discord login the browser POSTs the OAuth code to
# `${NUXT_PUBLIC_API_BASE_URL}/oauth/callback` to set SAPPHIRE_AUTH on this origin.
# Production/internal: https://api.wolfstar.rocks (default when unset)
# Local bot instance: http://localhost:8282
# Sapphire local tip: prefer http://127.0.0.1:8282 + bot domainOverwrite if cookies fail.
NUXT_PUBLIC_API_BASE_URL=http://localhost:8282

# Optional: sapphire-plugin-api cookie name for SSR auth cookie injection.
# Defaults to SAPPHIRE_AUTH. Encryption uses NUXT_OAUTH_DISCORD_CLIENT_SECRET.
# NUXT_BOT_API_AUTH_COOKIE=SAPPHIRE_AUTH

# Site URL (e.g., https://wolfstar.rocks)
NUXT_PUBLIC_SITE_URL=
# ===================================

# Enable PWA in development mode (true or false)
VITE_DEV_PWA=false

# ===================================
# Sentry (Optional)
# ===================================

# Sentry config for Auth Token
SENTRY_AUTH_TOKEN=

# Sentry config for Project Name
SENTRY_PROJECT=

# Sentry config for organization
SENTRY_ORG=

# Sentry DSN for error tracking:
SENTRY_DSN=

# Sentry trace sampling rate: a number from 0 to 1 (0 = no traces, 1 = all).
# Defaults to 0.2 when unset; invalid values fall back to the default.
NUXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE=

# ===================================
# Port and Hostname (Optional)
# ===================================

# uncomment this if you want change port or hostname
# PORT=8281
# HOSTNAME="localhost"

# ===================================
# Database (Required)
# ===================================
# This was inserted by `prisma init`:
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/wolfstar?schema=public"

# ===================================
# Audit log (dev only)
# ===================================
# No configuration required. When NODE_ENV=development, audit events are written
# to .audit/ via evlog/signed + FS drain (hash-chain, local inspection only).
# Run `pnpm audit:verify` to validate chain integrity offline.
# In production, audit events go to the AuditEvent Postgres table instead.
15 changes: 3 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ jobs:
cache: true
sfw: true

- name: 🔼 Generate Prisma Client
run: vp run prisma:generate

- name: 🔎 Typecheck project
run: vp run typecheck

Expand Down Expand Up @@ -162,15 +159,13 @@ jobs:
cache: true
sfw: true

- name: 🔼 Generate Prisma Client
run: vp run prisma:generate

- name: 🏗️ Build project
run: vp run build:test
env:
VALIDATE_HTML: true
NODE_OPTIONS: --max-old-space-size=4096
NUXT_PUBLIC_SITE_URL: https://wolfstar.rocks
NUXT_PUBLIC_API_BASE_URL: http://localhost:8282

- name: 🖥️ Test project (browser)
run: vp run test:browser:prebuilt
Expand Down Expand Up @@ -225,13 +220,11 @@ jobs:
cache: true
sfw: true

- name: 🔼 Generate Prisma Client
run: vp run prisma:generate

- name: 🏗️ Build project
run: vp run build:test
env:
NUXT_PUBLIC_SITE_URL: https://wolfstar.rocks
NUXT_PUBLIC_API_BASE_URL: http://localhost:8282

- name: ♿ Accessibility audit (Lighthouse - ${{ matrix.mode }} mode)
run: vp run test:a11y:prebuilt
Expand All @@ -254,13 +247,11 @@ jobs:
cache: true
sfw: true

- name: 🔼 Generate Prisma Client
run: vp run prisma:generate

- name: 🏗️ Build project
run: vp run build:test
env:
NUXT_PUBLIC_SITE_URL: https://wolfstar.rocks
NUXT_PUBLIC_API_BASE_URL: http://localhost:8282

- name: ⚡ Performance audit (Lighthouse)
run: vp run test:perf:prebuilt
Expand Down
1 change: 1 addition & 0 deletions app/components/UserMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const items = computed<DropdownMenuItem[][]>(() => [
label: "Sign out",
async onSelect(e: Event) {
e.preventDefault();
await logoutBotOauth();
await signOut();
await navigateTo("/");
},
Expand Down
1 change: 1 addition & 0 deletions app/components/app/HeaderAuth.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const items = ref<DropdownMenuItem[]>([
]);

async function logout() {
await logoutBotOauth();
await signOut({
onSuccess: () => {
void navigateTo("/");
Expand Down
43 changes: 6 additions & 37 deletions app/components/command/SubCategory.vue
Original file line number Diff line number Diff line change
@@ -1,51 +1,20 @@
<template>
<div
v-if="filteredCommands.length > 0"
role="region"
:aria-labelledby="`category-${categoryName.replace(/\s+/g, '-').toLowerCase()}`"
>
<div v-if="filteredCommands.length > 0" class="animate-fade-in">
<UAccordion
:items="categoryItems"
:ui="{
root: 'space-y-3',
item: '',
trigger:
'w-full justify-between rounded-2xl border border-base-content/10 bg-base-200/50 px-6 py-4 transition-all hover:bg-base-200/80 data-[state=open]:rounded-b-none',
content:
'rounded-2xl rounded-t-none overflow-hidden transition-all border border-t-0 border-base-content/10 bg-base-200/30',
label: 'truncate text-xl font-bold',
trailingIcon: 'size-5 shrink-0',
}"
class="animate-fade-in"
>
<template #default="{ item, open }">
<UButton
color="neutral"
variant="ghost"
class="w-full justify-between rounded-2xl border border-base-content/10 bg-base-200/50 px-6 py-4 transition-all hover:bg-base-200/80"
:class="{ 'rounded-b-none': open }"
:aria-expanded="open"
:aria-controls="`category-content-${item.value.replace(/\s+/g, '-').toLowerCase()}`"
>
<span
:id="`category-${item.value.replace(/\s+/g, '-').toLowerCase()}`"
class="truncate text-xl font-bold"
>
{{ item.label }}
</span>

<template #trailing>
<UIcon
name="i-heroicons-chevron-down-20-solid"
class="size-5 shrink-0 transform transition-transform duration-200"
:class="[open && 'rotate-180']"
aria-hidden="true"
/>
</template>
</UButton>
</template>

<template #body="{ item }">
<div
:id="`category-content-${item.value.replace(/\s+/g, '-').toLowerCase()}`"
class="space-y-3 p-4"
>
<div class="space-y-3 p-4">
<UAccordion
:items="
getCommandsByCategory(item.label).map((command) => ({
Expand Down
2 changes: 1 addition & 1 deletion app/components/guild/logs/CommandLogTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
</template>

<script setup lang="ts">
import type { CommandLogData } from "#server/database";
import type { CommandLogData } from "#shared/types";
import type { TableColumn } from "@nuxt/ui";
import type { APIGuildMember } from "discord-api-types/v10";
import { getPaginationRowModel } from "@tanstack/table-core";
Expand Down
2 changes: 1 addition & 1 deletion app/components/guild/settings/Channels.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
</template>

<script setup lang="ts">
import type { GuildData } from "#server/database";
import type { GuildData } from "#shared/types";
import type { FormErrorEvent } from "@nuxt/ui";
import { ChannelsSettingsSchema, type ChannelsSettingsSchemaType } from "#shared/schemas";
import { setGuildDataChange } from "#shared/utils/guild-settings-map";
Expand Down
2 changes: 1 addition & 1 deletion app/components/guild/settings/DisabledCommands.vue
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
</template>

<script setup lang="ts">
import type { GuildData } from "#server/database";
import type { GuildData } from "#shared/types";
import type { DisableCommands } from "#shared/types";
import type { FormErrorEvent } from "@nuxt/ui";
import type * as v from "valibot";
Expand Down
2 changes: 1 addition & 1 deletion app/components/guild/settings/Events.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
</template>

<script setup lang="ts">
import type { GuildData } from "#server/database";
import type { GuildData } from "#shared/types";
import type { FormErrorEvent } from "@nuxt/ui";
import { EventsSettingsSchema, type EventsSettingsSchemaType } from "#shared/schemas";
import { setGuildDataChange } from "#shared/utils/guild-settings-map";
Expand Down
2 changes: 1 addition & 1 deletion app/components/guild/settings/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</template>

<script setup lang="ts" generic="T extends Record<string, unknown>">
import type { GuildData } from "#server/database";
import type { GuildData } from "#shared/types";
import type { FormError, FormErrorEvent, FormSubmitEvent } from "@nuxt/ui";
import type { GenericSchema } from "valibot";
import { setGuildDataChange } from "#shared/utils/guild-settings-map";
Expand Down
2 changes: 1 addition & 1 deletion app/components/guild/settings/General.vue
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
</template>

<script lang="ts" setup>
import type { GuildData } from "#server/database";
import type { GuildData } from "#shared/types";
import type { FormErrorEvent } from "@nuxt/ui";
import type { TableColumn } from "@nuxt/ui";
import {
Expand Down
2 changes: 1 addition & 1 deletion app/components/guild/settings/Moderation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</template>

<script setup lang="ts">
import type { GuildData } from "#server/database";
import type { GuildData } from "#shared/types";
import type { FormErrorEvent } from "@nuxt/ui";
import { ModerationSettingsSchema, type ModerationSettingsSchemaType } from "#shared/schemas";
import { setGuildDataChange } from "#shared/utils/guild-settings-map";
Expand Down
Loading