@djangocfg/nextjs 2.1.225 → 2.1.227
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -80
- package/dist/config/index.mjs +6 -17
- package/dist/config/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -6
- package/dist/index.mjs +9 -865
- package/dist/index.mjs.map +1 -1
- package/dist/og-image/index.d.mts +40 -100
- package/dist/og-image/index.mjs +46 -823
- package/dist/og-image/index.mjs.map +1 -1
- package/package.json +14 -25
- package/src/index.ts +0 -3
- package/src/og-image/README.md +142 -53
- package/src/og-image/index.ts +3 -27
- package/src/og-image/metadata.ts +67 -0
- package/src/og-image/types.ts +28 -44
- package/src/og-image/url.ts +58 -0
- package/dist/og-image/components/index.d.mts +0 -59
- package/dist/og-image/components/index.mjs +0 -338
- package/dist/og-image/components/index.mjs.map +0 -1
- package/dist/og-image/utils/index.d.mts +0 -308
- package/dist/og-image/utils/index.mjs +0 -327
- package/dist/og-image/utils/index.mjs.map +0 -1
- package/src/og-image/components/DefaultTemplate.tsx +0 -369
- package/src/og-image/components/index.ts +0 -9
- package/src/og-image/route.tsx +0 -312
- package/src/og-image/utils/fonts.ts +0 -150
- package/src/og-image/utils/index.ts +0 -28
- package/src/og-image/utils/metadata.ts +0 -269
- package/src/og-image/utils/url.ts +0 -386
package/src/og-image/route.tsx
DELETED
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OG Image Route Handler
|
|
3
|
-
*
|
|
4
|
-
* Factory function to create OG Image route handler for Next.js App Router
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* ```tsx
|
|
8
|
-
* // app/api/og/route.tsx
|
|
9
|
-
* import { createOgImageHandler } from '@djangocfg/nextjs/og-image';
|
|
10
|
-
* import { MyTemplate } from './templates';
|
|
11
|
-
*
|
|
12
|
-
* export const { GET, runtime } = createOgImageHandler({
|
|
13
|
-
* template: MyTemplate,
|
|
14
|
-
* defaultProps: {
|
|
15
|
-
* siteName: 'My Site',
|
|
16
|
-
* },
|
|
17
|
-
* fonts: [{ family: 'Manrope', weight: 700 }],
|
|
18
|
-
* });
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import { ImageResponse } from 'next/og';
|
|
23
|
-
import { NextRequest } from 'next/server';
|
|
24
|
-
|
|
25
|
-
import { DefaultTemplate } from './components/DefaultTemplate';
|
|
26
|
-
import { loadGoogleFonts } from './utils';
|
|
27
|
-
import { parseOgImageData } from './utils/url';
|
|
28
|
-
|
|
29
|
-
import type { ReactElement } from 'react';
|
|
30
|
-
import type { OgImageTemplateProps } from './types';
|
|
31
|
-
|
|
32
|
-
export interface OgImageHandlerConfig {
|
|
33
|
-
/** Custom template component (optional, defaults to DefaultTemplate) */
|
|
34
|
-
template?: (props: OgImageTemplateProps) => ReactElement;
|
|
35
|
-
/** Default props to merge with query params */
|
|
36
|
-
defaultProps?: Partial<OgImageTemplateProps>;
|
|
37
|
-
/** Google Fonts to load */
|
|
38
|
-
fonts?: Array<{ family: string; weight: 400 | 500 | 600 | 700 | 800 | 900 }>;
|
|
39
|
-
/** Image size */
|
|
40
|
-
size?: { width: number; height: number };
|
|
41
|
-
/** Enable debug mode */
|
|
42
|
-
debug?: boolean;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Factory function to create OG Image route handler
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```tsx
|
|
50
|
-
* // app/api/og/route.tsx
|
|
51
|
-
* import { createOgImageHandler } from '@djangocfg/nextjs/og-image';
|
|
52
|
-
* import { MyTemplate } from '@/components/MyTemplate';
|
|
53
|
-
*
|
|
54
|
-
* export const { GET, runtime } = createOgImageHandler({
|
|
55
|
-
* template: MyTemplate,
|
|
56
|
-
* defaultProps: { siteName: 'My Site' },
|
|
57
|
-
* fonts: [{ family: 'Inter', weight: 700 }],
|
|
58
|
-
* });
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
export function createOgImageHandler(config: OgImageHandlerConfig) {
|
|
62
|
-
const {
|
|
63
|
-
template: Template = DefaultTemplate,
|
|
64
|
-
defaultProps = {},
|
|
65
|
-
fonts: fontConfig = [],
|
|
66
|
-
size = { width: 1200, height: 630 },
|
|
67
|
-
debug = false,
|
|
68
|
-
} = config;
|
|
69
|
-
|
|
70
|
-
async function GET(req: NextRequest) {
|
|
71
|
-
let searchParams: URLSearchParams = new URLSearchParams();
|
|
72
|
-
|
|
73
|
-
// Try to get searchParams from multiple sources
|
|
74
|
-
if (req.nextUrl?.searchParams && req.nextUrl.searchParams.size > 0) {
|
|
75
|
-
searchParams = req.nextUrl.searchParams;
|
|
76
|
-
} else if (req.nextUrl?.search && req.nextUrl.search.length > 1) {
|
|
77
|
-
searchParams = new URLSearchParams(req.nextUrl.search);
|
|
78
|
-
} else {
|
|
79
|
-
try {
|
|
80
|
-
const url = new URL(req.url);
|
|
81
|
-
if (url.searchParams.size > 0) {
|
|
82
|
-
searchParams = url.searchParams;
|
|
83
|
-
}
|
|
84
|
-
} catch (error) {
|
|
85
|
-
// Ignore
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (searchParams.size === 0 && req.url) {
|
|
89
|
-
const queryIndex = req.url.indexOf('?');
|
|
90
|
-
if (queryIndex !== -1) {
|
|
91
|
-
const queryString = req.url.substring(queryIndex + 1);
|
|
92
|
-
searchParams = new URLSearchParams(queryString);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (searchParams.size === 0) {
|
|
97
|
-
const customParams = req.headers.get('x-og-search-params');
|
|
98
|
-
if (customParams) {
|
|
99
|
-
searchParams = new URLSearchParams(customParams);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Initialize with defaults
|
|
105
|
-
let title = defaultProps.title || 'Untitled';
|
|
106
|
-
let subtitle = defaultProps.subtitle || '';
|
|
107
|
-
let description = defaultProps.description || subtitle;
|
|
108
|
-
|
|
109
|
-
// Support base64 data parameter (priority: base64 > query params > defaults)
|
|
110
|
-
// All template props can be encoded in base64, including styling params
|
|
111
|
-
const dataParam = searchParams.get('data');
|
|
112
|
-
let decodedParams: Record<string, any> = {};
|
|
113
|
-
|
|
114
|
-
if (dataParam) {
|
|
115
|
-
try {
|
|
116
|
-
const paramsObj: Record<string, string> = { data: dataParam };
|
|
117
|
-
for (const [key, value] of searchParams.entries()) {
|
|
118
|
-
if (key !== 'data') {
|
|
119
|
-
paramsObj[key] = value;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
decodedParams = parseOgImageData(paramsObj);
|
|
123
|
-
|
|
124
|
-
// Base64 data takes precedence - apply all decoded values
|
|
125
|
-
if (decodedParams.title && typeof decodedParams.title === 'string' && decodedParams.title.trim() !== '') {
|
|
126
|
-
title = decodedParams.title.trim();
|
|
127
|
-
}
|
|
128
|
-
if (decodedParams.subtitle && typeof decodedParams.subtitle === 'string' && decodedParams.subtitle.trim() !== '') {
|
|
129
|
-
subtitle = decodedParams.subtitle.trim();
|
|
130
|
-
}
|
|
131
|
-
if (decodedParams.description && typeof decodedParams.description === 'string' && decodedParams.description.trim() !== '') {
|
|
132
|
-
description = decodedParams.description.trim();
|
|
133
|
-
}
|
|
134
|
-
} catch (error) {
|
|
135
|
-
// Silently fall back to defaults
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Fallback to query params if not set from base64
|
|
140
|
-
if (!title || title === 'Untitled') {
|
|
141
|
-
const titleParam = searchParams.get('title');
|
|
142
|
-
if (titleParam) {
|
|
143
|
-
title = titleParam;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (!subtitle) {
|
|
147
|
-
const subtitleParam = searchParams.get('subtitle');
|
|
148
|
-
if (subtitleParam) {
|
|
149
|
-
subtitle = subtitleParam;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (!description || description === subtitle) {
|
|
153
|
-
const descParam = searchParams.get('description');
|
|
154
|
-
if (descParam) {
|
|
155
|
-
description = descParam;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Load fonts if configured
|
|
160
|
-
let fonts: any[] = [];
|
|
161
|
-
if (fontConfig.length > 0) {
|
|
162
|
-
fonts = await loadGoogleFonts(fontConfig);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Helper function to parse numeric/boolean values from decoded params
|
|
166
|
-
const parseValue = (value: any, type: 'number' | 'boolean' | 'string' = 'string'): any => {
|
|
167
|
-
if (value === undefined || value === null || value === '') {
|
|
168
|
-
return undefined;
|
|
169
|
-
}
|
|
170
|
-
if (type === 'number') {
|
|
171
|
-
const num = Number(value);
|
|
172
|
-
return isNaN(num) ? undefined : num;
|
|
173
|
-
}
|
|
174
|
-
if (type === 'boolean') {
|
|
175
|
-
if (typeof value === 'boolean') return value;
|
|
176
|
-
if (typeof value === 'string') {
|
|
177
|
-
return value.toLowerCase() === 'true' || value === '1';
|
|
178
|
-
}
|
|
179
|
-
return Boolean(value);
|
|
180
|
-
}
|
|
181
|
-
return String(value);
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Merge props: decoded params from URL override defaultProps
|
|
185
|
-
const templateProps: OgImageTemplateProps = {
|
|
186
|
-
...defaultProps,
|
|
187
|
-
// Content
|
|
188
|
-
title,
|
|
189
|
-
subtitle,
|
|
190
|
-
description,
|
|
191
|
-
// Override with decoded params if present
|
|
192
|
-
siteName: decodedParams.siteName || defaultProps.siteName,
|
|
193
|
-
logo: decodedParams.logo || defaultProps.logo,
|
|
194
|
-
// Background
|
|
195
|
-
backgroundType: (decodedParams.backgroundType as 'gradient' | 'solid') || defaultProps.backgroundType,
|
|
196
|
-
gradientStart: decodedParams.gradientStart || defaultProps.gradientStart,
|
|
197
|
-
gradientEnd: decodedParams.gradientEnd || defaultProps.gradientEnd,
|
|
198
|
-
backgroundColor: decodedParams.backgroundColor || defaultProps.backgroundColor,
|
|
199
|
-
// Typography - Title
|
|
200
|
-
titleSize: parseValue(decodedParams.titleSize, 'number') ?? defaultProps.titleSize,
|
|
201
|
-
titleWeight: parseValue(decodedParams.titleWeight, 'number') ?? defaultProps.titleWeight,
|
|
202
|
-
titleColor: decodedParams.titleColor || defaultProps.titleColor,
|
|
203
|
-
// Typography - Description
|
|
204
|
-
descriptionSize: parseValue(decodedParams.descriptionSize, 'number') ?? defaultProps.descriptionSize,
|
|
205
|
-
descriptionColor: decodedParams.descriptionColor || defaultProps.descriptionColor,
|
|
206
|
-
// Typography - Site Name
|
|
207
|
-
siteNameSize: parseValue(decodedParams.siteNameSize, 'number') ?? defaultProps.siteNameSize,
|
|
208
|
-
siteNameColor: decodedParams.siteNameColor || defaultProps.siteNameColor,
|
|
209
|
-
// Layout
|
|
210
|
-
padding: parseValue(decodedParams.padding, 'number') ?? defaultProps.padding,
|
|
211
|
-
logoSize: parseValue(decodedParams.logoSize, 'number') ?? defaultProps.logoSize,
|
|
212
|
-
// Visibility flags
|
|
213
|
-
showLogo: parseValue(decodedParams.showLogo, 'boolean') ?? defaultProps.showLogo,
|
|
214
|
-
showSiteName: parseValue(decodedParams.showSiteName, 'boolean') ?? defaultProps.showSiteName,
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return new ImageResponse(
|
|
219
|
-
<Template {...templateProps} />,
|
|
220
|
-
{
|
|
221
|
-
width: size.width,
|
|
222
|
-
height: size.height,
|
|
223
|
-
fonts,
|
|
224
|
-
debug: debug || process.env.NODE_ENV === 'development',
|
|
225
|
-
}
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return {
|
|
230
|
-
GET,
|
|
231
|
-
runtime: 'edge' as const,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Create OG Image route handler for dynamic route with path parameter
|
|
237
|
-
*
|
|
238
|
-
* This is a convenience wrapper for Next.js dynamic routes like `/api/og/[data]/route.tsx`.
|
|
239
|
-
* It extracts the `data` parameter from the path and passes it to the handler as a query parameter.
|
|
240
|
-
* Also handles static export mode automatically.
|
|
241
|
-
*
|
|
242
|
-
* @example
|
|
243
|
-
* ```tsx
|
|
244
|
-
* // app/api/og/[data]/route.tsx
|
|
245
|
-
* import { createOgImageDynamicRoute } from '@djangocfg/nextjs/og-image';
|
|
246
|
-
* import { OgImageTemplate } from '@/components/OgImageTemplate';
|
|
247
|
-
*
|
|
248
|
-
* export const runtime = 'nodejs';
|
|
249
|
-
* export const dynamic = 'force-static';
|
|
250
|
-
* export const revalidate = false;
|
|
251
|
-
*
|
|
252
|
-
* const handler = createOgImageDynamicRoute({
|
|
253
|
-
* template: OgImageTemplate,
|
|
254
|
-
* defaultProps: {
|
|
255
|
-
* siteName: 'My App',
|
|
256
|
-
* logo: '/logo.svg',
|
|
257
|
-
* },
|
|
258
|
-
* });
|
|
259
|
-
*
|
|
260
|
-
* export async function GET(
|
|
261
|
-
* request: NextRequest,
|
|
262
|
-
* { params }: { params: { data: string } }
|
|
263
|
-
) {
|
|
264
|
-
* return handler(request, params);
|
|
265
|
-
* }
|
|
266
|
-
* ```
|
|
267
|
-
*/
|
|
268
|
-
export function createOgImageDynamicRoute(config: OgImageHandlerConfig) {
|
|
269
|
-
const handler = createOgImageHandler(config);
|
|
270
|
-
const isStaticBuild = typeof process !== 'undefined' && process.env.NEXT_PUBLIC_STATIC_BUILD === 'true';
|
|
271
|
-
|
|
272
|
-
async function GET(
|
|
273
|
-
request: NextRequest,
|
|
274
|
-
context: { params: Promise<{ data: string }> }
|
|
275
|
-
) {
|
|
276
|
-
// In static export mode, return a simple error response
|
|
277
|
-
if (isStaticBuild) {
|
|
278
|
-
return new Response('OG Image generation is not available in static export mode', {
|
|
279
|
-
status: 404,
|
|
280
|
-
headers: { 'Content-Type': 'text/plain' },
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Await params (Next.js 15+ uses Promise)
|
|
285
|
-
const params = await context.params;
|
|
286
|
-
|
|
287
|
-
// Extract data from path parameter
|
|
288
|
-
const dataParam = params.data;
|
|
289
|
-
|
|
290
|
-
// Create a request with the data parameter as a query param for the handler
|
|
291
|
-
const url = new URL(request.url);
|
|
292
|
-
url.searchParams.set('data', dataParam);
|
|
293
|
-
|
|
294
|
-
const modifiedRequest = new NextRequest(url.toString(), {
|
|
295
|
-
method: request.method,
|
|
296
|
-
headers: request.headers,
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
return handler.GET(modifiedRequest);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// For static export, provide generateStaticParams that returns empty array
|
|
303
|
-
// This allows the route to be excluded from static build
|
|
304
|
-
async function generateStaticParams(): Promise<Array<{ data: string }>> {
|
|
305
|
-
return [];
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
return {
|
|
309
|
-
GET,
|
|
310
|
-
generateStaticParams,
|
|
311
|
-
};
|
|
312
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Font Utilities for OG Image Generation
|
|
3
|
-
*
|
|
4
|
-
* Provides dynamic font loading from Google Fonts without requiring files in public/
|
|
5
|
-
* Based on Vercel's official @vercel/og documentation
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export interface FontConfig {
|
|
9
|
-
name: string;
|
|
10
|
-
weight?: 400 | 500 | 600 | 700 | 800 | 900;
|
|
11
|
-
style?: 'normal' | 'italic';
|
|
12
|
-
data: ArrayBuffer;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Load a Google Font dynamically
|
|
17
|
-
*
|
|
18
|
-
* @param font - Font family name (e.g., "Inter", "Roboto", "Manrope")
|
|
19
|
-
* @param text - Text to optimize font for (optional, reduces file size)
|
|
20
|
-
* @param weight - Font weight (default: 700)
|
|
21
|
-
* @returns ArrayBuffer of font data
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* const fontData = await loadGoogleFont('Manrope', 'Hello World', 700);
|
|
25
|
-
*/
|
|
26
|
-
export async function loadGoogleFont(
|
|
27
|
-
font: string,
|
|
28
|
-
text?: string,
|
|
29
|
-
weight: number = 700
|
|
30
|
-
): Promise<ArrayBuffer> {
|
|
31
|
-
// Construct Google Fonts API URL
|
|
32
|
-
let url = `https://fonts.googleapis.com/css2?family=${font}:wght@${weight}`;
|
|
33
|
-
|
|
34
|
-
// Add text parameter to optimize font subset (reduces size)
|
|
35
|
-
if (text) {
|
|
36
|
-
url += `&text=${encodeURIComponent(text)}`;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
// Fetch CSS containing font URL
|
|
41
|
-
const css = await fetch(url, {
|
|
42
|
-
headers: {
|
|
43
|
-
// Required to get TTF format instead of WOFF2
|
|
44
|
-
'User-Agent':
|
|
45
|
-
'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',
|
|
46
|
-
},
|
|
47
|
-
}).then((res) => res.text());
|
|
48
|
-
|
|
49
|
-
// Extract font URL from CSS
|
|
50
|
-
const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/);
|
|
51
|
-
|
|
52
|
-
if (!resource || !resource[1]) {
|
|
53
|
-
throw new Error(`Failed to parse font URL from CSS for font: ${font}`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Fetch actual font file
|
|
57
|
-
const response = await fetch(resource[1]);
|
|
58
|
-
|
|
59
|
-
if (response.status !== 200) {
|
|
60
|
-
throw new Error(`Failed to fetch font data: HTTP ${response.status}`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return await response.arrayBuffer();
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.error(`Error loading Google Font "${font}":`, error);
|
|
66
|
-
throw new Error(`Failed to load font "${font}": ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Load multiple Google Fonts
|
|
72
|
-
*
|
|
73
|
-
* @param fonts - Array of font configurations to load
|
|
74
|
-
* @returns Array of FontConfig objects ready for ImageResponse
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* const fonts = await loadGoogleFonts([
|
|
78
|
-
* { family: 'Manrope', weight: 700 },
|
|
79
|
-
* { family: 'Inter', weight: 400 }
|
|
80
|
-
* ]);
|
|
81
|
-
*/
|
|
82
|
-
export async function loadGoogleFonts(
|
|
83
|
-
fonts: Array<{
|
|
84
|
-
family: string;
|
|
85
|
-
weight?: 400 | 500 | 600 | 700 | 800 | 900;
|
|
86
|
-
style?: 'normal' | 'italic';
|
|
87
|
-
text?: string;
|
|
88
|
-
}>
|
|
89
|
-
): Promise<FontConfig[]> {
|
|
90
|
-
const fontConfigs = await Promise.all(
|
|
91
|
-
fonts.map(async ({ family, weight = 700, style = 'normal', text }) => {
|
|
92
|
-
const data = await loadGoogleFont(family, text, weight);
|
|
93
|
-
return {
|
|
94
|
-
name: family,
|
|
95
|
-
weight,
|
|
96
|
-
style,
|
|
97
|
-
data,
|
|
98
|
-
};
|
|
99
|
-
})
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
return fontConfigs;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Create a font loader with caching
|
|
107
|
-
*
|
|
108
|
-
* Useful for reusing font data across multiple OG image requests
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* const fontLoader = createFontLoader();
|
|
112
|
-
* const font = await fontLoader.load('Manrope', 700);
|
|
113
|
-
*/
|
|
114
|
-
export function createFontLoader() {
|
|
115
|
-
const cache = new Map<string, Promise<ArrayBuffer>>();
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
/**
|
|
119
|
-
* Load a font with caching
|
|
120
|
-
*/
|
|
121
|
-
async load(
|
|
122
|
-
family: string,
|
|
123
|
-
weight: number = 700,
|
|
124
|
-
text?: string
|
|
125
|
-
): Promise<ArrayBuffer> {
|
|
126
|
-
const cacheKey = `${family}-${weight}-${text || 'all'}`;
|
|
127
|
-
|
|
128
|
-
if (!cache.has(cacheKey)) {
|
|
129
|
-
cache.set(cacheKey, loadGoogleFont(family, text, weight));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return cache.get(cacheKey)!;
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Clear the cache
|
|
137
|
-
*/
|
|
138
|
-
clear() {
|
|
139
|
-
cache.clear();
|
|
140
|
-
},
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Get cache size
|
|
144
|
-
*/
|
|
145
|
-
size() {
|
|
146
|
-
return cache.size;
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utilities for OG Image Generation
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
loadGoogleFont,
|
|
7
|
-
loadGoogleFonts,
|
|
8
|
-
createFontLoader,
|
|
9
|
-
type FontConfig,
|
|
10
|
-
} from './fonts';
|
|
11
|
-
|
|
12
|
-
export {
|
|
13
|
-
generateOgImageUrl,
|
|
14
|
-
getAbsoluteOgImageUrl,
|
|
15
|
-
createOgImageUrlBuilder,
|
|
16
|
-
parseOgImageUrl,
|
|
17
|
-
parseOgImageData,
|
|
18
|
-
encodeBase64,
|
|
19
|
-
decodeBase64,
|
|
20
|
-
type OgImageUrlParams,
|
|
21
|
-
} from './url';
|
|
22
|
-
|
|
23
|
-
export {
|
|
24
|
-
generateAppMetadata,
|
|
25
|
-
createAppMetadataGenerator,
|
|
26
|
-
type AppMetadataOptions,
|
|
27
|
-
} from './metadata';
|
|
28
|
-
|