Skip to content

Commit dd91647

Browse files
committed
chore(utils): update buildSubscan resolver
1 parent 9ac6050 commit dd91647

1 file changed

Lines changed: 88 additions & 81 deletions

File tree

src/lib/utils/explorer.ts

Lines changed: 88 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,99 +2,106 @@ interface Network {
22
name: string;
33
symbol: string;
44
decimals: number;
5-
explorer?: string; // Opcional para evitar erros
5+
explorer?: string;
66
rpcUrl?: string;
77
endpoint?: string;
88
}
99

10-
export const buildSubscanUrl = (
11-
network: Network,
12-
type: 'block' | 'extrinsic' | 'account' | 'runtime',
10+
type UrlType = 'block' | 'extrinsic' | 'account' | 'runtime';
11+
12+
13+
const SUBSCAN_DOMAIN = 'subscan.io';
14+
const DEFAULT_NETWORK = 'polkadot';
15+
const DEFAULT_FALLBACK_URL = `https://${DEFAULT_NETWORK}.${SUBSCAN_DOMAIN}`;
16+
17+
18+
const URL_PATHS: Record<UrlType, { singular: string; plural: string }> = {
19+
block: { singular: 'block', plural: 'blocks' },
20+
extrinsic: { singular: 'extrinsic', plural: 'extrinsics' },
21+
account: { singular: 'account', plural: '' },
22+
runtime: { singular: '', plural: '' }
23+
} as const;
24+
25+
26+
const isValidExplorerUrl = (explorerUrl?: string): explorerUrl is string => {
27+
return Boolean(
28+
explorerUrl?.trim() &&
29+
explorerUrl !== 'undefined' &&
30+
explorerUrl !== 'null'
31+
);
32+
};
33+
34+
35+
const normalizeNetworkName = (name?: string): string =>
36+
name?.toLowerCase().replace(/\s+/g, '-') || DEFAULT_NETWORK;
37+
38+
39+
const extractNetworkFromUrl = (url: string, fallbackName?: string): string => {
40+
try {
41+
const { hostname } = new URL(url);
42+
return hostname.split('.')[0] || normalizeNetworkName(fallbackName);
43+
} catch {
44+
return normalizeNetworkName(fallbackName);
45+
}
46+
};
47+
48+
49+
const buildUrlPath = (type: UrlType, identifier?: string | number): string => {
50+
const { singular, plural } = URL_PATHS[type];
51+
52+
if (!identifier) {
53+
return plural ? `/${plural}` : '';
54+
}
55+
56+
return singular ? `/${singular}/${identifier}` : '';
57+
};
58+
59+
60+
const createFallbackUrl = (
61+
networkName: string,
62+
type: UrlType,
1363
identifier?: string | number
1464
): string => {
15-
// Verificação de segurança inicial
16-
if (!network) {
17-
console.warn('Network object is null or undefined');
18-
return `https://polkadot.subscan.io/${type}${identifier ? `/${identifier}` : ''}`;
19-
}
65+
const baseUrl = `https://${networkName}.${SUBSCAN_DOMAIN}`;
66+
return `${baseUrl}${buildUrlPath(type, identifier)}`;
67+
};
68+
2069

21-
// Validação robusta do explorer URL
22-
const explorerUrl = network.explorer;
23-
24-
// Verifica se o explorer URL é válido
25-
if (!explorerUrl ||
26-
typeof explorerUrl !== 'string' ||
27-
explorerUrl.trim() === '' ||
28-
explorerUrl === 'undefined' ||
29-
explorerUrl === 'null') {
30-
31-
console.debug('Using fallback explorer URL for network:', network.name, 'explorer was:', explorerUrl);
32-
33-
// Fallback usando o nome da rede
34-
const networkName = network.name?.toLowerCase()?.replace(/\s+/g, '-') || 'polkadot';
35-
const fallbackUrl = `https://${networkName}.subscan.io`;
36-
37-
// Retorna URL baseado no tipo
38-
switch (type) {
39-
case 'block':
40-
return identifier ? `${fallbackUrl}/block/${identifier}` : `${fallbackUrl}/blocks`;
41-
case 'extrinsic':
42-
return identifier ? `${fallbackUrl}/extrinsic/${identifier}` : `${fallbackUrl}/extrinsics`;
43-
case 'account':
44-
return identifier ? `${fallbackUrl}/account/${identifier}` : fallbackUrl;
45-
case 'runtime':
46-
return fallbackUrl;
47-
default:
48-
return fallbackUrl;
49-
}
70+
const resolveBaseUrl = (network: Network): string => {
71+
if (!isValidExplorerUrl(network.explorer)) {
72+
console.debug('Using fallback explorer URL for network:', network.name, 'explorer was:', network.explorer);
73+
return `https://${normalizeNetworkName(network.name)}.${SUBSCAN_DOMAIN}`;
5074
}
5175

52-
// Remove barra final do URL base
53-
const baseUrl = explorerUrl.replace(/\/$/, '');
76+
const baseUrl = network.explorer.replace(/\/$/, '');
5477

55-
// Verifica se é um URL válido do Subscan
56-
if (!baseUrl.includes('subscan.io')) {
78+
if (!baseUrl.includes(SUBSCAN_DOMAIN)) {
5779
console.debug('Explorer URL is not a Subscan URL, creating fallback:', baseUrl);
58-
59-
// Tenta extrair o nome da rede do URL ou usa o nome da rede
60-
let networkName = 'polkadot';
61-
62-
try {
63-
const urlObj = new URL(baseUrl);
64-
const subdomain = urlObj.hostname.split('.')[0];
65-
networkName = subdomain || network.name?.toLowerCase()?.replace(/\s+/g, '-') || 'polkadot';
66-
} catch {
67-
networkName = network.name?.toLowerCase()?.replace(/\s+/g, '-') || 'polkadot';
68-
}
69-
70-
const fallbackUrl = `https://${networkName}.subscan.io`;
71-
72-
// Retorna URL baseado no tipo
73-
switch (type) {
74-
case 'block':
75-
return identifier ? `${fallbackUrl}/block/${identifier}` : `${fallbackUrl}/blocks`;
76-
case 'extrinsic':
77-
return identifier ? `${fallbackUrl}/extrinsic/${identifier}` : `${fallbackUrl}/extrinsics`;
78-
case 'account':
79-
return identifier ? `${fallbackUrl}/account/${identifier}` : fallbackUrl;
80-
case 'runtime':
81-
return fallbackUrl;
82-
default:
83-
return fallbackUrl;
84-
}
80+
const networkName = extractNetworkFromUrl(baseUrl, network.name);
81+
return `https://${networkName}.${SUBSCAN_DOMAIN}`;
8582
}
8683

87-
// URL válido do Subscan - constrói o URL final
88-
switch (type) {
89-
case 'block':
90-
return identifier ? `${baseUrl}/block/${identifier}` : `${baseUrl}/blocks`;
91-
case 'extrinsic':
92-
return identifier ? `${baseUrl}/extrinsic/${identifier}` : `${baseUrl}/extrinsics`;
93-
case 'account':
94-
return identifier ? `${baseUrl}/account/${identifier}` : baseUrl;
95-
case 'runtime':
96-
return baseUrl;
97-
default:
98-
return baseUrl;
84+
return baseUrl;
85+
};
86+
87+
/**
88+
* Builds Subscan URL for different resource types
89+
*
90+
* @param network - Network configuration object
91+
* @param type - Type of resource to link to
92+
* @param identifier - Optional identifier for the resource
93+
* @returns Complete Subscan URL
94+
*/
95+
export const buildSubscanUrl = (
96+
network: Network | null | undefined,
97+
type: UrlType,
98+
identifier?: string | number
99+
): string => {
100+
if (!network) {
101+
console.warn('Network object is null or undefined');
102+
return `${DEFAULT_FALLBACK_URL}${buildUrlPath(type, identifier)}`;
99103
}
104+
105+
const baseUrl = resolveBaseUrl(network);
106+
return `${baseUrl}${buildUrlPath(type, identifier)}`;
100107
};

0 commit comments

Comments
 (0)