mirror of
https://github.com/openclaw/clawhub.git
synced 2026-07-22 03:35:29 -04:00
refactor(cli): centralize auth token lookup
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
import { readGlobalConfig } from '../config.js'
|
||||
import { fail } from './ui.js'
|
||||
|
||||
export async function getOptionalAuthToken(): Promise<string | undefined> {
|
||||
const cfg = await readGlobalConfig()
|
||||
return cfg?.token ?? undefined
|
||||
}
|
||||
|
||||
export async function requireAuthToken(): Promise<string> {
|
||||
const token = await getOptionalAuthToken()
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
return token
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { readGlobalConfig, writeGlobalConfig } from '../../config.js'
|
||||
import { discoverRegistryFromSite } from '../../discovery.js'
|
||||
import { apiRequest } from '../../http.js'
|
||||
import { ApiRoutes, ApiV1WhoamiResponseSchema } from '../../schema/index.js'
|
||||
import { requireAuthToken } from '../authToken.js'
|
||||
import { getRegistry } from '../registry.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
import { createSpinner, fail, formatError, openInBrowser, promptHidden } from '../ui.js'
|
||||
@@ -78,9 +79,7 @@ export async function cmdLogout(opts: GlobalOpts) {
|
||||
}
|
||||
|
||||
export async function cmdWhoami(opts: GlobalOpts) {
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
|
||||
const spinner = createSpinner('Checking token')
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { GlobalOpts } from '../types'
|
||||
|
||||
vi.mock('../../config.js', () => ({
|
||||
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawhub.ai', token: 'tkn' })),
|
||||
vi.mock('../authToken.js', () => ({
|
||||
requireAuthToken: vi.fn(async () => 'tkn'),
|
||||
}))
|
||||
|
||||
vi.mock('../registry.js', () => ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { apiRequest } from '../../http.js'
|
||||
import { ApiRoutes, ApiV1DeleteResponseSchema, parseArk } from '../../schema/index.js'
|
||||
import { requireAuthToken } from '../authToken.js'
|
||||
import { getRegistry } from '../registry.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '../ui.js'
|
||||
@@ -40,13 +40,6 @@ const unhideLabels: SkillActionLabels = {
|
||||
promptSuffix: 'requires moderator/admin',
|
||||
}
|
||||
|
||||
async function requireToken() {
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
return token
|
||||
}
|
||||
|
||||
export async function cmdDeleteSkill(
|
||||
opts: GlobalOpts,
|
||||
slugArg: string,
|
||||
@@ -64,7 +57,7 @@ export async function cmdDeleteSkill(
|
||||
if (!ok) return
|
||||
}
|
||||
|
||||
const token = await requireToken()
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const spinner = createSpinner(`${labels.progress} ${slug}`)
|
||||
try {
|
||||
@@ -98,7 +91,7 @@ export async function cmdUndeleteSkill(
|
||||
if (!ok) return
|
||||
}
|
||||
|
||||
const token = await requireToken()
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const spinner = createSpinner(`${labels.progress} ${slug}`)
|
||||
try {
|
||||
|
||||
@@ -16,9 +16,9 @@ vi.mock('../registry.js', () => ({
|
||||
getRegistry: () => mockGetRegistry(),
|
||||
}))
|
||||
|
||||
const mockReadGlobalConfig = vi.fn(async () => null as { token?: string } | null)
|
||||
vi.mock('../../config.js', () => ({
|
||||
readGlobalConfig: () => mockReadGlobalConfig(),
|
||||
const mockGetOptionalAuthToken = vi.fn(async () => undefined as string | undefined)
|
||||
vi.mock('../authToken.js', () => ({
|
||||
getOptionalAuthToken: () => mockGetOptionalAuthToken(),
|
||||
}))
|
||||
|
||||
const mockSpinner = {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
ApiV1SkillVersionListResponseSchema,
|
||||
ApiV1SkillVersionResponseSchema,
|
||||
} from '../../schema/index.js'
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { getOptionalAuthToken } from '../authToken.js'
|
||||
import { getRegistry } from '../registry.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
import { createSpinner, fail, formatError } from '../ui.js'
|
||||
@@ -32,9 +32,7 @@ export async function cmdInspect(opts: GlobalOpts, slug: string, options: Inspec
|
||||
if (!trimmed) fail('Slug required')
|
||||
if (options.version && options.tag) fail('Use either --version or --tag')
|
||||
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token ?? undefined
|
||||
|
||||
const token = await getOptionalAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const spinner = createSpinner('Fetching skill')
|
||||
try {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { GlobalOpts } from '../types'
|
||||
|
||||
vi.mock('../../config.js', () => ({
|
||||
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawhub.ai', token: 'tkn' })),
|
||||
vi.mock('../authToken.js', () => ({
|
||||
requireAuthToken: vi.fn(async () => 'tkn'),
|
||||
}))
|
||||
|
||||
vi.mock('../registry.js', () => ({
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { isCancel, select } from '@clack/prompts'
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { apiRequest } from '../../http.js'
|
||||
import {
|
||||
ApiRoutes,
|
||||
@@ -8,17 +7,11 @@ import {
|
||||
ApiV1UserSearchResponseSchema,
|
||||
parseArk,
|
||||
} from '../../schema/index.js'
|
||||
import { requireAuthToken } from '../authToken.js'
|
||||
import { getRegistry } from '../registry.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '../ui.js'
|
||||
|
||||
async function requireToken() {
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
return token
|
||||
}
|
||||
|
||||
export async function cmdBanUser(
|
||||
opts: GlobalOpts,
|
||||
identifierArg: string,
|
||||
@@ -30,7 +23,7 @@ export async function cmdBanUser(
|
||||
|
||||
const reason = options.reason?.trim() || undefined
|
||||
|
||||
const token = await requireToken()
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const allowPrompt = isInteractive() && inputAllowed !== false
|
||||
const resolved = await resolveUserIdentifier(
|
||||
@@ -87,7 +80,7 @@ export async function cmdSetRole(
|
||||
if (!raw) fail('Handle or user id required')
|
||||
const role = normalizeRole(roleArg)
|
||||
|
||||
const token = await requireToken()
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const allowPrompt = isInteractive() && inputAllowed !== false
|
||||
const resolved = await resolveUserIdentifier(
|
||||
|
||||
@@ -6,8 +6,8 @@ import { join } from 'node:path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { GlobalOpts } from '../types'
|
||||
|
||||
vi.mock('../../config.js', () => ({
|
||||
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawhub.ai', token: 'tkn' })),
|
||||
vi.mock('../authToken.js', () => ({
|
||||
requireAuthToken: vi.fn(async () => 'tkn'),
|
||||
}))
|
||||
|
||||
const mockGetRegistry = vi.fn(async (_opts: unknown, _params?: unknown) => 'https://clawhub.ai')
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { stat } from 'node:fs/promises'
|
||||
import { basename, resolve } from 'node:path'
|
||||
import semver from 'semver'
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { apiRequestForm } from '../../http.js'
|
||||
import { ApiRoutes, ApiV1PublishResponseSchema } from '../../schema/index.js'
|
||||
import { listTextFiles } from '../../skills.js'
|
||||
import { requireAuthToken } from '../authToken.js'
|
||||
import { getRegistry } from '../registry.js'
|
||||
import { sanitizeSlug, titleCase } from '../slug.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
@@ -27,9 +27,7 @@ export async function cmdPublish(
|
||||
const folderStat = await stat(folder).catch(() => null)
|
||||
if (!folderStat || !folderStat.isDirectory()) fail('Path must be a folder')
|
||||
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
|
||||
const slug = options.slug ?? sanitizeSlug(basename(folder))
|
||||
|
||||
@@ -16,9 +16,9 @@ vi.mock('../registry.js', () => ({
|
||||
getRegistry: () => mockGetRegistry(),
|
||||
}))
|
||||
|
||||
const mockReadGlobalConfig = vi.fn(async () => null as { token?: string } | null)
|
||||
vi.mock('../../config.js', () => ({
|
||||
readGlobalConfig: () => mockReadGlobalConfig(),
|
||||
const mockGetOptionalAuthToken = vi.fn(async () => undefined as string | undefined)
|
||||
vi.mock('../authToken.js', () => ({
|
||||
getOptionalAuthToken: () => mockGetOptionalAuthToken(),
|
||||
}))
|
||||
|
||||
const mockSpinner = {
|
||||
@@ -197,7 +197,7 @@ describe('cmdUpdate', () => {
|
||||
|
||||
describe('cmdInstall', () => {
|
||||
it('passes optional auth token to API + download requests', async () => {
|
||||
mockReadGlobalConfig.mockResolvedValue({ token: 'tkn' })
|
||||
mockGetOptionalAuthToken.mockResolvedValue('tkn')
|
||||
mockApiRequest.mockResolvedValue({
|
||||
skill: { slug: 'demo', displayName: 'Demo', summary: null, tags: {}, stats: {}, createdAt: 0, updatedAt: 0 },
|
||||
latestVersion: { version: '1.0.0' },
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import { getRegistry } from '../registry.js'
|
||||
import type { GlobalOpts, ResolveResult } from '../types.js'
|
||||
import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '../ui.js'
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { getOptionalAuthToken } from '../authToken.js'
|
||||
|
||||
export async function cmdSearch(opts: GlobalOpts, query: string, limit?: number) {
|
||||
if (!query) fail('Query required')
|
||||
@@ -62,8 +62,7 @@ export async function cmdInstall(
|
||||
const trimmed = slug.trim()
|
||||
if (!trimmed) fail('Slug required')
|
||||
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token ?? undefined
|
||||
const token = await getOptionalAuthToken()
|
||||
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
await mkdir(opts.dir, { recursive: true })
|
||||
@@ -148,8 +147,7 @@ export async function cmdUpdate(
|
||||
if (options.version && !semver.valid(options.version)) fail('--version must be valid semver')
|
||||
const allowPrompt = isInteractive() && inputAllowed !== false
|
||||
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token ?? undefined
|
||||
const token = await getOptionalAuthToken()
|
||||
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const lock = await readLockfile(opts.workdir)
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { apiRequest } from '../../http.js'
|
||||
import { ApiRoutes, ApiV1StarResponseSchema } from '../../schema/index.js'
|
||||
import { requireAuthToken } from '../authToken.js'
|
||||
import { getRegistry } from '../registry.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '../ui.js'
|
||||
|
||||
async function requireToken() {
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
return token
|
||||
}
|
||||
|
||||
export async function cmdStarSkill(
|
||||
opts: GlobalOpts,
|
||||
slugArg: string,
|
||||
@@ -28,7 +21,7 @@ export async function cmdStarSkill(
|
||||
if (!ok) return
|
||||
}
|
||||
|
||||
const token = await requireToken()
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const spinner = createSpinner(`Starring ${slug}`)
|
||||
try {
|
||||
|
||||
@@ -26,8 +26,8 @@ vi.mock('@clack/prompts', () => ({
|
||||
isCancel: () => false,
|
||||
}))
|
||||
|
||||
vi.mock('../../config.js', () => ({
|
||||
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawhub.ai', token: 'tkn' })),
|
||||
vi.mock('../authToken.js', () => ({
|
||||
requireAuthToken: vi.fn(async () => 'tkn'),
|
||||
}))
|
||||
|
||||
const mockGetRegistry = vi.fn(async () => 'https://clawhub.ai')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { intro, outro } from '@clack/prompts'
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { hashSkillFiles, listTextFiles, readSkillOrigin } from '../../skills.js'
|
||||
import { resolveClawdbotSkillRoots } from '../clawdbotConfig.js'
|
||||
import { requireAuthToken } from '../authToken.js'
|
||||
import { getFallbackSkillRoots } from '../scanSkills.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
import { createSpinner, fail, formatError, isInteractive } from '../ui.js'
|
||||
@@ -32,9 +32,7 @@ export async function cmdSync(opts: GlobalOpts, options: SyncOptions, inputAllow
|
||||
const allowPrompt = isInteractive() && inputAllowed !== false
|
||||
intro('ClawHub sync')
|
||||
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
const token = await requireAuthToken()
|
||||
|
||||
const registry = await getRegistryWithAuth(opts, token)
|
||||
const selectedRoots = buildScanRoots(opts, options.root)
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import { readGlobalConfig } from '../../config.js'
|
||||
import { apiRequest } from '../../http.js'
|
||||
import { ApiRoutes, ApiV1UnstarResponseSchema } from '../../schema/index.js'
|
||||
import { requireAuthToken } from '../authToken.js'
|
||||
import { getRegistry } from '../registry.js'
|
||||
import type { GlobalOpts } from '../types.js'
|
||||
import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '../ui.js'
|
||||
|
||||
async function requireToken() {
|
||||
const cfg = await readGlobalConfig()
|
||||
const token = cfg?.token
|
||||
if (!token) fail('Not logged in. Run: clawhub login')
|
||||
return token
|
||||
}
|
||||
|
||||
export async function cmdUnstarSkill(
|
||||
opts: GlobalOpts,
|
||||
slugArg: string,
|
||||
@@ -28,7 +21,7 @@ export async function cmdUnstarSkill(
|
||||
if (!ok) return
|
||||
}
|
||||
|
||||
const token = await requireToken()
|
||||
const token = await requireAuthToken()
|
||||
const registry = await getRegistry(opts, { cache: true })
|
||||
const spinner = createSpinner(`Unstarring ${slug}`)
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user