Skip to content

Commit 7308af3

Browse files
antfuclaude
andcommitted
feat(self-inspect): add auth tokens management tab
Add an "Auth Tokens" tab to the self-inspect debug panel that lists all trusted clients with their auth ID, user agent, origin, and trust date. Each token can be revoked individually. - Add get-auth-tokens and revoke-auth-token RPC functions - Export getInternalContext from @vitejs/devtools for cross-package access - Add AuthTokensList component and auth page to self-inspect UI Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cdb5d08 commit 7308af3

10 files changed

Lines changed: 600 additions & 5 deletions

File tree

packages/core/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export { createDevToolsContext } from './node/context'
2+
export { getInternalContext } from './node/context-internal'
3+
export type { DevToolsInternalContext, InternalAnonymousAuthStorage } from './node/context-internal'
24
export { DevTools } from './node/plugins'
35
export { createDevToolsMiddleware } from './node/server'

packages/self-inspect/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"prepack": "pnpm build"
3333
},
3434
"dependencies": {
35+
"@vitejs/devtools": "workspace:*",
3536
"@vitejs/devtools-kit": "workspace:*",
3637
"@vitejs/devtools-rpc": "workspace:*",
3738
"birpc": "catalog:deps",

packages/self-inspect/src/app/app.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const navItems = [
1616
{ title: 'Docks', to: '/docks', icon: 'i-ph-layout-duotone' },
1717
{ title: 'Client Scripts', to: '/scripts', icon: 'i-ph-code-duotone' },
1818
{ title: 'Plugins', to: '/plugins', icon: 'i-ph-puzzle-piece-duotone' },
19+
{ title: 'Auth Tokens', to: '/auth', icon: 'i-ph-key-duotone' },
1920
]
2021
2122
const { refresh, loading } = useRefresh()
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<script setup lang="ts">
2+
interface AuthToken {
3+
authId: string
4+
ua: string
5+
origin: string
6+
timestamp: number
7+
}
8+
9+
defineProps<{
10+
tokens: AuthToken[]
11+
}>()
12+
13+
const emit = defineEmits<{
14+
revoke: [authId: string]
15+
}>()
16+
17+
function formatDate(timestamp: number): string {
18+
return new Date(timestamp).toLocaleString()
19+
}
20+
</script>
21+
22+
<template>
23+
<div flex="~ col gap-3" p4>
24+
<div flex="~ items-center gap-3" text-xs>
25+
<span op60>
26+
{{ tokens.length }} trusted client{{ tokens.length !== 1 ? 's' : '' }}
27+
</span>
28+
</div>
29+
30+
<div v-if="tokens.length === 0" op40 text-sm py4 text-center>
31+
No auth tokens found.
32+
</div>
33+
34+
<table v-else w-full text-sm>
35+
<thead>
36+
<tr border="b base" text-left>
37+
<th px2 py1 font-medium op60 text-xs>
38+
Auth ID
39+
</th>
40+
<th px2 py1 font-medium op60 text-xs>
41+
User Agent
42+
</th>
43+
<th px2 py1 font-medium op60 text-xs>
44+
Origin
45+
</th>
46+
<th px2 py1 font-medium op60 text-xs>
47+
Trusted At
48+
</th>
49+
<th px2 py1 font-medium op60 text-xs text-center>
50+
Actions
51+
</th>
52+
</tr>
53+
</thead>
54+
<tbody>
55+
<tr
56+
v-for="token in tokens" :key="token.authId"
57+
border="b base" hover:bg-active
58+
>
59+
<td px2 py1.5 font-mono text-xs>
60+
{{ token.authId }}
61+
</td>
62+
<td px2 py1.5 text-xs op75 max-w-60 truncate>
63+
{{ token.ua || '-' }}
64+
</td>
65+
<td px2 py1.5 text-xs op75>
66+
{{ token.origin || '-' }}
67+
</td>
68+
<td px2 py1.5 text-xs op75>
69+
{{ formatDate(token.timestamp) }}
70+
</td>
71+
<td px2 py1.5 text-center>
72+
<button
73+
text-xs px2 py0.5 rounded
74+
text-red border="~ red/30"
75+
hover:bg-red:10
76+
@click="emit('revoke', token.authId)"
77+
>
78+
Revoke
79+
</button>
80+
</td>
81+
</tr>
82+
</tbody>
83+
</table>
84+
</div>
85+
</template>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<script setup lang="ts">
2+
import { useRpc } from '#imports'
3+
import { onMounted, shallowRef } from 'vue'
4+
import { useRefreshProvider } from '../composables/refresh'
5+
6+
interface AuthToken {
7+
authId: string
8+
ua: string
9+
origin: string
10+
timestamp: number
11+
}
12+
13+
const rpc = useRpc()
14+
const data = shallowRef<AuthToken[]>()
15+
16+
async function fetchData() {
17+
data.value = await rpc.value.call('devtoolskit:self-inspect:get-auth-tokens')
18+
}
19+
20+
async function revoke(authId: string) {
21+
await rpc.value.call('devtoolskit:self-inspect:revoke-auth-token', authId)
22+
await fetchData()
23+
}
24+
25+
useRefreshProvider(fetchData)
26+
onMounted(fetchData)
27+
</script>
28+
29+
<template>
30+
<VisualLoading v-if="!data" />
31+
<AuthTokensList v-else :tokens="data" @revoke="revoke" />
32+
</template>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { getInternalContext } from '@vitejs/devtools'
2+
import { defineRpcFunction } from '@vitejs/devtools-kit'
3+
4+
export const getAuthTokens = defineRpcFunction({
5+
name: 'devtoolskit:self-inspect:get-auth-tokens',
6+
type: 'query',
7+
setup: (context) => {
8+
const internal = getInternalContext(context)
9+
const storage = internal.storage.auth
10+
return {
11+
handler: async () => {
12+
const trusted = storage.value().trusted
13+
return Object.values(trusted)
14+
},
15+
}
16+
},
17+
})
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { getInternalContext } from '@vitejs/devtools'
2+
import { defineRpcFunction } from '@vitejs/devtools-kit'
3+
4+
export const revokeAuthToken = defineRpcFunction({
5+
name: 'devtoolskit:self-inspect:revoke-auth-token',
6+
type: 'action',
7+
setup: (context) => {
8+
const internal = getInternalContext(context)
9+
const storage = internal.storage.auth
10+
return {
11+
handler: async (authId: string) => {
12+
storage.mutate((state) => {
13+
delete state.trusted[authId]
14+
})
15+
},
16+
}
17+
},
18+
})

packages/self-inspect/src/node/rpc/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import type { RpcDefinitionsFilter, RpcDefinitionsToFunctions } from '@vitejs/devtools-kit'
2+
import { getAuthTokens } from './functions/get-auth-tokens'
23
import { getClientScripts } from './functions/get-client-scripts'
34
import { getDevtoolsPlugins } from './functions/get-devtools-plugins'
45
import { getDocks } from './functions/get-docks'
56
import { getRpcFunctions } from './functions/get-rpc-functions'
7+
import { revokeAuthToken } from './functions/revoke-auth-token'
68
import '@vitejs/devtools-kit'
79

810
export const rpcFunctions = [
911
getDocks,
1012
getRpcFunctions,
1113
getClientScripts,
1214
getDevtoolsPlugins,
15+
getAuthTokens,
16+
revokeAuthToken,
1317
] as const
1418

1519
export type ServerFunctions = RpcDefinitionsToFunctions<typeof rpcFunctions>

0 commit comments

Comments
 (0)