Skip to content

Commit d878cea

Browse files
committed
feat: working passkey endpoint
1 parent 4281c06 commit d878cea

File tree

10 files changed

+141
-12
lines changed

10 files changed

+141
-12
lines changed

apps/explorer/src/comps/ConnectWallet.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,65 @@ import { filterSupportedInjectedConnectors } from '#lib/wallets.ts'
1515
import LucideLogOut from '~icons/lucide/log-out'
1616
import LucideWalletCards from '~icons/lucide/wallet-cards'
1717

18+
export function ConnectPasskey() {
19+
const connect = useConnect()
20+
21+
const connection = useConnection()
22+
const connectors = useConnectors()
23+
24+
const connector = React.useMemo(
25+
() => connectors.find((connector) => connector.id === 'webAuthn'),
26+
[connectors],
27+
)
28+
29+
if (!connector || connector.id !== 'webAuthn')
30+
return <span className="text-negative">no passkey connector</span>
31+
32+
if (connect.status === 'pending') return <p>check prompt…</p>
33+
34+
if (connection.isConnected && connection.address) {
35+
return (
36+
<div className="flex items-center gap-2">
37+
<a
38+
target="_blank"
39+
rel="noopener noreferrer"
40+
className="font-light text-[12px] text-white/80"
41+
href={`https://docs.tempo.xyz/quickstart/faucet#funding-others`}
42+
>
43+
[faucet]
44+
</a>
45+
<Address
46+
chars={7}
47+
align="end"
48+
address={connection.address}
49+
className="text-accent font-light text-sm"
50+
/>
51+
<SignOut />
52+
</div>
53+
)
54+
}
55+
56+
return (
57+
<Button
58+
onClick={() =>
59+
connect
60+
.mutateAsync({
61+
connector,
62+
capabilities: { type: 'sign-in' },
63+
})
64+
.catch(() =>
65+
connect.mutateAsync({
66+
connector,
67+
capabilities: { type: 'sign-up' },
68+
}),
69+
)
70+
}
71+
>
72+
Connect
73+
</Button>
74+
)
75+
}
76+
1877
export function ConnectWallet({
1978
showAddChain = true,
2079
}: {

apps/explorer/src/comps/Contract.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Address } from 'ox'
22
import * as React from 'react'
33
import type { Abi } from 'viem'
44
import { useBytecode } from 'wagmi'
5-
import { ConnectWallet } from '#comps/ConnectWallet.tsx'
5+
import { ConnectPasskey } from '#comps/ConnectWallet.tsx'
66
import { AbiViewer } from '#comps/ContractAbi.tsx'
77
import { ContractReader } from '#comps/ContractReader.tsx'
88
import { SourceSection } from '#comps/ContractSource.tsx'
@@ -247,7 +247,7 @@ export function InteractTabContent(props: {
247247
title="Write contract"
248248
expanded={writeExpanded}
249249
onToggle={() => setWriteExpanded(!writeExpanded)}
250-
actions={<ConnectWallet />}
250+
actions={<ConnectPasskey />}
251251
>
252252
<div className="px-[10px] pb-[10px]">
253253
<ContractWriter address={address} abi={abi} />

apps/explorer/src/index.server.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,18 @@ export default Sentry.withSentry(
1919
// Adds request headers and IP for users, for more info visit:
2020
// https://docs.sentry.io/platforms/javascript/guides/cloudflare/configuration/options/#sendDefaultPii
2121
sendDefaultPii: true,
22-
enableLogs: true,
22+
enableLogs: false,
2323
}
2424
},
2525
{
2626
fetch: (request: Request, opts) => {
2727
const url = new URL(request.url)
28-
if (url.pathname === '/debug-sentry')
29-
throw new Error('My first Sentry error!')
3028

3129
for (const { from, to } of redirects) {
3230
const match = url.pathname.match(from)
33-
if (match) {
34-
url.pathname = to(match)
35-
return Response.redirect(url, 301)
36-
}
31+
if (!match) continue
32+
url.pathname = to(match)
33+
return Response.redirect(url, 301)
3734
}
3835

3936
return handler.fetch(request, opts as Parameters<ServerEntry['fetch']>[1])

apps/explorer/src/routeTree.gen.ts

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/explorer/src/router.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const getRouter = () => {
3737
if (!router.isServer) {
3838
Sentry.init({
3939
dsn: 'https://170113585c24ca7a67704f86cccd6750@o4510262603481088.ingest.us.sentry.io/4510467689218048',
40-
enabled: import.meta.env.PROD,
40+
enabled: false,
4141
replaysSessionSampleRate: 0.1,
4242
replaysOnErrorSampleRate: 1.0,
4343
sendDefaultPii: true,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { env } from 'cloudflare:workers'
2+
import { createFileRoute } from '@tanstack/react-router'
3+
import { Handler, Kv } from 'tempo.ts/server'
4+
5+
export const Route = createFileRoute('/api/webauthn/$')({
6+
server: {
7+
handlers: {
8+
GET: ({ request }) => {
9+
const url = new URL(request.url)
10+
const path = url.pathname
11+
12+
console.info('webauthn request', path)
13+
return Handler.keyManager({
14+
path: '/api/webauthn',
15+
kv: Kv.cloudflare(env.EXPLORER_PASSKEY_STORE),
16+
}).fetch(request)
17+
},
18+
},
19+
},
20+
})

apps/explorer/src/wagmi.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const DEFAULT_TESTNET_RPC_URL = 'https://rpc-orchestra.testnet.tempo.xyz'
1313
export const queryClient: QueryClient = new QueryClient({
1414
defaultOptions: {
1515
queries: {
16-
gcTime: 1000 * 60 * 60 * 24, // 24 hours
16+
gcTime: 1_000 * 60 * 60 * 24, // 24 hours
1717
queryKeyHashFn: Json.stringify,
1818
refetchOnReconnect: () => !queryClient.isMutating(),
1919
retry: 0,
@@ -48,7 +48,7 @@ export const config = createConfig({
4848
],
4949
connectors: [
5050
webAuthn({
51-
keyManager: KeyManager.http('psstkey'),
51+
keyManager: KeyManager.http(`${__BASE_URL__}/api/webauthn`),
5252
}),
5353
],
5454
batch: { multicall: false },

apps/explorer/vite.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import vitePluginChromiumDevTools from 'vite-plugin-devtools-json'
1010

1111
const [, , , ...args] = process.argv
1212

13+
const SENTRY_OFF_TEMPORARILY = true
14+
1315
export default defineConfig((config) => {
1416
const env = loadEnv(config.mode, process.cwd(), '')
1517
const showDevtools = env.VITE_ENABLE_DEVTOOLS !== 'false'
@@ -45,6 +47,7 @@ export default defineConfig((config) => {
4547
showDevtools && devtools(),
4648
showDevtools && vitePluginChromiumDevTools(),
4749
config.mode === 'production' &&
50+
!SENTRY_OFF_TEMPORARILY &&
4851
sentryVitePlugin({
4952
org: 'tempoxyz',
5053
telemetry: false,
@@ -67,6 +70,7 @@ export default defineConfig((config) => {
6770
],
6871
server: {
6972
port,
73+
cors: config.mode === 'development' ? true : undefined,
7074
allowedHosts: config.mode === 'development' ? true : undefined,
7175
},
7276
build: {

apps/explorer/wrangler.jsonc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
"mode": "smart"
1414
},
1515
"keep_vars": true,
16+
"kv_namespaces": [
17+
{
18+
"remote": true,
19+
"binding": "EXPLORER_PASSKEY_STORE",
20+
"id": "9d662ec25881455da0d3766e9d38e15d"
21+
}
22+
],
1623
"observability": {
1724
"enabled": true,
1825
"logs": {

justfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
set dotenv-load := true
2+
set positional-arguments := true
3+
4+
# generate random # between 1024 and 49151
5+
@random-port:
6+
echo $((RANDOM % 49151 + 1024))
7+
8+
# utilities
9+
[group('Utilities')]
10+
@lowercase value:
11+
@echo {{ lowercase(value) }}
12+
13+
# kill process on port
14+
[group('utilities')]
15+
@kill-port port:
16+
lsof -ti :{{ port }} | xargs kill -9 2>/dev/null || true
17+
18+
# run workspace in dev mode
19+
@dev workspace:
20+
just kill-port 42069
21+
cd apps/{{ lowercase(workspace) }} && pnpm node --run dev -- --port $(just random-port)

0 commit comments

Comments
 (0)