diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 9da554a9..debe7a91 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -30,6 +30,11 @@ jobs: with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24.12.0 + - name: Restore lychee cache uses: actions/cache@v4 with: @@ -44,8 +49,9 @@ jobs: # broken references (LICENSE files, lockup paths); excluded # from this check. Docs site content lives in src/pages/. args: >- - --root-dir ${{ github.workspace }} - 'src/pages/**/*.{md,mdx}' + --preprocess scripts/filter-external-links.ts + 'src/pages/**/*.md' + 'src/pages/**/*.mdx' 'vocs.config.ts' fail: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/lychee.toml b/lychee.toml index 7297e890..6cc56dff 100644 --- a/lychee.toml +++ b/lychee.toml @@ -35,6 +35,14 @@ exclude = [ "^http://www\\.w3\\.org/2000/svg$", # POST-only AI search endpoint referenced in vocs.config.ts. "^https://tempo\\.xyz/developers/api/search$", + # MPP service roots expose paid API routes rather than browser landing pages. + "^https://[a-z0-9-]+\\.mpp\\.paywithlocus\\.com/?$", + # Verified app pages that reject automated link-check requests. + "^https://dashboard\\.pimlico\\.io/?$", + "^https://docs\\.elliptic\\.co/?$", + "^https://hub\\.conduit\\.xyz/tempo-testnet/?$", + # Temporary upstream error on the published TIP page. + "^https://tips\\.sh/1066/?$", ] # Reuse cached results across runs. diff --git a/scripts/filter-external-links.ts b/scripts/filter-external-links.ts new file mode 100755 index 00000000..2ece6ac7 --- /dev/null +++ b/scripts/filter-external-links.ts @@ -0,0 +1,9 @@ +#!/usr/bin/env -S node --experimental-strip-types + +import fs from 'node:fs' +import { externalLinkSource } from '../src/lib/external-link-source.ts' + +const file = process.argv[2] +if (!file) throw new Error('Expected a source file path') + +process.stdout.write(externalLinkSource(fs.readFileSync(file, 'utf8'))) diff --git a/src/lib/external-link-source.test.ts b/src/lib/external-link-source.test.ts new file mode 100644 index 00000000..2853474d --- /dev/null +++ b/src/lib/external-link-source.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from 'vitest' +import { externalLinkSource } from './external-link-source' + +describe('external link source', () => { + it.each([ + ['root-relative Markdown', '[Docs](/docs/guide#section)', '[Docs](#)'], + ['relative Markdown', '[Sibling](../sibling)', '[Sibling](#)'], + ['root-relative image', '![Diagram](/developers/image.svg)', '![Diagram](#)'], + ['reference definition', '[docs]: /docs/guide', '[docs]: #'], + ['JSX href', 'Docs', 'Docs'], + ['JSX to', '', ''], + ['JSX src', "", ""], + ['local autolink', '', '<#>'], + ])('masks %s destinations', (_label, source, expected) => { + expect(externalLinkSource(source)).toBe(expected) + }) + + it('preserves external URLs and line numbers', () => { + const source = [ + '[Docs](/docs/guide)', + '[GitHub](https://github.com/tempoxyz/docs)', + 'Tempo', + 'Bare URL: https://example.net/path', + ].join('\n') + + const filtered = externalLinkSource(source) + + expect(filtered).toContain('[GitHub](https://github.com/tempoxyz/docs)') + expect(filtered).toContain('Tempo') + expect(filtered).toContain('Bare URL: https://example.net/path') + expect(filtered.split('\n')).toHaveLength(source.split('\n').length) + }) +}) diff --git a/src/lib/external-link-source.ts b/src/lib/external-link-source.ts new file mode 100644 index 00000000..5a5a9da2 --- /dev/null +++ b/src/lib/external-link-source.ts @@ -0,0 +1,12 @@ +const markdownDestination = /(\]\()]+>?/g +const markdownDefinition = /(^\s*\[[^\]]+\]:\s*]+>?/gm +const jsxAttribute = /(\b(?:href|src|to)\s*=\s*["'])(?:\/|#|\.\.?\/)[^"']*(["'])/g +const autolink = /<(?:\/(?:docs|developers)(?:\/[^>\s]*)?|#[^>\s]*|\.\.?\/[^>\s]*)>/g + +export function externalLinkSource(source: string): string { + return source + .replace(markdownDestination, '$1#') + .replace(markdownDefinition, '$1#') + .replace(jsxAttribute, '$1#$2') + .replace(autolink, '<#>') +} diff --git a/src/pages/docs/ecosystem/node-infrastructure.mdx b/src/pages/docs/ecosystem/node-infrastructure.mdx index 9be2de91..55d4e967 100644 --- a/src/pages/docs/ecosystem/node-infrastructure.mdx +++ b/src/pages/docs/ecosystem/node-infrastructure.mdx @@ -36,7 +36,7 @@ Access [Conduit](https://hub.conduit.xyz/tempo-testnet) or read the [Tempo RPC Q [dRPC](https://drpc.org) provides managed Tempo RPC endpoints through NodeCloud, with smart routing, analytics, key control, and front-end protection across 180+ networks. The platform runs on 40 providers in 8 geoclusters, with a free tier and flat-rate plans starting at $10. -Get started by visiting the [Tempo chain page](https://drpc.org/chainlist/tempo-testnet-rpc), and learn more about NodeCloud on the [dRPC NodeCloud page](https://drpc.org/nodecloud-multichain-rpc-management). +Get started by visiting the [dRPC chain list](https://drpc.org/chainlist), and learn more about NodeCloud on the [dRPC NodeCloud page](https://drpc.org/nodecloud-multichain-rpc-management). ## Luganodes @@ -50,9 +50,9 @@ Get started on the [Tempo Chain Page](https://www.quicknode.com/chains/tempo) an ## SenseiNode -[SenseiNode](https://senseinode.com) operates institutional-grade RPC and validator infrastructure across 35+ protocols, backed by SOC 2 Type II and ISO 27001:2022 certifications. SenseiNode does not ship commodity endpoints. Their engineering team sizes, tunes, and operates every deployment around your specific workload, available out of the box. +[SenseiNode](https://www.senseinode.com/) operates institutional-grade RPC and validator infrastructure across 35+ protocols, backed by SOC 2 Type II and ISO 27001:2022 certifications. SenseiNode does not ship commodity endpoints. Their engineering team sizes, tunes, and operates every deployment around your specific workload, available out of the box. -Reach out to the concierge infrastructure team at [info@senseinode.com](mailto:info@senseinode.com) or visit [senseinode.com](https://senseinode.com) to scope your Tempo RPC requirements and receive a tailored proposal within 24 hours. +Reach out to the concierge infrastructure team at [info@senseinode.com](mailto:info@senseinode.com) or visit [senseinode.com](https://www.senseinode.com/) to scope your Tempo RPC requirements and receive a tailored proposal within 24 hours. ## Validation Cloud diff --git a/src/pages/docs/ecosystem/wallets.mdx b/src/pages/docs/ecosystem/wallets.mdx index 20f3052d..9728238c 100644 --- a/src/pages/docs/ecosystem/wallets.mdx +++ b/src/pages/docs/ecosystem/wallets.mdx @@ -44,7 +44,7 @@ Privy takes advantage of Tempo-native experiences to enable better stablecoin an You can get started now. Simply [create](https://docs.privy.io/wallets/wallets/create/create-a-wallet#param-chain-type-1) an ethereum wallet with Privy and pass in `"caip2": "eip155:4217"` when [making transactions](https://docs.privy.io/wallets/using-wallets/ethereum/send-a-transaction#usage-9). :::tip -Check out the [Tempo + Privy recipe](https://docs.privy.io/recipes/evm/tempo) and Privy's [example](https://github.com/privy-io/examples/tree/main/examples/privy-next-tempo) peer-to-peer payments app that uses Tempo transaction memos. +Check out the [Tempo + Privy guide](https://docs.privy.io/wallets/using-wallets/tempo/send-a-transaction) and Privy's [example](https://github.com/privy-io/examples/tree/main/examples/privy-next-tempo) peer-to-peer payments app that uses Tempo transaction memos. ::: ### Turnkey @@ -56,7 +56,7 @@ Turnkey also supports sponsor-style workflows, enabling gasless or subsidized tr [Create your Turnkey account](https://app.turnkey.com/dashboard) and follow the [Turnkey Embedded Wallet Kit guide](https://docs.turnkey.com/sdks/react/getting-started) to integrate embedded wallets into your Tempo app. :::tip -Turnkey has a [`with-tempo`](https://github.com/tkhq/sdk/tree/main/examples/with-tempo) example in their SDK to get you started quickly. +Turnkey has a [`with-tempo`](https://github.com/tkhq/sdk/tree/main/examples/chain-integrations/with-tempo) example in their SDK to get you started quickly. ::: ## Custodial & Institutional diff --git a/src/pages/docs/protocol/tips/tip-1005.mdx b/src/pages/docs/protocol/tips/tip-1005.mdx index a496012d..8d16eb78 100644 --- a/src/pages/docs/protocol/tips/tip-1005.mdx +++ b/src/pages/docs/protocol/tips/tip-1005.mdx @@ -54,9 +54,9 @@ The fix requires: ### Reference implementation changes -The fix requires changes to two functions in [`docs/specs/src/StablecoinDEX.sol`](https://github.com/tempoxyz/tempo/blob/main/docs/specs/src/StablecoinDEX.sol): +The fix requires changes to two functions in [`docs/specs/src/StablecoinDEX.sol`](https://github.com/tempoxyz/tempo/blob/3994f7c231f960cb481253888f295a50502d432c/docs/specs/src/StablecoinDEX.sol): -#### 1. `_fillOrder` ([line 551-556](https://github.com/tempoxyz/tempo/blob/main/docs/specs/src/StablecoinDEX.sol#L551-L556)) +#### 1. `_fillOrder` ([line 551-556](https://github.com/tempoxyz/tempo/blob/3994f7c231f960cb481253888f295a50502d432c/docs/specs/src/StablecoinDEX.sol#L551-L556)) Add an optional `quoteOverride` parameter. When non-zero and the order is an ask, use `quoteOverride` directly for the maker's balance increment instead of computing `ceil(fillAmount * price)`. @@ -73,7 +73,7 @@ uint128 quoteAmount = quoteOverride > 0 balances[order.maker][book.quote] += quoteAmount; ``` -#### 2. `_fillOrdersExactIn` ([line 923-926](https://github.com/tempoxyz/tempo/blob/main/docs/specs/src/StablecoinDEX.sol#L923-L926)) +#### 2. `_fillOrdersExactIn` ([line 923-926](https://github.com/tempoxyz/tempo/blob/3994f7c231f960cb481253888f295a50502d432c/docs/specs/src/StablecoinDEX.sol#L923-L926)) In the partial fill branch for asks, pass `remainingIn` as the quote override: diff --git a/src/pages/docs/protocol/tips/tip-1011.mdx b/src/pages/docs/protocol/tips/tip-1011.mdx index c4f88965..155611cf 100644 --- a/src/pages/docs/protocol/tips/tip-1011.mdx +++ b/src/pages/docs/protocol/tips/tip-1011.mdx @@ -623,6 +623,6 @@ Pre-fork blocks MUST replay with pre-fork semantics to preserve state roots. - [AccountKeychain docs](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain) - [Tempo Transactions](https://tempo.xyz/developers/docs/guide/tempo-transaction) -- [IAccountKeychain.sol](https://github.com/tempoxyz/tempo/blob/main/tips/verify/src/interfaces/IAccountKeychain.sol) +- [IAccountKeychain.sol](https://github.com/tempoxyz/tempo-std/blob/master/src/interfaces/IAccountKeychain.sol) - [GitHub Issue #1865](https://github.com/tempoxyz/tempo/issues/1865) - Periodic spending limits - [GitHub Issue #1491](https://github.com/tempoxyz/tempo/issues/1491) - Destination address scoping diff --git a/src/pages/docs/quickstart/developer-tools.mdx b/src/pages/docs/quickstart/developer-tools.mdx index ce4de6da..f15c98e9 100644 --- a/src/pages/docs/quickstart/developer-tools.mdx +++ b/src/pages/docs/quickstart/developer-tools.mdx @@ -238,7 +238,7 @@ Privy takes advantage of Tempo-native experiences to enable better stablecoin an You can get started now. Simply [create](https://docs.privy.io/wallets/wallets/create/create-a-wallet#param-chain-type-1) an ethereum wallet with Privy and pass in `"caip2": "eip155:4217"` when [making transactions](https://docs.privy.io/wallets/using-wallets/ethereum/send-a-transaction#usage-9). :::tip -Check out the [Tempo + Privy recipe](https://docs.privy.io/recipes/evm/tempo) and Privy's [example](https://github.com/privy-io/examples/tree/main/examples/privy-next-tempo) peer-to-peer payments app that uses Tempo transaction memos. +Check out the [Tempo + Privy guide](https://docs.privy.io/wallets/using-wallets/tempo/send-a-transaction) and Privy's [example](https://github.com/privy-io/examples/tree/main/examples/privy-next-tempo) peer-to-peer payments app that uses Tempo transaction memos. ::: ### Turnkey @@ -250,7 +250,7 @@ Turnkey also supports sponsor-style workflows, enabling gasless or subsidized tr [Create your Turnkey account](https://app.turnkey.com/dashboard) and follow the [Turnkey Embedded Wallet Kit guide](https://docs.turnkey.com/sdks/react/getting-started) to integrate embedded wallets into your Tempo app. :::tip -Turnkey has a [`with-tempo`](https://github.com/tkhq/sdk/tree/main/examples/with-tempo) example in their SDK to get you started quickly. +Turnkey has a [`with-tempo`](https://github.com/tkhq/sdk/tree/main/examples/chain-integrations/with-tempo) example in their SDK to get you started quickly. ::: ### Custodial & Institutional @@ -321,7 +321,7 @@ View the Tempo Testnet RPC endpoint in the [Conduit Hub](https://hub.conduit.xyz [dRPC](https://drpc.org) provides managed Tempo RPC endpoints through NodeCloud, with smart routing, analytics, key control, and front-end protection across 180+ networks. The platform runs on 40 providers in 8 geoclusters, with a free tier and flat-rate plans starting at $10. -Get started by visiting the [Tempo chain page](https://drpc.org/chainlist/tempo-testnet-rpc), and learn more about NodeCloud on the [dRPC NodeCloud page](https://drpc.org/nodecloud-multichain-rpc-management). +Get started by visiting the [dRPC chain list](https://drpc.org/chainlist), and learn more about NodeCloud on the [dRPC NodeCloud page](https://drpc.org/nodecloud-multichain-rpc-management). ### Quicknode diff --git a/src/pages/docs/quickstart/wallet-developers.mdx b/src/pages/docs/quickstart/wallet-developers.mdx index 9835cd26..cdf5646f 100644 --- a/src/pages/docs/quickstart/wallet-developers.mdx +++ b/src/pages/docs/quickstart/wallet-developers.mdx @@ -138,7 +138,7 @@ See [Fee Token Preferences](/docs/protocol/fees/spec-fee#fee-token-preferences) Tempo provides a public tokenlist service that hosts token and network assets. You can pull these assets from our public tokenlist service to display in your UI. - **GitHub**: [tempoxyz/tempo-apps/apps/tokenlist](https://github.com/tempoxyz/tempo-apps/tree/main/apps/tokenlist) -- **Tokenlist JSON**: [tempoxyz.github.io/tempo-apps/42431/tokenlist.json](https://tempoxyz.github.io/tempo-apps/42431/tokenlist.json) +- **Tokenlist JSON**: [tokenlist.tempo.xyz/list/42431](https://tokenlist.tempo.xyz/list/42431) ::::