import { injectable } from 'tsyringe'; export type SearchParams = Record; export interface Params { pathname: string[]; } export default interface PageProps { params: Promise; searchParams?: Promise; } @injectable() export class UrlProvider { public async getUrl(props: PageProps): Promise { // @ts-expect-error: Next.js missing exports prevents ESM resolution with 'nodenext'. const headerList = await import('next/headers').then((headers) => headers.headers()); const { pathname } = await props.params; const url = new URL(`https://${headerList.get('host')}/${(pathname || [])?.join('/')}`); const queryParams = props ? await props.searchParams : null; if (queryParams) { url.search = this.toUrlSearchParams(queryParams).toString(); } return url; } private toUrlSearchParams(searchParams: Record): URLSearchParams { const params = new URLSearchParams(); Object.entries(searchParams).forEach(([key, value]) => { if (!value) { return; } if (Array.isArray(value)) { value.forEach((v) => params.append(key, v)); } else { params.append(key, value); } }); return params; } }