Skip to content

Commit

Permalink
feat: proxy frame image requests (#1049)
Browse files Browse the repository at this point in the history
  • Loading branch information
JFrankfurt authored Oct 8, 2024
1 parent a16234e commit dab3447
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
29 changes: 29 additions & 0 deletions apps/web/app/frames/img-proxy/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const url = searchParams.get('url');

if (!url) {
return NextResponse.json({ error: 'Missing url' }, { status: 400 });
}

try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`);
}
const contentType = response.headers.get('content-type');
const imageBuffer = await response.arrayBuffer();
return new NextResponse(imageBuffer, {
status: 200,
headers: {
'Content-Type': contentType ?? 'application/octet-stream',
'Cache-Control': 'public, max-age=86400',
},
});
} catch (error) {
console.error('Error fetching image:', error);
return NextResponse.json({ error: 'Failed to fetch image' }, { status: 500 });
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { FrameUIComponents, FrameUITheme } from '@frames.js/render/ui';
import classNames from 'classnames';
import Image from 'next/image';
import { useEffect, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import baseLoading from './base-loading.gif';

type StylingProps = {
Expand Down Expand Up @@ -40,6 +40,14 @@ export const theme: FrameUITheme<StylingProps> = {
},
};

function isDataUrl(url: string) {
return /^data:image\/[a-zA-Z]+;base64,/.test(url);
}

function isSvgDataUrl(url: string) {
return url.startsWith('data:image/svg+xml');
}

type TransitionWrapperProps = {
aspectRatio: '1:1' | '1.91:1';
src: string;
Expand Down Expand Up @@ -75,6 +83,24 @@ function TransitionWrapper({

const ar = aspectRatio.replace(':', '/');

const style = useMemo(
() => ({
'--frame-image-aspect-ratio': ar,
...(isCssProperties(stylingProps.style) && stylingProps.style),
}),
[ar, stylingProps.style],
);

const assetSrc = useMemo(
() =>
isLoading || isSvgDataUrl(src)
? '' // todo: in the svg case, add an error state instead
: isDataUrl(src)
? src
: `/frames/img-proxy?url=${encodeURIComponent(src)}`,
[isLoading, src],
);

return (
<div className="relative">
{/* Loading Screen */}
Expand All @@ -90,15 +116,12 @@ function TransitionWrapper({
{/* Image */}
<img
{...stylingProps}
src={isLoading ? undefined : src}
src={assetSrc}
alt={alt}
onLoad={onImageLoadEnd}
onError={onImageLoadEnd}
data-aspect-ratio={ar}
style={{
'--frame-image-aspect-ratio': ar,
...(isCssProperties(stylingProps.style) && stylingProps.style),
}}
style={style}
className={classNames('transition-opacity duration-500', {
'opacity-0': isLoading || isTransitioning,
'opacity-100': !isLoading && !isTransitioning,
Expand Down

0 comments on commit dab3447

Please sign in to comment.