Skip to content

Commit

Permalink
πŸ› fix: Fix og
Browse files Browse the repository at this point in the history
  • Loading branch information
canisminor1990 committed Dec 6, 2023
1 parent 8b23926 commit 703f45a
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ __test__
# production
dist
es
lib
logs

# misc
# add other ignore file below
lib
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ coverage
# production
dist
es
lib
logs
test-output

Expand All @@ -42,4 +41,5 @@ test-output

# misc
# add other ignore file below
bun.lockb
bun.lockb
.vercel
1 change: 0 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ __snapshots__
# production
dist
es
lib
logs

# umi
Expand Down
39 changes: 37 additions & 2 deletions api/sponsor.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
import { ImageResponse } from '@vercel/og';

import cors from '../lib/cors';
import Sponsor from '../src/Sponsor';

const fetchFonts = async () => {
// Regular Font
const fontFileRegular = await fetch(
'https://gw.alipayobjects.com/os/kitchen/BUfo9kyDYs/HarmonyOS_Sans_Regular.ttf',
);
const fontRegular: ArrayBuffer = await fontFileRegular.arrayBuffer();

// Bold Font
const fontFileBold = await fetch(
'https://gw.alipayobjects.com/os/kitchen/ywwdIaXDZa/HarmonyOS_Sans_Bold.ttf',
);
const fontBold: ArrayBuffer = await fontFileBold.arrayBuffer();

return { fontBold, fontRegular };
};

export const config = {
runtime: 'edge',
};
Expand All @@ -24,24 +41,40 @@ export default async function handler(request: Request): Promise<any> {

const avatarSize = getNumber(searchParams.get('avatarSize'));
const width = getNumber(searchParams.get('width'), 800);
const height = getNumber(searchParams.get('height'));
const height = getNumber(searchParams.get('height'), 88);
const padding = getNumber(searchParams.get('padding'));
const themeMode = searchParams.get('themeMode') === 'dark' ? 'dark' : 'light';
const id = searchParams.get('id') || 'lobehub';
const data = (await getData(id)) as any;
const { fontBold, fontRegular } = await fetchFonts();

return new ImageResponse(
const res = new ImageResponse(
(
<Sponsor
avatarSize={avatarSize}
data={data}
padding={padding}
style={{ fontFamily: '"HarmonyOS Sans"' }}
themeMode={themeMode}
width={width}
/>
),
{
emoji: 'fluent',
fonts: [
{
data: fontRegular,
name: 'HarmonyOS Sans',
style: 'normal',
weight: 400,
},
{
data: fontBold,
name: 'HarmonyOS Sans',
style: 'normal',
weight: 600,
},
],
headers: {
'CDN-Cache-Control': 'public, s-maxage=120',
'Vercel-CDN-Cache-Control': 'public, s-maxage=3600',
Expand All @@ -52,6 +85,8 @@ export default async function handler(request: Request): Promise<any> {
width,
},
);

return cors(request, res);
} catch (error: any) {
console.log(`${error.message}`);
return new Response(`Failed to generate the image`, {
Expand Down
140 changes: 140 additions & 0 deletions lib/cors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/**
* Multi purpose CORS lib.
* Note: Based on the `cors` package in npm but using only
* web APIs. Feel free to use it in your own projects.
*/

type StaticOrigin = boolean | string | RegExp | (boolean | string | RegExp)[];

type OriginFn = (origin: string | undefined, req: Request) => StaticOrigin | Promise<StaticOrigin>;

interface CorsOptions {
origin?: StaticOrigin | OriginFn;
methods?: string | string[];
allowedHeaders?: string | string[];
exposedHeaders?: string | string[];
credentials?: boolean;
maxAge?: number;
preflightContinue?: boolean;
optionsSuccessStatus?: number;
}

const defaultOptions: CorsOptions = {
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
preflightContinue: false,
optionsSuccessStatus: 204,
};

function isOriginAllowed(origin: string, allowed: StaticOrigin): boolean {
return Array.isArray(allowed)
? allowed.some((o) => isOriginAllowed(origin, o))
: typeof allowed === 'string'
? origin === allowed
: allowed instanceof RegExp
? allowed.test(origin)
: !!allowed;
}

function getOriginHeaders(reqOrigin: string | undefined, origin: StaticOrigin) {
const headers = new Headers();

if (origin === '*') {
// Allow any origin
headers.set('Access-Control-Allow-Origin', '*');
} else if (typeof origin === 'string') {
// Fixed origin
headers.set('Access-Control-Allow-Origin', origin);
headers.append('Vary', 'Origin');
} else {
const allowed = isOriginAllowed(reqOrigin ?? '', origin);

if (allowed && reqOrigin) {
headers.set('Access-Control-Allow-Origin', reqOrigin);
}
headers.append('Vary', 'Origin');
}

return headers;
}

// originHeadersFromReq

async function originHeadersFromReq(req: Request, origin: StaticOrigin | OriginFn) {
const reqOrigin = req.headers.get('Origin') || undefined;
const value = typeof origin === 'function' ? await origin(reqOrigin, req) : origin;

if (!value) return;
return getOriginHeaders(reqOrigin, value);
}

function getAllowedHeaders(req: Request, allowed?: string | string[]) {
const headers = new Headers();

if (!allowed) {
allowed = req.headers.get('Access-Control-Request-Headers')!;
headers.append('Vary', 'Access-Control-Request-Headers');
} else if (Array.isArray(allowed)) {
// If the allowed headers is an array, turn it into a string
allowed = allowed.join(',');
}
if (allowed) {
headers.set('Access-Control-Allow-Headers', allowed);
}

return headers;
}

export default async function cors(req: Request, res: Response, options?: CorsOptions) {
const opts = { ...defaultOptions, ...options };
const { headers } = res;
const originHeaders = await originHeadersFromReq(req, opts.origin ?? false);
const mergeHeaders = (v: string, k: string) => {
if (k === 'Vary') headers.append(k, v);
else headers.set(k, v);
};

// If there's no origin we won't touch the response
if (!originHeaders) return res;

originHeaders.forEach(mergeHeaders);

if (opts.credentials) {
headers.set('Access-Control-Allow-Credentials', 'true');
}

const exposed = Array.isArray(opts.exposedHeaders)
? opts.exposedHeaders.join(',')
: opts.exposedHeaders;

if (exposed) {
headers.set('Access-Control-Expose-Headers', exposed);
}

// Handle the preflight request
if (req.method === 'OPTIONS') {
if (opts.methods) {
const methods = Array.isArray(opts.methods) ? opts.methods.join(',') : opts.methods;

headers.set('Access-Control-Allow-Methods', methods);
}

getAllowedHeaders(req, opts.allowedHeaders).forEach(mergeHeaders);

if (typeof opts.maxAge === 'number') {
headers.set('Access-Control-Max-Age', String(opts.maxAge));
}

if (opts.preflightContinue) return res;

headers.set('Content-Length', '0');
return new Response(null, { status: opts.optionsSuccessStatus, headers });
}

// If we got here, it's a normal request
return res;
}

export function initCors(options?: CorsOptions) {
return (req: Request, res: Response) => cors(req, res, options);
}
2 changes: 0 additions & 2 deletions src/Sponsor/demos/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export default () => {
{
avatarSize: 64,
id: 'lobehub',
padding: 0,
width: 800,
},
{ store },
);
Expand Down
14 changes: 5 additions & 9 deletions src/Sponsor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,14 @@ export interface SponsorProps {
groupBy?: TierItem[];
height?: number;
padding?: number;
style?: CSSProperties;
texts?: [string, string];
themeMode?: 'light' | 'dark';
width?: number;
}

const Sponsor: FC<SponsorProps> = ({
padding,
width = 800,
height,
style,
data,
groupBy = DEFAULT_GROUP,
fallbackTier = '🌟 One Time',
Expand Down Expand Up @@ -132,9 +131,7 @@ const Sponsor: FC<SponsorProps> = ({
display: 'flex',
flexWrap: 'wrap',
gap: avatarSize / 8,
height,
padding,
width,
...style,
}}
>
{sortedData().map((item) => {
Expand Down Expand Up @@ -177,7 +174,6 @@ const Sponsor: FC<SponsorProps> = ({
justifyContent: 'center',
marginTop: -avatarSize / 6,
padding: avatarSize / 16,
zIndex: 2,
}}
>
{`${tierConfig.emoji} ${
Expand All @@ -202,8 +198,8 @@ const Sponsor: FC<SponsorProps> = ({
padding: `${avatarSize / 8}px ${avatarSize / 6}px`,
}}
>
<div style={{ fontSize: avatarSize / 6 }}>{texts[0]}</div>
<div style={{ fontSize: avatarSize / 4, fontWeight: 'bold' }}>
<div style={{ display: 'flex', fontSize: avatarSize / 6 }}>{texts[0]}</div>
<div style={{ display: 'flex', fontSize: avatarSize / 4, fontWeight: 'bold' }}>
{`${texts[1]} `}
<span style={{ color: '#DC485F' }}>S</span>
<span style={{ color: '#AB4ABB' }}>p</span>
Expand Down

0 comments on commit 703f45a

Please sign in to comment.