@quartz-community/og-image 0.1.1 → 1.0.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Stable 1.0 release. All `@quartz-community/*` dependencies now use `^1.0.0` ranges.
8
+
9
+ Pre-1.0 caret ranges pinned the minor version (`^0.2.1` means `>=0.2.1 <0.3.0`), so
10
+ published fixes to shared packages could never be resolved by dependents. Moving the
11
+ ecosystem to 1.0 makes caret ranges behave conventionally.
12
+
13
+ ## 0.1.2
14
+
15
+ ### Patch Changes
16
+
17
+ - ab7b8e9: Fix build crash when Google Fonts is unreachable (fetch failed). Added error handling to font fetching, system font fallback for macOS/Linux/Windows, and graceful skip when no fonts are available.
18
+
3
19
  All notable changes to this project will be documented in this file.
4
20
 
5
21
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
package/dist/index.js CHANGED
@@ -23924,7 +23924,50 @@ async function getSatoriFonts(headerFont, bodyFont) {
23924
23924
  ...headerFonts.filter((font) => font !== null),
23925
23925
  ...bodyFonts.filter((font) => font !== null)
23926
23926
  ];
23927
- return fonts;
23927
+ if (fonts.length > 0) {
23928
+ return fonts;
23929
+ }
23930
+ console.log(
23931
+ styleText(
23932
+ "yellow",
23933
+ `
23934
+ Warning: Could not fetch any Google Fonts. Attempting to use a system font as fallback for OG image generation.`
23935
+ )
23936
+ );
23937
+ const [regularFont, boldFont] = await Promise.all([loadSystemFont(false), loadSystemFont(true)]);
23938
+ const systemFonts = [];
23939
+ if (regularFont) {
23940
+ systemFonts.push({
23941
+ name: headerFontName,
23942
+ data: regularFont.data,
23943
+ weight: 400,
23944
+ style: "normal"
23945
+ });
23946
+ systemFonts.push({
23947
+ name: bodyFontName,
23948
+ data: regularFont.data,
23949
+ weight: 400,
23950
+ style: "normal"
23951
+ });
23952
+ }
23953
+ if (boldFont) {
23954
+ systemFonts.push({
23955
+ name: headerFontName,
23956
+ data: boldFont.data,
23957
+ weight: 700,
23958
+ style: "normal"
23959
+ });
23960
+ }
23961
+ if (systemFonts.length > 0) {
23962
+ const fontName = regularFont?.name ?? boldFont?.name;
23963
+ console.log(
23964
+ styleText(
23965
+ "yellow",
23966
+ `Warning: Using system font "${fontName}" as fallback. OG images may look different than intended.`
23967
+ )
23968
+ );
23969
+ }
23970
+ return systemFonts;
23928
23971
  }
23929
23972
  async function fetchTtf(rawFontName, weight) {
23930
23973
  const fontName = rawFontName.replaceAll(" ", "+");
@@ -23936,31 +23979,127 @@ async function fetchTtf(rawFontName, weight) {
23936
23979
  return fs.readFile(cachePath);
23937
23980
  } catch {
23938
23981
  }
23939
- const cssResponse = await fetch(
23940
- `https://fonts.googleapis.com/css2?family=${fontName}:wght@${weight}`
23941
- );
23942
- const css = await cssResponse.text();
23943
- const urlRegex = /url\((https:\/\/fonts.gstatic.com\/s\/.*?.ttf)\)/g;
23944
- const match = urlRegex.exec(css);
23945
- if (!match) {
23982
+ try {
23983
+ const cssUrl = `https://fonts.googleapis.com/css2?family=${fontName}:wght@${weight}`;
23984
+ const cssResponse = await fetch(cssUrl);
23985
+ if (!cssResponse.ok) {
23986
+ console.log(
23987
+ styleText(
23988
+ "yellow",
23989
+ `
23990
+ Warning: Google Fonts returned HTTP ${cssResponse.status} for ${rawFontName} (weight ${weight})`
23991
+ )
23992
+ );
23993
+ return;
23994
+ }
23995
+ const css = await cssResponse.text();
23996
+ const urlRegex = /url\((https:\/\/fonts.gstatic.com\/s\/.*?.ttf)\)/g;
23997
+ const match = urlRegex.exec(css);
23998
+ if (!match) {
23999
+ console.log(
24000
+ styleText(
24001
+ "yellow",
24002
+ `
24003
+ Warning: Could not extract font URL for ${rawFontName} (weight ${weight}) from Google Fonts CSS`
24004
+ )
24005
+ );
24006
+ return;
24007
+ }
24008
+ const fontUrl = match[1];
24009
+ if (!fontUrl) {
24010
+ return;
24011
+ }
24012
+ const fontResponse = await fetch(fontUrl);
24013
+ if (!fontResponse.ok) {
24014
+ console.log(
24015
+ styleText(
24016
+ "yellow",
24017
+ `
24018
+ Warning: Failed to download font file for ${rawFontName} (weight ${weight}): HTTP ${fontResponse.status}`
24019
+ )
24020
+ );
24021
+ return;
24022
+ }
24023
+ const fontData = Buffer.from(await fontResponse.arrayBuffer());
24024
+ await fs.mkdir(cacheDir, { recursive: true });
24025
+ await fs.writeFile(cachePath, fontData);
24026
+ return fontData;
24027
+ } catch (err2) {
24028
+ const message = err2 instanceof Error ? err2.message : String(err2);
23946
24029
  console.log(
23947
24030
  styleText(
23948
24031
  "yellow",
23949
24032
  `
23950
- Warning: Failed to fetch font ${rawFontName} with weight ${weight}, got ${cssResponse.statusText}`
24033
+ Warning: Failed to fetch font "${rawFontName}" (weight ${weight}) from Google Fonts: ${message}`
23951
24034
  )
23952
24035
  );
23953
24036
  return;
23954
24037
  }
23955
- const fontUrl = match[1];
23956
- if (!fontUrl) {
23957
- return;
24038
+ }
24039
+ var SYSTEM_FONT_CANDIDATES = {
24040
+ darwin: [
24041
+ // San Francisco (macOS 10.15+)
24042
+ "/System/Library/Fonts/SFNS.ttf",
24043
+ // Helvetica Neue
24044
+ "/System/Library/Fonts/HelveticaNeue.ttc",
24045
+ // Helvetica
24046
+ "/System/Library/Fonts/Helvetica.ttc",
24047
+ // Arial
24048
+ "/Library/Fonts/Arial.ttf",
24049
+ // Fallback: guaranteed present on every macOS
24050
+ "/System/Library/Fonts/Supplemental/Arial.ttf"
24051
+ ],
24052
+ linux: [
24053
+ // DejaVu Sans — ubiquitous on most distros
24054
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
24055
+ // Liberation Sans (Red Hat / Fedora)
24056
+ "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
24057
+ "/usr/share/fonts/liberation-sans/LiberationSans-Regular.ttf",
24058
+ // Noto Sans
24059
+ "/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf",
24060
+ "/usr/share/fonts/noto/NotoSans-Regular.ttf",
24061
+ // FreeSans
24062
+ "/usr/share/fonts/truetype/freefont/FreeSans.ttf"
24063
+ ],
24064
+ win32: [
24065
+ "C:\\Windows\\Fonts\\arial.ttf",
24066
+ "C:\\Windows\\Fonts\\segoeui.ttf",
24067
+ "C:\\Windows\\Fonts\\calibri.ttf",
24068
+ "C:\\Windows\\Fonts\\verdana.ttf"
24069
+ ]
24070
+ };
24071
+ var SYSTEM_FONT_CANDIDATES_BOLD = {
24072
+ darwin: [
24073
+ "/System/Library/Fonts/SFNS.ttf",
24074
+ "/Library/Fonts/Arial Bold.ttf",
24075
+ "/System/Library/Fonts/Supplemental/Arial Bold.ttf"
24076
+ ],
24077
+ linux: [
24078
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
24079
+ "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
24080
+ "/usr/share/fonts/liberation-sans/LiberationSans-Bold.ttf",
24081
+ "/usr/share/fonts/truetype/noto/NotoSans-Bold.ttf",
24082
+ "/usr/share/fonts/noto/NotoSans-Bold.ttf",
24083
+ "/usr/share/fonts/truetype/freefont/FreeSansBold.ttf"
24084
+ ],
24085
+ win32: [
24086
+ "C:\\Windows\\Fonts\\arialbd.ttf",
24087
+ "C:\\Windows\\Fonts\\segoeuib.ttf",
24088
+ "C:\\Windows\\Fonts\\calibrib.ttf",
24089
+ "C:\\Windows\\Fonts\\verdanab.ttf"
24090
+ ]
24091
+ };
24092
+ async function loadSystemFont(bold) {
24093
+ const candidates = bold ? SYSTEM_FONT_CANDIDATES_BOLD[process.platform] ?? [] : SYSTEM_FONT_CANDIDATES[process.platform] ?? [];
24094
+ for (const fontPath of candidates) {
24095
+ try {
24096
+ const data = await fs.readFile(fontPath);
24097
+ const name = path.basename(fontPath, path.extname(fontPath));
24098
+ return { data, name };
24099
+ } catch {
24100
+ }
23958
24101
  }
23959
- const fontResponse = await fetch(fontUrl);
23960
- const fontData = Buffer.from(await fontResponse.arrayBuffer());
23961
- await fs.mkdir(cacheDir, { recursive: true });
23962
- await fs.writeFile(cachePath, fontData);
23963
- return fontData;
24102
+ return void 0;
23964
24103
  }
23965
24104
  var defaultImage = ({
23966
24105
  cfg,
@@ -24272,6 +24411,18 @@ var CustomOgImages = (userOpts) => {
24272
24411
  const headerFont = theme.typography.header;
24273
24412
  const bodyFont = theme.typography.body;
24274
24413
  const fonts = await getSatoriFonts(headerFont, bodyFont);
24414
+ if (fonts.length === 0) {
24415
+ console.log(
24416
+ styleText(
24417
+ "yellow",
24418
+ `
24419
+ Warning: Skipping OG image generation \u2014 no fonts available (Google Fonts unreachable and no system fonts found). To suppress this warning, disable the plugin in your config:
24420
+ - source: "@quartz-community/og-image"
24421
+ enabled: false`
24422
+ )
24423
+ );
24424
+ return;
24425
+ }
24275
24426
  for (const [_tree, vfile] of content) {
24276
24427
  const data = vfile.data;
24277
24428
  if (data.frontmatter?.socialImage !== void 0) continue;
@@ -24284,6 +24435,9 @@ var CustomOgImages = (userOpts) => {
24284
24435
  const headerFont = theme.typography.header;
24285
24436
  const bodyFont = theme.typography.body;
24286
24437
  const fonts = await getSatoriFonts(headerFont, bodyFont);
24438
+ if (fonts.length === 0) {
24439
+ return;
24440
+ }
24287
24441
  for (const changeEvent of changeEvents) {
24288
24442
  if (!changeEvent.file) continue;
24289
24443
  const data = changeEvent.file.data;