@@ -4,73 +4,66 @@ import { html } from "satori-html";
4
4
import fonts from "../src/fonts.js" ;
5
5
import mainLayout from "../src/layouts/main.js" ;
6
6
import frames from '../src/frames/index.js' ;
7
- import { Frame , FrameActionDataParsed , GetFrameHtmlOptions , getFrameHtml } from " frames.js" ;
7
+ import { type Frame , type FrameActionDataParsed , type GetFrameHtmlOptions , getFrameHtml } from ' frames.js' ;
8
8
import landingPage from '../src/landing-page.js' ;
9
9
import { isFrameStolen } from './antitheft.js' ;
10
10
11
+ const DEFAULT_FRAME = 'poster' ;
12
+ const DEFAULT_STATE = {
13
+ frame : DEFAULT_FRAME ,
14
+ } ;
15
+
11
16
/**
12
17
* Determines the next frame to display based on the context and message of the current frame.
13
18
*
14
- * @param frameContext Contains context information about the current frame, such as the source frame.
15
- * @param frameMessage An object containing the parsed data for the frame action.
19
+ * @param prevFrameName The name of the frame
20
+ * @param frameData An object containing the parsed data for the frame action.
16
21
* @returns A promise that resolves to the response for displaying the next frame.
17
22
*/
18
- export default async ( frameContext , frameMessage : FrameActionDataParsed ) => {
19
- let nextFrameName = 'poster' ;
20
- const prevFrame = frames [ frameContext . searchParams ?. get ( 'frame' ) ] ;
23
+ export default async ( prevFrameName : string , frameData : FrameActionDataParsed ) => {
24
+ const prevFrame = prevFrameName ? frames [ prevFrameName ] : null ;
21
25
26
+ let nextState = DEFAULT_STATE ;
22
27
if ( prevFrame && typeof prevFrame . handleInteraction === 'function' ) {
23
- nextFrameName = await prevFrame . handleInteraction ( frameMessage , frameContext ) ;
28
+ nextState = await prevFrame . handleInteraction ( frameData ) ;
24
29
}
25
30
26
- if ( await isFrameStolen ( frameMessage ) ) {
27
- nextFrameName = 'stolen' ;
31
+ if ( await isFrameStolen ( frameData ) ) {
32
+ nextState . frame = 'stolen' ;
28
33
}
29
34
30
- const nextFrame = await frames [ nextFrameName ] . render ( frameMessage ) ;
35
+ const nextFrame = frames [ nextState . frame ] ;
36
+ frameData . state = nextFrame . state = JSON . stringify ( { ...nextFrame . state , ...nextState } ) ;
31
37
32
38
// TODO: not yet handling redirects
33
39
if ( nextFrame ) {
34
- return await respondWithFrame ( nextFrameName , nextFrame , frameMessage ) ;
40
+ return await respondWithFrame ( nextFrame , frameData ) ;
35
41
} else {
36
- console . error ( `Unknown frame requested: ${ nextFrameName } ` ) ;
42
+ console . error ( `Unknown frame requested: ${ nextState . frame } ` ) ;
37
43
}
38
44
}
39
45
40
- // const respondWithRedirect = (redirectURL) => {
41
- // const internalRedirectURL = new URL(`${process.env.URL}/redirect`)
42
- // internalRedirectURL.searchParams.set('redirectURL',redirectURL);
43
- // return new Response('<div>redirect</div>',
44
- // {
45
- // status: 302,
46
- // headers: {
47
- // 'Location': internalRedirectURL.toString(),
48
- // },
49
- // }
50
- // );
51
- // }
52
-
53
46
/**
54
47
* Constructs and responds with the HTML for a given frame based on the simpleFrame object and a frame message.
55
48
*
56
- * @param simpleFrame The frame object containing minimal information needed to construct the full frame.
49
+ * @param renderedFrame The frame object containing minimal information needed to construct the full frame.
57
50
* @param message An object containing the parsed data for the frame action.
58
51
* @returns A promise that resolves to a Response object containing the HTML for the frame.
59
52
*/
60
53
const respondWithFrame = async (
61
- name ,
62
- simpleFrame ,
63
- message : FrameActionDataParsed
54
+ nextFrame ,
55
+ frameData : FrameActionDataParsed
64
56
) => {
65
57
const postVars = new URLSearchParams ( ) ;
66
- postVars . set ( 'frame ' , name ) ;
67
- const host = process . env . URL ;
58
+ postVars . set ( 'currFrame ' , nextFrame . name ) ;
59
+ const renderedFrame = await nextFrame . render ( frameData ) ;
68
60
const frame : Frame = {
69
61
version : 'vNext' ,
70
- image : await handleImageSource ( simpleFrame , message ) ,
71
- buttons : simpleFrame . buttons ,
72
- inputText : simpleFrame . inputText ,
73
- postUrl : `${ host } /?${ postVars . toString ( ) } `
62
+ image : await handleImageSource ( renderedFrame . image , frameData ) ,
63
+ buttons : renderedFrame . buttons ,
64
+ inputText : renderedFrame . inputText ,
65
+ postUrl : `${ process . env . URL } /?${ postVars . toString ( ) } ` ,
66
+ state : nextFrame . state ,
74
67
} ;
75
68
76
69
const index = await landingPage ( frame ) ;
@@ -94,15 +87,13 @@ const respondWithFrame = async (
94
87
) ;
95
88
} ;
96
89
97
- async function handleImageSource ( frame , message ) :Promise < string > {
90
+ async function handleImageSource ( image , frameData ) :Promise < string > {
98
91
const dataUriPattern = / ^ d a t a : i m a g e \/ [ a - z A - Z ] + ; b a s e 6 4 , / ;
99
92
const absoluteUrlPattern = / ^ h t t p s ? : \/ \/ / ;
100
- const host = process . env . URL ;
93
+ const htmlPattern = / ( < ( [ ^ > ] + ) > ) / gi ;
101
94
102
- const { imageURL, imageMarkup } = frame ;
103
-
104
- if ( imageMarkup ) {
105
- const frameMarkupInLayout = mainLayout ( imageMarkup , message )
95
+ if ( htmlPattern . test ( image ) ) {
96
+ const frameMarkupInLayout = mainLayout ( image , frameData )
106
97
const svg = await satori (
107
98
html ( frameMarkupInLayout ) ,
108
99
{
@@ -117,20 +108,13 @@ async function handleImageSource(frame, message):Promise<string> {
117
108
return `data:image/png;base64,${ imageBuffer . toString ( 'base64' ) } ` ;
118
109
}
119
110
120
- // data URI
121
- else if ( dataUriPattern . test ( imageURL ) ) {
122
- return imageURL ;
111
+ // data URI or external url
112
+ else if ( dataUriPattern . test ( image ) || absoluteUrlPattern . test ( image ) ) {
113
+ return image ;
123
114
}
124
115
125
- // external image: need to proxy it
126
- else if ( absoluteUrlPattern . test ( imageURL ) ) {
127
- const ogImageResponse = await fetch ( imageURL ) ;
128
- const dataURI = await ogImageResponse . text ( ) ; // Assuming og-image returns the data URI in the response body
129
- return dataURI ;
130
- }
131
-
132
116
// local image
133
117
else {
134
- return `${ host } /${ imageURL } ` ;
118
+ return `${ process . env . URL } /${ image } ` ;
135
119
}
136
120
}
0 commit comments