Skip to content

Commit efaf777

Browse files
committed
Merge branch 'dev'
2 parents e5f2235 + c0c651e commit efaf777

36 files changed

+854
-157
lines changed

docs/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# docs
22

3+
## 0.3.13
4+
5+
### Patch Changes
6+
7+
- Updated dependencies [86e03b9]
8+
9+
310
## 0.3.12
411

512
### Patch Changes

docs/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "docs",
3-
"version": "0.3.12",
3+
"version": "0.3.13",
44
"type": "module",
55
"private": true,
66
"scripts": {
@@ -9,7 +9,7 @@
99
"preview": "vocs preview"
1010
},
1111
"dependencies": {
12-
"frames.js": "0.21.1",
12+
"frames.js": "0.21.2",
1313
"lucide-react": "^0.372.0",
1414
"next": "14.1.4",
1515
"react": "^18.2.0",

packages/debugger/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# @frames.js/debugger
22

3+
## 0.4.2
4+
5+
### Patch Changes
6+
7+
- 96a5831: feat: view profile dialog
8+
- 86e03b9: feat: support for app key signatures
9+
310
## 0.4.1
411

512
### Patch Changes
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* eslint-disable @next/next/no-img-element */
2+
import React from "react";
3+
import {
4+
Dialog,
5+
DialogContent,
6+
DialogTitle,
7+
DialogDescription,
8+
} from "@/components/ui/dialog";
9+
import { useQuery } from "@tanstack/react-query";
10+
import { z } from "zod";
11+
import { Loader2Icon, TriangleAlertIcon } from "lucide-react";
12+
import Image from "next/image";
13+
14+
type UserDetails = {
15+
username: string;
16+
pfp_url: string;
17+
profile: {
18+
bio: {
19+
text: string;
20+
};
21+
};
22+
follower_count: number;
23+
following_count: number;
24+
};
25+
26+
type FrameAppDebuggerViewProfileDialogProps = {
27+
fid: number;
28+
onDismiss: () => void;
29+
};
30+
31+
const UserDetailsSchema = z.object({
32+
username: z.string(),
33+
pfp_url: z.string().url(),
34+
profile: z.object({
35+
bio: z.object({
36+
text: z.string(),
37+
}),
38+
}),
39+
follower_count: z.number().int(),
40+
following_count: z.number().int(),
41+
});
42+
43+
async function fetchUser(fid: number): Promise<UserDetails> {
44+
const response = await fetch(`/farcaster/user/${fid}`);
45+
46+
if (!response.ok) {
47+
throw new Error("Network response was not ok");
48+
}
49+
50+
const data = await response.json();
51+
52+
return UserDetailsSchema.parse(data);
53+
}
54+
55+
export function FrameAppDebuggerViewProfileDialog({
56+
fid,
57+
onDismiss,
58+
}: FrameAppDebuggerViewProfileDialogProps) {
59+
const query = useQuery({
60+
queryKey: ["user", fid],
61+
queryFn: () => fetchUser(fid),
62+
});
63+
64+
return (
65+
<Dialog open={true} onOpenChange={onDismiss}>
66+
<DialogContent>
67+
<DialogTitle>Profile Details</DialogTitle>
68+
{query.isLoading && (
69+
<DialogDescription className="flex items-center justify-center">
70+
<Loader2Icon className="animate-spin" />
71+
</DialogDescription>
72+
)}
73+
{query.isError && (
74+
<DialogDescription className="flex flex-col items-center justify-center text-red-500">
75+
<TriangleAlertIcon className="mb-2 w-6 h-6" />
76+
<span className="font-semibold">Unexpected error occurred</span>
77+
</DialogDescription>
78+
)}
79+
{query.isSuccess && (
80+
<DialogDescription className="flex flex-col gap-2 items-center justify-center">
81+
<div className="flex items-center">
82+
<div className="aspect-square h-[80px] w-[80px] rounded-full overflow-hidden">
83+
<img
84+
className="w-full h-full object-contain"
85+
src={query.data.pfp_url}
86+
alt={query.data.username}
87+
width={80}
88+
/>
89+
</div>
90+
</div>
91+
<strong className="text-lg">{query.data.username}</strong>
92+
<div className="grid grid-cols-2 gap-4 text-sm text-gray-500 text-center">
93+
<div>
94+
<strong>{formatCount(query.data.follower_count)}</strong>{" "}
95+
followers
96+
</div>
97+
<div>
98+
<strong>{formatCount(query.data.following_count)}</strong>{" "}
99+
following
100+
</div>
101+
</div>
102+
<span>{query.data.profile.bio.text}</span>
103+
</DialogDescription>
104+
)}
105+
</DialogContent>
106+
</Dialog>
107+
);
108+
}
109+
110+
function formatCount(count: number): string {
111+
if (count < 1000) {
112+
return count.toString();
113+
} else if (count >= 1000 && count < 1000000) {
114+
return (count / 1000).toFixed(1) + "K";
115+
}
116+
117+
return (count / 1000000).toFixed(1) + "M";
118+
}

packages/debugger/app/components/frame-app-debugger.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import type { EIP6963ProviderInfo } from "@farcaster/frame-sdk";
3030
import { z } from "zod";
3131
import { Dialog, DialogContent } from "@/components/ui/dialog";
3232
import { useCopyToClipboard } from "../hooks/useCopyToClipboad";
33+
import { FrameAppDebuggerViewProfileDialog } from "./frame-app-debugger-view-profile-dialog";
3334

3435
type TabValues = "events" | "console" | "notifications";
3536

@@ -153,6 +154,7 @@ export function FrameAppDebugger({
153154
};
154155
}
155156
}, [toast]);
157+
const [viewFidProfile, setViewFidProfile] = useState<number | null>(null);
156158
const frameApp = useFrameAppInIframe({
157159
debug: true,
158160
source: context.parseResult,
@@ -289,6 +291,11 @@ export function FrameAppDebugger({
289291
});
290292
},
291293
async onSignIn({ nonce, notBefore, expirationTime, frame }) {
294+
console.info("sdk.actions.signIn() called", {
295+
nonce,
296+
notBefore,
297+
expirationTime,
298+
});
292299
let abortTimeout: NodeJS.Timeout | undefined;
293300

294301
try {
@@ -373,6 +380,10 @@ export function FrameAppDebugger({
373380
setFarcasterSignInAbortControllerURL(null);
374381
}
375382
},
383+
async onViewProfile(params) {
384+
console.info("sdk.actions.viewProfile() called", params);
385+
setViewFidProfile(params.fid);
386+
},
376387
});
377388

378389
return (
@@ -552,6 +563,14 @@ export function FrameAppDebugger({
552563
) : null}
553564
</div>
554565
</div>
566+
{viewFidProfile !== null && (
567+
<FrameAppDebuggerViewProfileDialog
568+
fid={viewFidProfile}
569+
onDismiss={() => {
570+
setViewFidProfile(null);
571+
}}
572+
/>
573+
)}
555574
</>
556575
);
557576
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { NextRequest } from "next/server";
2+
import { z } from "zod";
3+
4+
const validator = z.object({
5+
fid: z.coerce.number().int().positive(),
6+
});
7+
8+
export async function GET(
9+
_: NextRequest,
10+
{ params }: { params: { fid: string } }
11+
) {
12+
try {
13+
const { fid } = validator.parse(params);
14+
15+
const url = new URL("https://api.neynar.com/v2/farcaster/user/bulk");
16+
17+
url.searchParams.set("fids", fid.toString());
18+
19+
const response = await fetch(url, {
20+
headers: {
21+
accept: "application/json",
22+
"x-api-key": "NEYNAR_FRAMES_JS",
23+
},
24+
});
25+
26+
if (!response.ok) {
27+
if (response.status === 404) {
28+
return Response.json({ error: "User not found" }, { status: 404 });
29+
}
30+
31+
throw new Error(`Unexpected response: ${response.status}`);
32+
}
33+
34+
const data = await response.json();
35+
36+
return Response.json(data.users[0]);
37+
} catch (e) {
38+
if (e instanceof z.ZodError) {
39+
return Response.json({ error: e.errors }, { status: 400 });
40+
}
41+
42+
throw e;
43+
}
44+
}

packages/debugger/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"frames.js",
66
"farcaster"
77
],
8-
"version": "0.4.1",
8+
"version": "0.4.2",
99
"bin": {
1010
"frames": "./bin/debugger.js"
1111
},
@@ -37,7 +37,7 @@
3737
},
3838
"devDependencies": {
3939
"@farcaster/core": "^0.15.6",
40-
"@frames.js/render": "^0.5.1",
40+
"@frames.js/render": "^0.5.2",
4141
"@primer/octicons-react": "^19.9.0",
4242
"@radix-ui/react-accordion": "^1.1.2",
4343
"@radix-ui/react-checkbox": "^1.0.4",
@@ -69,7 +69,7 @@
6969
"console-feed": "^3.6.0",
7070
"eslint": "^8.56.0",
7171
"eslint-config-next": "^14.1.0",
72-
"frames.js": "^0.21.1",
72+
"frames.js": "^0.21.2",
7373
"lucide-react": "^0.408.0",
7474
"postcss": "^8",
7575
"qrcode.react": "^3.1.0",

packages/frames.js/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# frames.js
22

3+
## 0.21.2
4+
5+
### Patch Changes
6+
7+
- 86e03b9: feat: support for app key signatures
8+
39
## 0.21.1
410

511
### Patch Changes

packages/frames.js/package.json

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "frames.js",
3-
"version": "0.21.1",
3+
"version": "0.21.2",
44
"type": "module",
55
"main": "./dist/index.cjs",
66
"types": "index.d.cts",
@@ -187,6 +187,16 @@
187187
"default": "./dist/farcaster-v2/types.cjs"
188188
}
189189
},
190+
"./farcaster-v2/verify": {
191+
"import": {
192+
"types": "./dist/farcaster-v2/verify.d.ts",
193+
"default": "./dist/farcaster-v2/verify.js"
194+
},
195+
"require": {
196+
"types": "./dist/farcaster-v2/verify.d.cts",
197+
"default": "./dist/farcaster-v2/verify.cjs"
198+
}
199+
},
190200
"./core": {
191201
"import": {
192202
"types": "./dist/core/index.d.ts",
@@ -420,12 +430,14 @@
420430
},
421431
"dependencies": {
422432
"@farcaster/frame-core": "^0.0.24",
423-
"@farcaster/frame-node": "^0.0.13",
433+
"@noble/ed25519": "^2.2.3",
434+
"@noble/hashes": "^1.7.1",
424435
"@vercel/og": "^0.6.3",
425436
"cheerio": "^1.0.0-rc.12",
437+
"ox": "^0.4.4",
426438
"protobufjs": "^7.2.6",
427-
"viem": "^2.7.8",
428439
"type-fest": "^4.28.1",
440+
"viem": "^2.7.8",
429441
"zod": "^3.24.1"
430442
}
431443
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { sha512 } from "@noble/hashes/sha512";
2+
import { etc, getPublicKey, sign, verify } from "@noble/ed25519";
3+
4+
if (!etc.sha512Sync) {
5+
etc.sha512Sync = (...m: Uint8Array[]) => sha512(etc.concatBytes(...m));
6+
}
7+
8+
export { getPublicKey, sign, verify };

0 commit comments

Comments
 (0)