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
6 changes: 4 additions & 2 deletions apps/explorer/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,11 @@ export const Route = createRootRouteWithContext<{
// Patch fetch/Request to strip basic auth credentials from same-origin URLs.
// Required for TanStack Start server functions (/_serverFn/...) which use
// relative fetches that inherit credentials from the page URL.
// Only activates when URL contains credentials (preview/staging environments).
// Always active because browsers hide URL credentials from JS (Location has
// no username/password, and Chrome strips them from location.href), making
// detection impossible. The patch is a no-op when no credentials are present.
scripts.push({
children: `(function(){var l=window.location;if(!l.username&&!l.password)return;var o=l.protocol+"//"+l.host;var F=window.fetch;var R=window.Request;var s=function(i){var u=i instanceof Request?i.url:String(i);try{var a=new URL(u,o);if(a.origin===o){a.username="";a.password="";}return a.href}catch(e){return null}};window.fetch=function(i,n){try{var h=s(i);if(h){if(i instanceof Request)return F.call(this,new R(h,i),n);return F.call(this,h,n)}}catch(e){}return F.call(this,i,n)};var W=function(i,n){var h=s(i);if(h)return new R(h,n||i);return new R(i,n)};W.prototype=R.prototype;window.Request=W;})();`,
children: `(function(){var o=window.location.protocol+"//"+window.location.host;var F=window.fetch;var R=window.Request;var s=function(i){var u=i instanceof Request?i.url:String(i);try{var a=new URL(u,o);if(a.origin===o){a.username="";a.password="";}return a.href}catch(e){return null}};window.fetch=function(i,n){try{var h=s(i);if(h){if(i instanceof Request)return F.call(this,new R(h,i),n);return F.call(this,h,n)}}catch(e){}return F.call(this,i,n)};var W=function(i,n){var h=s(i);if(h)return new R(h,n||i);return new R(i,n)};W.prototype=R.prototype;window.Request=W;})();`,
type: 'text/javascript',
})

Expand Down
8 changes: 7 additions & 1 deletion apps/explorer/src/routes/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ export const Route = createFileRoute('/_layout')({
validateSearch: z.object({
plain: z.optional(z.string()),
}).parse,
loader: () => fetchLatestBlock(),
loader: async () => {
try {
return await fetchLatestBlock()
} catch {
return 0n
}
},
})

function RouteComponent() {
Expand Down
56 changes: 28 additions & 28 deletions apps/explorer/src/wagmi.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import { tempoActions } from 'viem/tempo'
import { loadBalance, rateLimit } from '@tempo/rpc-utils'
import { tempoPresto } from './lib/chains'
import {
cookieStorage,
cookieToInitialState,
createConfig,
createStorage,
http,
serialize,
cookieStorage,
cookieToInitialState,
createConfig,
createStorage,
http,
serialize,
} from 'wagmi'
import { KeyManager, webAuthn } from 'wagmi/tempo'

Expand Down Expand Up @@ -64,12 +64,10 @@ const getRpcProxyUrl = createIsomorphicFn()
})

const getFallbackUrls = createIsomorphicFn()
.client(() => {
const chain = getTempoChain()
return {
http: chain.rpcUrls.default.http,
}
})
.client(() => ({
// Browser requests must never hit direct RPC fallbacks.
http: [] as string[],
}))
.server(() => {
const chain = getTempoChain()
const key = process.env.TEMPO_RPC_KEY
Expand All @@ -81,23 +79,25 @@ const getFallbackUrls = createIsomorphicFn()
})

const getTempoTransport = createIsomorphicFn()
.client(() => {
const proxy = getRpcProxyUrl()
const fallbackUrls = getFallbackUrls()
const proxyTransport = rateLimit(http(proxy.http), {
requestsPerSecond: 20,
})
const fallbackTransports = fallbackUrls.http.map((url) =>
rateLimit(http(url), { requestsPerSecond: 10 }),
)
.client(() => {
const proxy = getRpcProxyUrl()

return loadBalance([proxyTransport, ...fallbackTransports])
})
.server(() => {
const proxy = getRpcProxyUrl()
const fallbackUrls = getFallbackUrls()
return loadBalance([http(proxy.http), ...fallbackUrls.http.map(http)])
})
// Browser traffic should only hit the RPC proxy. Direct chain RPC endpoints
// may require credentials that are only available server-side.
return loadBalance([
rateLimit(http(proxy.http), {
requestsPerSecond: 20,
}),
])
})
.server(() => {
const proxy = getRpcProxyUrl()
const fallbackUrls = getFallbackUrls()
return loadBalance([
http(proxy.http),
...fallbackUrls.http.map((url) => http(url)),
])
})

export function getWagmiConfig() {
if (wagmiConfigSingleton) return wagmiConfigSingleton
Expand Down
Loading