Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
09aff98
adds clusters api configs
ayv8er Jun 22, 2025
18eeee5
adds clusters api configs
ayv8er Jun 22, 2025
3e8c016
adds api types
ayv8er Jun 22, 2025
073ff24
adds props routes and titles for cluster pages
ayv8er Jun 22, 2025
98c2ac4
adds query param enum for clusters api
ayv8er Jun 22, 2025
ebc3b21
adds clusters svg
ayv8er Jun 22, 2025
416e1ac
adds dynamic page routes
ayv8er Jun 22, 2025
489f650
adds clusters entity ui in ui/shared/entities
ayv8er Jun 22, 2025
3c78b55
adds functions to detect input type; will be used to check whether a …
ayv8er Jun 22, 2025
bcc9f55
adds stubs for loading skeleton view
ayv8er Jun 22, 2025
ba2481a
adds pagination hook
ayv8er Jun 23, 2025
6e82802
adds query param hooks for clusters trpc endpoints
ayv8er Jun 23, 2025
e3176db
adds query param hooks for clusters trpc endpoints
ayv8er Jun 23, 2025
f51fb65
adds components that make up the /clusters ui
ayv8er Jun 23, 2025
7abf89a
adds components for /cluster ui
ayv8er Jun 23, 2025
283ca0a
adds clusters api endpoint to query by cluster id
ayv8er Jun 23, 2025
31d0ae5
implements call to cluster id endpoint to get ac
ayv8er Jun 23, 2025
7603627
adds clusters search types and in api category
ayv8er Jun 23, 2025
0f30607
creates clusters search hook and wraps useQuickSearchQuery hook
ayv8er Jun 23, 2025
c5698ff
replaces useQuickSearchQuery for useSearchWithClusters hook for both …
ayv8er Jun 23, 2025
a2e02f1
add search suggestion ui
ayv8er Jun 23, 2025
b75739b
adds optional chaining to handle react re-render when search type cha…
ayv8er Jun 23, 2025
f50021c
adds cluster ui to ui/pages/address on address details
ayv8er Jun 24, 2025
912538f
prevents clicking on cluster suggestion if address is non EVM
ayv8er Jun 24, 2025
5c66c45
adds util functions for testability along with tests, for action bar …
ayv8er Jun 24, 2025
d74ebe0
refactor - extract clusters display logic wit
ayv8er Jun 24, 2025
370a674
refactor: extract page utilities from Clusters.tsx with tests
ayv8er Jun 24, 2025
9a11dc3
adds jest testing infra for react components
ayv8er Jun 25, 2025
265788d
adds hook testing coverage
ayv8er Jun 25, 2025
5176607
adds component and integration tests
ayv8er Jun 25, 2025
182daae
adds detectInputType util tests
ayv8er Jun 25, 2025
fb4f80a
removes generic parameters from clusters pagination types
ayv8er Jun 25, 2025
1603710
replaces any type with proper cluster config types
ayv8er Jun 25, 2025
aaa02d1
adds cluster routes to metadata and analytics mappings
ayv8er Jun 25, 2025
a21d2fd
updates order and stacks action bar items vertically when mobile view
ayv8er Jun 25, 2025
9888e77
repositions clusters logo
ayv8er Jun 25, 2025
88af76f
refactors search logic to render community clusters in search sugge
ayv8er Jun 25, 2025
75133fc
adding clusters env vars
ayv8er Jun 25, 2025
d37f17d
centers directory/leaderboard toggle in mobile view
ayv8er Jun 25, 2025
057d8e6
resizes and sets proper color to logo in entity component
ayv8er Jun 27, 2025
304766d
hides clusters nav when clusters env is missing
ayv8er Jun 30, 2025
ae4a40e
removes duplicate trailing slashes in cluster community names
ayv8er Jun 30, 2025
54c816f
Bump `react` to v19 (#2782)
maxaleks Jun 11, 2025
c4ad60c
change links to ton explorer
tom2drum Jun 6, 2025
38f9fed
fix internal links in ENVS.md file
tom2drum Jun 6, 2025
98277c2
tx info: tac operation stage could be an array
tom2drum Jun 9, 2025
65ea2a5
fix display of ad banner
maxaleks Jun 9, 2025
6a0ff19
tac ui updates
tom2drum Jun 9, 2025
7f8c6c2
add more "button click" events
tom2drum Jun 9, 2025
1f33137
update clock icon
tom2drum Jun 9, 2025
7caeec4
update screenshots
tom2drum Jun 9, 2025
27a601f
fix age filter reset
isstuev Jun 11, 2025
095c2d9
change tac operation status once again
tom2drum Jun 12, 2025
7076d36
fix address icon tooltip content
tom2drum Jun 13, 2025
24114c9
[skip ci] label released issues workflow: don't override release tag …
tom2drum Jun 16, 2025
dd0c1e3
puzzle-15 (#2471)
isstuev Jun 17, 2025
7fc0cf4
fix testnet and rollup stage badges
tom2drum Jun 18, 2025
090fcfd
New styles for pagination and "Add / Remove" buttons (#2791)
tom2drum Jun 23, 2025
a5c8693
Gas tracker: bug fixes and improvements (#2792)
tom2drum Jun 23, 2025
c2b8d30
Public tags form improvements (#2796)
tom2drum Jun 23, 2025
2b602a4
NFT marketplaces: make `collection_url` and `instance_url ` optional …
tom2drum Jun 23, 2025
52d481e
Bump brace-expansion from 1.1.11 to 1.1.12 in /deploy/tools/affected-…
dependabot[bot] Jun 25, 2025
82992d6
allow toaster to render custom description
tom2drum Jun 26, 2025
7b168f8
Encode the address hash for links to the TON chain (#2813)
tom2drum Jun 27, 2025
5adc1d8
Support redirects for known address discrepancies (#2799)
tom2drum Jun 30, 2025
97c31e9
Celo: support L2 epochs (#2784)
tom2drum Jun 30, 2025
1864a82
Icons in footer links (#2809)
tom2drum Jun 30, 2025
01557d2
Metadata: send address to fetchers once visited (#2814)
tom2drum Jun 30, 2025
c153dde
replaces jest-dom matchers with standard matchers
ayv8er Jul 1, 2025
fadeb3b
makes /clusters page default view the directory instead of leaderboar…
ayv8er Jul 2, 2025
99b687e
updates columnn name from backing to total backing, in leaderboard di…
ayv8er Jul 2, 2025
3e07a7f
alphabetically reorders clusters export
ayv8er Jul 2, 2025
387f225
adds Cluster section to the Table of Cont
ayv8er Jul 2, 2025
c2f506a
removes redundant Flex component wrapper around ClustersEntity
ayv8er Jul 2, 2025
671fdc7
uses standard toolkit values for border radius and color
ayv8er Jul 2, 2025
979eea5
uses getFeaturePayload util instead of type coercion
ayv8er Jul 2, 2025
1ff5248
extends ImageProps interface to ClusterIconProps, and uses getFeature…
ayv8er Jul 2, 2025
4527410
adds evm address regexp in regexp.ts as single source of truth
ayv8er Jul 3, 2025
76928cd
updates imports for files that used form validator address regexp to …
ayv8er Jul 3, 2025
4458aee
removes unused args, unnecessary type coercions and memoizations. upp…
ayv8er Jul 3, 2025
98c8e6c
sets correct action bar height using ACTION_BAR_HEIGHT_DESKTOP constant
ayv8er Jul 3, 2025
ee79771
implements TimeFormatToggle to Joined column
ayv8er Jul 3, 2025
bff04df
simplifies conditionals and removes unnecessary Box component wrapper
ayv8er Jul 3, 2025
4847ec6
displays standard 404 error screen on erroneous ClusterDetails query
ayv8er Jul 3, 2025
8bc9b8d
standardizes details page to display ETH value and time in line with …
ayv8er Jul 3, 2025
e0850bc
removes redundant debouncing
ayv8er Jul 3, 2025
3084704
moves useQueryParams hook to lib/router and updates imports and test …
ayv8er Jul 3, 2025
e0f0b74
moves config.features.cluster
ayv8er Jul 3, 2025
77cfe87
removes unnecessary 3rd column and isContractVerified since it is alw…
ayv8er Jul 3, 2025
6807e95
checks clusters enable for placeholder
ayv8er Jul 3, 2025
ab0ddf6
makes isClusterClickable condition more generic for future repurpose
ayv8er Jul 3, 2025
3168dce
splits isEvmAddress out to general purpose utility in lib/address, up…
ayv8er Jul 3, 2025
1456acf
moves all cluster hooks and tests to lib/clusters folder
ayv8er Jul 3, 2025
5b6d0ab
wraps action bar with standard button wrapper
ayv8er Jul 4, 2025
7b86f70
makes nextjs-routes mock condition stricter
ayv8er Jul 4, 2025
ee589ba
adds mock clusters api data
ayv8er Jul 7, 2025
50f5cbb
adds pw tests for cluster detail page
ayv8er Jul 7, 2025
80e9dab
adds pw tests for clusters directory page
ayv8er Jul 7, 2025
b195776
adds pw tests for clustersentity ui component
ayv8er Jul 7, 2025
f46c569
adds mock envs for pw tests
ayv8er Jul 7, 2025
844ed54
adds clusters api host and cdn url to env.pw
ayv8er Jul 7, 2025
a9fafeb
fixes resolve react-hooks/rules-of-hooks violation in cluster search …
ayv8er Jul 14, 2025
5374fb2
throws error instead of using app error component
ayv8er Jul 14, 2025
95b16ba
uses semantic token to reference color as per standard method in chak…
ayv8er Jul 14, 2025
4b855f7
removes empty or loading state pw tests
ayv8er Jul 14, 2025
e379292
pw tests - uses mockAssetResponse for icons, removes redundant tests,…
ayv8er Jul 14, 2025
1583a20
migrates all clusters pw tests from page.route to mockApiResponse
ayv8er Jul 14, 2025
47426b1
updates docker generated pw screenshots
ayv8er Jul 14, 2025
e87e345
removes object cloning in useSearchWithClusters hook
ayv8er Jul 15, 2025
441ccc2
uses standardized chakra name for backgroundColor
ayv8er Jul 15, 2025
510afad
resolves Clusters.pw.tsx docker screen generation issues and updates …
ayv8er Jul 15, 2025
4a47831
removes unneeded screenshots for Cluster.pw.tsx
ayv8er Jul 15, 2025
e86ac70
standardizes mobile testing approach with +@mobile tag by removing ex…
ayv8er Jul 15, 2025
a3cc84b
reverts expanded pw test coverage for ClustersEntity
ayv8er Jul 17, 2025
f7d6e92
removes all clusters pw screenshots
ayv8er Jul 17, 2025
dc07db6
removes nested describe which was resulting in a failed test
ayv8er Jul 17, 2025
20baa35
uploads latest docker generated screenshots for pw
ayv8er Jul 17, 2025
ef55984
force trigger for conflict check
ayv8er Jul 18, 2025
079ea87
Merge remote-tracking branch 'upstream/main' into clusters-page
ayv8er Jul 18, 2025
10fe80b
removes repeating var from blockchainNavItems array
ayv8er Jul 18, 2025
519a41a
fix screenshot merge conflicts - use upstream versions
ayv8er Jul 21, 2025
f7f73bf
updates yarn.lock with upstream lib
ayv8er Jul 21, 2025
def146e
fix jest tests by mocking useQuery directly to resolve QueryClient co…
ayv8er Jul 21, 2025
91758bb
creates global mock object and proper typing to reduce duplication
ayv8er Jul 22, 2025
5521e62
updates clusters pw screenshots with docker generation. update helia …
ayv8er Jul 29, 2025
082959b
updates yarn.lock
ayv8er Jul 29, 2025
06e3e9d
Merge branch 'main' into clusters-page
ayv8er Jul 30, 2025
011dbbd
removes unused imports from upstream/main
ayv8er Jul 30, 2025
eea01dc
add vite aliases for @libp2p/utils and @helia/verified-fetch to resol…
ayv8er Jul 31, 2025
8b55892
updates pw screenshots for hero banner, home page and desktop header
ayv8er Aug 6, 2025
dbe21aa
downgrades helia to v2.6.12
ayv8er Aug 6, 2025
d24db05
revert changes in yarn.lock file related to helia package
ayv8er Aug 6, 2025
314639a
updates yarn.lock with helia downgrade
ayv8er Aug 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 30 additions & 20 deletions configs/app/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,26 +100,6 @@ const rewardsApi = (() => {
endpoint: apiHost,
});
})();

const multichainApi = (() => {
const apiHost = getEnvValue('NEXT_PUBLIC_MULTICHAIN_AGGREGATOR_API_HOST');
if (!apiHost) {
return;
}

try {
const url = new URL(apiHost);

return Object.freeze({
endpoint: apiHost,
socketEndpoint: `wss://${ url.host }`,
});
} catch (error) {
return;
}

})();

const statsApi = (() => {
const apiHost = getEnvValue('NEXT_PUBLIC_STATS_API_HOST');
if (!apiHost) {
Expand Down Expand Up @@ -166,6 +146,35 @@ const visualizeApi = (() => {
});
})();

const clustersApi = (() => {
const apiHost = getEnvValue('NEXT_PUBLIC_CLUSTERS_API_HOST');
if (!apiHost) {
return;
}

return Object.freeze({
endpoint: apiHost,
});
})();

const multichainApi = (() => {
const apiHost = getEnvValue('NEXT_PUBLIC_MULTICHAIN_AGGREGATOR_API_HOST');
if (!apiHost) {
return;
}

try {
const url = new URL(apiHost);

return Object.freeze({
endpoint: apiHost,
socketEndpoint: `wss://${ url.host }`,
});
} catch (error) {
return;
}
})();

export type Apis = {
general: ApiPropsFull;
} & Partial<Record<Exclude<ApiName, 'general'>, ApiPropsBase>>;
Expand All @@ -174,6 +183,7 @@ const apis: Apis = Object.freeze({
general: generalApi,
admin: adminApi,
bens: bensApi,
clusters: clustersApi,
contractInfo: contractInfoApi,
metadata: metadataApi,
multichain: multichainApi,
Expand Down
26 changes: 26 additions & 0 deletions configs/app/features/clusters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Feature } from './types';

import apis from '../apis';
import { getEnvValue } from '../utils';

const title = 'Clusters Universal Name Service';

const config: Feature<{ cdnUrl: string }> = (() => {
const cdnUrl = getEnvValue('NEXT_PUBLIC_CLUSTERS_CDN_URL') || 'https://cdn.clusters.xyz';

if (apis.clusters) {
return Object.freeze({
title,
isEnabled: true,
cdnUrl,
});
}

return Object.freeze({
title,
isEnabled: false,
cdnUrl,
});
})();

export default config;
1 change: 1 addition & 0 deletions configs/app/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { default as beaconChain } from './beaconChain';
export { default as bridgedTokens } from './bridgedTokens';
export { default as blockchainInteraction } from './blockchainInteraction';
export { default as celo } from './celo';
export { default as clusters } from './clusters';
export { default as csvExport } from './csvExport';
export { default as dataAvailability } from './dataAvailability';
export { default as deFiDropdown } from './deFiDropdown';
Expand Down
4 changes: 4 additions & 0 deletions configs/envs/.env.jest
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx

# clusters feature
NEXT_PUBLIC_CLUSTERS_API_HOST=https://api.clusters.xyz
NEXT_PUBLIC_CLUSTERS_CDN_URL=https://cdn.clusters.xyz
4 changes: 4 additions & 0 deletions configs/envs/.env.localhost
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout

# clusters feature
NEXT_PUBLIC_CLUSTERS_API_HOST=https://api.clusters.xyz
NEXT_PUBLIC_CLUSTERS_CDN_URL=https://cdn.clusters.xyz
4 changes: 3 additions & 1 deletion configs/envs/.env.pw
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=xxx
NEXT_PUBLIC_VIEWS_ADDRESS_FORMAT=['base16','bech32']
NEXT_PUBLIC_VIEWS_ADDRESS_BECH_32_PREFIX=tom
NEXT_PUBLIC_HELIA_VERIFIED_FETCH_ENABLED=false
NEXT_PUBLIC_GAS_TRACKER_UNITS=['usd','gwei']
NEXT_PUBLIC_GAS_TRACKER_UNITS=['usd','gwei']
NEXT_PUBLIC_CLUSTERS_API_HOST=https://api.clusters.xyz
NEXT_PUBLIC_CLUSTERS_CDN_URL=https://cdn.clusters.xyz
4 changes: 3 additions & 1 deletion deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ const rollupSchema = yup
}),
});

const celoSchema = yup
const celoSchema = yup
.object()
.shape({
NEXT_PUBLIC_CELO_ENABLED: yup.boolean(),
Expand Down Expand Up @@ -1050,6 +1050,8 @@ const schema = yup
NEXT_PUBLIC_VISUALIZE_API_BASE_PATH: yup.string(),
NEXT_PUBLIC_CONTRACT_INFO_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_NAME_SERVICE_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_CLUSTERS_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_CLUSTERS_CDN_URL: yup.string().test(urlTest),
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_WEB3_WALLETS: yup
.mixed()
Expand Down
2 changes: 2 additions & 0 deletions deploy/values/review/values.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ frontend:
PROMETHEUS_METRICS_ENABLED: true
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED: true
NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED: true
NEXT_PUBLIC_CLUSTERS_API_HOST: https://api.clusters.xyz
NEXT_PUBLIC_CLUSTERS_CDN_URL: https://cdn.clusters.xyz
envFromSecret:
NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID
Expand Down
12 changes: 12 additions & 0 deletions docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ All json-like values should be single-quoted. If it contains a hash (`#`) or a d
- [Verified tokens info](#verified-tokens-info)
- [Name service integration](#name-service-integration)
- [Metadata service integration](#metadata-service-integration)
- [Clusters Universal Name Service](#clusters-universal-name-service)
- [Public tag submission](#public-tag-submission)
- [Data availability](#data-availability)
- [Bridged tokens](#bridged-tokens)
Expand Down Expand Up @@ -672,6 +673,17 @@ This feature allows name tags and other public tags for addresses.

&nbsp;

### Clusters Universal Name Service

This feature integrates Clusters.xyz universal naming service, enabling users to look up and track cross-chain identities through human-readable names like "vitalik/" or "uniswap/". Unlike traditional domain services that work on single chains, clusters span multiple blockchains - one cluster name can represent addresses on Ethereum, Base, Optimism, and other networks. This integration adds cluster lookup pages (/clusters/[name]), a clusters directory (/clusters), search functionality in the main search bar, and displays cluster profile information and images throughout the explorer.

| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_CLUSTERS_API_HOST | `string` | Clusters.xyz API endpoint for fetching cluster data, directory listings, and cross-chain address mappings | Required | - | `https://example.com/clusters-api` | v2.2.0+ |
| NEXT_PUBLIC_CLUSTERS_CDN_URL | `string` | CDN base URL for serving cluster profile images and avatars displayed in search results and cluster pages | - | `https://cdn.clusters.xyz` | `https://your-cdn.example.com` | v2.2.0+ |

&nbsp;

### Public tag submission

This feature allows you to submit an application with a public address tag.
Expand Down
14 changes: 14 additions & 0 deletions icons/clusters.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const config: JestConfigWithTsJest = {
],
moduleNameMapper: {
'^jest/(.*)': '<rootDir>/jest/$1',
'^nextjs-routes$': '<rootDir>/jest/mocks/nextjs-routes.js',
'\\.svg$': '<rootDir>/jest/mocks/svg.js',
'^@uidotdev/usehooks$': '<rootDir>/jest/mocks/usehooks.js',
},
modulePathIgnorePatterns: [
'node_modules_linux',
Expand Down
18 changes: 18 additions & 0 deletions jest/mocks/nextjs-routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
route: jest.fn((opts) => {
const pathname = opts?.pathname;
const query = opts?.query || {};

if (pathname === '/address/[hash]') {
return `/address/${ query.hash || 'test-hash' }`;
}
if (pathname === '/tx/[hash]') {
return `/tx/${ query.hash || 'test-hash' }`;
}
if (pathname === '/clusters/[name]') {
return `/clusters/${ query.name || 'test-cluster' }`;
}

return pathname || '/';
}),
};
1 change: 1 addition & 0 deletions jest/mocks/svg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'test-file-stub';
12 changes: 12 additions & 0 deletions jest/mocks/usehooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
useClickAway: jest.fn(() => jest.fn()),
useEventListener: jest.fn(),
useLocalStorage: jest.fn(() => [ '', jest.fn() ]),
useSessionStorage: jest.fn(() => [ '', jest.fn() ]),
useToggle: jest.fn(() => [ false, jest.fn() ]),
useDebounce: jest.fn((value) => value),
useThrottle: jest.fn((value) => value),
usePrevious: jest.fn(),
useCounter: jest.fn(() => ({ count: 0, increment: jest.fn(), decrement: jest.fn(), reset: jest.fn() })),
useCopyToClipboard: jest.fn(() => [ '', jest.fn() ]),
};
6 changes: 6 additions & 0 deletions lib/address/isEvmAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ADDRESS_REGEXP } from 'toolkit/utils/regexp';

export function isEvmAddress(address: string): boolean {
if (!address) return false;
return ADDRESS_REGEXP.test(address.trim());
}
6 changes: 6 additions & 0 deletions lib/api/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { AdminApiResourceName, AdminApiResourcePayload } from './services/a
import { ADMIN_API_RESOURCES } from './services/admin';
import { BENS_API_RESOURCES } from './services/bens';
import type { BensApiResourceName, BensApiResourcePayload, BensApiPaginationFilters, BensApiPaginationSorting } from './services/bens';
import { CLUSTERS_API_RESOURCES } from './services/clusters';
import type { ClustersApiResourceName, ClustersApiResourcePayload, ClustersApiPaginationFilters, ClustersApiPaginationSorting } from './services/clusters';
import { CONTRACT_INFO_API_RESOURCES } from './services/contractInfo';
import type { ContractInfoApiPaginationFilters, ContractInfoApiResourceName, ContractInfoApiResourcePayload } from './services/contractInfo';
import { GENERAL_API_RESOURCES } from './services/general';
Expand All @@ -30,6 +32,7 @@ import type { VisualizeApiResourceName, VisualizeApiResourcePayload } from './se
export const RESOURCES = {
admin: ADMIN_API_RESOURCES,
bens: BENS_API_RESOURCES,
clusters: CLUSTERS_API_RESOURCES,
contractInfo: CONTRACT_INFO_API_RESOURCES,
general: GENERAL_API_RESOURCES,
metadata: METADATA_API_RESOURCES,
Expand All @@ -53,6 +56,7 @@ export type ResourcePath = string;
export type ResourcePayload<R extends ResourceName> =
R extends AdminApiResourceName ? AdminApiResourcePayload<R> :
R extends BensApiResourceName ? BensApiResourcePayload<R> :
R extends ClustersApiResourceName ? ClustersApiResourcePayload<R> :
R extends ContractInfoApiResourceName ? ContractInfoApiResourcePayload<R> :
R extends GeneralApiResourceName ? GeneralApiResourcePayload<R> :
R extends MetadataApiResourceName ? MetadataApiResourcePayload<R> :
Expand Down Expand Up @@ -89,6 +93,7 @@ export type ResourceErrorAccount<T> = ResourceError<{ errors: T }>;
/* eslint-disable @stylistic/indent */
export type PaginationFilters<R extends ResourceName> =
R extends BensApiResourceName ? BensApiPaginationFilters<R> :
R extends ClustersApiResourceName ? ClustersApiPaginationFilters :
R extends GeneralApiResourceName ? GeneralApiPaginationFilters<R> :
R extends ContractInfoApiResourceName ? ContractInfoApiPaginationFilters<R> :
R extends TacOperationLifecycleApiResourceName ? TacOperationLifecycleApiPaginationFilters<R> :
Expand All @@ -100,6 +105,7 @@ export const SORTING_FIELDS = [ 'sort', 'order' ];
/* eslint-disable @stylistic/indent */
export type PaginationSorting<R extends ResourceName> =
R extends BensApiResourceName ? BensApiPaginationSorting<R> :
R extends ClustersApiResourceName ? ClustersApiPaginationSorting :
R extends GeneralApiResourceName ? GeneralApiPaginationSorting<R> :
never;
/* eslint-enable @stylistic/indent */
Expand Down
57 changes: 57 additions & 0 deletions lib/api/services/clusters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { ApiResource } from '../types';
import type {
ClustersByAddressResponse,
ClusterByNameResponse,
ClustersLeaderboardResponse,
ClustersDirectoryResponse,
ClustersByAddressQueryParams,
ClusterByNameQueryParams,
ClustersLeaderboardQueryParams,
ClustersDirectoryQueryParams,
ClusterByIdQueryParams,
ClusterByIdResponse,
} from 'types/api/clusters';

export const CLUSTERS_API_RESOURCES = {
get_clusters_by_address: {
path: '/v1/trpc/names.getNamesByOwnerAddress',
pathParams: [],
},
get_cluster_by_name: {
path: '/v1/trpc/names.get',
pathParams: [],
},
get_cluster_by_id: {
path: '/v1/trpc/clusters.getClusterById',
pathParams: [],
},
get_leaderboard: {
path: '/v1/trpc/names.leaderboard',
pathParams: [],
},
get_directory: {
path: '/v1/trpc/names.search',
pathParams: [],
},
} satisfies Record<string, ApiResource>;

export type ClustersApiResourceName = `clusters:${ keyof typeof CLUSTERS_API_RESOURCES }`;

export type ClustersApiResourcePayload<R extends ClustersApiResourceName> =
R extends 'clusters:get_clusters_by_address' ? ClustersByAddressResponse :
R extends 'clusters:get_cluster_by_name' ? ClusterByNameResponse :
R extends 'clusters:get_cluster_by_id' ? ClusterByIdResponse :
R extends 'clusters:get_leaderboard' ? ClustersLeaderboardResponse :
R extends 'clusters:get_directory' ? ClustersDirectoryResponse :
never;

export type ClustersApiQueryParams<R extends ClustersApiResourceName> =
R extends 'clusters:get_clusters_by_address' ? ClustersByAddressQueryParams :
R extends 'clusters:get_cluster_by_name' ? ClusterByNameQueryParams :
R extends 'clusters:get_cluster_by_id' ? ClusterByIdQueryParams :
R extends 'clusters:get_leaderboard' ? ClustersLeaderboardQueryParams :
R extends 'clusters:get_directory' ? ClustersDirectoryQueryParams :
never;

export type ClustersApiPaginationFilters = never;
export type ClustersApiPaginationSorting = never;
5 changes: 4 additions & 1 deletion lib/api/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export type ApiName = 'general' | 'admin' | 'bens' | 'contractInfo' | 'metadata' | 'multichain' | 'rewards' | 'stats' | 'tac' | 'userOps' | 'visualize';
export type ApiName =
'general' | 'admin' | 'bens' | 'contractInfo' | 'clusters' |
'metadata' | 'multichain' | 'rewards' | 'stats' | 'tac' |
'userOps' | 'visualize';

export interface ApiResource {
path: string;
Expand Down
Loading