Skip to content

Commit

Permalink
Merge pull request #289 from framesjs/feat/cast-actions-support
Browse files Browse the repository at this point in the history
feat: cast actions support
  • Loading branch information
stephancill authored Apr 5, 2024
2 parents 814b4ce + 9962b83 commit f72fb6d
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/brown-walls-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"frames.js": minor
---

feat: allow arbitrary response in frames handler
5 changes: 5 additions & 0 deletions .changeset/tasty-panthers-protect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"framesjs-starter": patch
---

feat: cast actions example
12 changes: 12 additions & 0 deletions docs/pages/guides/cast-actions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: "Cast Actions"
description: "A guide to demonstrate how to create cast actions with Frames.js"
---

# Cast Actions

The [Cast Actions](https://warpcast.notion.site/Frames-Cast-Actions-v1-84d5a85d479a43139ea883f6823d8caa) specification lets you define actions that can be performed on a cast. This guide will show you how to create cast actions with Frames.js.

## Example

[See the example on GitHub](https://github.com/framesjs/frames.js/tree/main/examples/framesjs-starter/app/examples/new-api-cast-actions)
4 changes: 4 additions & 0 deletions docs/vocs.config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ const sidebar = [
text: "Open Frames",
link: "/guides/open-frames",
},
{
text: "Cast Actions",
link: "/guides/cast-actions",
},
],
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createFrames } from "frames.js/next";

export const frames = createFrames({
basePath: "/examples/new-api-cast-actions/frames",
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable react/jsx-key */
import { Button } from "frames.js/next";
import { frames } from "./frames";
import { constructCastActionUrl } from "../utils";

export const GET = frames(async (ctx) => {
const currentUrl = new URL(ctx.url.toString());
currentUrl.pathname = "/examples/new-api-cast-actions/frames";

const installActionUrl = constructCastActionUrl({
actionType: "post",
icon: "number",
name: "Check FID",
postUrl: currentUrl.toString(),
});

return {
image: <div>FID Action</div>,
buttons: [
<Button action="link" target={installActionUrl}>
Install
</Button>,
],
};
});

export const POST = frames(async (ctx) => {
return Response.json({
message: `The user's FID is ${ctx.message?.castId?.fid}`,
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Link from "next/link";
import { currentURL, vercelURL } from "../../utils";
import { createDebugUrl } from "../../debug";
import type { Metadata } from "next";
import { fetchMetadata } from "frames.js/next";

export async function generateMetadata(): Promise<Metadata> {
return {
title: "New api example",
description: "This is a new api example",
other: {
...(await fetchMetadata(
new URL(
"/examples/new-api-cast-actions/frames",
vercelURL() || "http://localhost:3000"
)
)),
},
};
}

export default async function Home() {
const url = currentURL("/examples/new-api-cast-actions");

return (
<div>
New api cast actions example.{" "}
<Link href={createDebugUrl(url)} className="underline">
Debug
</Link>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
type CastActionParams = {
/** The action name. Must be less than 30 characters. */
name: string;
/** An [Octicons](https://primer.style/foundations/icons) icon name. */
icon: string;
/** The action type. (Same type options as frame buttons). Only post is accepted in V1. */
actionType: "post";
postUrl: string;
};
export function constructCastActionUrl(params: CastActionParams): string {
// Validate the input parameters
if (params.name.length > 30) {
throw new Error("The action name must be less than 30 characters.");
}

if (params.actionType.toLowerCase() !== "post") {
throw new Error('The action type must be "post" in V1.');
}

// Construct the URL
const baseUrl = "https://warpcast.com/~/add-cast-action";
const urlParams = new URLSearchParams({
name: params.name,
icon: params.icon,
actionType: params.actionType,
postUrl: params.postUrl,
});

return `${baseUrl}?${urlParams.toString()}`;
}
2 changes: 1 addition & 1 deletion packages/frames.js/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export type FrameRedirect = {

export type FramesHandlerFunctionReturnType<
TState extends JsonValue | undefined,
> = FrameDefinition<TState> | FrameRedirect;
> = FrameDefinition<TState> | FrameRedirect | Response;

type FramesMiddlewareNextFunction<
TState extends JsonValue | undefined,
Expand Down

0 comments on commit f72fb6d

Please sign in to comment.