Skip to content

Commit 3fad5ba

Browse files
refactor: provide parse result and current specification to resolveActionContext
1 parent b0f0b31 commit 3fad5ba

File tree

8 files changed

+259
-103
lines changed

8 files changed

+259
-103
lines changed

packages/render/src/collapsed-frame-ui.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ export function CollapsedFrameUI({
149149
cursor: isLoading ? undefined : "pointer",
150150
}}
151151
>
152-
{frame.buttons.length === 1 && frame.buttons[0].label.length < 12
152+
{frame.buttons.length === 1 &&
153+
!!frame.buttons[0] &&
154+
frame.buttons[0].label.length < 12
153155
? frame.buttons[0].label
154156
: "View"}
155157
</button>

packages/render/src/frame-ui.tsx

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import type { ImgHTMLAttributes } from "react";
22
import React, { useState } from "react";
3-
import type { Frame, FrameButton } from "frames.js";
3+
import type {
4+
Frame,
5+
FrameButton,
6+
SupportedParsingSpecification,
7+
} from "frames.js";
8+
import type {
9+
ParseFramesWithReportsResult,
10+
ParseResult,
11+
} from "frames.js/frame-parsers";
412
import type { FrameTheme, FrameState } from "./types";
513
import {
614
getErrorMessageFromFramesStackItem,
@@ -146,28 +154,35 @@ export function FrameUI({
146154
}
147155

148156
let frame: Frame | Partial<Frame> | undefined;
157+
let parseResult: ParseFramesWithReportsResult | undefined;
158+
let specification: SupportedParsingSpecification | undefined;
149159
let debugImage: string | undefined;
150160

151161
if (currentFrameStackItem.status === "done") {
152-
const parseResult = getFrameParseResultFromStackItemBySpecifications(
162+
const parseResultBySpec = getFrameParseResultFromStackItemBySpecifications(
153163
currentFrameStackItem,
154164
specifications
155165
);
156166

157-
frame = parseResult.frame;
167+
frame = parseResultBySpec.frame;
168+
parseResult = currentFrameStackItem.parseResult;
169+
specification = parseResultBySpec.specification;
158170
debugImage = enableImageDebugging
159-
? parseResult.framesDebugInfo?.image
171+
? parseResultBySpec.framesDebugInfo?.image
160172
: undefined;
161173
} else if (
162174
currentFrameStackItem.status === "message" ||
163175
currentFrameStackItem.status === "doneRedirect"
164176
) {
165177
frame = currentFrameStackItem.request.sourceFrame;
178+
parseResult = currentFrameStackItem.request.sourceParseResult;
179+
specification = currentFrameStackItem.request.specification;
166180
} else if (currentFrameStackItem.status === "requestError") {
167-
frame =
168-
"sourceFrame" in currentFrameStackItem.request
169-
? currentFrameStackItem.request.sourceFrame
170-
: undefined;
181+
if ("sourceFrame" in currentFrameStackItem.request) {
182+
frame = currentFrameStackItem.request.sourceFrame;
183+
parseResult = currentFrameStackItem.request.sourceParseResult;
184+
specification = currentFrameStackItem.request.specification;
185+
}
171186
}
172187

173188
const ImageEl = FrameImage ? FrameImage : "img";
@@ -233,7 +248,11 @@ export function FrameUI({
233248
}}
234249
/>
235250
) : null}
236-
{!!frame && !!frame.buttons && frame.buttons.length > 0 ? (
251+
{!!parseResult &&
252+
!!specification &&
253+
!!frame &&
254+
!!frame.buttons &&
255+
frame.buttons.length > 0 ? (
237256
<div className="flex gap-[8px] px-2 pb-2">
238257
{frame.buttons.map((frameButton: FrameButton, index: number) => (
239258
<button
@@ -252,12 +271,12 @@ export function FrameUI({
252271
}}
253272
onClick={() => {
254273
Promise.resolve(
255-
frameState.onButtonPress(
256-
// Partial frame could have enough data to handle button press
257-
frame as Frame,
274+
frameState.onButtonPress({
275+
parseResult,
258276
frameButton,
259-
index
260-
)
277+
index,
278+
specification,
279+
})
261280
).catch((e: unknown) => {
262281
// eslint-disable-next-line no-console -- provide feedback to the user
263282
console.error(e);

packages/render/src/helpers.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ export function createParseFramesWithReportsObject(
7272
// this is open frame
7373
return {
7474
openframes: input,
75-
farcaster: { status: "failure", frame: input.frame, reports: {} },
75+
farcaster: {
76+
status: "failure",
77+
frame: input.frame,
78+
reports: {},
79+
specification: "farcaster",
80+
},
7681
};
7782
}
7883

@@ -81,18 +86,38 @@ export function createParseFramesWithReportsObject(
8186
openframes:
8287
"accepts" in input.frame || "accepts" in input.reports
8388
? input
84-
: { status: "failure", frame: input.frame, reports: {} },
89+
: {
90+
status: "failure",
91+
frame: input.frame,
92+
reports: {},
93+
specification: "openframes",
94+
},
8595
};
8696
}
8797

8898
return {
8999
// always treat the frame as farcaster frame
90-
farcaster: { status: "success", frame: input, reports: {} },
100+
farcaster: {
101+
status: "success",
102+
frame: input,
103+
reports: {},
104+
specification: "farcaster",
105+
},
91106
openframes:
92107
// detect if it is a valid openframe
93108
!input.accepts || input.accepts.length === 0
94-
? { status: "failure", frame: input, reports: {} }
95-
: { status: "success", frame: input, reports: {} },
109+
? {
110+
status: "failure",
111+
frame: input,
112+
reports: {},
113+
specification: "openframes",
114+
}
115+
: {
116+
status: "success",
117+
frame: input,
118+
reports: {},
119+
specification: "openframes",
120+
},
96121
};
97122
}
98123

packages/render/src/types.ts

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,8 @@ export type SignFrameActionFunc<
8080
actionContext: SignerStateActionContext<TSignerStorageType, TFrameContextType>
8181
) => Promise<SignedFrameAction<TFrameActionBodyType>>;
8282

83-
export type UseFetchFrameSignFrameActionFunction = (arg: {
84-
actionContext: SignerStateActionContext;
85-
/**
86-
* @defaultValue false
87-
*/
88-
forceRealSigner?: boolean;
89-
}) => Promise<SignedFrameAction>;
90-
9183
export type UseFetchFrameOptions = {
84+
dangerousSkipSigning: boolean;
9285
stackAPI: FrameStackAPI;
9386
/**
9487
* URL or path to the frame proxy handling GET requests.
@@ -102,7 +95,6 @@ export type UseFetchFrameOptions = {
10295
* Extra payload to be sent with the POST request.
10396
*/
10497
extraButtonRequestPayload?: Record<string, unknown>;
105-
signFrameAction: UseFetchFrameSignFrameActionFunction;
10698
/**
10799
* Called after transaction data has been returned from the server and user needs to approve the transaction.
108100
*/
@@ -195,10 +187,25 @@ export type UseFetchFrameOptions = {
195187
onTransactionProcessingError?: (error: Error) => void;
196188
};
197189

190+
export type ResolveFrameActionContextArgumentAction =
191+
| { type: "composer" }
192+
| { type: "cast" }
193+
| {
194+
type: "frame";
195+
/**
196+
* Current parse result that is active
197+
*/
198+
parseResult: ParseFramesWithReportsResult;
199+
/**
200+
* Specification that is currently active
201+
*/
202+
specification: SupportedParsingSpecification;
203+
};
204+
198205
export type ResolveFrameActionContextArgument = {
199-
readonly dangerouslySkipSigning: boolean;
200206
readonly frameStack: FramesStack;
201207
readonly specifications: SupportedParsingSpecification[];
208+
readonly action: ResolveFrameActionContextArgumentAction;
202209
};
203210

204211
export type ResolveFrameActionContextResult = {
@@ -420,19 +427,25 @@ export type FramePOSTRequest =
420427
source?: never;
421428
frameButton: FrameButtonPost | FrameButtonTx;
422429
signerStateActionContext: SignerStateActionContext;
430+
signerState: SignerStateInstance<any, any, any>;
423431
isDangerousSkipSigning: boolean;
424432
/**
425433
* The frame that was the source of the button press.
426434
*/
427435
sourceFrame: Frame;
436+
sourceParseResult: ParseFramesWithReportsResult;
437+
specification: SupportedParsingSpecification;
428438
}
429439
| {
430440
method: "POST";
431441
source: "cast-action" | "composer-action";
432442
frameButton: FrameButtonPost | FrameButtonTx;
433443
signerStateActionContext: SignerStateActionContext;
444+
signerState: SignerStateInstance<any, any, any>;
434445
isDangerousSkipSigning: boolean;
435446
sourceFrame: undefined;
447+
sourceParseResult: undefined;
448+
specification: undefined;
436449
};
437450

438451
export type FrameRequest = FrameGETRequest | FramePOSTRequest;
@@ -541,12 +554,13 @@ export type FrameReducerActions =
541554
homeframeUrl: string;
542555
};
543556

544-
export type ButtonPressFunction = (
545-
frame: Frame,
546-
frameButton: FrameButton,
547-
index: number,
548-
fetchFrameOverride?: FetchFrameFunction
549-
) => void | Promise<void>;
557+
export type ButtonPressFunction = (arg: {
558+
frameButton: FrameButton;
559+
parseResult: ParseFramesWithReportsResult;
560+
specification: SupportedParsingSpecification;
561+
index: number;
562+
fetchFrameOverride?: FetchFrameFunction;
563+
}) => void | Promise<void>;
550564

551565
type CastActionButtonPressFunctionArg = {
552566
castAction: CastActionResponse & {
@@ -581,7 +595,12 @@ export type ComposerActionButtonPressFunction = (
581595

582596
export type CastActionRequest = Omit<
583597
FramePOSTRequest,
584-
"method" | "frameButton" | "sourceFrame" | "signerStateActionContext"
598+
| "method"
599+
| "frameButton"
600+
| "specification"
601+
| "sourceFrame"
602+
| "sourceParseResult"
603+
| "signerStateActionContext"
585604
> & {
586605
method: "CAST_ACTION";
587606
action: CastActionResponse & {
@@ -595,7 +614,12 @@ export type CastActionRequest = Omit<
595614

596615
export type ComposerActionRequest = Omit<
597616
FramePOSTRequest,
598-
"method" | "frameButton" | "sourceFrame" | "signerStateActionContext"
617+
| "method"
618+
| "frameButton"
619+
| "specification"
620+
| "sourceFrame"
621+
| "sourceParseResult"
622+
| "signerStateActionContext"
599623
> & {
600624
method: "COMPOSER_ACTION";
601625
action: CastActionResponse & {

packages/render/src/ui/frame.base.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export function BaseFrameUI<TStylingProps extends Record<string, unknown>>({
150150
case "requestError": {
151151
if (
152152
"sourceFrame" in currentFrameStackItem.request &&
153-
currentFrameStackItem.request.sourceFrame
153+
currentFrameStackItem.request.sourceParseResult
154154
) {
155155
frameUiState = {
156156
status: "complete",
@@ -159,6 +159,8 @@ export function BaseFrameUI<TStylingProps extends Record<string, unknown>>({
159159
isImageLoading,
160160
id: currentFrameStackItem.timestamp.getTime(),
161161
frameState,
162+
parseResult: currentFrameStackItem.request.sourceParseResult,
163+
specification: currentFrameStackItem.request.specification,
162164
};
163165
} else {
164166
return components.Error(
@@ -192,6 +194,8 @@ export function BaseFrameUI<TStylingProps extends Record<string, unknown>>({
192194
isImageLoading,
193195
id: currentFrameStackItem.timestamp.getTime(),
194196
frameState,
197+
parseResult: currentFrameStackItem.request.sourceParseResult,
198+
specification: currentFrameStackItem.request.specification,
195199
};
196200

197201
break;
@@ -211,6 +215,8 @@ export function BaseFrameUI<TStylingProps extends Record<string, unknown>>({
211215
isImageLoading,
212216
id: currentFrameStackItem.timestamp.getTime(),
213217
frameState,
218+
parseResult: currentFrameStackItem.request.sourceParseResult,
219+
specification: currentFrameStackItem.request.specification,
214220
};
215221
}
216222

@@ -233,6 +239,8 @@ export function BaseFrameUI<TStylingProps extends Record<string, unknown>>({
233239
isImageLoading,
234240
id: currentFrameStackItem.timestamp.getTime(),
235241
frameState,
242+
parseResult: currentFrameStackItem.parseResult,
243+
specification: parseResult.specification,
236244
};
237245
} else if (isPartialFrameParseResult(parseResult) && allowPartialFrame) {
238246
frameUiState = {
@@ -245,6 +253,8 @@ export function BaseFrameUI<TStylingProps extends Record<string, unknown>>({
245253
isImageLoading,
246254
id: currentFrameStackItem.timestamp.getTime(),
247255
frameState,
256+
parseResult: currentFrameStackItem.parseResult,
257+
specification: parseResult.specification,
248258
};
249259
} else {
250260
return components.Error(
@@ -284,12 +294,12 @@ export function BaseFrameUI<TStylingProps extends Record<string, unknown>>({
284294
rootDimensionsRef.current = rootRef.current?.computeDimensions();
285295

286296
Promise.resolve(
287-
frameState.onButtonPress(
288-
// @todo change the type onButtonPress to accept partial frame as well because that can happen if partial frames are enabled
289-
frameUiState.frame as Frame,
297+
frameState.onButtonPress({
290298
frameButton,
291-
index
292-
)
299+
index,
300+
parseResult: frameUiState.parseResult,
301+
specification: frameUiState.specification,
302+
})
293303
).catch((error) => {
294304
// eslint-disable-next-line no-console -- provide feedback to the user
295305
console.error(error);

packages/render/src/ui/types.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
import type { Frame, FrameButton } from "frames.js";
1+
import type {
2+
Frame,
3+
FrameButton,
4+
SupportedParsingSpecification,
5+
} from "frames.js";
26
import type { createElement, ReactElement } from "react";
7+
import type { ParseFramesWithReportsResult } from "frames.js/frame-parsers";
38
import type { FrameState } from "../types";
49

510
/**
@@ -44,6 +49,8 @@ export type FrameUIState =
4449
frameState: FrameState;
4550
debugImage?: string;
4651
isImageLoading: boolean;
52+
parseResult: ParseFramesWithReportsResult;
53+
specification: SupportedParsingSpecification;
4754
}
4855
| {
4956
id: number;
@@ -53,6 +60,8 @@ export type FrameUIState =
5360
frameState: FrameState;
5461
debugImage?: string;
5562
isImageLoading: boolean;
63+
parseResult: ParseFramesWithReportsResult;
64+
specification: SupportedParsingSpecification;
5665
};
5766

5867
type FrameUIStateProps = {

0 commit comments

Comments
 (0)