feat(canary): TanStack Query hooks for token lifecycle
Four hooks wired through the canary api/client envelope helpers.
Module-augmented defaultError surfaces ApiError everywhere.
- useTokenTypes: GET /tokens/types, parsed via typeDescriptorListSchema.
Uses QUERY_STRATEGIES.static (Infinity stale, no refetch on focus)
since the discoverable types list is build-time stable.
- useCreateToken: POST /tokens (CreateTokenInput -> CreateTokenResponse).
On success invalidates ['canary','manage', manage_id] so a freshly
created token's manage page hydrates with the new row on first hit.
- useManageToken: GET /m/{id} with cursor pagination. URLSearchParams
builds ?cursor=&limit= only for defined values; manageId is
URI-encoded. QUERY_STRATEGIES.frequent enables 30s polling so the
events list feels live. enabled=false when manageId is empty.
- useDeleteToken: DELETE /m/{id}. On success removes the cached
manage data entirely (no point keeping it after a delete).
This commit is contained in:
parent
2d13e649a6
commit
f6194d87b9
|
|
@ -2,3 +2,8 @@
|
|||
// ©AngelaMos | 2026
|
||||
// index.ts
|
||||
// ===================
|
||||
|
||||
export * from './useCreateToken'
|
||||
export * from './useDeleteToken'
|
||||
export * from './useManageToken'
|
||||
export * from './useTokenTypes'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// ===================
|
||||
// ©AngelaMos | 2026
|
||||
// useCreateToken.ts
|
||||
// ===================
|
||||
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { apiPost } from '../client'
|
||||
import {
|
||||
type CreateTokenInput,
|
||||
type CreateTokenResponse,
|
||||
createTokenResponseSchema,
|
||||
} from '../types/token'
|
||||
|
||||
const CREATE_TOKEN_PATH = '/tokens'
|
||||
const MANAGE_KEY_PREFIX = ['canary', 'manage'] as const
|
||||
|
||||
export function useCreateToken() {
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation<CreateTokenResponse, Error, CreateTokenInput>({
|
||||
mutationFn: (body) =>
|
||||
apiPost(CREATE_TOKEN_PATH, body, createTokenResponseSchema),
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [...MANAGE_KEY_PREFIX, data.token.manage_id],
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// ===================
|
||||
// ©AngelaMos | 2026
|
||||
// useDeleteToken.ts
|
||||
// ===================
|
||||
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { apiDelete } from '../client'
|
||||
|
||||
const MANAGE_PATH_PREFIX = '/m/'
|
||||
const MANAGE_KEY_PREFIX = ['canary', 'manage'] as const
|
||||
|
||||
export function useDeleteToken() {
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation<void, Error, string>({
|
||||
mutationFn: (manageId) =>
|
||||
apiDelete(`${MANAGE_PATH_PREFIX}${encodeURIComponent(manageId)}`),
|
||||
onSuccess: (_data, manageId) => {
|
||||
queryClient.removeQueries({
|
||||
queryKey: [...MANAGE_KEY_PREFIX, manageId],
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// ===================
|
||||
// ©AngelaMos | 2026
|
||||
// useManageToken.ts
|
||||
// ===================
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { QUERY_STRATEGIES } from '@/core/api'
|
||||
import { apiGet } from '../client'
|
||||
import { manageResponseSchema } from '../types/event'
|
||||
|
||||
const MANAGE_PATH_PREFIX = '/m/'
|
||||
const MANAGE_KEY_PREFIX = ['canary', 'manage'] as const
|
||||
|
||||
export type UseManageTokenParams = {
|
||||
cursor?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
function buildSearch(params: UseManageTokenParams | undefined): string {
|
||||
if (!params) {
|
||||
return ''
|
||||
}
|
||||
const sp = new URLSearchParams()
|
||||
if (params.cursor !== undefined && params.cursor.length > 0) {
|
||||
sp.set('cursor', params.cursor)
|
||||
}
|
||||
if (params.limit !== undefined) {
|
||||
sp.set('limit', String(params.limit))
|
||||
}
|
||||
const query = sp.toString()
|
||||
return query.length > 0 ? `?${query}` : ''
|
||||
}
|
||||
|
||||
export function useManageToken(manageId: string, params?: UseManageTokenParams) {
|
||||
const search = buildSearch(params)
|
||||
const path = `${MANAGE_PATH_PREFIX}${encodeURIComponent(manageId)}${search}`
|
||||
return useQuery({
|
||||
queryKey: [...MANAGE_KEY_PREFIX, manageId, params ?? null],
|
||||
queryFn: () => apiGet(path, manageResponseSchema),
|
||||
enabled: manageId.length > 0,
|
||||
...QUERY_STRATEGIES.frequent,
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// ===================
|
||||
// ©AngelaMos | 2026
|
||||
// useTokenTypes.ts
|
||||
// ===================
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { QUERY_STRATEGIES } from '@/core/api'
|
||||
import { apiGet } from '../client'
|
||||
import { typeDescriptorListSchema } from '../types/token'
|
||||
|
||||
const TOKEN_TYPES_PATH = '/tokens/types'
|
||||
const TOKEN_TYPES_KEY = ['canary', 'token-types'] as const
|
||||
|
||||
export function useTokenTypes() {
|
||||
return useQuery({
|
||||
queryKey: TOKEN_TYPES_KEY,
|
||||
queryFn: () => apiGet(TOKEN_TYPES_PATH, typeDescriptorListSchema),
|
||||
...QUERY_STRATEGIES.static,
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue