diff --git a/scripts/finalize-sitemap.ts b/scripts/finalize-sitemap.ts index 6c959779..99f80807 100644 --- a/scripts/finalize-sitemap.ts +++ b/scripts/finalize-sitemap.ts @@ -8,6 +8,20 @@ const distSitemapPath = path.resolve('dist/public/sitemap.xml') const vercelSitemapPath = path.resolve('.vercel/output/static/sitemap.xml') const openApiMarkdownPath = path.resolve('dist/public/assets/md/docs/api') +async function findMarkdownRouteSlugs(directory: string, root = directory): Promise { + const entries = await fs.readdir(directory, { withFileTypes: true }) + const slugs = await Promise.all( + entries.map(async (entry) => { + const entryPath = path.join(directory, entry.name) + if (entry.isDirectory()) return findMarkdownRouteSlugs(entryPath, root) + if (!entry.isFile() || !entry.name.endsWith('.md')) return [] + const relativePath = path.relative(root, entryPath).slice(0, -'.md'.length) + return [relativePath.split(path.sep).join('/')] + }), + ) + return slugs.flat() +} + function getGitLastmod(filePath: string): string | undefined { try { const timestamp = execFileSync('git', ['log', '-1', '--format=%cI', '--', filePath], { @@ -49,17 +63,12 @@ const blogPosts = getBlogPostSlugs().map((slug) => ({ lastmod: getGitLastmod(`blogs/${slug}.md`), })) -const openApiRouteSlugs = await fs - .readdir(openApiMarkdownPath, { withFileTypes: true }) - .then((entries) => - entries - .filter((entry) => entry.isFile() && entry.name.endsWith('.md')) - .map((entry) => entry.name.slice(0, -'.md'.length)), - ) - .catch((error: NodeJS.ErrnoException) => { +const openApiRouteSlugs = await findMarkdownRouteSlugs(openApiMarkdownPath).catch( + (error: NodeJS.ErrnoException) => { if (error.code === 'ENOENT') return [] throw error - }) + }, +) const wroteDistSitemap = await writeFinalizedSitemap(distSitemapPath, blogPosts, openApiRouteSlugs) diff --git a/src/lib/sitemap.test.ts b/src/lib/sitemap.test.ts index fb912a6c..266b7fda 100644 --- a/src/lib/sitemap.test.ts +++ b/src/lib/sitemap.test.ts @@ -62,10 +62,15 @@ describe('finalizeSitemap', () => { }) it('adds generated OpenAPI routes without lastmod in stable order', () => { - const result = finalizeSitemap(sitemap, [], ['billing', 'activities', 'billing']) + const result = finalizeSitemap( + sitemap, + [], + ['billing', 'activities', 'funding/quotes', 'billing'], + ) expect(result).toContain('https://tempo.xyz/developers/docs/api/activities') expect(result).toContain('https://tempo.xyz/developers/docs/api/billing') + expect(result).toContain('https://tempo.xyz/developers/docs/api/funding/quotes') expect(result.indexOf('/api/activities')).toBeLessThan(result.indexOf('/api/billing')) expect(result).not.toMatch( /https:\/\/tempo\.xyz\/developers\/docs\/api\/(?:activities|billing)<\/loc>\s*/, diff --git a/src/lib/sitemap.ts b/src/lib/sitemap.ts index 27ddf8a6..1e3c735d 100644 --- a/src/lib/sitemap.ts +++ b/src/lib/sitemap.ts @@ -51,7 +51,7 @@ export function finalizeSitemap( const openApiBaseUrl = `${openApiIndexUrl.replace(/\/$/, '')}/` entries.push( ...uniqueOpenApiSlugs.map((slug) => ({ - location: `${openApiBaseUrl}${encodeURIComponent(slug)}`, + location: `${openApiBaseUrl}${slug.split('/').map(encodeURIComponent).join('/')}`, })), ) } diff --git a/src/pages/docs/api.mdx b/src/pages/docs/api.mdx index ebd4f659..9e18edd6 100644 --- a/src/pages/docs/api.mdx +++ b/src/pages/docs/api.mdx @@ -73,7 +73,7 @@ Create production and sandbox API keys in [Tempo API Console](https://console.te - **Track and reconcile a stablecoin payment.** Look up the [transaction and receipt](/docs/api/transactions), then inspect its [transaction activities](/docs/api/activities#list-transaction-activities) to confirm the token movement. Use [webhooks](/docs/api/webhooks) when your backend needs signed event callbacks. - **Monitor an account.** Read [balances](/docs/api/balances) and [activity](/docs/api/activities) to build payment history, treasury, or account views. -- **Fund and exchange stablecoins.** Compare [funding quotes](/docs/api/quotes) across supported chains and providers, then [create a transfer](/docs/api/transfers) or [create a reusable deposit address](/docs/api/deposit-addresses). Use [exchange quotes](/docs/api/exchange) to prepare unsigned approval and swap calls for you to sign and submit. +- **Fund and exchange stablecoins.** Compare [funding quotes](/docs/api/funding/quotes) across supported chains and providers, then [create a transfer](/docs/api/funding/transfers) or [create a reusable deposit address](/docs/api/funding/deposit-addresses). Use [exchange quotes](/docs/api/exchange) to prepare unsigned approval and swap calls for you to sign and submit. - **Sponsor transaction fees.** Use the [Fee Payer API](/docs/api/fee-payer) to apply sponsorship policy and fill, sponsor, and broadcast user transactions. - **Query custom payment data.** Use the [Indexer API](/docs/api/indexer-api) for read-only SQL across indexed blocks, transactions, receipts, logs, transfers, and exchange data. - **Prepare a production integration.** Create projects and keys in [Tempo API Console](/docs/api/console), then review [authentication](/docs/api/authentication), [rate limits](/docs/api/rate-limits), and [errors](/docs/api/errors). diff --git a/src/pages/docs/api/faq.mdx b/src/pages/docs/api/faq.mdx index e87522be..3d465c65 100644 --- a/src/pages/docs/api/faq.mdx +++ b/src/pages/docs/api/faq.mdx @@ -25,7 +25,7 @@ Read the [transaction and receipt](/docs/api/transactions) to follow execution, ## Does the Tempo Funding API execute a transfer? -No. The [Funding API](/docs/api/quotes) compares live quotes across supported chains and providers, but it does not execute a transfer. Execute the chosen transfer separately. +No. The [Funding API](/docs/api/funding/quotes) compares live quotes across supported chains and providers, but it does not execute a transfer. Execute the chosen transfer separately. ## Does the Tempo Exchange API submit a transaction?