Skip to content

Commit 0e7244d

Browse files
chore: update dependencies and fix debugger issues (#534)
* feat: update dependencies, add new methods * fix: allow localhost as domain in account association * fix: typo * fix: load dev env variables from backend * fix: in non strict mode only warn instead of error on non https urls * test: correctly test non strict parser * feat: farcaster v2 sign in * chore: changeset * refactor: remove signer dependency from useFrameApp hook
1 parent f19b6a6 commit 0e7244d

File tree

12 files changed

+697
-298
lines changed

12 files changed

+697
-298
lines changed

.changeset/five-zoos-wash.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"frames.js": patch
3+
"@frames.js/debugger": patch
4+
"@frames.js/render": patch
5+
---
6+
7+
feat: farcaster v2 sign in and libs update
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { z } from "zod";
2+
3+
export function GET() {
4+
return Response.json(
5+
{
6+
fid: z.coerce
7+
.number()
8+
.int()
9+
.parse(process.env.FARCASTER_DEVELOPER_FID || "-1"),
10+
},
11+
{
12+
headers: {
13+
"Cache-Control": "no-store",
14+
},
15+
}
16+
);
17+
}

packages/debugger/app/components/farcaster-domain-account-association-dialog.tsx

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import {
1212
DialogTitle,
1313
} from "@/components/ui/dialog";
1414
import { useAccount, useSignMessage, useSwitchChain } from "wagmi";
15-
import { FormEvent, useCallback, useState } from "react";
15+
import { FormEvent, useCallback, useRef, useState } from "react";
1616
import { CopyIcon, CopyCheckIcon, CopyXIcon, Loader2Icon } from "lucide-react";
17+
import { z } from "zod";
1718
import { Input } from "@/components/ui/input";
1819
import { Label } from "@/components/ui/label";
1920
import { useFarcasterIdentity } from "../hooks/useFarcasterIdentity";
@@ -28,6 +29,7 @@ type FarcasterDomainAccountAssociationDialogProps = {
2829
export function FarcasterDomainAccountAssociationDialog({
2930
onClose,
3031
}: FarcasterDomainAccountAssociationDialogProps) {
32+
const domainInputRef = useRef<HTMLInputElement>(null);
3133
const copyCompact = useCopyToClipboard();
3234
const copyJSON = useCopyToClipboard();
3335
const account = useAccount();
@@ -44,7 +46,7 @@ export function FarcasterDomainAccountAssociationDialog({
4446
async (event: FormEvent<HTMLFormElement>) => {
4547
event.preventDefault();
4648

47-
const data = new FormData(event.currentTarget);
49+
const data = Object.fromEntries(new FormData(event.currentTarget));
4850

4951
try {
5052
if (farcasterSigner.signer?.status !== "approved") {
@@ -55,12 +57,36 @@ export function FarcasterDomainAccountAssociationDialog({
5557
throw new Error("Account address is not available");
5658
}
5759

58-
const domain = data.get("domain");
60+
const parser = z.object({
61+
domain: z
62+
.preprocess((val) => {
63+
if (typeof val === "string") {
64+
// prepend with prefix because normally it is the domain but we want to validate
65+
// it is in valid format
66+
return `http://${val}`;
67+
}
5968

60-
if (typeof domain !== "string" || !domain) {
61-
throw new Error("Domain is required");
69+
return val;
70+
}, z.string().url("Invalid domain"))
71+
// remove the protocol prefix
72+
.transform((val) => val.substring(7)),
73+
});
74+
75+
const parseResult = parser.safeParse(data);
76+
77+
if (!parseResult.success) {
78+
parseResult.error.errors.map((error) => {
79+
domainInputRef.current?.setCustomValidity(error.message);
80+
});
81+
82+
event.currentTarget.reportValidity();
83+
84+
return;
6285
}
6386

87+
domainInputRef.current?.setCustomValidity("");
88+
event.currentTarget.reportValidity();
89+
6490
setIsGenerating(true);
6591

6692
await switchChainAsync({
@@ -69,8 +95,9 @@ export function FarcasterDomainAccountAssociationDialog({
6995

7096
const result = await sign({
7197
fid: farcasterSigner.signer.fid,
72-
payload:
73-
constructJSONFarcasterSignatureAccountAssociationPaylod(domain),
98+
payload: constructJSONFarcasterSignatureAccountAssociationPaylod(
99+
parseResult.data.domain
100+
),
74101
signer: {
75102
type: "custody",
76103
custodyAddress: account.address,
@@ -117,15 +144,25 @@ export function FarcasterDomainAccountAssociationDialog({
117144
<DialogTitle>Domain Account Association</DialogTitle>
118145
</DialogHeader>
119146
{!associationResult && (
120-
<form id="domain-account-association-form" onSubmit={handleSubmit}>
147+
<form
148+
className="flex flex-col gap-2"
149+
id="domain-account-association-form"
150+
onSubmit={handleSubmit}
151+
noValidate
152+
>
121153
<Label htmlFor="domain">Domain</Label>
122154
<Input
123155
id="domain"
124156
name="domain"
125-
pattern="^.+\..+$"
126157
required
127158
type="text"
159+
ref={domainInputRef}
128160
/>
161+
<span className="text-muted-foreground text-sm">
162+
A domain of your frame, e.g. for https://framesjs.org the domain
163+
is framesjs.org, for http://localhost:3000 the domain is
164+
localhost.
165+
</span>
129166
</form>
130167
)}
131168
{associationResult && (

0 commit comments

Comments
 (0)