1 Commits

Author SHA1 Message Date
jules
9147a06c00 chore: fix start/stop.sh to use this app's name, not the template's (frontend audit rank 15)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 21:23:11 +10:00
4 changed files with 5 additions and 43 deletions

View File

@@ -44,10 +44,6 @@ function readFromStorage(): Session | null {
typeof parsed.token !== "string" typeof parsed.token !== "string"
) )
return null return null
// An expired JWT is not a session: without this the shell renders as
// "logged in" and every API call 401s silently. Treat it as null so the
// app bounces to /login. (Frontend audit 2026-06-20.)
if (isTokenExpired(parsed.token)) return null
return { return {
userId: parsed.userId, userId: parsed.userId,
name: name:
@@ -80,35 +76,6 @@ export function loadSession(): Session | null {
return readFromStorage() return readFromStorage()
} }
// A token counts as expired only if it's a JWT carrying an `exp` in the past
// (minus a small clock-skew grace). Non-JWT dev/mock tokens (no decodable
// `exp`) are treated as non-expiring so offline/test flows keep working.
const TOKEN_EXPIRY_SKEW_S = 30
export function isTokenExpired(token: string | undefined | null): boolean {
if (!token) return true
const claims = decodeJwtPayload(token)
const exp =
claims && typeof claims.exp === "number" ? (claims.exp as number) : null
if (exp === null) return false
return Date.now() / 1000 >= exp - TOKEN_EXPIRY_SKEW_S
}
function decodeJwtPayload(token: string): Record<string, unknown> | null {
const parts = token.split(".")
if (parts.length !== 3) return null
try {
const b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/")
const pad = b64.length % 4 === 0 ? "" : "=".repeat(4 - (b64.length % 4))
const json =
typeof atob === "function"
? atob(b64 + pad)
: Buffer.from(b64 + pad, "base64").toString("utf-8")
return JSON.parse(json) as Record<string, unknown>
} catch {
return null
}
}
export function signOut() { export function signOut() {
if (typeof window === "undefined") return if (typeof window === "undefined") return
localStorage.removeItem(STORAGE_KEY) localStorage.removeItem(STORAGE_KEY)

View File

@@ -15,7 +15,6 @@ import { CommandBusProvider } from "@crema/action-bus"
import { ArcadiaProvider } from "@crema/arcadia-client" import { ArcadiaProvider } from "@crema/arcadia-client"
import { LlmConfigBootstrap } from "~/lib/llm-config-bootstrap" import { LlmConfigBootstrap } from "~/lib/llm-config-bootstrap"
import { ProfileBootstrap } from "~/lib/profile-bootstrap" import { ProfileBootstrap } from "~/lib/profile-bootstrap"
import { signOut } from "~/lib/session"
// CREMA:PROVIDERS-IMPORTS // CREMA:PROVIDERS-IMPORTS
const ARCADIA_URL = import.meta.env.VITE_ARCADIA_URL ?? "http://localhost:4000" const ARCADIA_URL = import.meta.env.VITE_ARCADIA_URL ?? "http://localhost:4000"
@@ -60,10 +59,6 @@ export default function App() {
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
sessionStorage.removeItem("arcadia_access_token") sessionStorage.removeItem("arcadia_access_token")
sessionStorage.removeItem("arcadia_refresh_token") sessionStorage.removeItem("arcadia_refresh_token")
// Also clear the localStorage Session (crema.session); otherwise
// useSession() still reports "logged in" after a 401 and the shell
// keeps mounting with a dead token. (Frontend audit 2026-06-20.)
signOut()
} }
}} }}
> >

View File

@@ -9,7 +9,7 @@ LOG_FILE=".demo.log"
if [ -f "$PID_FILE" ]; then if [ -f "$PID_FILE" ]; then
existing="$(cat "$PID_FILE")" existing="$(cat "$PID_FILE")"
if [ -n "$existing" ] && kill -0 "$existing" 2>/dev/null; then if [ -n "$existing" ] && kill -0 "$existing" 2>/dev/null; then
echo "crema-app-aifirst-template already running (pid $existing)" echo "arcadia-admin already running (pid $existing)"
exit 0 exit 0
fi fi
rm -f "$PID_FILE" rm -f "$PID_FILE"
@@ -20,4 +20,4 @@ pid=$!
echo "$pid" >"$PID_FILE" echo "$pid" >"$PID_FILE"
disown "$pid" 2>/dev/null || true disown "$pid" 2>/dev/null || true
echo "crema-app-aifirst-template started (pid $pid) — logs: $LOG_FILE" echo "arcadia-admin started (pid $pid) — logs: $LOG_FILE"

View File

@@ -6,7 +6,7 @@ cd "$(dirname "$0")"
PID_FILE=".demo.pid" PID_FILE=".demo.pid"
if [ ! -f "$PID_FILE" ]; then if [ ! -f "$PID_FILE" ]; then
echo "crema-app-aifirst-template not running (no .demo.pid)" echo "arcadia-admin not running (no .demo.pid)"
exit 0 exit 0
fi fi
@@ -15,9 +15,9 @@ pid="$(cat "$PID_FILE")"
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
pkill -P "$pid" 2>/dev/null || true pkill -P "$pid" 2>/dev/null || true
kill "$pid" 2>/dev/null || true kill "$pid" 2>/dev/null || true
echo "crema-app-aifirst-template stopped (pid $pid)" echo "arcadia-admin stopped (pid $pid)"
else else
echo "crema-app-aifirst-template pid $pid not alive, cleaning up" echo "arcadia-admin pid $pid not alive, cleaning up"
fi fi
rm -f "$PID_FILE" rm -f "$PID_FILE"