1157 lines
28 KiB
TypeScript
1157 lines
28 KiB
TypeScript
import axios, { AxiosError } from 'axios';
|
|
import {
|
|
useMutation,
|
|
useQuery,
|
|
UseMutationOptions,
|
|
UseQueryOptions,
|
|
} from 'react-query';
|
|
|
|
import { request } from "~/shared/libs";
|
|
import { clearAdminAuth, persistAdminAuth } from "~/shared/libs/admin-auth";
|
|
|
|
export type AdminServiceState = {
|
|
name: string;
|
|
status?: string;
|
|
last_reported_seconds: number | null;
|
|
};
|
|
|
|
export type AdminOverviewResponse = {
|
|
project: {
|
|
host: string | null;
|
|
name: string;
|
|
privacy: string;
|
|
};
|
|
codebase: {
|
|
branch: string | null;
|
|
commit: string | null;
|
|
};
|
|
node: {
|
|
id: string;
|
|
service_wallet: string;
|
|
ton_master: string;
|
|
};
|
|
runtime: {
|
|
python: string;
|
|
implementation: string;
|
|
platform: string;
|
|
utc_now: string;
|
|
};
|
|
ipfs: Record<string, unknown> & {
|
|
identity?: Record<string, unknown> | { error: string };
|
|
bitswap?: Record<string, unknown> | { error: string };
|
|
repo?: Record<string, unknown> | { error: string };
|
|
};
|
|
content: {
|
|
encrypted_total: number;
|
|
upload_sessions_total: number;
|
|
derivatives_ready: number;
|
|
};
|
|
ton: {
|
|
host: string | null;
|
|
api_key_configured: boolean;
|
|
testnet: boolean;
|
|
};
|
|
services: AdminServiceState[];
|
|
};
|
|
|
|
export type AdminStorageResponse = {
|
|
directories: Array<{
|
|
label: string;
|
|
path: string;
|
|
exists: boolean;
|
|
file_count: number;
|
|
size_bytes: number;
|
|
}>;
|
|
disk: null | {
|
|
path: string;
|
|
total_bytes: number;
|
|
used_bytes: number;
|
|
free_bytes: number;
|
|
percent_used: number | null;
|
|
};
|
|
derivatives: {
|
|
ready: number;
|
|
processing: number;
|
|
pending: number;
|
|
failed: number;
|
|
total_bytes: number;
|
|
};
|
|
};
|
|
|
|
export type AdminUploadsContentDerivative = {
|
|
kind: string;
|
|
status: string;
|
|
size_bytes: number | null;
|
|
error: string | null;
|
|
created_at: string | null;
|
|
updated_at: string | null;
|
|
attempts: number;
|
|
download_url: string | null;
|
|
};
|
|
|
|
export type AdminUploadsContentUploadHistoryItem = {
|
|
state: string;
|
|
at: string | null;
|
|
error: string | null;
|
|
filename: string | null;
|
|
};
|
|
|
|
export type AdminUploadsContentIpfs = {
|
|
pin_state: string | null;
|
|
pin_error: string | null;
|
|
bytes_total: number | null;
|
|
bytes_fetched: number | null;
|
|
pinned_at: string | null;
|
|
updated_at: string | null;
|
|
} | null;
|
|
|
|
export type AdminUploadsContentStored = {
|
|
stored_id: number | null;
|
|
type: string | null;
|
|
owner_address: string | null;
|
|
user_id: number | null;
|
|
status: string | null;
|
|
content_url: string | null;
|
|
download_url: string | null;
|
|
created: string | null;
|
|
updated: string | null;
|
|
user?: {
|
|
id: number;
|
|
telegram_id: number;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
last_name: string | null;
|
|
};
|
|
} | null;
|
|
|
|
export type AdminUploadsContentLinks = {
|
|
web_view: string | null;
|
|
start_app: string | null;
|
|
api_view: string | null;
|
|
download_primary: string | null;
|
|
download_derivatives: Array<{
|
|
kind: string;
|
|
url: string;
|
|
size_bytes: number | null;
|
|
}>;
|
|
};
|
|
|
|
export type AdminUploadsContentFlags = {
|
|
issues: boolean;
|
|
processing: boolean;
|
|
ready: boolean;
|
|
unindexed: boolean;
|
|
};
|
|
|
|
export type AdminContentDistributionNode = {
|
|
node_id: number | null;
|
|
is_local: boolean;
|
|
host: string | null;
|
|
public_host: string | null;
|
|
version: string | null;
|
|
role: string | null;
|
|
last_seen: string | null;
|
|
content: {
|
|
encrypted_cid: string | null;
|
|
content_type: string | null;
|
|
size_bytes: number | null;
|
|
preview_enabled: boolean | null;
|
|
updated_at: string | null;
|
|
metadata_cid?: string | null;
|
|
issuer_node_id?: string | null;
|
|
};
|
|
links: {
|
|
web_view: string | null;
|
|
api_view: string | null;
|
|
gateway_view: string | null;
|
|
};
|
|
};
|
|
|
|
export type AdminContentDistribution = {
|
|
local_present: boolean;
|
|
nodes: AdminContentDistributionNode[];
|
|
};
|
|
|
|
export type AdminUploadsContentStatus = {
|
|
upload_state: string | null;
|
|
conversion_state: string | null;
|
|
ipfs_state: string | null;
|
|
onchain: {
|
|
indexed: boolean;
|
|
onchain_index: number | null;
|
|
item_address: string | null;
|
|
license_count?: number;
|
|
} | null;
|
|
};
|
|
|
|
export type AdminUploadsContent = {
|
|
encrypted_cid: string;
|
|
metadata_cid: string | null;
|
|
content_hash: string | null;
|
|
title: string;
|
|
description: string | null;
|
|
content_type: string;
|
|
size: {
|
|
encrypted: number | null;
|
|
plain: number | null;
|
|
};
|
|
created_at: string | null;
|
|
updated_at: string | null;
|
|
status: AdminUploadsContentStatus;
|
|
upload_history: AdminUploadsContentUploadHistoryItem[];
|
|
derivative_summary: Record<string, number>;
|
|
derivatives: AdminUploadsContentDerivative[];
|
|
ipfs: AdminUploadsContentIpfs;
|
|
stored: AdminUploadsContentStored;
|
|
links: AdminUploadsContentLinks;
|
|
distribution: AdminContentDistribution;
|
|
flags?: AdminUploadsContentFlags;
|
|
};
|
|
|
|
export type AdminUploadsResponse = {
|
|
total: number;
|
|
states: Record<string, number>;
|
|
recent: Array<{
|
|
id: string;
|
|
filename: string | null;
|
|
size_bytes: number | null;
|
|
state: string;
|
|
encrypted_cid: string | null;
|
|
error: string | null;
|
|
updated_at: string;
|
|
created_at: string;
|
|
}>;
|
|
contents: AdminUploadsContent[];
|
|
matching_total?: number;
|
|
filter?: string[];
|
|
search?: string | null;
|
|
limit?: number;
|
|
scan?: number;
|
|
scanned?: number;
|
|
category_totals?: Record<string, number>;
|
|
};
|
|
|
|
export type AdminUploadsQueryParams = {
|
|
filter?: string | string[];
|
|
search?: string;
|
|
limit?: number;
|
|
scan?: number;
|
|
};
|
|
|
|
type AdminUploadsQueryKey = ['admin', 'uploads', string | null, string | null, number | null, number | null];
|
|
|
|
export type AdminUserWalletConnectionSummary = {
|
|
primary_address: string | null;
|
|
active_count: number;
|
|
total_count: number;
|
|
last_connected_at: string | null;
|
|
connections: Array<{
|
|
id: number;
|
|
address: string;
|
|
network: string;
|
|
invalidated: boolean;
|
|
created_at: string | null;
|
|
updated_at: string | null;
|
|
}>;
|
|
};
|
|
|
|
export type AdminUserContentSummary = {
|
|
total: number;
|
|
onchain: number;
|
|
local: number;
|
|
disabled: number;
|
|
};
|
|
|
|
export type AdminUserLicensesSummary = {
|
|
total: number;
|
|
active: number;
|
|
by_type: Record<string, number>;
|
|
by_status: Record<string, number>;
|
|
};
|
|
|
|
export type AdminUserStarsSummary = {
|
|
total: number;
|
|
paid: number;
|
|
unpaid: number;
|
|
amount_total: number;
|
|
amount_paid: number;
|
|
amount_unpaid: number;
|
|
};
|
|
|
|
export type AdminUserIpActivity = {
|
|
last: {
|
|
ip: string | null;
|
|
type: string | null;
|
|
seen_at: string | null;
|
|
} | null;
|
|
unique_ips: number;
|
|
recent: Array<{
|
|
ip: string | null;
|
|
type: string | null;
|
|
seen_at: string | null;
|
|
}>;
|
|
};
|
|
|
|
export type AdminUserItem = {
|
|
id: number;
|
|
is_admin: boolean;
|
|
telegram_id: number;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
last_name: string | null;
|
|
lang_code: string | null;
|
|
created_at: string | null;
|
|
updated_at: string | null;
|
|
last_use: string | null;
|
|
meta: {
|
|
ref_id?: string | null;
|
|
referrer_id?: string | null;
|
|
};
|
|
wallets: AdminUserWalletConnectionSummary;
|
|
content: AdminUserContentSummary;
|
|
licenses: AdminUserLicensesSummary;
|
|
stars: AdminUserStarsSummary;
|
|
ip_activity: AdminUserIpActivity;
|
|
};
|
|
|
|
export type AdminEventItem = {
|
|
id: number;
|
|
origin_public_key: string | null;
|
|
origin_host: string | null;
|
|
seq: number;
|
|
uid: string;
|
|
event_type: string;
|
|
status: string;
|
|
created_at: string | null;
|
|
received_at: string | null;
|
|
applied_at: string | null;
|
|
payload: Record<string, unknown>;
|
|
links: Record<string, string | null>;
|
|
};
|
|
|
|
export type AdminEventsResponse = {
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
filters?: Record<string, unknown>;
|
|
items: AdminEventItem[];
|
|
available_filters: {
|
|
types: Record<string, number>;
|
|
statuses: Record<string, number>;
|
|
origins: Record<string, number>;
|
|
};
|
|
};
|
|
|
|
export type AdminEventsQueryParams = {
|
|
limit?: number;
|
|
offset?: number;
|
|
type?: string | string[];
|
|
status?: string | string[];
|
|
origin?: string | string[];
|
|
search?: string;
|
|
};
|
|
|
|
type AdminEventsQueryKey = ['admin', 'events', string];
|
|
|
|
export type AdminUsersSummary = {
|
|
users_returned: number;
|
|
admins_total: number;
|
|
wallets_total: number;
|
|
wallets_active: number;
|
|
licenses_total: number;
|
|
licenses_active: number;
|
|
stars_total: number;
|
|
stars_paid: number;
|
|
stars_unpaid: number;
|
|
stars_amount_total: number;
|
|
stars_amount_paid: number;
|
|
stars_amount_unpaid: number;
|
|
unique_ips_total: number;
|
|
};
|
|
|
|
export type AdminUsersResponse = {
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
search?: string | null;
|
|
filters?: Record<string, unknown>;
|
|
has_more: boolean;
|
|
items: AdminUserItem[];
|
|
summary: AdminUsersSummary;
|
|
};
|
|
|
|
export type AdminUsersQueryParams = {
|
|
limit?: number;
|
|
offset?: number;
|
|
search?: string;
|
|
};
|
|
|
|
type AdminUsersQueryKey = ['admin', 'users', string];
|
|
|
|
export type AdminLicenseItem = {
|
|
id: number;
|
|
type: string | null;
|
|
status: string | null;
|
|
license_type: number | null;
|
|
onchain_address: string | null;
|
|
owner_address: string | null;
|
|
user: {
|
|
id: number;
|
|
telegram_id: number;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
last_name: string | null;
|
|
} | null;
|
|
wallet_connection: {
|
|
id: number;
|
|
address: string;
|
|
network: string;
|
|
invalidated: boolean;
|
|
created_at: string | null;
|
|
updated_at: string | null;
|
|
} | null;
|
|
content: {
|
|
id: number | null;
|
|
hash: string | null;
|
|
cid: string | null;
|
|
title: string | null;
|
|
type: string | null;
|
|
owner_address: string | null;
|
|
onchain_index: number | null;
|
|
user_id: number | null;
|
|
download_url: string | null;
|
|
} | null;
|
|
created_at: string | null;
|
|
updated_at: string | null;
|
|
meta: Record<string, unknown>;
|
|
links: {
|
|
tonviewer: string | null;
|
|
content_view: string | null;
|
|
};
|
|
};
|
|
|
|
export type AdminLicensesCounts = {
|
|
status: Record<string, number>;
|
|
type: Record<string, number>;
|
|
license_type: Record<string, number>;
|
|
};
|
|
|
|
export type AdminLicensesResponse = {
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
search?: string | null;
|
|
filters?: Record<string, unknown>;
|
|
has_more: boolean;
|
|
items: AdminLicenseItem[];
|
|
counts: AdminLicensesCounts;
|
|
};
|
|
|
|
export type AdminLicensesQueryParams = {
|
|
limit?: number;
|
|
offset?: number;
|
|
search?: string;
|
|
type?: string | string[];
|
|
status?: string | string[];
|
|
license_type?: number | string | Array<number | string>;
|
|
user_id?: number;
|
|
owner?: string;
|
|
address?: string;
|
|
content_hash?: string;
|
|
};
|
|
|
|
type AdminLicensesQueryKey = ['admin', 'licenses', string];
|
|
|
|
export type AdminStarsInvoiceItem = {
|
|
id: number;
|
|
external_id: string;
|
|
type: string | null;
|
|
amount: number;
|
|
paid: boolean;
|
|
invoice_url: string | null;
|
|
created_at: string | null;
|
|
status: 'paid' | 'pending';
|
|
user: {
|
|
id: number;
|
|
telegram_id: number;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
last_name: string | null;
|
|
} | null;
|
|
content: {
|
|
id: number | null;
|
|
hash: string | null;
|
|
cid: string | null;
|
|
title: string | null;
|
|
onchain_index: number | null;
|
|
owner_address: string | null;
|
|
user_id: number | null;
|
|
download_url: string | null;
|
|
} | null;
|
|
};
|
|
|
|
export type AdminStarsStats = {
|
|
total: number;
|
|
paid: number;
|
|
unpaid: number;
|
|
amount_total: number;
|
|
amount_paid: number;
|
|
amount_unpaid: number;
|
|
by_type: Record<string, {
|
|
total: number;
|
|
paid: number;
|
|
unpaid: number;
|
|
amount_total: number;
|
|
amount_paid: number;
|
|
amount_unpaid: number;
|
|
}>;
|
|
};
|
|
|
|
export type AdminStarsResponse = {
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
search?: string | null;
|
|
filters?: Record<string, unknown>;
|
|
has_more: boolean;
|
|
items: AdminStarsInvoiceItem[];
|
|
stats: AdminStarsStats;
|
|
};
|
|
|
|
export type AdminStarsQueryParams = {
|
|
limit?: number;
|
|
offset?: number;
|
|
search?: string;
|
|
type?: string | string[];
|
|
paid?: boolean;
|
|
user_id?: number;
|
|
content_hash?: string;
|
|
};
|
|
|
|
type AdminStarsQueryKey = ['admin', 'stars', string];
|
|
|
|
export type AdminSystemResponse = {
|
|
env: Record<string, string | null | undefined>;
|
|
service_config: Array<{
|
|
key: string;
|
|
value: string | null;
|
|
raw: string | null;
|
|
}>;
|
|
services: AdminServiceState[];
|
|
blockchain_tasks: Record<string, number>;
|
|
latest_index_items: Array<{
|
|
encrypted_cid: string | null;
|
|
updated_at: string;
|
|
}>;
|
|
telegram_bots: Array<{
|
|
role: string;
|
|
username: string;
|
|
url: string;
|
|
}>;
|
|
};
|
|
|
|
export type AdminBlockchainResponse = {
|
|
counts: Record<string, number>;
|
|
recent: Array<{
|
|
id: string;
|
|
destination: string | null;
|
|
amount: string | null;
|
|
status: string;
|
|
epoch: number | null;
|
|
seqno: number | null;
|
|
transaction_hash: string | null;
|
|
updated: string;
|
|
}>;
|
|
};
|
|
|
|
export type AdminNodesResponse = {
|
|
items: Array<{
|
|
ip: string | null;
|
|
port: number | null;
|
|
public_key: string | null;
|
|
role: 'trusted' | 'read-only' | 'deny';
|
|
version?: string | null;
|
|
last_seen?: string | null;
|
|
notes?: string | null;
|
|
}>;
|
|
};
|
|
|
|
// --------- Состояние сети (новый раздел) ---------
|
|
|
|
export type AdminNetworkMember = {
|
|
node_id: string;
|
|
public_key: string | null;
|
|
public_host: string | null;
|
|
version: string | null;
|
|
role: string;
|
|
ip: string | null;
|
|
asn: number | null;
|
|
ip_first_octet: number | null;
|
|
reachability_ratio: number;
|
|
last_update: number | null;
|
|
accepts_inbound: boolean;
|
|
is_bootstrap: boolean;
|
|
receipts_total?: number;
|
|
receipts_asn_unique?: number;
|
|
};
|
|
|
|
export type AdminNetworkPerNodeReplication = Record<
|
|
string,
|
|
{
|
|
leases_held: number;
|
|
leaderships: number;
|
|
sample_contents: string[];
|
|
}
|
|
>;
|
|
|
|
export type AdminNetworkResponse = {
|
|
summary: {
|
|
n_estimate: number;
|
|
n_estimate_trusted: number;
|
|
active_trusted: number;
|
|
members_total: number;
|
|
active: number;
|
|
islands: number;
|
|
replication_conflicts: { under: number; over: number };
|
|
config: {
|
|
heartbeat_interval: number;
|
|
lease_ttl: number;
|
|
gossip_interval_sec: number;
|
|
gossip_backoff_base_sec: number;
|
|
gossip_backoff_cap_sec: number;
|
|
};
|
|
};
|
|
members: AdminNetworkMember[];
|
|
per_node_replication: AdminNetworkPerNodeReplication;
|
|
receipts: Array<{
|
|
target_id: string;
|
|
issuer_id: string;
|
|
asn: number | null;
|
|
timestamp: number | null;
|
|
status: 'valid' | 'bad_signature' | 'unknown_issuer' | 'mismatch_node_id' | 'unknown';
|
|
}>;
|
|
};
|
|
|
|
export const useAdminNetwork = (
|
|
options?: QueryOptions<AdminNetworkResponse, ['admin', 'network']>,
|
|
) => {
|
|
return useQuery<AdminNetworkResponse, AxiosError, AdminNetworkResponse, ['admin', 'network']>(
|
|
['admin', 'network'],
|
|
async () => {
|
|
const { data } = await request.get<AdminNetworkResponse>('/admin.network');
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export type AdminStatusResponse = {
|
|
ipfs: {
|
|
bitswap: Record<string, unknown>;
|
|
repo: Record<string, unknown>;
|
|
};
|
|
pin_counts: Record<string, number>;
|
|
derivatives: {
|
|
ready: number;
|
|
processing: number;
|
|
pending: number;
|
|
failed: number;
|
|
total_bytes: number;
|
|
};
|
|
convert_backlog: number;
|
|
limits: {
|
|
DERIVATIVE_CACHE_MAX_GB: number;
|
|
DERIVATIVE_CACHE_TTL_DAYS: number;
|
|
SYNC_MAX_CONCURRENT_PINS: number;
|
|
SYNC_DISK_LOW_WATERMARK_PCT: number;
|
|
};
|
|
};
|
|
|
|
export type AdminCacheSetLimitsPayload = {
|
|
max_gb: number;
|
|
ttl_days: number;
|
|
};
|
|
|
|
export type AdminCacheCleanupPayload =
|
|
| {
|
|
mode: 'ttl';
|
|
}
|
|
| {
|
|
mode?: 'fit';
|
|
max_gb: number;
|
|
};
|
|
|
|
export type AdminSyncSetLimitsPayload = {
|
|
max_concurrent_pins: number;
|
|
disk_low_watermark_pct: number;
|
|
};
|
|
|
|
export type AdminNodeSetRolePayload = {
|
|
public_key?: string;
|
|
host?: string;
|
|
role: 'trusted' | 'read-only' | 'deny';
|
|
};
|
|
|
|
const defaultQueryOptions = {
|
|
staleTime: 30_000,
|
|
refetchOnWindowFocus: false,
|
|
} as const;
|
|
|
|
type QueryOptions<TData, TQueryKey extends readonly unknown[]> = UseQueryOptions<
|
|
TData,
|
|
AxiosError,
|
|
TData,
|
|
TQueryKey
|
|
>;
|
|
|
|
type MutationOptions<TData, TVariables> = UseMutationOptions<
|
|
TData,
|
|
AxiosError,
|
|
TVariables
|
|
>;
|
|
|
|
export const useAdminOverview = (
|
|
options?: QueryOptions<AdminOverviewResponse, ['admin', 'overview']>,
|
|
) => {
|
|
return useQuery<AdminOverviewResponse, AxiosError, AdminOverviewResponse, ['admin', 'overview']>(
|
|
['admin', 'overview'],
|
|
async () => {
|
|
const { data } = await request.get<AdminOverviewResponse>('/admin.overview');
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminStorage = (
|
|
options?: QueryOptions<AdminStorageResponse, ['admin', 'storage']>,
|
|
) => {
|
|
return useQuery<AdminStorageResponse, AxiosError, AdminStorageResponse, ['admin', 'storage']>(
|
|
['admin', 'storage'],
|
|
async () => {
|
|
const { data } = await request.get<AdminStorageResponse>('/admin.storage');
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminUploads = (
|
|
params?: AdminUploadsQueryParams,
|
|
options?: QueryOptions<AdminUploadsResponse, AdminUploadsQueryKey>,
|
|
) => {
|
|
const filterParts = Array.isArray(params?.filter)
|
|
? params.filter.filter(Boolean)
|
|
: params?.filter
|
|
? [params.filter]
|
|
: [];
|
|
const filterValue = filterParts.length > 0 ? filterParts.join(',') : null;
|
|
const searchValue = params?.search?.trim() || null;
|
|
const limitValue = params?.limit ?? null;
|
|
const scanValue = params?.scan ?? null;
|
|
|
|
const queryKey: AdminUploadsQueryKey = ['admin', 'uploads', filterValue, searchValue, limitValue, scanValue];
|
|
|
|
const queryParams: Record<string, string | number | undefined> = {
|
|
filter: filterValue ?? undefined,
|
|
search: searchValue ?? undefined,
|
|
limit: limitValue ?? undefined,
|
|
scan: scanValue ?? undefined,
|
|
};
|
|
|
|
return useQuery<AdminUploadsResponse, AxiosError, AdminUploadsResponse, AdminUploadsQueryKey>(
|
|
queryKey,
|
|
async () => {
|
|
const { data } = await request.get<AdminUploadsResponse>('/admin.uploads', {
|
|
params: queryParams,
|
|
});
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminUsers = (
|
|
params?: AdminUsersQueryParams,
|
|
options?: QueryOptions<AdminUsersResponse, AdminUsersQueryKey>,
|
|
) => {
|
|
const normalizedSearch = params?.search?.trim() || null;
|
|
const paramsKeyPayload = {
|
|
limit: params?.limit ?? null,
|
|
offset: params?.offset ?? null,
|
|
search: normalizedSearch,
|
|
};
|
|
const paramsKey = JSON.stringify(paramsKeyPayload);
|
|
|
|
const queryParams: Record<string, string | number | undefined> = {
|
|
limit: params?.limit,
|
|
offset: params?.offset,
|
|
search: normalizedSearch ?? undefined,
|
|
};
|
|
|
|
return useQuery<AdminUsersResponse, AxiosError, AdminUsersResponse, AdminUsersQueryKey>(
|
|
['admin', 'users', paramsKey],
|
|
async () => {
|
|
const { data } = await request.get<AdminUsersResponse>('/admin.users', {
|
|
params: queryParams,
|
|
});
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminLicenses = (
|
|
params?: AdminLicensesQueryParams,
|
|
options?: QueryOptions<AdminLicensesResponse, AdminLicensesQueryKey>,
|
|
) => {
|
|
const normalizedSearch = params?.search?.trim() || null;
|
|
const typeValue = Array.isArray(params?.type)
|
|
? params.type.filter(Boolean).join(',')
|
|
: params?.type ?? null;
|
|
const statusValue = Array.isArray(params?.status)
|
|
? params.status.filter(Boolean).join(',')
|
|
: params?.status ?? null;
|
|
const licenseTypeValue = Array.isArray(params?.license_type)
|
|
? params.license_type.filter((value) => value !== undefined && value !== null).join(',')
|
|
: params?.license_type ?? null;
|
|
|
|
const paramsKeyPayload = {
|
|
limit: params?.limit ?? null,
|
|
offset: params?.offset ?? null,
|
|
search: normalizedSearch,
|
|
type: typeValue,
|
|
status: statusValue,
|
|
license_type: licenseTypeValue,
|
|
user_id: params?.user_id ?? null,
|
|
owner: params?.owner ?? null,
|
|
address: params?.address ?? null,
|
|
content_hash: params?.content_hash ?? null,
|
|
};
|
|
const paramsKey = JSON.stringify(paramsKeyPayload);
|
|
|
|
const queryParams: Record<string, string | number | undefined> = {
|
|
limit: params?.limit,
|
|
offset: params?.offset,
|
|
search: normalizedSearch ?? undefined,
|
|
type: typeValue ?? undefined,
|
|
status: statusValue ?? undefined,
|
|
license_type: licenseTypeValue ?? undefined,
|
|
user_id: params?.user_id,
|
|
owner: params?.owner ?? undefined,
|
|
address: params?.address ?? undefined,
|
|
content_hash: params?.content_hash ?? undefined,
|
|
};
|
|
|
|
return useQuery<AdminLicensesResponse, AxiosError, AdminLicensesResponse, AdminLicensesQueryKey>(
|
|
['admin', 'licenses', paramsKey],
|
|
async () => {
|
|
const { data } = await request.get<AdminLicensesResponse>('/admin.licenses', {
|
|
params: queryParams,
|
|
});
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminStars = (
|
|
params?: AdminStarsQueryParams,
|
|
options?: QueryOptions<AdminStarsResponse, AdminStarsQueryKey>,
|
|
) => {
|
|
const normalizedSearch = params?.search?.trim() || null;
|
|
const typeValue = Array.isArray(params?.type)
|
|
? params.type.filter(Boolean).join(',')
|
|
: params?.type ?? null;
|
|
|
|
const paramsKeyPayload = {
|
|
limit: params?.limit ?? null,
|
|
offset: params?.offset ?? null,
|
|
search: normalizedSearch,
|
|
type: typeValue,
|
|
paid: typeof params?.paid === 'boolean' ? params.paid : null,
|
|
user_id: params?.user_id ?? null,
|
|
content_hash: params?.content_hash ?? null,
|
|
};
|
|
const paramsKey = JSON.stringify(paramsKeyPayload);
|
|
|
|
const queryParams: Record<string, string | number | undefined> = {
|
|
limit: params?.limit,
|
|
offset: params?.offset,
|
|
search: normalizedSearch ?? undefined,
|
|
type: typeValue ?? undefined,
|
|
user_id: params?.user_id,
|
|
content_hash: params?.content_hash ?? undefined,
|
|
};
|
|
|
|
if (typeof params?.paid === 'boolean') {
|
|
queryParams.paid = params.paid ? 1 : 0;
|
|
}
|
|
|
|
return useQuery<AdminStarsResponse, AxiosError, AdminStarsResponse, AdminStarsQueryKey>(
|
|
['admin', 'stars', paramsKey],
|
|
async () => {
|
|
const { data } = await request.get<AdminStarsResponse>('/admin.stars', {
|
|
params: queryParams,
|
|
});
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminEvents = (
|
|
params?: AdminEventsQueryParams,
|
|
options?: QueryOptions<AdminEventsResponse, AdminEventsQueryKey>,
|
|
) => {
|
|
const normalizedSearch = params?.search?.trim() || null;
|
|
const typeValue = Array.isArray(params?.type)
|
|
? params.type.filter(Boolean).join(',')
|
|
: params?.type ?? null;
|
|
const statusValue = Array.isArray(params?.status)
|
|
? params.status.filter(Boolean).join(',')
|
|
: params?.status ?? null;
|
|
const originValue = Array.isArray(params?.origin)
|
|
? params.origin.filter(Boolean).join(',')
|
|
: params?.origin ?? null;
|
|
|
|
const paramsKeyPayload = {
|
|
limit: params?.limit ?? null,
|
|
offset: params?.offset ?? null,
|
|
search: normalizedSearch,
|
|
type: typeValue,
|
|
status: statusValue,
|
|
origin: originValue,
|
|
};
|
|
const paramsKey = JSON.stringify(paramsKeyPayload);
|
|
|
|
const queryParams: Record<string, string | number | undefined> = {
|
|
limit: params?.limit,
|
|
offset: params?.offset,
|
|
search: normalizedSearch ?? undefined,
|
|
type: typeValue ?? undefined,
|
|
status: statusValue ?? undefined,
|
|
origin: originValue ?? undefined,
|
|
};
|
|
|
|
return useQuery<AdminEventsResponse, AxiosError, AdminEventsResponse, AdminEventsQueryKey>(
|
|
['admin', 'events', paramsKey],
|
|
async () => {
|
|
const { data } = await request.get<AdminEventsResponse>('/admin.events', {
|
|
params: queryParams,
|
|
});
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminSystem = (
|
|
options?: QueryOptions<AdminSystemResponse, ['admin', 'system']>,
|
|
) => {
|
|
return useQuery<AdminSystemResponse, AxiosError, AdminSystemResponse, ['admin', 'system']>(
|
|
['admin', 'system'],
|
|
async () => {
|
|
const { data } = await request.get<AdminSystemResponse>('/admin.system');
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminBlockchain = (
|
|
options?: QueryOptions<AdminBlockchainResponse, ['admin', 'blockchain']>,
|
|
) => {
|
|
return useQuery<AdminBlockchainResponse, AxiosError, AdminBlockchainResponse, ['admin', 'blockchain']>(
|
|
['admin', 'blockchain'],
|
|
async () => {
|
|
const { data } = await request.get<AdminBlockchainResponse>('/admin.blockchain');
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminNodes = (
|
|
options?: QueryOptions<AdminNodesResponse, ['admin', 'nodes']>,
|
|
) => {
|
|
return useQuery<AdminNodesResponse, AxiosError, AdminNodesResponse, ['admin', 'nodes']>(
|
|
['admin', 'nodes'],
|
|
async () => {
|
|
const { data } = await request.get<AdminNodesResponse>('/admin.nodes');
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useAdminStatus = (
|
|
options?: QueryOptions<AdminStatusResponse, ['admin', 'status']>,
|
|
) => {
|
|
return useQuery<AdminStatusResponse, AxiosError, AdminStatusResponse, ['admin', 'status']>(
|
|
['admin', 'status'],
|
|
async () => {
|
|
const { data } = await request.get<AdminStatusResponse>('/admin.status');
|
|
return data;
|
|
},
|
|
{
|
|
...defaultQueryOptions,
|
|
...options,
|
|
},
|
|
);
|
|
};
|
|
|
|
export type AdminLoginResponse = {
|
|
ok: true;
|
|
cookie_name?: string;
|
|
header_name?: string;
|
|
max_age?: number;
|
|
};
|
|
|
|
export const useAdminLogin = (
|
|
options?: MutationOptions<AdminLoginResponse, { secret: string }>,
|
|
) => {
|
|
return useMutation<AdminLoginResponse, AxiosError, { secret: string }>(
|
|
async ({ secret }) => {
|
|
const { data } = await request.post<AdminLoginResponse>('/admin.login', { secret });
|
|
persistAdminAuth({
|
|
token: secret,
|
|
headerName: data.header_name,
|
|
cookieName: data.cookie_name,
|
|
maxAge: data.max_age,
|
|
});
|
|
return data;
|
|
},
|
|
options,
|
|
);
|
|
};
|
|
|
|
export const useAdminLogout = (
|
|
options?: MutationOptions<{ ok: true }, void>,
|
|
) => {
|
|
return useMutation<{ ok: true }, AxiosError, void>(
|
|
async () => {
|
|
const { data } = await request.post<{ ok: true }>('/admin.logout');
|
|
clearAdminAuth();
|
|
return data;
|
|
},
|
|
options,
|
|
);
|
|
};
|
|
|
|
export const useAdminCacheSetLimits = (
|
|
options?: MutationOptions<{ ok: true }, AdminCacheSetLimitsPayload>,
|
|
) => {
|
|
return useMutation<{ ok: true }, AxiosError, AdminCacheSetLimitsPayload>(
|
|
async (payload) => {
|
|
const { data } = await request.post<{ ok: true }>('/admin.cache.setLimits', payload);
|
|
return data;
|
|
},
|
|
options,
|
|
);
|
|
};
|
|
|
|
export const useAdminCacheCleanup = (
|
|
options?: MutationOptions<{ ok: true; removed?: number }, AdminCacheCleanupPayload>,
|
|
) => {
|
|
return useMutation<{ ok: true; removed?: number }, AxiosError, AdminCacheCleanupPayload>(
|
|
async (payload) => {
|
|
const { data } = await request.post<{ ok: true; removed?: number }>('/admin.cache.cleanup', payload);
|
|
return data;
|
|
},
|
|
options,
|
|
);
|
|
};
|
|
|
|
export const useAdminSyncSetLimits = (
|
|
options?: MutationOptions<{ ok: true }, AdminSyncSetLimitsPayload>,
|
|
) => {
|
|
return useMutation<{ ok: true }, AxiosError, AdminSyncSetLimitsPayload>(
|
|
async (payload) => {
|
|
const { data } = await request.post<{ ok: true }>('/admin.sync.setLimits', payload);
|
|
return data;
|
|
},
|
|
options,
|
|
);
|
|
};
|
|
|
|
export const useAdminNodeSetRole = (
|
|
options?: MutationOptions<{ ok: true; node: { ip: string | null; public_key: string | null; role: string } }, AdminNodeSetRolePayload>,
|
|
) => {
|
|
return useMutation<
|
|
{ ok: true; node: { ip: string | null; public_key: string | null; role: string } },
|
|
AxiosError,
|
|
AdminNodeSetRolePayload
|
|
>(
|
|
async (payload) => {
|
|
const { data } = await request.post<{ ok: true; node: { ip: string | null; public_key: string | null; role: string } }>(
|
|
'/admin.node.setRole',
|
|
payload,
|
|
);
|
|
return data;
|
|
},
|
|
options,
|
|
);
|
|
};
|
|
|
|
export const useAdminSetUserAdmin = (
|
|
options?: MutationOptions<{ ok: true; user: { id: number; is_admin: boolean } }, { user_id: number; is_admin: boolean }>,
|
|
) => {
|
|
return useMutation<{ ok: true; user: { id: number; is_admin: boolean } }, AxiosError, { user_id: number; is_admin: boolean }>(
|
|
async (payload) => {
|
|
const { data } = await request.post<{ ok: true; user: { id: number; is_admin: boolean } }>('/admin.users.setAdmin', payload);
|
|
return data;
|
|
},
|
|
options,
|
|
);
|
|
};
|
|
|
|
export const useAdminSyncLimits = () => {
|
|
const cacheSetLimits = useAdminCacheSetLimits();
|
|
const syncSetLimits = useAdminSyncSetLimits();
|
|
return { cacheSetLimits, syncSetLimits };
|
|
};
|
|
|
|
export const isUnauthorizedError = (error: unknown) => {
|
|
if (!error) {
|
|
return false;
|
|
}
|
|
if (axios.isAxiosError(error)) {
|
|
return error.response?.status === 401;
|
|
}
|
|
return false;
|
|
};
|