feat(frontends,security,api,ui): a frontend can hold a token scope of its own

This commit is contained in:
hh committed 2026-09-06 23:26:26 +02:00
1 parent 60782d6276
commit e79e9fc149
11 files changed
+245 -21

No files matched your search

+34 -9
View File
@@ -2,7 +2,7 @@
import CopyIcon from "@lucide/svelte/icons/copy";
import PlusIcon from "@lucide/svelte/icons/plus";
import { toast } from "svelte-sonner";
import type { TokenRow } from "$lib/api/types";
import type { ScopeRow, TokenRow } from "$lib/api/types";
import EmptyState from "$lib/components/empty-state.svelte";
import ErrorNote from "$lib/components/error-note.svelte";
import { Button } from "$lib/components/ui/button";
@@ -15,13 +15,23 @@
import { session } from "$lib/session.svelte";
import { cn } from "$lib/utils";
const SCOPES = [
{ hint: "every frontend", value: "*" },
{ hint: "conversations API and SSE (panel, plugin)", value: "api" },
{ hint: "Anthropic /v1/messages", value: "messages" },
{ hint: "MCP server", value: "mcp" },
{ hint: "tokens and audit over the API", value: "admin" },
];
const HINTS: Record<string, string> = {
"*": "every frontend",
admin: "tokens and audit over the API",
api: "conversations API and SSE (panel, plugin)",
mcp: "MCP server",
messages: "Anthropic /v1/messages",
};
let scopes = $state<ScopeRow[]>([]);
const options = $derived(
scopes.map((row) => ({
hint: row.frontend
? `the ${row.frontend} frontend`
: (HINTS[row.scope] ?? ""),
value: row.scope,
}))
);
let tokens = $state<TokenRow[] | null>(null);
let includeRevoked = $state(false);
@@ -49,6 +59,21 @@
load(includeRevoked);
});
$effect(() => {
const { client } = session;
if (!client) {
return;
}
client
.scopes()
.then(({ scopes: rows }) => {
scopes = rows;
})
.catch(() => {
scopes = [];
});
});
async function create() {
const { client } = session;
if (!client) {
@@ -254,7 +279,7 @@
>
<Select.Trigger class="w-full">{scope}</Select.Trigger>
<Select.Content>
{#each SCOPES as option (option.value)}
{#each options as option (option.value)}
<Select.Item label={option.value} value={option.value}>
<span class="flex flex-col">
<span>{option.value}</span>