Skip to content

Commit

Permalink
feat: frames v2 support (#531)
Browse files Browse the repository at this point in the history
* chore: frames v2 test app template

* fix: cast action message response definition

* feat: basic frames v2 parsing

* fix: do not cause infinite render cycle when using initialPendingExtra

* feat: basic frames v2 support

* fix: properly type current frame stack item

* refactor: types

* feat: useCastAction hook and fixing issues with signer copy

* refactor: use new cast action hook and unstable frame hooks in debugger

* feat: export signer instance types

* chore: add farcaster v2 to protocol selector

* fix: make frame v2 parsing compatible with spec

* fix: parsing frame button

* feat: allow multi spec signer

* feat: allow debugger to lock specification

* fix: launch button type

* chore: define handler for frame launching

* feat: add new hook to handle frames v2 app

* feat: add app frame dialog

* chore: basic frames 2 example

* fix: test

* test: add farcaster v2 tests

* chore: update sdk

* fix: unregister exposed comlink listeners

* chore: unregister all exposed listeners

* feat: add helpers to detect fully valid frames

* chore: split parse result types

* feat: add json farcaster signature utils

* fix: make json signatures browser compatible

* feat: add domain account association generator to debugger

* chore: add comments

* test: signature signing

* chore: eslint fix

* feat: parse and validate farcaster v2 frames and manifest

* fix: make route handlers compatible with async parsing

* fix: use 3:2 aspect ratio for frame

* feat: support react native

* chore: remove our starter

* fix: add missing parse result

* feat: show fc v1/v2 alert

* feat: manifest debugger tab

* chore: update peer dep and properly handle events

* chore: enable debug mode

* fix: throw an error because the error message is not the same as sdk expects

* feat: allow to hook into tx, messages and typed data signing

* feat: add an option to enable manifest parsing

* fix: wait for wallet client

* feat: allow to use different connectors

* chore: use new provider in debugger

* feat: fetch frame in useFrameApp hook

* fix: peer dep

* chore: return props as object

* fix: use iframeProps

* fix: eslint issue

* chore: export return and option types

* fix: check if emitter is really set

* chore: update peer deps

* fix: frame app dialog layout

* chore: remove unnecessary handler

* chore: allow to debug eth provider requests

* feat: allow to launch app in different contexts

* fix: respect abort signal

* feat: allow to resolve client

* feat: simple notifications support

* chore: do not allow to run frame app debugger from cast action debugger

* feat: allow to manage frame and notification settings

* feat: notifications event log and webhooks

* chore: use bigger ttl

* chore: add cli options for kv store

* chore: integrate farcaster implementation of frames v2

* feat: emit events

* chore: rename variables

* fix: compilation error

* fix: import as type

* chore: emit events

* fix: do not reload frame app on notifications state changes

* chore: do not store signer key

* feat: use sqlite if redis is not available

* feat: allow non strict parsing

* chore: changeset

* chore: remove package that doesn't exist

* chore: bump facaster/core and protobuf

* chore: allow non https urls in debugger notifications endpoints

* chore: make sqlite optional dep

* fix: event log scrolling

* chore: add alert on unsupported signer state

* chore: allow impersonated signers

* fix: correcly show notifications panel
  • Loading branch information
michalkvasnicak authored Dec 20, 2024
1 parent ef118a4 commit 1f3e724
Show file tree
Hide file tree
Showing 104 changed files with 11,275 additions and 2,440 deletions.
7 changes: 7 additions & 0 deletions .changeset/ninety-ducks-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"frames.js": minor
"@frames.js/debugger": minor
"@frames.js/render": minor
---

feat: farcaster v2 support
6 changes: 5 additions & 1 deletion packages/debugger/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ FARCASTER_DEVELOPER_MNEMONIC=
# Example: FARCASTER_DEVELOPER_FID=1214
FARCASTER_DEVELOPER_FID=

NEXT_PUBLIC_WALLETCONNECT_ID=
NEXT_PUBLIC_WALLETCONNECT_ID=

# Required to debug Farcaster Frames v2 notifications
KV_REST_API_TOKEN=""
KV_REST_API_URL=""
3 changes: 2 additions & 1 deletion packages/debugger/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
mocks.json
mocks.json
/notifications.db
120 changes: 120 additions & 0 deletions packages/debugger/app/components/action-debugger-properties-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { useMemo } from "react";
import type { CastActionDefinitionResponse } from "../frames/route";
import type { ParsingReport } from "frames.js";
import { Table, TableBody, TableCell, TableRow } from "@/components/table";
import { AlertTriangleIcon, CheckCircle2Icon, XCircleIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { ShortenedText } from "./shortened-text";

function isPropertyExperimental([key, value]: [string, string]) {
return false;
}

type ActionDebuggerPropertiesTableProps = {
actionMetadataItem: CastActionDefinitionResponse;
};

export function ActionDebuggerPropertiesTable({
actionMetadataItem,
}: ActionDebuggerPropertiesTableProps) {
const properties = useMemo(() => {
/** tuple of key and value */
const validProperties: [string, string][] = [];
/** tuple of key and error message */
const invalidProperties: [string, ParsingReport[]][] = [];
const visitedInvalidProperties: string[] = [];
const result = actionMetadataItem;

// we need to check validation errors first because getFrame incorrectly return a value for a key even if it's invalid
for (const [key, reports] of Object.entries(result.reports)) {
invalidProperties.push([key, reports]);
visitedInvalidProperties.push(key);
}

for (const [key, value] of Object.entries(result.action)) {
if (visitedInvalidProperties.includes(key) || value == null) {
continue;
}

if (typeof value === "object") {
validProperties.push([key, JSON.stringify(value)]);
} else {
validProperties.push([key, value]);
}
}

return {
validProperties,
invalidProperties,
isValid: invalidProperties.length === 0,
hasExperimentalProperties: false,
};
}, [actionMetadataItem]);

return (
<Table>
<TableBody>
{properties.validProperties.map(([propertyKey, value]) => {
return (
<TableRow key={`${propertyKey}-valid`}>
<TableCell>
{isPropertyExperimental([propertyKey, value]) ? (
<span className="whitespace-nowrap flex">
<div className="inline">
<CheckCircle2Icon size={20} color="orange" />
</div>
<div className="inline text-slate-500">*</div>
</span>
) : (
<CheckCircle2Icon size={20} color="green" />
)}
</TableCell>
<TableCell>{propertyKey}</TableCell>
<TableCell className="text-slate-500">
<ShortenedText text={value} maxLength={30} />
</TableCell>
</TableRow>
);
})}
{properties.invalidProperties.flatMap(
([propertyKey, errorMessages]) => {
return errorMessages.map((errorMessage, i) => {
return (
<TableRow key={`${propertyKey}-${i}-invalid`}>
<TableCell>
{errorMessage.level === "error" ? (
<XCircleIcon size={20} color="red" />
) : (
<AlertTriangleIcon size={20} color="orange" />
)}
</TableCell>
<TableCell>{propertyKey}</TableCell>
<TableCell className="text-slate-500">
<p
className={cn(
"font-bold",
errorMessage.level === "error"
? "text-red-500"
: "text-orange-500"
)}
>
{errorMessage.message}
</p>
</TableCell>
</TableRow>
);
});
}
)}
{properties.hasExperimentalProperties && (
<TableRow>
<TableCell colSpan={3} className="text-slate-500">
*This property is experimental and may not have been adopted in
clients yet
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
);
}
Loading

0 comments on commit 1f3e724

Please sign in to comment.