diff --git a/.cursor/rules/contributor-workflow.mdc b/.cursor/rules/contributor-workflow.mdc index ff7cff8f8cf..efc76c21620 100644 --- a/.cursor/rules/contributor-workflow.mdc +++ b/.cursor/rules/contributor-workflow.mdc @@ -12,21 +12,24 @@ the requirements that are most often missed. Every new documentation page must be added to the appropriate sidebar file: -| Product | Sidebar file | -|----------------------|--------------------------| -| MetaMask Connect | `mm-connect-sidebar.js` | -| Embedded Wallets | `ew-sidebar.js` | -| Smart Accounts Kit | `gator-sidebar.js` | -| Agent Wallet | `agent-wallet-sidebar.js` | -| Services | `services-sidebar.js` | -| Developer dashboard | `dashboard-sidebar.js` | -| Snaps | `snaps-sidebar.js` | +| Product | Sidebar file | +| ------------------- | ------------------------- | +| MetaMask Connect | `mm-connect-sidebar.js` | +| Embedded Wallets | `ew-sidebar.js` | +| Smart Accounts Kit | `gator-sidebar.js` | +| Agent Wallet | `agent-wallet-sidebar.js` | +| Services | `services-sidebar.js` | +| Developer dashboard | `dashboard-sidebar.js` | +| Snaps | `snaps-sidebar.js` | ## Redirects Every deleted, renamed, or moved page must have a redirect added in `vercel.json`. Docusaurus is configured with `onBrokenLinks: 'throw'`, so broken internal links will fail the build. +Follow the trailing-slash rules in `vercel-redirects.mdc`: use a **slash-terminated `source`** +only (no duplicate no-slash entry), and a slash-terminated `destination` for normal paths. + ## Factual accuracy Do not state as fact any API behavior, parameter, or return value that you have not verified diff --git a/.cursor/rules/vercel-redirects.mdc b/.cursor/rules/vercel-redirects.mdc new file mode 100644 index 00000000000..7a180ce8348 --- /dev/null +++ b/.cursor/rules/vercel-redirects.mdc @@ -0,0 +1,81 @@ +--- +description: Vercel redirect rules for vercel.json — trailing-slash source patterns and what not to duplicate. +globs: vercel.json +alwaysApply: false +--- + +# Vercel redirects (`vercel.json`) + +Every deleted, renamed, or moved page needs a redirect in `vercel.json`. Docusaurus sets +`onBrokenLinks: 'throw'`, so fix internal links in the repo too. + +## Platform settings + +`vercel.json` sets `"trailingSlash": true` and `"cleanUrls": false`. Docusaurus also uses +`trailingSlash: true`. Redirect rules must match how Vercel actually routes requests. + +## Trailing-slash behavior + +With `trailingSlash: true`, Vercel **always normalizes** a no-slash URL to its slash form +**before** custom redirects run: + +```text +/foo/bar → 308 /foo/bar/ → (custom redirect, if source matches) +``` + +Therefore: + +- **`source` must end with `/`** for normal documentation paths. +- **Do not add a duplicate** no-slash `source` for the same redirect. Only `/foo/bar/` is + needed; `/foo/bar` is redundant. +- **`destination` must end with `/`** for normal documentation paths (unless the target is a + static file or includes a `#` fragment). + +### File-extension paths + +Paths whose final segment contains a dot (for example, `.html`, `.txt`) are treated as files. +Vercel does **not** append a trailing slash. Keep the **no-slash** `source` for those paths only. + +## Examples + +```json +// ✅ GOOD — one rule; works for both /old/path and /old/path/ +{ + "source": "/agent-wallet/get-started/quickstart/", + "destination": "/agent-wallet/quickstart/", + "permanent": true +} + +// ❌ BAD — no-slash source never matches after Vercel normalization +{ + "source": "/agent-wallet/get-started/quickstart", + "destination": "/agent-wallet/quickstart" +} + +// ❌ BAD — duplicate rules for the same redirect +{ + "source": "/agent-wallet/get-started/quickstart/", + "destination": "/agent-wallet/quickstart/" +}, +{ + "source": "/agent-wallet/get-started/quickstart", + "destination": "/agent-wallet/quickstart/" +} + +// ✅ GOOD — file path; no trailing slash on source +{ + "source": "/guide/ethereum-provider.html", + "destination": "/metamask-connect/evm/reference/provider-api/" +} +``` + +## Verify before merging + +Test the **slash** `source` (and optionally the no-slash entry URL, which should chain through): + +```bash +curl -sI -L "https://docs.metamask.io/old/path/" | grep -E "^HTTP|^location" +``` + +Expect a `308` chain ending in `200` at the destination. A `404` after a trailing-slash +normalization hop usually means the `source` is missing its final `/`. diff --git a/vercel.json b/vercel.json index 1fc0983976e..f850a1ea4d5 100644 --- a/vercel.json +++ b/vercel.json @@ -55,34 +55,18 @@ "source": "/whats-new/", "destination": "/" }, - { - "source": "/whats-new", - "destination": "/" - }, { "source": "/blog/", "destination": "/" }, - { - "source": "/blog", - "destination": "/" - }, { "source": "/search/", "destination": "/" }, - { - "source": "/search", - "destination": "/" - }, { "source": "/developer-tools/", "destination": "/developer-tools/dashboard/" }, - { - "source": "/developer-tools", - "destination": "/developer-tools/dashboard/" - }, { "source": "/developer-tools/dashboard/how-to/project-sharing/", "destination": "/developer-tools/dashboard/" @@ -221,19 +205,19 @@ }, { "source": "/wallet/reference/(eth_.*)", - "destination": "/metamask-connect/evm/reference/json-rpc-api/$1" + "destination": "/metamask-connect/evm/reference/json-rpc-api/$1/" }, { "source": "/wallet/reference/(wallet_.*)", - "destination": "/metamask-connect/evm/reference/json-rpc-api/$1" + "destination": "/metamask-connect/evm/reference/json-rpc-api/$1/" }, { "source": "/wallet/reference/(personal_.*)", - "destination": "/metamask-connect/evm/reference/json-rpc-api/$1" + "destination": "/metamask-connect/evm/reference/json-rpc-api/$1/" }, { "source": "/wallet/reference/(web3_.*)", - "destination": "/metamask-connect/evm/reference/json-rpc-api/$1" + "destination": "/metamask-connect/evm/reference/json-rpc-api/$1/" }, { "source": "/metamask-connect/guides/advanced/connect-and-sign/", @@ -609,27 +593,27 @@ }, { "source": "/services/get-started/", - "destination": "/services/get-started/infura" + "destination": "/services/get-started/infura/" }, { "source": "/services/how-to/", - "destination": "/services/how-to/avoid-rate-limiting" + "destination": "/services/how-to/avoid-rate-limiting/" }, { - "source": "/services/how-to/use-ipfs/access-ipfs-content", - "destination": "/services/how-to/use-ipfs/access-ipfs-content/dedicated-gateways" + "source": "/services/how-to/use-ipfs/access-ipfs-content/", + "destination": "/services/how-to/use-ipfs/access-ipfs-content/dedicated-gateways/" }, { "source": "/services/concepts/", - "destination": "/services/concepts/failover-protection" + "destination": "/services/concepts/failover-protection/" }, { "source": "/services/tutorials/", - "destination": "/services/tutorials/ethereum/authenticate-with-jwt" + "destination": "/services/tutorials/ethereum/authenticate-with-jwt/" }, { "source": "/services/tutorials/ethereum/", - "destination": "/services/tutorials/ethereum/authenticate-with-jwt" + "destination": "/services/tutorials/ethereum/authenticate-with-jwt/" }, { "source": "/services/tutorials/layer-2-networks/deploy-an-nft-smart-contract-on-palm/", @@ -780,258 +764,258 @@ "destination": "/metamask-connect/" }, { - "source": "/embedded-wallets/sdk/ios/usage/enableMFA", - "destination": "/embedded-wallets/sdk/ios/usage/enable-mfa", + "source": "/embedded-wallets/sdk/ios/usage/enableMFA/", + "destination": "/embedded-wallets/sdk/ios/usage/enable-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/ios/usage/getEd25519PrivKey", - "destination": "/embedded-wallets/sdk/ios/usage/get-ed25519-private-key", + "source": "/embedded-wallets/sdk/ios/usage/getEd25519PrivKey/", + "destination": "/embedded-wallets/sdk/ios/usage/get-ed25519-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/ios/usage/getPrivKey", - "destination": "/embedded-wallets/sdk/ios/usage/get-private-key", + "source": "/embedded-wallets/sdk/ios/usage/getPrivKey/", + "destination": "/embedded-wallets/sdk/ios/usage/get-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/ios/usage/getUserInfo", - "destination": "/embedded-wallets/sdk/ios/usage/get-user-info", + "source": "/embedded-wallets/sdk/ios/usage/getUserInfo/", + "destination": "/embedded-wallets/sdk/ios/usage/get-user-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/ios/usage/launchWalletServices", - "destination": "/embedded-wallets/sdk/ios/usage/launch-wallet-services", + "source": "/embedded-wallets/sdk/ios/usage/launchWalletServices/", + "destination": "/embedded-wallets/sdk/ios/usage/launch-wallet-services/", "permanent": true }, { - "source": "/embedded-wallets/sdk/ios/usage/manageMFA", - "destination": "/embedded-wallets/sdk/ios/usage/manage-mfa", + "source": "/embedded-wallets/sdk/ios/usage/manageMFA/", + "destination": "/embedded-wallets/sdk/ios/usage/manage-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/android/usage/enableMFA", - "destination": "/embedded-wallets/sdk/android/usage/enable-mfa", + "source": "/embedded-wallets/sdk/android/usage/enableMFA/", + "destination": "/embedded-wallets/sdk/android/usage/enable-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/android/usage/getEd25519PrivKey", - "destination": "/embedded-wallets/sdk/android/usage/get-ed25519-private-key", + "source": "/embedded-wallets/sdk/android/usage/getEd25519PrivKey/", + "destination": "/embedded-wallets/sdk/android/usage/get-ed25519-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/android/usage/getPrivKey", - "destination": "/embedded-wallets/sdk/android/usage/get-private-key", + "source": "/embedded-wallets/sdk/android/usage/getPrivKey/", + "destination": "/embedded-wallets/sdk/android/usage/get-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/android/usage/getUserInfo", - "destination": "/embedded-wallets/sdk/android/usage/get-user-info", + "source": "/embedded-wallets/sdk/android/usage/getUserInfo/", + "destination": "/embedded-wallets/sdk/android/usage/get-user-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/android/usage/launchWalletServices", - "destination": "/embedded-wallets/sdk/android/usage/launch-wallet-services", + "source": "/embedded-wallets/sdk/android/usage/launchWalletServices/", + "destination": "/embedded-wallets/sdk/android/usage/launch-wallet-services/", "permanent": true }, { - "source": "/embedded-wallets/sdk/android/usage/manageMFA", - "destination": "/embedded-wallets/sdk/android/usage/manage-mfa", + "source": "/embedded-wallets/sdk/android/usage/manageMFA/", + "destination": "/embedded-wallets/sdk/android/usage/manage-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/flutter/usage/enableMFA", - "destination": "/embedded-wallets/sdk/flutter/usage/enable-mfa", + "source": "/embedded-wallets/sdk/flutter/usage/enableMFA/", + "destination": "/embedded-wallets/sdk/flutter/usage/enable-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/flutter/usage/getEd25519PrivKey", - "destination": "/embedded-wallets/sdk/flutter/usage/get-ed25519-private-key", + "source": "/embedded-wallets/sdk/flutter/usage/getEd25519PrivKey/", + "destination": "/embedded-wallets/sdk/flutter/usage/get-ed25519-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/flutter/usage/getPrivKey", - "destination": "/embedded-wallets/sdk/flutter/usage/get-private-key", + "source": "/embedded-wallets/sdk/flutter/usage/getPrivKey/", + "destination": "/embedded-wallets/sdk/flutter/usage/get-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/flutter/usage/getUserInfo", - "destination": "/embedded-wallets/sdk/flutter/usage/get-user-info", + "source": "/embedded-wallets/sdk/flutter/usage/getUserInfo/", + "destination": "/embedded-wallets/sdk/flutter/usage/get-user-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/flutter/usage/launchWalletServices", - "destination": "/embedded-wallets/sdk/flutter/usage/launch-wallet-services", + "source": "/embedded-wallets/sdk/flutter/usage/launchWalletServices/", + "destination": "/embedded-wallets/sdk/flutter/usage/launch-wallet-services/", "permanent": true }, { - "source": "/embedded-wallets/sdk/flutter/usage/manageMFA", - "destination": "/embedded-wallets/sdk/flutter/usage/manage-mfa", + "source": "/embedded-wallets/sdk/flutter/usage/manageMFA/", + "destination": "/embedded-wallets/sdk/flutter/usage/manage-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/react-native/usage/enableMFA", - "destination": "/embedded-wallets/sdk/react-native/usage/enable-mfa", + "source": "/embedded-wallets/sdk/react-native/usage/enableMFA/", + "destination": "/embedded-wallets/sdk/react-native/usage/enable-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/react-native/usage/launchWalletServices", - "destination": "/embedded-wallets/sdk/react-native/usage/launch-wallet-services", + "source": "/embedded-wallets/sdk/react-native/usage/launchWalletServices/", + "destination": "/embedded-wallets/sdk/react-native/usage/launch-wallet-services/", "permanent": true }, { - "source": "/embedded-wallets/sdk/react-native/usage/ed25519Key", - "destination": "/embedded-wallets/sdk/react-native/usage/ed25519-key", + "source": "/embedded-wallets/sdk/react-native/usage/ed25519Key/", + "destination": "/embedded-wallets/sdk/react-native/usage/ed25519-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/react-native/usage/privKey", - "destination": "/embedded-wallets/sdk/react-native/usage/private-key", + "source": "/embedded-wallets/sdk/react-native/usage/privKey/", + "destination": "/embedded-wallets/sdk/react-native/usage/private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/react-native/usage/userInfo", - "destination": "/embedded-wallets/sdk/react-native/usage/user-info", + "source": "/embedded-wallets/sdk/react-native/usage/userInfo/", + "destination": "/embedded-wallets/sdk/react-native/usage/user-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unity/usage/enableMFA", - "destination": "/embedded-wallets/sdk/unity/usage/enable-mfa", + "source": "/embedded-wallets/sdk/unity/usage/enableMFA/", + "destination": "/embedded-wallets/sdk/unity/usage/enable-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unity/usage/getEd25519PrivKey", - "destination": "/embedded-wallets/sdk/unity/usage/get-ed25519-private-key", + "source": "/embedded-wallets/sdk/unity/usage/getEd25519PrivKey/", + "destination": "/embedded-wallets/sdk/unity/usage/get-ed25519-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unity/usage/getPrivKey", - "destination": "/embedded-wallets/sdk/unity/usage/get-private-key", + "source": "/embedded-wallets/sdk/unity/usage/getPrivKey/", + "destination": "/embedded-wallets/sdk/unity/usage/get-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unity/usage/getUserInfo", - "destination": "/embedded-wallets/sdk/unity/usage/get-user-info", + "source": "/embedded-wallets/sdk/unity/usage/getUserInfo/", + "destination": "/embedded-wallets/sdk/unity/usage/get-user-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unity/usage/launchWalletServices", - "destination": "/embedded-wallets/sdk/unity/usage/launch-wallet-services", + "source": "/embedded-wallets/sdk/unity/usage/launchWalletServices/", + "destination": "/embedded-wallets/sdk/unity/usage/launch-wallet-services/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unreal/usage/getEd25519PrivKey", - "destination": "/embedded-wallets/sdk/unreal/usage/get-ed25519-private-key", + "source": "/embedded-wallets/sdk/unreal/usage/getEd25519PrivKey/", + "destination": "/embedded-wallets/sdk/unreal/usage/get-ed25519-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unreal/usage/getPrivKey", - "destination": "/embedded-wallets/sdk/unreal/usage/get-private-key", + "source": "/embedded-wallets/sdk/unreal/usage/getPrivKey/", + "destination": "/embedded-wallets/sdk/unreal/usage/get-private-key/", "permanent": true }, { - "source": "/embedded-wallets/sdk/unreal/usage/getUserInfo", - "destination": "/embedded-wallets/sdk/unreal/usage/get-user-info", + "source": "/embedded-wallets/sdk/unreal/usage/getUserInfo/", + "destination": "/embedded-wallets/sdk/unreal/usage/get-user-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/enableMFA", - "destination": "/embedded-wallets/sdk/js/usage/enable-mfa", + "source": "/embedded-wallets/sdk/js/usage/enableMFA/", + "destination": "/embedded-wallets/sdk/js/usage/enable-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/getUserInfo", - "destination": "/embedded-wallets/sdk/js/usage/get-user-info", + "source": "/embedded-wallets/sdk/js/usage/getUserInfo/", + "destination": "/embedded-wallets/sdk/js/usage/get-user-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/manageMFA", - "destination": "/embedded-wallets/sdk/js/usage/manage-mfa", + "source": "/embedded-wallets/sdk/js/usage/manageMFA/", + "destination": "/embedded-wallets/sdk/js/usage/manage-mfa/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/getIdentityToken", - "destination": "/embedded-wallets/sdk/js/usage/get-auth-token-info", + "source": "/embedded-wallets/sdk/js/usage/getIdentityToken/", + "destination": "/embedded-wallets/sdk/js/usage/get-auth-token-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/get-identity-token", - "destination": "/embedded-wallets/sdk/js/usage/get-auth-token-info", + "source": "/embedded-wallets/sdk/js/usage/get-identity-token/", + "destination": "/embedded-wallets/sdk/js/usage/get-auth-token-info/", "permanent": true }, { - "source": "/embedded-wallets/sdk/react/hooks/useIdentityToken", - "destination": "/embedded-wallets/sdk/react/hooks/useAuthTokenInfo", + "source": "/embedded-wallets/sdk/react/hooks/useIdentityToken/", + "destination": "/embedded-wallets/sdk/react/hooks/useAuthTokenInfo/", "permanent": true }, { - "source": "/embedded-wallets/sdk/vue/composables/useIdentityToken", - "destination": "/embedded-wallets/sdk/vue/composables/useAuthTokenInfo", + "source": "/embedded-wallets/sdk/vue/composables/useIdentityToken/", + "destination": "/embedded-wallets/sdk/vue/composables/useAuthTokenInfo/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/showCheckout", - "destination": "/embedded-wallets/sdk/js/usage/show-checkout", + "source": "/embedded-wallets/sdk/js/usage/showCheckout/", + "destination": "/embedded-wallets/sdk/js/usage/show-checkout/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/showSwap", - "destination": "/embedded-wallets/sdk/js/usage/show-swap", + "source": "/embedded-wallets/sdk/js/usage/showSwap/", + "destination": "/embedded-wallets/sdk/js/usage/show-swap/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/showWalletConnectScanner", - "destination": "/embedded-wallets/sdk/js/usage/show-wallet-connect-scanner", + "source": "/embedded-wallets/sdk/js/usage/showWalletConnectScanner/", + "destination": "/embedded-wallets/sdk/js/usage/show-wallet-connect-scanner/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/showWalletUI", - "destination": "/embedded-wallets/sdk/js/usage/show-wallet-ui", + "source": "/embedded-wallets/sdk/js/usage/showWalletUI/", + "destination": "/embedded-wallets/sdk/js/usage/show-wallet-ui/", "permanent": true }, { - "source": "/embedded-wallets/sdk/js/usage/switchChain", - "destination": "/embedded-wallets/sdk/js/usage/switch-chain", + "source": "/embedded-wallets/sdk/js/usage/switchChain/", + "destination": "/embedded-wallets/sdk/js/usage/switch-chain/", "permanent": true }, { "source": "/embedded-wallets/sdk/js/migration-guides/:path*", - "destination": "/embedded-wallets/migration-guides/web", + "destination": "/embedded-wallets/migration-guides/web/", "permanent": true }, { "source": "/embedded-wallets/sdk/react/migration-guides/:path*", - "destination": "/embedded-wallets/migration-guides/web", + "destination": "/embedded-wallets/migration-guides/web/", "permanent": true }, { "source": "/embedded-wallets/sdk/vue/migration-guides/:path*", - "destination": "/embedded-wallets/migration-guides/web", + "destination": "/embedded-wallets/migration-guides/web/", "permanent": true }, { "source": "/embedded-wallets/sdk/android/migration-guides/:path*", - "destination": "/embedded-wallets/migration-guides/android", + "destination": "/embedded-wallets/migration-guides/android/", "permanent": true }, { "source": "/embedded-wallets/sdk/ios/migration-guides/:path*", - "destination": "/embedded-wallets/migration-guides/ios", + "destination": "/embedded-wallets/migration-guides/ios/", "permanent": true }, { "source": "/embedded-wallets/sdk/react-native/migration-guides/:path*", - "destination": "/embedded-wallets/migration-guides/react-native", + "destination": "/embedded-wallets/migration-guides/react-native/", "permanent": true }, { "source": "/embedded-wallets/sdk/flutter/migration-guides/:path*", - "destination": "/embedded-wallets/migration-guides/flutter", + "destination": "/embedded-wallets/migration-guides/flutter/", "permanent": true }, { - "source": "/agent-wallet/get-started/quickstart", - "destination": "/agent-wallet/quickstart", + "source": "/agent-wallet/get-started/quickstart/", + "destination": "/agent-wallet/quickstart/", "permanent": true } ]