diff --git a/src/components/StaticMermaidDiagram.tsx b/src/components/StaticMermaidDiagram.tsx deleted file mode 100644 index 8f1136de..00000000 --- a/src/components/StaticMermaidDiagram.tsx +++ /dev/null @@ -1,247 +0,0 @@ -'use client' - -import { useEffect, useRef, useState } from 'react' -import { estW, LAYOUT, THEMES, type ThemeColors } from './MermaidDiagram' - -// --------------------------------------------------------------------------- -// Types -// --------------------------------------------------------------------------- - -interface FlowNode { - id: string - label: string -} - -interface FlowEdge { - from: string - to: string - label: string -} - -interface ParsedFlowchart { - nodes: FlowNode[] - edges: FlowEdge[] -} - -// --------------------------------------------------------------------------- -// Parser — handles `flowchart TD` blocks -// --------------------------------------------------------------------------- - -function parseFlowchart(source: string): ParsedFlowchart { - const lines = source - .split('\n') - .map((l) => l.trim()) - .filter((l) => l && !l.startsWith('%%')) - const nodes = new Map() - const edges: FlowEdge[] = [] - - const ensureNode = (id: string, label?: string) => { - if (!nodes.has(id)) { - nodes.set(id, { id, label: label ?? id }) - } else if (label) { - const existing = nodes.get(id) - if (existing) existing.label = label - } - } - - // Extract id and optional label: id["label"] or just id - const parseNodeRef = (raw: string): { id: string; label?: string } => { - const m = raw.match(/^(\w+)\["(.+?)"\]$/) - if (m) return { id: m[1], label: m[2] } - return { id: raw.trim() } - } - - for (const line of lines) { - if (/^flowchart/i.test(line)) continue - - // Edge: from -->|"label"| to OR from --> to - const mEdge = line.match(/^(.+?)\s*-->(?:\|"(.+?)"\|)?\s*(.+)$/) - if (mEdge) { - const fromRef = parseNodeRef(mEdge[1].trim()) - const toRef = parseNodeRef(mEdge[3].trim()) - ensureNode(fromRef.id, fromRef.label) - ensureNode(toRef.id, toRef.label) - edges.push({ from: fromRef.id, to: toRef.id, label: mEdge[2] ?? '' }) - continue - } - - // Standalone node definition: id["label"] - const mNode = line.match(/^(\w+)\["(.+?)"\]$/) - if (mNode) { - ensureNode(mNode[1], mNode[2]) - } - } - - return { nodes: Array.from(nodes.values()), edges } -} - -// --------------------------------------------------------------------------- -// Layout constants for flowchart -// --------------------------------------------------------------------------- - -const FLOW = { - nodeH: 36, - nodePadX: 24, - nodeGapY: 40, - arrowSize: 7, -} - -// --------------------------------------------------------------------------- -// SVG renderer -// --------------------------------------------------------------------------- - -function renderFlowchart(parsed: ParsedFlowchart, th: ThemeColors): string { - const L = LAYOUT - const F = FLOW - const o: string[] = [] - - // Measure node widths - const nodeW = parsed.nodes.map((n) => estW(n.label, L.actorFontSize) + F.nodePadX * 2) - const maxW = Math.max(...nodeW) - - // Use uniform width for clean vertical alignment - const uniformW = maxW - - // Account for edge labels rendered to the right of center - const maxLabelW = parsed.edges.reduce( - (max, e) => (e.label ? Math.max(max, estW(e.label, L.labelFontSize)) : max), - 0, - ) - - // Center x - const padding = L.padding - const cx = padding + uniformW / 2 - const totalW = Math.max(uniformW + padding * 2, cx + uniformW / 2 + 10 + maxLabelW + padding) - - // Compute node y positions - const nodeY: number[] = [] - let y = padding - for (let i = 0; i < parsed.nodes.length; i++) { - nodeY.push(y) - if (i < parsed.nodes.length - 1) { - y += F.nodeH + F.nodeGapY - } - } - const totalH = y + F.nodeH + padding - - const nodeIdx = new Map() - for (let i = 0; i < parsed.nodes.length; i++) { - nodeIdx.set(parsed.nodes[i].id, i) - } - - o.push( - ``, - ) - o.push(``) - - // Edges (draw before nodes so lines go behind) - for (const e of parsed.edges) { - const fi = nodeIdx.get(e.from) - const ti = nodeIdx.get(e.to) - if (fi === undefined || ti === undefined) continue - - const fromY = nodeY[fi] + F.nodeH - const toY = nodeY[ti] - const sz = F.arrowSize - - // Vertical line - o.push( - ``, - ) - - // Arrow - o.push( - ``, - ) - - // Edge label - if (e.label) { - const midY = (fromY + toY) / 2 - o.push( - `${esc(e.label)}`, - ) - } - } - - // Nodes - for (let i = 0; i < parsed.nodes.length; i++) { - const n = parsed.nodes[i] - const nw = uniformW - const nx = cx - nw / 2 - const ny = nodeY[i] - - o.push( - ``, - ) - o.push( - `${esc(n.label)}`, - ) - } - - o.push('') - return o.join('\n') -} - -function esc(s: string): string { - return s - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') -} - -// --------------------------------------------------------------------------- -// React component -// --------------------------------------------------------------------------- - -export function StaticMermaidDiagram({ chart }: { chart: string }) { - const svgRef = useRef(null) - const [isDark, setIsDark] = useState(false) - - useEffect(() => { - const check = () => - setIsDark( - document.documentElement.style.colorScheme === 'dark' || - document.documentElement.classList.contains('dark'), - ) - check() - const obs = new MutationObserver(check) - obs.observe(document.documentElement, { - attributes: true, - attributeFilter: ['class', 'style'], - }) - return () => obs.disconnect() - }, []) - - useEffect(() => { - const el = svgRef.current - if (!el) return - const parsed = parseFlowchart(chart) - const th = isDark ? THEMES.dark : THEMES.light - el.innerHTML = renderFlowchart(parsed, th) - const svg = el.querySelector('svg') - if (svg) { - svg.style.maxWidth = '100%' - svg.style.height = 'auto' - svg.style.display = 'block' - svg.style.margin = '0 auto' - } - }, [chart, isDark]) - - return ( -
-
-
- ) -} diff --git a/src/pages/accounts/index.mdx b/src/pages/accounts/index.mdx index a99647d7..453489e5 100644 --- a/src/pages/accounts/index.mdx +++ b/src/pages/accounts/index.mdx @@ -4,7 +4,6 @@ description: Set up the Tempo Accounts SDK to create, manage, and interact with --- import { Cards, Card } from 'vocs' -import { StaticMermaidDiagram } from '../../components/StaticMermaidDiagram' import * as Demo from '../../components/guides/Demo.tsx' import * as Step from '../../components/guides/steps' import IconGitHub from '~icons/simple-icons/github' @@ -15,11 +14,19 @@ import IconGitHub from '~icons/simple-icons/github' The Tempo Accounts SDK is a TypeScript library for applications and wallets to create, manage, and interact with accounts on Tempo. -|"EIP-5792 requests"| wallet["Tempo Wallet + WebAuthn Passkey"] - wallet -->|"delegates to"| sdk["Accounts SDK"] - sdk -->|"built on"| infra["Wagmi + Viem"] -`} /> + ### Demo @@ -274,17 +281,3 @@ export default defineConfig({ Have questions or building something cool with the Accounts SDK? Join the Telegram group to chat with the team and other devs: [@mpp_devs](https://t.me/mpp_devs) - - diff --git a/src/wagmi.config.ts b/src/wagmi.config.ts index fd742c30..dd49bc67 100644 --- a/src/wagmi.config.ts +++ b/src/wagmi.config.ts @@ -1,6 +1,6 @@ import { QueryClient } from '@tanstack/react-query' import { Expiry } from 'accounts' -import { tempoWallet, webAuthn } from 'accounts/wagmi' +import { tempoWallet, webAuthn as webAuthnAccounts } from 'accounts/wagmi' import * as React from 'react' import { parseUnits } from 'viem' import { tempoDevnet, tempoLocalnet, tempoModerato } from 'viem/chains' @@ -13,6 +13,7 @@ import { useConnectors, webSocket, } from 'wagmi' +import { KeyManager, webAuthn } from 'wagmi/tempo' import { alphaUsd, betaUsd, pathUsd, thetaUsd } from './components/guides/tokens' const feeToken = '0x20c0000000000000000000000000000000000001' @@ -24,6 +25,13 @@ const chain = ? tempoDevnet.extend({ feeToken }) : tempoModerato.extend({ feeToken }) +const rpId = (() => { + const hostname = globalThis.location?.hostname + if (!hostname) return undefined + const parts = hostname.split('.') + return parts.length > 2 ? parts.slice(-2).join('.') : hostname +})() + export function getConfig(options: getConfig.Options = {}) { const { multiInjectedProviderDiscovery = false } = options return createConfig({ @@ -32,22 +40,35 @@ export function getConfig(options: getConfig.Options = {}) { }, chains: [chain], connectors: [ - tempoWallet({ - authorizeAccessKey: () => ({ - expiry: Expiry.days(1), - limits: [ - { token: pathUsd, limit: parseUnits('500', 6) }, - { token: alphaUsd, limit: parseUnits('500', 6) }, - { token: betaUsd, limit: parseUnits('500', 6) }, - { token: thetaUsd, limit: parseUnits('500', 6) }, - ], - }), - feePayerUrl: 'https://sponsor.moderato.tempo.xyz', - }), - webAuthn({ - authUrl: 'https://keys.tempo.xyz', - rdns: 'webAuthn', - }), + ...(import.meta.env.VITE_E2E === 'true' + ? [ + webAuthnAccounts({ + authUrl: 'https://keys.tempo.xyz', + rdns: 'webAuthn', + }), + ] + : [ + tempoWallet({ + authorizeAccessKey: () => ({ + expiry: Expiry.days(1), + limits: [ + { token: pathUsd, limit: parseUnits('500', 6) }, + { token: alphaUsd, limit: parseUnits('500', 6) }, + { token: betaUsd, limit: parseUnits('500', 6) }, + { token: thetaUsd, limit: parseUnits('500', 6) }, + ], + }), + feePayerUrl: 'https://sponsor.moderato.tempo.xyz', + }), + webAuthn({ + grantAccessKey: { + // @ts-expect-error - TODO: migrate to webAuthn on Accounts SDK + chainId: BigInt(chain.id), + }, + keyManager: KeyManager.http('https://keys.tempo.xyz'), + rpId, + }), + ]), ], multiInjectedProviderDiscovery, storage: createStorage({