1
+ import satori from "satori" ;
2
+ import sharp from "sharp" ;
3
+ import { html } from "satori-html" ;
4
+ import fonts from "../src/fonts.js" ;
5
+ import mainLayout from "../src/layouts/main.js" ;
1
6
import frames from '../src/frames/index.js' ;
2
7
import { Frame , FrameActionDataParsed , GetFrameHtmlOptions , getFrameHtml } from "frames.js" ;
3
8
import landingPage from '../src/landing-page.js' ;
4
- import { objectToURLSearchParams } from '../modules/utils.js' ;
5
9
import { isFrameStolen } from './antitheft.js' ;
6
10
7
11
/**
@@ -63,7 +67,7 @@ const respondWithFrame = async (
63
67
const host = process . env . URL ;
64
68
const frame : Frame = {
65
69
version : 'vNext' ,
66
- image : handleImageSource ( name , simpleFrame , message ) ,
70
+ image : await handleImageSource ( simpleFrame , message ) ,
67
71
buttons : simpleFrame . buttons ,
68
72
inputText : simpleFrame . inputText ,
69
73
postUrl : `${ host } /?${ postVars . toString ( ) } `
@@ -90,26 +94,43 @@ const respondWithFrame = async (
90
94
) ;
91
95
} ;
92
96
93
- function handleImageSource ( name , frame , message ) :string {
97
+ async function handleImageSource ( frame , message ) :Promise < string > {
94
98
const dataUriPattern = / ^ d a t a : i m a g e \/ [ a - z A - Z ] + ; b a s e 6 4 , / ;
95
99
const absoluteUrlPattern = / ^ h t t p s ? : \/ \/ / ;
96
100
const host = process . env . URL ;
97
101
98
- const { image } = frame ;
102
+ const { imageURL , imageMarkup } = frame ;
99
103
100
- if ( dataUriPattern . test ( image ) ) {
101
- return `${ host } /og-image?${ objectToURLSearchParams ( {
102
- dataUri : image ,
103
- } ) } `;
104
- } else if ( absoluteUrlPattern . test ( image ) ) {
105
- return `${ host } /og-image?${ objectToURLSearchParams ( {
106
- imageUrl : image ,
107
- } ) } `;
108
- } else {
109
- return `${ host } /og-image?${ objectToURLSearchParams ( {
110
- t : new Date ( ) . valueOf ( ) , // Current timestamp for cache busting.
111
- frameName : name || '' ,
112
- message
113
- } ) } `;
104
+ if ( imageMarkup ) {
105
+ const frameMarkupInLayout = mainLayout ( imageMarkup , message )
106
+ const svg = await satori (
107
+ html ( frameMarkupInLayout ) ,
108
+ {
109
+ width : 1200 ,
110
+ height : 630 ,
111
+ fonts : fonts ,
112
+ }
113
+ ) ;
114
+ const svgBuffer = Buffer . from ( svg ) ;
115
+ const imgOutput = sharp ( svgBuffer ) . webp ( ) ;
116
+ const imageBuffer = await imgOutput . toBuffer ( ) ;
117
+ return `data:image/png;base64,${ imageBuffer . toString ( 'base64' ) } ` ;
118
+ }
119
+
120
+ // data URI
121
+ else if ( dataUriPattern . test ( imageURL ) ) {
122
+ return imageURL ;
123
+ }
124
+
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
+ // local image
133
+ else {
134
+ return `${ host } /${ imageURL } ` ;
114
135
}
115
136
}
0 commit comments