Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
69 changes: 38 additions & 31 deletions app/account/[ownerEthAddr]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,41 +30,48 @@ const getCachedNodeOperatorProfile = unstable_cache(
{ revalidate: 60 },
);

export async function generateMetadata({ params }) {
const { ownerEthAddr } = await params;

if (!ownerEthAddr || !isAddress(ownerEthAddr) || isZeroAddress(ownerEthAddr)) {
return {
title: 'Error',
openGraph: {
title: 'Error',
},
};
}

try {
const [ensName, publicProfile] = await Promise.all([
cachedGetENSName(ownerEthAddr),
getCachedNodeOperatorProfile(ownerEthAddr as types.EthAddress),
export async function generateMetadata({ params }) {
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The params parameter is missing type annotations. According to Next.js best practices, this should be typed. Consider adding a type annotation like { params: Promise<{ ownerEthAddr: string }> } to improve type safety and catch potential errors at compile time.

Suggested change
export async function generateMetadata({ params }) {
export async function generateMetadata({
params,
}: {
params: Promise<{ ownerEthAddr: string }>;
}) {

Copilot uses AI. Check for mistakes.
const { ownerEthAddr } = await params;
const errorMetadata = {
title: 'Error',
openGraph: {
title: 'Error',
},
};

if (!ownerEthAddr || !isAddress(ownerEthAddr) || isZeroAddress(ownerEthAddr)) {
return errorMetadata;
}

const canonical = `/account/${encodeURIComponent(ownerEthAddr)}`;
const errorMetadataWithCanonical = {
...errorMetadata,
alternates: {
canonical,
},
};

try {
const [ensName, publicProfile] = await Promise.all([
cachedGetENSName(ownerEthAddr),
getCachedNodeOperatorProfile(ownerEthAddr as types.EthAddress),
]);

const primaryName = publicProfile?.name || ensName || getShortAddress(ownerEthAddr, 4, true);

return {
title: `Node Operator • ${primaryName}`,
openGraph: {
title: `Node Operator • ${primaryName}`,
},
};
} catch (error) {
return {
title: 'Error',
openGraph: {
title: 'Error',
},
};
}
}
return {
title: `Node Operator • ${primaryName}`,
openGraph: {
title: `Node Operator • ${primaryName}`,
},
alternates: {
canonical,
},
};
} catch (error) {
return errorMetadataWithCanonical;
}
}

export default async function NodeOperatorPage({ params }) {
const { ownerEthAddr } = await params;
Expand Down
26 changes: 18 additions & 8 deletions app/cloud-service-providers/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@ import CSPsList from '../server-components/CPSs/CSPsList';
import { BorderedCard } from '../server-components/shared/cards/BorderedCard';
import { CardHorizontal } from '../server-components/shared/cards/CardHorizontal';

export async function generateMetadata() {
return {
title: 'Cloud Service Providers',
openGraph: {
title: 'Cloud Service Providers',
},
};
}
export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ page?: string }> }) {
const resolvedSearchParams = await searchParams;
const pageParam = Number.parseInt(resolvedSearchParams?.page ?? '', 10);
const canonical =
Number.isFinite(pageParam) && pageParam > 1
? `/cloud-service-providers?page=${pageParam}`
: '/cloud-service-providers';

return {
title: 'Cloud Service Providers',
openGraph: {
title: 'Cloud Service Providers',
},
alternates: {
canonical,
},
};
}

export default async function CSPsPage(props: {
searchParams?: Promise<{
Expand Down
70 changes: 40 additions & 30 deletions app/license/[licenseType]/[licenseId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,49 @@ import * as types from '@/typedefs/blockchain';
import { Skeleton } from '@heroui/skeleton';
import { cache, Suspense } from 'react';

const errorMetadata = {
title: 'Error',
openGraph: {
title: 'Error',
},
};

export async function generateMetadata({ params }) {
const { licenseType, licenseId } = await params;

if (!licenseType || !['ND', 'MND', 'GND'].includes(licenseType)) {
return errorMetadata;
}
export async function generateMetadata({ params }) {
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The params parameter is missing type annotations. According to Next.js best practices, this should be typed. Consider adding a type annotation like { params: Promise<{ licenseType: string; licenseId: string }> } to improve type safety and catch potential errors at compile time.

Suggested change
export async function generateMetadata({ params }) {
export async function generateMetadata({
params,
}: { params: Promise<{ licenseType: string; licenseId: string }> }) {

Copilot uses AI. Check for mistakes.
const { licenseType, licenseId } = await params;
const errorMetadata = {
title: 'Error',
openGraph: {
title: 'Error',
},
};

if (!licenseType || !['ND', 'MND', 'GND'].includes(licenseType)) {
return errorMetadata;
}

const licenseIdNum = parseInt(licenseId);

if (isNaN(licenseIdNum) || licenseIdNum < 0 || licenseIdNum > 10000) {
return errorMetadata;
}

try {
await fetchLicense(licenseType, licenseId, config.environment);
} catch (error) {
return errorMetadata;
}

return {
title: `License #${licenseId}`,
openGraph: {
title: `License #${licenseId}`,
},
};
}
if (isNaN(licenseIdNum) || licenseIdNum < 0 || licenseIdNum > 10000) {
return errorMetadata;
}

const canonical = `/license/${encodeURIComponent(licenseType)}/${encodeURIComponent(licenseId)}`;
const errorMetadataWithCanonical = {
...errorMetadata,
alternates: {
canonical,
},
};

try {
await fetchLicense(licenseType, licenseId, config.environment);
} catch (error) {
return errorMetadataWithCanonical;
}

return {
title: `License #${licenseId}`,
openGraph: {
title: `License #${licenseId}`,
},
alternates: {
canonical,
},
};
}

const fetchLicense = async (
licenseType: 'ND' | 'MND' | 'GND',
Expand Down
23 changes: 15 additions & 8 deletions app/licenses/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@ import List from '../server-components/Licenses/List';
import { BorderedCard } from '../server-components/shared/cards/BorderedCard';
import { CardHorizontal } from '../server-components/shared/cards/CardHorizontal';

export async function generateMetadata() {
return {
title: 'Licenses',
openGraph: {
title: 'Licenses',
},
};
}
export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ page?: string }> }) {
const resolvedSearchParams = await searchParams;
const pageParam = Number.parseInt(resolvedSearchParams?.page ?? '', 10);
const canonical = Number.isFinite(pageParam) && pageParam > 1 ? `/licenses?page=${pageParam}` : '/licenses';

return {
title: 'Licenses',
openGraph: {
title: 'Licenses',
},
alternates: {
canonical,
},
};
}

export default async function LicensesPage(props: {
searchParams?: Promise<{
Expand Down
24 changes: 16 additions & 8 deletions app/node-operators/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@ import List from '../server-components/NodeOperators/List';
import { BorderedCard } from '../server-components/shared/cards/BorderedCard';
import { CardHorizontal } from '../server-components/shared/cards/CardHorizontal';

export async function generateMetadata() {
return {
title: 'Node Operators',
openGraph: {
title: 'Node Operators',
},
};
}
export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ page?: string }> }) {
const resolvedSearchParams = await searchParams;
const pageParam = Number.parseInt(resolvedSearchParams?.page ?? '', 10);
const canonical =
Number.isFinite(pageParam) && pageParam > 1 ? `/node-operators?page=${pageParam}` : '/node-operators';

return {
title: 'Node Operators',
openGraph: {
title: 'Node Operators',
},
alternates: {
canonical,
},
};
}

const fetchLicenseHolders = async (environment: 'mainnet' | 'testnet' | 'devnet') => {
const url = await getSSURL(`license-holders?env=${environment}`);
Expand Down
80 changes: 45 additions & 35 deletions app/node/[nodeAddr]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,9 @@ import * as types from '@/typedefs/blockchain';
import { RiCloseLine } from 'react-icons/ri';
import { isAddress } from 'viem';

const errorMetadata = {
title: 'Error',
openGraph: {
title: 'Error',
},
};

const resolveNodeEthAddress = (nodeAddress?: string): types.EthAddress | null => {
if (!nodeAddress) {
return null;
const resolveNodeEthAddress = (nodeAddress?: string): types.EthAddress | null => {
if (!nodeAddress) {
return null;
}

if (nodeAddress.startsWith('0xai_')) {
Expand All @@ -39,31 +32,48 @@ const resolveNodeEthAddress = (nodeAddress?: string): types.EthAddress | null =>
return nodeAddress;
};

export async function generateMetadata({ params }) {
const { nodeAddr } = await params;
const resolvedNodeEthAddr = resolveNodeEthAddress(nodeAddr);

if (!resolvedNodeEthAddr) {
console.log(`[Node Page] Invalid node address: ${nodeAddr}`);
return errorMetadata;
}

let nodeResponse: types.OraclesAvailabilityResult & types.OraclesDefaultResult;

try {
({ nodeResponse } = await fetchLicenseDetailsAndNodeAvailability(resolvedNodeEthAddr, config.environment));
} catch (error) {
console.error(error);
return errorMetadata;
}

return {
title: `Node • ${nodeResponse.node_alias}`,
openGraph: {
title: `Node • ${nodeResponse.node_alias}`,
},
};
}
export async function generateMetadata({ params }) {
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The params parameter is missing type annotations. According to Next.js best practices, this should be typed. Consider adding a type annotation like { params: Promise<{ nodeAddr: string }> } to improve type safety and catch potential errors at compile time.

Suggested change
export async function generateMetadata({ params }) {
export async function generateMetadata({ params }: { params: Promise<{ nodeAddr: string }> }) {

Copilot uses AI. Check for mistakes.
const { nodeAddr } = await params;
const errorMetadata = {
title: 'Error',
openGraph: {
title: 'Error',
},
};
const resolvedNodeEthAddr = resolveNodeEthAddress(nodeAddr);

if (!resolvedNodeEthAddr) {
console.log(`[Node Page] Invalid node address: ${nodeAddr}`);
return errorMetadata;
}

const canonical = `/node/${encodeURIComponent(nodeAddr)}`;
const errorMetadataWithCanonical = {
...errorMetadata,
alternates: {
canonical,
},
};

let nodeResponse: types.OraclesAvailabilityResult & types.OraclesDefaultResult;

try {
({ nodeResponse } = await fetchLicenseDetailsAndNodeAvailability(resolvedNodeEthAddr, config.environment));
} catch (error) {
console.error(error);
return errorMetadataWithCanonical;
}

return {
title: `Node • ${nodeResponse.node_alias}`,
openGraph: {
title: `Node • ${nodeResponse.node_alias}`,
},
alternates: {
canonical,
},
};
}

const fetchLicenseDetailsAndNodeAvailability = async (
nodeEthAddr: types.EthAddress,
Expand Down
12 changes: 12 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ import List from './server-components/Nodes/List';
import NodesListSkeleton from './server-components/Skeletons/NodesListSkeleton';
import { DetailedAlert } from './server-components/shared/DetailedAlert';

export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ page?: string }> }) {
const resolvedSearchParams = await searchParams;
const pageParam = Number.parseInt(resolvedSearchParams?.page ?? '', 10);
const canonical = Number.isFinite(pageParam) && pageParam > 1 ? `/?page=${pageParam}` : '/';

return {
alternates: {
canonical,
},
};
}

export default async function HomePage(props: {
searchParams?: Promise<{
page?: string;
Expand Down
12 changes: 12 additions & 0 deletions app/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ import { isNonZeroInteger } from '@/lib/utils';
import SearchResultsList from '../server-components/SearchResultsList';
import { BorderedCard } from '../server-components/shared/cards/BorderedCard';

export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ query?: string }> }) {
const resolvedSearchParams = await searchParams;
const rawQuery = resolvedSearchParams?.query?.trim();
const canonical = rawQuery ? `/search?query=${encodeURIComponent(rawQuery)}` : '/search';

return {
alternates: {
canonical,
},
};
}

export default async function SearchPage(props: {
searchParams?: Promise<{
query?: string;
Expand Down
Loading