@pixldocs/canvas-renderer 0.5.171 → 0.5.173

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.
Files changed (29) hide show
  1. package/dist/{index-Cq9sQGri.js → index-ChHYFk0E.js} +306 -79
  2. package/dist/index-ChHYFk0E.js.map +1 -0
  3. package/dist/{index-BgOzEKmN.cjs → index-ZehEOqUB.cjs} +291 -64
  4. package/dist/index-ZehEOqUB.cjs.map +1 -0
  5. package/dist/index.cjs +2 -1
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.ts +31 -0
  8. package/dist/index.js +16 -15
  9. package/dist/{pdfFonts-BTEVnYX8.cjs → pdfFonts-BTj2f465.cjs} +12 -3
  10. package/dist/pdfFonts-BTj2f465.cjs.map +1 -0
  11. package/dist/{pdfFonts-b3_bv7F0.js → pdfFonts-DhEaMTZl.js} +12 -3
  12. package/dist/pdfFonts-DhEaMTZl.js.map +1 -0
  13. package/dist/{svgTextToPath-IM1f6F-f.cjs → svgTextToPath-BLk_mcqi.cjs} +85 -3
  14. package/dist/svgTextToPath-BLk_mcqi.cjs.map +1 -0
  15. package/dist/{svgTextToPath-BXAzwaaR.js → svgTextToPath-ra4EhtBL.js} +86 -4
  16. package/dist/svgTextToPath-ra4EhtBL.js.map +1 -0
  17. package/dist/{vectorPdfExport-BrwXcGkA.cjs → vectorPdfExport-BWDj55kq.cjs} +36 -10
  18. package/dist/vectorPdfExport-BWDj55kq.cjs.map +1 -0
  19. package/dist/{vectorPdfExport--EtCdnlG.js → vectorPdfExport-CyTa-D1p.js} +36 -10
  20. package/dist/vectorPdfExport-CyTa-D1p.js.map +1 -0
  21. package/package.json +1 -1
  22. package/dist/index-BgOzEKmN.cjs.map +0 -1
  23. package/dist/index-Cq9sQGri.js.map +0 -1
  24. package/dist/pdfFonts-BTEVnYX8.cjs.map +0 -1
  25. package/dist/pdfFonts-b3_bv7F0.js.map +0 -1
  26. package/dist/svgTextToPath-BXAzwaaR.js.map +0 -1
  27. package/dist/svgTextToPath-IM1f6F-f.cjs.map +0 -1
  28. package/dist/vectorPdfExport--EtCdnlG.js.map +0 -1
  29. package/dist/vectorPdfExport-BrwXcGkA.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const index = require("./index-BgOzEKmN.cjs");
3
+ const index = require("./index-ZehEOqUB.cjs");
4
4
  exports.DEPLOYMENT_VERSION_MARKER = index.DEPLOYMENT_VERSION_MARKER;
5
5
  exports.FONT_FALLBACK_DEVANAGARI = index.FONT_FALLBACK_DEVANAGARI;
6
6
  exports.FONT_FALLBACK_MATH = index.FONT_FALLBACK_MATH;
@@ -25,6 +25,7 @@ exports.extractFontFamiliesFromSvgs = index.extractFontFamiliesFromSvgs;
25
25
  exports.getEmbeddedJsPDFFontName = index.getEmbeddedJsPDFFontName;
26
26
  exports.getProxiedImageUrl = index.getProxiedImageUrl;
27
27
  exports.getPublishedTemplate = index.getPublishedTemplate;
28
+ exports.getTemplateForm = index.getTemplateForm;
28
29
  exports.isBundledAssetUrl = index.isBundledAssetUrl;
29
30
  exports.isFontAvailable = index.isFontAvailable;
30
31
  exports.isPrivateUrl = index.isPrivateUrl;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -243,6 +243,16 @@ export declare function getPublishedTemplate(options: {
243
243
  supabaseAnonKey: string;
244
244
  }): Promise<PublishedTemplate | null>;
245
245
 
246
+ export declare function getTemplateForm(options: GetTemplateFormOptions): Promise<TemplateForm>;
247
+
248
+ export declare interface GetTemplateFormOptions {
249
+ templateId: string;
250
+ /** Optional — when omitted we read the template row and auto-detect from `template.form_schema_id`. */
251
+ formSchemaId?: string;
252
+ supabaseUrl: string;
253
+ supabaseAnonKey: string;
254
+ }
255
+
246
256
  export { InferredSection }
247
257
 
248
258
  export { isBundledAssetUrl }
@@ -797,6 +807,27 @@ export declare interface TemplateConfigPage {
797
807
  boundRepeatablePageId?: string;
798
808
  }
799
809
 
810
+ export declare interface TemplateForm {
811
+ templateId: string;
812
+ templateName: string;
813
+ /** 0 = free, >0 = paid (watermark applies on rendered output). */
814
+ price: number;
815
+ /**
816
+ * The bound form_schema id, if any. Pass this back as `formSchemaId` when
817
+ * rendering. `null` indicates a manual-fields template — pass the
818
+ * sectionState as-is to `renderFromForm` (without `formSchemaId`).
819
+ */
820
+ formSchemaId: string | null;
821
+ /** Inferred section/field structure — drives the edit UI. */
822
+ sections: InferredSection[];
823
+ /**
824
+ * Pre-seeded section state: defaults from the template's `default_data`
825
+ * (V2) or saved default form values, falling back to empty values. Use
826
+ * this as the initial value of your form state.
827
+ */
828
+ initialSectionState: SectionFormState;
829
+ }
830
+
800
831
  export declare interface ThemeConfig {
801
832
  variables?: Record<string, {
802
833
  value: string;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { D, F, o, q, s, P, t, u, v, w, x, y, z, B, C, E, G, H, I, J, K, L, b, M, N, O, Q, R, S, U, V, W, X, Y, Z, _, $, a0 } from "./index-Cq9sQGri.js";
1
+ import { D, F, o, q, s, P, t, u, v, w, x, y, z, B, C, E, G, H, I, J, K, L, b, M, N, O, Q, R, S, U, V, W, X, Y, Z, _, $, a0, a1 } from "./index-ChHYFk0E.js";
2
2
  export {
3
3
  D as DEPLOYMENT_VERSION_MARKER,
4
4
  F as FONT_FALLBACK_DEVANAGARI,
@@ -24,19 +24,20 @@ export {
24
24
  L as getEmbeddedJsPDFFontName,
25
25
  b as getProxiedImageUrl,
26
26
  M as getPublishedTemplate,
27
- N as isBundledAssetUrl,
28
- O as isFontAvailable,
29
- Q as isPrivateUrl,
30
- R as listPublishedTemplates,
31
- S as loadGoogleFontCSS,
32
- U as normalizeFontFamily,
33
- V as resolveFontWeight,
34
- W as resolveFromForm,
35
- X as resolveTemplateData,
36
- Y as rewriteSvgFontsForJsPDF,
37
- Z as setAutoShrinkDebug,
38
- _ as setBundledAssetPrefixes,
39
- $ as warmResolvedTemplateForPreview,
40
- a0 as warmTemplateFromForm
27
+ N as getTemplateForm,
28
+ O as isBundledAssetUrl,
29
+ Q as isFontAvailable,
30
+ R as isPrivateUrl,
31
+ S as listPublishedTemplates,
32
+ U as loadGoogleFontCSS,
33
+ V as normalizeFontFamily,
34
+ W as resolveFontWeight,
35
+ X as resolveFromForm,
36
+ Y as resolveTemplateData,
37
+ Z as rewriteSvgFontsForJsPDF,
38
+ _ as setAutoShrinkDebug,
39
+ $ as setBundledAssetPrefixes,
40
+ a0 as warmResolvedTemplateForPreview,
41
+ a1 as warmTemplateFromForm
41
42
  };
42
43
  //# sourceMappingURL=index.js.map
@@ -10,7 +10,8 @@ const familyNotOnAnyCdn = /* @__PURE__ */ new Set();
10
10
  const familyConfirmedOnSomeCdn = /* @__PURE__ */ new Set();
11
11
  const proxyKey = (family, weight, isItalic, source) => `${source}|${family}|${weight}|${isItalic ? "i" : "n"}`;
12
12
  const LS_KEY = "pdfFonts.negCache.v1";
13
- const LS_VERSION = 1;
13
+ const LS_VERSION = 2;
14
+ const familyProbedWeights = /* @__PURE__ */ new Map();
14
15
  function loadPersistedCaches() {
15
16
  try {
16
17
  if (typeof localStorage === "undefined") return;
@@ -21,6 +22,13 @@ function loadPersistedCaches() {
21
22
  (obj.proxyNotFound || []).forEach((k) => proxyNotFound.add(k));
22
23
  (obj.familyNotOnAnyCdn || []).forEach((k) => familyNotOnAnyCdn.add(k));
23
24
  (obj.familyConfirmedOnSomeCdn || []).forEach((k) => familyConfirmedOnSomeCdn.add(k));
25
+ if (obj.familyProbedWeights && typeof obj.familyProbedWeights === "object") {
26
+ for (const [k, v] of Object.entries(obj.familyProbedWeights)) {
27
+ if (Array.isArray(v) && v.every((n) => typeof n === "number")) {
28
+ familyProbedWeights.set(k, v);
29
+ }
30
+ }
31
+ }
24
32
  } catch {
25
33
  }
26
34
  }
@@ -35,7 +43,8 @@ function persistCaches() {
35
43
  v: LS_VERSION,
36
44
  proxyNotFound: Array.from(proxyNotFound),
37
45
  familyNotOnAnyCdn: Array.from(familyNotOnAnyCdn),
38
- familyConfirmedOnSomeCdn: Array.from(familyConfirmedOnSomeCdn)
46
+ familyConfirmedOnSomeCdn: Array.from(familyConfirmedOnSomeCdn),
47
+ familyProbedWeights: Object.fromEntries(familyProbedWeights)
39
48
  }));
40
49
  } catch {
41
50
  }
@@ -1128,4 +1137,4 @@ exports.resetPdfFontRegistry = resetPdfFontRegistry;
1128
1137
  exports.resolveBestRegisteredVariant = resolveBestRegisteredVariant;
1129
1138
  exports.resolveDevanagariSibling = resolveDevanagariSibling;
1130
1139
  exports.resolveFontWeight = resolveFontWeight;
1131
- //# sourceMappingURL=pdfFonts-BTEVnYX8.cjs.map
1140
+ //# sourceMappingURL=pdfFonts-BTj2f465.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdfFonts-BTj2f465.cjs","sources":["../../../src/lib/pdfFonts.ts"],"sourcesContent":["// Utility for loading local TTF fonts into jsPDF for vector PDF rendering\nimport { findFontEntry as _findFontEntry } from '@/lib/googleFonts';\n\nconst fontCache: Map<string, string> = new Map();\n/** Cache for raw font bytes (used by HarfBuzz / opentype.js for path conversion) */\nconst fontBytesCache: Map<string, Uint8Array> = new Map();\n/** Cache for Google Fonts CSS-parsed TTF URLs (so we don't re-fetch CSS for every weight) */\nconst googleFontUrlCache: Map<string, string> = new Map();\n/** Negative cache — specific Google Font variants known not to exist; don't keep retrying */\nconst googleFontNotFound: Set<string> = new Set();\n/**\n * Negative cache for the Supabase font-proxy edge function. Once a specific\n * (family, weight, italic, source) tuple returns a non-OK / fallback response\n * we never probe again for the lifetime of this module — eliminates the\n * hundreds of 4xx/5xx requests in DevTools when a template references font\n * families that don't exist on Google Fonts or Fontshare.\n */\nconst proxyNotFound: Set<string> = new Set();\n/**\n * Family-level short-circuit cache. If the base (family, 400, upright) probe\n * fails on BOTH google and fontshare, the family doesn't exist on either CDN\n * — skip every subsequent weight/italic probe for the same family.\n */\nconst familyNotOnAnyCdn: Set<string> = new Set();\nconst familyConfirmedOnSomeCdn: Set<string> = new Set();\n\nconst proxyKey = (family: string, weight: number, isItalic: boolean, source: string): string =>\n `${source}|${family}|${weight}|${isItalic ? 'i' : 'n'}`;\n\n// ── localStorage persistence ──\n// Negative caches survive page reloads so the FIRST export of a new tab\n// doesn't pay the full font-probe ladder for families known to be missing\n// from previous sessions. Positive cache (`familyConfirmedOnSomeCdn`) is\n// also persisted so we can short-circuit \"family exists, only this variant\n// is missing\" decisions without a probe.\nconst LS_KEY = 'pdfFonts.negCache.v1';\nconst LS_VERSION = 2;\n/**\n * Per-family probed weight ladder (sorted ascending). Cached in localStorage\n * so subsequent sessions short-circuit. Only populated for non-local\n * (Google Fonts / Fontshare) families — local fonts use FONT_FILES directly.\n */\nconst familyProbedWeights: Map<string, number[]> = new Map();\nfunction loadPersistedCaches(): void {\n try {\n if (typeof localStorage === 'undefined') return;\n const raw = localStorage.getItem(LS_KEY);\n if (!raw) return;\n const obj = JSON.parse(raw);\n if (!obj || obj.v !== LS_VERSION) return;\n (obj.proxyNotFound || []).forEach((k: string) => proxyNotFound.add(k));\n (obj.familyNotOnAnyCdn || []).forEach((k: string) => familyNotOnAnyCdn.add(k));\n (obj.familyConfirmedOnSomeCdn || []).forEach((k: string) => familyConfirmedOnSomeCdn.add(k));\n if (obj.familyProbedWeights && typeof obj.familyProbedWeights === 'object') {\n for (const [k, v] of Object.entries(obj.familyProbedWeights)) {\n if (Array.isArray(v) && v.every((n) => typeof n === 'number')) {\n familyProbedWeights.set(k, v as number[]);\n }\n }\n }\n } catch { /* ignore corrupt cache */ }\n}\nlet persistTimer: any = null;\nfunction persistCaches(): void {\n try {\n if (typeof localStorage === 'undefined') return;\n if (persistTimer) clearTimeout(persistTimer);\n persistTimer = setTimeout(() => {\n try {\n localStorage.setItem(LS_KEY, JSON.stringify({\n v: LS_VERSION,\n proxyNotFound: Array.from(proxyNotFound),\n familyNotOnAnyCdn: Array.from(familyNotOnAnyCdn),\n familyConfirmedOnSomeCdn: Array.from(familyConfirmedOnSomeCdn),\n familyProbedWeights: Object.fromEntries(familyProbedWeights),\n }));\n } catch { /* quota exceeded — ignore */ }\n }, 250);\n } catch { /* ignore */ }\n}\nloadPersistedCaches();\n\n/** Force-clear all negative caches (useful for debugging). Not called automatically. */\nexport const resetPdfFontProbeCaches = (): void => {\n proxyNotFound.clear();\n familyNotOnAnyCdn.clear();\n familyConfirmedOnSomeCdn.clear();\n googleFontNotFound.clear();\n familyProbedWeights.clear();\n try { if (typeof localStorage !== 'undefined') localStorage.removeItem(LS_KEY); } catch {}\n};\n/** Runtime registry of families successfully embedded into the active jsPDF bundle. */\nconst registeredFamilies: Set<string> = new Set();\n/** Runtime glyph coverage for each embedded (family, weight, italic) variant. */\nconst registeredVariantCoverage: Map<string, Set<number>> = new Map();\n\nexport const isFamilyEmbedded = (family: string): boolean => registeredFamilies.has(family);\n\n/**\n * Per-variant registry: which (family, weight, italic) tuples were actually\n * registered into the active jsPDF document. The SVG rewriter uses this to\n * avoid emitting a font-family like \"DMSerifDisplay-Bold\" when only the\n * Regular variant was embedded — emitting an unregistered name causes jsPDF\n * to silently fall back to Helvetica, breaking visual font parity with the\n * canvas preview.\n */\nconst registeredVariants: Set<string> = new Set();\n\nconst variantKey = (family: string, weight: number, italic: boolean): string =>\n `${family}|${weight}|${italic ? 'i' : 'n'}`;\n\nconst remoteVariantKey = (family: string, weight: number, italic: boolean): string =>\n `${family}|${resolveFontWeight(weight)}|${italic ? 'i' : 'n'}`;\n\nexport const resetPdfFontRegistry = (): void => {\n registeredFamilies.clear();\n registeredVariants.clear();\n registeredVariantCoverage.clear();\n};\n\nexport const isVariantEmbedded = (family: string, weight: number, italic: boolean): boolean =>\n registeredVariants.has(variantKey(family, resolveFontWeight(weight), italic));\n\n/**\n * Diagnostic: returns the sorted list of (family, weight, italic) variants\n * that were actually registered into the active jsPDF document. Useful for\n * comparing client vs server embed sets to diagnose file-size diffs.\n */\nexport const getEmbeddedVariantsList = (): string[] => {\n return Array.from(registeredVariants).sort();\n};\n\nexport const doesVariantSupportChar = (\n family: string,\n weight: number,\n italic: boolean,\n char: string,\n): boolean => {\n const cp = char.codePointAt(0);\n if (cp == null) return false;\n return registeredVariantCoverage.get(variantKey(family, resolveFontWeight(weight), italic))?.has(cp) === true;\n};\n\n/**\n * Pick the closest registered (weight, italic) variant for a family. Used by\n * the SVG-to-jsPDF rewriter when the requested exact variant isn't embedded\n * (e.g. user requested Bold but the family has no real Bold and Google's\n * fallback fetch returned 404). Returns null if the family has no registered\n * variants at all.\n */\nexport const resolveBestRegisteredVariant = (\n family: string,\n weight: number,\n italic: boolean,\n): { weight: number; italic: boolean } | null => {\n const want = resolveFontWeight(weight);\n const weights = [300, 400, 500, 600, 700];\n // 1. Exact match\n if (registeredVariants.has(variantKey(family, want, italic))) {\n return { weight: want, italic };\n }\n // 2. Same italic, nearest weight (prefer heavier when bold requested)\n const sortedByDistance = [...weights].sort((a, b) => {\n const da = Math.abs(a - want);\n const db = Math.abs(b - want);\n if (da !== db) return da - db;\n // tie: when wanting bold, prefer heavier; when wanting light, prefer lighter\n return want >= 500 ? b - a : a - b;\n });\n for (const w of sortedByDistance) {\n if (registeredVariants.has(variantKey(family, w, italic))) {\n return { weight: w, italic };\n }\n }\n // 3. Opposite italic, nearest weight\n for (const w of sortedByDistance) {\n if (registeredVariants.has(variantKey(family, w, !italic))) {\n return { weight: w, italic: !italic };\n }\n }\n return null;\n};\n\n// Server-side font proxy: needed because the browser sends modern UA hints\n// (sec-ch-ua) that override our custom User-Agent header, so Google Fonts\n// returns WOFF2 instead of TTF. The edge function spoofs a legacy UA and\n// returns embeddable TTF bytes for any Google Font / Fontshare family.\n//\n// Resolved LAZILY so this module works in two contexts:\n// 1. Client app — reads `import.meta.env.VITE_SUPABASE_URL` at build time.\n// 2. Server harness (`@pixldocs/canvas-renderer` browser bundle running\n// inside Puppeteer on EC2) — Vite does NOT inline VITE_SUPABASE_URL into\n// that standalone bundle, so we fall back to `window.__PIXLDOCS_SUPABASE_URL`,\n// which the harness HTML sets from the request payload before running.\nfunction resolveFontProxyUrl(): string {\n const fromEnv = (() => {\n try {\n return (import.meta as any).env?.VITE_SUPABASE_URL ?? '';\n } catch {\n return '';\n }\n })();\n const fromWindow = (() => {\n try {\n return (typeof window !== 'undefined' && (window as any).__PIXLDOCS_SUPABASE_URL) || '';\n } catch {\n return '';\n }\n })();\n const base = fromEnv || fromWindow || '';\n return base ? `${base}/functions/v1/font-proxy` : '';\n}\n\nasync function fetchTtfViaProxy(\n family: string,\n weight: number,\n isItalic: boolean,\n source: 'google' | 'fontshare',\n): Promise<Uint8Array | null> {\n const proxyUrl = resolveFontProxyUrl();\n if (!proxyUrl) return null;\n // Negative caches — skip probes that previously failed.\n const key = proxyKey(family, weight, isItalic, source);\n if (proxyNotFound.has(key)) return null;\n // Family short-circuit: if base variant failed on every CDN, skip everything.\n if (familyNotOnAnyCdn.has(family)) return null;\n try {\n const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${isItalic ? 1 : 0}&source=${source}`;\n const res = await fetch(url);\n if (!res.ok) {\n proxyNotFound.add(key);\n persistCaches();\n return null;\n }\n // Edge function may now return 200 + JSON `{fallback:true}` for upstream\n // misses (so DevTools doesn't flash red on every probe). Detect that\n // shape via Content-Type and treat as a miss.\n const ct = res.headers.get('content-type') || '';\n if (ct.startsWith('application/json')) {\n try {\n const j = await res.json();\n if (j && (j.fallback || j.error)) proxyNotFound.add(key);\n } catch {\n proxyNotFound.add(key);\n }\n persistCaches();\n return null;\n }\n const buf = await res.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (bytes.byteLength < 64) {\n proxyNotFound.add(key);\n persistCaches();\n return null;\n }\n familyConfirmedOnSomeCdn.add(family);\n persistCaches();\n return bytes;\n } catch {\n proxyNotFound.add(key);\n persistCaches();\n return null;\n }\n}\n\n/**\n * Probe the base (family, 400, upright) variant on both Google and Fontshare\n * before fetching every weight/italic combination. If both miss, mark the\n * family as missing so all subsequent variant probes are skipped.\n * Returns true if the family is available on at least one CDN.\n */\nexport async function familyProbe(family: string): Promise<boolean> {\n if (familyConfirmedOnSomeCdn.has(family)) return true;\n if (familyNotOnAnyCdn.has(family)) return false;\n // Reuse fetchTtfViaProxy for the base probe — populates negative caches and\n // the bytes cache as a side-effect, so the subsequent 400-regular embed\n // doesn't re-fetch.\n const g = await fetchTtfViaProxy(family, 400, false, 'google');\n if (g) return true;\n const f = await fetchTtfViaProxy(family, 400, false, 'fontshare');\n if (f) return true;\n familyNotOnAnyCdn.add(family);\n return false;\n}\n\n/**\n * Probe which weights from the standard ladder [300,400,500,600,700] actually\n * have a real TTF available via the font-proxy (Google Fonts → Fontshare).\n *\n * This is the **source of truth** for the weight selector UI: only weights\n * returned here will render identically in canvas (browser CSS) AND in PDF\n * (jsPDF embedding). Without this, a user can pick e.g. Ubuntu SemiBold\n * which the browser synthesizes via faux-bold, but the PDF embeds Regular\n * because Google does not publish a real 600-weight Ubuntu file.\n *\n * Results are cached per-family in memory + localStorage. Local fonts (in\n * FONT_FILES) bypass this — their available weights are the file map keys.\n */\nconst familyProbeInflight: Map<string, Promise<number[]>> = new Map();\nconst STANDARD_WEIGHT_LADDER = [300, 400, 500, 600, 700] as const;\n\nexport function getCachedAvailableWeights(family: string): number[] | null {\n if (FONT_FILES[family]) return getAvailableWeights(family);\n return familyProbedWeights.get(family) ?? null;\n}\n\nexport async function probeAvailableWeights(family: string): Promise<number[]> {\n // Local font — file map is authoritative.\n if (FONT_FILES[family]) return getAvailableWeights(family);\n const cached = familyProbedWeights.get(family);\n if (cached) return cached;\n const inflight = familyProbeInflight.get(family);\n if (inflight) return inflight;\n\n const entry = (() => { try { return _findFontEntry(family); } catch { return null; } })();\n const source: 'google' | 'fontshare' = entry?.source === 'fontshare' ? 'fontshare' : 'google';\n\n const job = (async () => {\n // Fast-path: family doesn't exist on any CDN — nothing is selectable.\n // Still expose Regular so the picker isn't empty (it'll fall back at render).\n if (familyNotOnAnyCdn.has(family)) {\n const fallback = [400];\n familyProbedWeights.set(family, fallback);\n persistCaches();\n return fallback;\n }\n const found: number[] = [];\n // Probe in parallel — fetchTtfViaProxy already short-circuits via the\n // negative cache, so repeat calls are cheap. We probe both upright and\n // italic and consider a weight \"available\" if EITHER variant exists.\n const probes = await Promise.all(\n STANDARD_WEIGHT_LADDER.flatMap((w) => [\n fetchTtfViaProxy(family, w, false, source).then((b) => ({ w, ok: !!b })),\n ])\n );\n for (const p of probes) if (p.ok && !found.includes(p.w)) found.push(p.w);\n found.sort((a, b) => a - b);\n // Always include Regular if we got any hit at all (so faux-fallback is\n // visually predictable). If we got zero hits, expose [400] as a safe\n // default — embedder will fallback to Helvetica at PDF time.\n const result = found.length > 0\n ? (found.includes(400) ? found : [400, ...found].sort((a, b) => a - b))\n : [400];\n familyProbedWeights.set(family, result);\n persistCaches();\n return result;\n })();\n familyProbeInflight.set(family, job);\n try { return await job; } finally { familyProbeInflight.delete(family); }\n}\n\n// Weight labels for jsPDF font names (editor uses 300, 400, 500, 600, 700)\nexport const FONT_WEIGHT_LABELS: Record<number, string> = {\n 300: 'Light',\n 400: 'Regular',\n 500: 'Medium',\n 600: 'SemiBold',\n 700: 'Bold',\n};\n\n// Resolve numeric weight to the closest supported key (300, 400, 500, 600, 700)\nexport function resolveFontWeight(weight: number): number {\n if (weight <= 350) return 300;\n if (weight <= 450) return 400;\n if (weight <= 550) return 500;\n if (weight <= 650) return 600;\n return 700;\n}\n\n// Font file mapping - maps font names to optional weight-specific TTF paths\nexport type FontWeightFiles = {\n regular: string;\n bold?: string;\n light?: string;\n medium?: string;\n semibold?: string;\n // Italic variants\n italic?: string;\n boldItalic?: string;\n lightItalic?: string;\n mediumItalic?: string;\n semiboldItalic?: string;\n};\n\n/** Font used for symbols (● ◆ ★ etc.) when the main font lacks the glyph. Must be in FONT_FILES. */\nexport const FONT_FALLBACK_SYMBOLS = 'Noto Sans';\n\n/** Tertiary fallback for math operators / arrows (≠ ≤ ≥ ≈ ∞ → ← × ÷ ∑ √ ∈ …)\n * that are not present in the main font OR in FONT_FALLBACK_SYMBOLS. Must be in FONT_FILES. */\nexport const FONT_FALLBACK_MATH = 'Noto Sans Math';\n\n/** Font used for Devanagari / Hindi script when the main font lacks the glyphs. Must be in FONT_FILES. */\nexport const FONT_FALLBACK_DEVANAGARI = 'Hind';\n\n// List paths under public/fonts.\n// All entries now use static (per-weight) TTF files for reliable PDF export.\n// Variable font files are kept in fonts.css for browser rendering only.\nexport const FONT_FILES: Record<string, FontWeightFiles> = {\n 'Playfair Display': {\n regular: '/fonts/PlayfairDisplay-Regular.ttf',\n bold: '/fonts/PlayfairDisplay-Bold.ttf',\n italic: '/fonts/PlayfairDisplay-Italic.ttf',\n boldItalic: '/fonts/PlayfairDisplay-BoldItalic.ttf',\n },\n 'Merriweather': {\n regular: '/fonts/Merriweather-Regular.ttf',\n bold: '/fonts/Merriweather-Bold.ttf',\n light: '/fonts/Merriweather-Light.ttf',\n italic: '/fonts/Merriweather-Italic.ttf',\n boldItalic: '/fonts/Merriweather-BoldItalic.ttf',\n lightItalic: '/fonts/Merriweather-LightItalic.ttf',\n },\n 'Lora': {\n regular: '/fonts/Lora-Regular.ttf',\n bold: '/fonts/Lora-Bold.ttf',\n italic: '/fonts/Lora-Italic.ttf',\n boldItalic: '/fonts/Lora-BoldItalic.ttf',\n },\n 'Montserrat': {\n regular: '/fonts/Montserrat-Regular.ttf',\n bold: '/fonts/Montserrat-Bold.ttf',\n light: '/fonts/Montserrat-Light.ttf',\n medium: '/fonts/Montserrat-Medium.ttf',\n semibold: '/fonts/Montserrat-SemiBold.ttf',\n italic: '/fonts/Montserrat-Italic.ttf',\n boldItalic: '/fonts/Montserrat-BoldItalic.ttf',\n lightItalic: '/fonts/Montserrat-LightItalic.ttf',\n mediumItalic: '/fonts/Montserrat-MediumItalic.ttf',\n semiboldItalic: '/fonts/Montserrat-SemiBoldItalic.ttf',\n },\n 'Open Sans': {\n regular: '/fonts/OpenSans-Regular.ttf',\n bold: '/fonts/OpenSans-Bold.ttf',\n light: '/fonts/OpenSans-Light.ttf',\n semibold: '/fonts/OpenSans-SemiBold.ttf',\n italic: '/fonts/OpenSans-Italic.ttf',\n boldItalic: '/fonts/OpenSans-BoldItalic.ttf',\n lightItalic: '/fonts/OpenSans-LightItalic.ttf',\n semiboldItalic: '/fonts/OpenSans-SemiBoldItalic.ttf',\n },\n 'Roboto': {\n regular: '/fonts/Roboto-Regular.ttf',\n bold: '/fonts/Roboto-Bold.ttf',\n light: '/fonts/Roboto-Light.ttf',\n medium: '/fonts/Roboto-Medium.ttf',\n italic: '/fonts/Roboto-Italic.ttf',\n boldItalic: '/fonts/Roboto-BoldItalic.ttf',\n lightItalic: '/fonts/Roboto-LightItalic.ttf',\n mediumItalic: '/fonts/Roboto-MediumItalic.ttf',\n },\n 'Lato': {\n regular: '/fonts/Lato-Regular.ttf',\n bold: '/fonts/Lato-Bold.ttf',\n light: '/fonts/Lato-Light.ttf',\n italic: '/fonts/Lato-Italic.ttf',\n boldItalic: '/fonts/Lato-BoldItalic.ttf',\n lightItalic: '/fonts/Lato-LightItalic.ttf',\n },\n 'Raleway': {\n regular: '/fonts/Raleway-Regular.ttf',\n bold: '/fonts/Raleway-Bold.ttf',\n light: '/fonts/Raleway-Light.ttf',\n medium: '/fonts/Raleway-Medium.ttf',\n semibold: '/fonts/Raleway-SemiBold.ttf',\n italic: '/fonts/Raleway-Italic.ttf',\n boldItalic: '/fonts/Raleway-BoldItalic.ttf',\n lightItalic: '/fonts/Raleway-LightItalic.ttf',\n },\n 'Poppins': {\n regular: '/fonts/Poppins-Regular.ttf',\n bold: '/fonts/Poppins-Bold.ttf',\n light: '/fonts/Poppins-Light.ttf',\n medium: '/fonts/Poppins-Medium.ttf',\n semibold: '/fonts/Poppins-SemiBold.ttf',\n italic: '/fonts/Poppins-Italic.ttf',\n boldItalic: '/fonts/Poppins-BoldItalic.ttf',\n lightItalic: '/fonts/Poppins-LightItalic.ttf',\n mediumItalic: '/fonts/Poppins-MediumItalic.ttf',\n semiboldItalic: '/fonts/Poppins-SemiBoldItalic.ttf',\n },\n 'Inter': {\n regular: '/fonts/Inter-Regular.ttf',\n bold: '/fonts/Inter-Bold.ttf',\n italic: '/fonts/Inter-Italic.ttf',\n boldItalic: '/fonts/Inter-BoldItalic.ttf',\n },\n 'Nunito': {\n regular: '/fonts/Nunito-Regular.ttf',\n bold: '/fonts/Nunito-Bold.ttf',\n light: '/fonts/Nunito-Light.ttf',\n medium: '/fonts/Nunito-Medium.ttf',\n semibold: '/fonts/Nunito-SemiBold.ttf',\n italic: '/fonts/Nunito-Italic.ttf',\n boldItalic: '/fonts/Nunito-BoldItalic.ttf',\n },\n 'Source Sans Pro': {\n regular: '/fonts/SourceSansPro-Regular.ttf',\n bold: '/fonts/SourceSansPro-Bold.ttf',\n light: '/fonts/SourceSansPro-Light.ttf',\n italic: '/fonts/SourceSansPro-Italic.ttf',\n boldItalic: '/fonts/SourceSansPro-BoldItalic.ttf',\n },\n 'Work Sans': {\n regular: '/fonts/WorkSans-Regular.ttf',\n bold: '/fonts/WorkSans-Bold.ttf',\n italic: '/fonts/WorkSans-Italic.ttf',\n boldItalic: '/fonts/WorkSans-BoldItalic.ttf',\n },\n 'Oswald': { regular: '/fonts/Oswald-Regular.ttf', bold: '/fonts/Oswald-Bold.ttf' },\n 'Bebas Neue': { regular: '/fonts/BebasNeue-Regular.ttf' },\n 'Abril Fatface': { regular: '/fonts/AbrilFatface-Regular.ttf' },\n 'Dancing Script': { regular: '/fonts/DancingScript-Regular.ttf', bold: '/fonts/DancingScript-Bold.ttf' },\n 'Pacifico': { regular: '/fonts/Pacifico-Regular.ttf' },\n 'Great Vibes': { regular: '/fonts/GreatVibes-Regular.ttf' },\n\n // ── Previously variable-only fonts — now with static per-weight TTFs for PDF export ──\n 'DM Sans': {\n regular: '/fonts/DMSans-Regular.ttf',\n bold: '/fonts/DMSans-Bold.ttf',\n light: '/fonts/DMSans-Light.ttf',\n medium: '/fonts/DMSans-Medium.ttf',\n semibold: '/fonts/DMSans-SemiBold.ttf',\n italic: '/fonts/DMSans-RegularItalic.ttf',\n boldItalic: '/fonts/DMSans-BoldItalic.ttf',\n lightItalic: '/fonts/DMSans-LightItalic.ttf',\n mediumItalic: '/fonts/DMSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/DMSans-SemiBoldItalic.ttf',\n },\n 'Outfit': {\n regular: '/fonts/Outfit-Regular.ttf',\n bold: '/fonts/Outfit-Bold.ttf',\n light: '/fonts/Outfit-Light.ttf',\n medium: '/fonts/Outfit-Medium.ttf',\n semibold: '/fonts/Outfit-SemiBold.ttf',\n },\n 'Figtree': {\n regular: '/fonts/Figtree-Regular.ttf',\n bold: '/fonts/Figtree-Bold.ttf',\n light: '/fonts/Figtree-Light.ttf',\n medium: '/fonts/Figtree-Medium.ttf',\n semibold: '/fonts/Figtree-SemiBold.ttf',\n italic: '/fonts/Figtree-RegularItalic.ttf',\n boldItalic: '/fonts/Figtree-BoldItalic.ttf',\n lightItalic: '/fonts/Figtree-LightItalic.ttf',\n mediumItalic: '/fonts/Figtree-MediumItalic.ttf',\n semiboldItalic: '/fonts/Figtree-SemiBoldItalic.ttf',\n },\n 'Manrope': {\n regular: '/fonts/Manrope-Regular.ttf',\n bold: '/fonts/Manrope-Bold.ttf',\n light: '/fonts/Manrope-Light.ttf',\n medium: '/fonts/Manrope-Medium.ttf',\n semibold: '/fonts/Manrope-SemiBold.ttf',\n },\n 'Space Grotesk': {\n regular: '/fonts/SpaceGrotesk-Regular.ttf',\n bold: '/fonts/SpaceGrotesk-Bold.ttf',\n light: '/fonts/SpaceGrotesk-Light.ttf',\n medium: '/fonts/SpaceGrotesk-Medium.ttf',\n semibold: '/fonts/SpaceGrotesk-SemiBold.ttf',\n },\n 'League Spartan': {\n regular: '/fonts/LeagueSpartan-Regular.ttf',\n bold: '/fonts/LeagueSpartan-Bold.ttf',\n light: '/fonts/LeagueSpartan-Light.ttf',\n medium: '/fonts/LeagueSpartan-Medium.ttf',\n semibold: '/fonts/LeagueSpartan-SemiBold.ttf',\n },\n 'EB Garamond': {\n regular: '/fonts/EBGaramond-Regular.ttf',\n bold: '/fonts/EBGaramond-Bold.ttf',\n medium: '/fonts/EBGaramond-Medium.ttf',\n semibold: '/fonts/EBGaramond-SemiBold.ttf',\n italic: '/fonts/EBGaramond-RegularItalic.ttf',\n boldItalic: '/fonts/EBGaramond-BoldItalic.ttf',\n mediumItalic: '/fonts/EBGaramond-MediumItalic.ttf',\n semiboldItalic: '/fonts/EBGaramond-SemiBoldItalic.ttf',\n },\n 'Libre Baskerville': {\n regular: '/fonts/LibreBaskerville-Regular.ttf',\n bold: '/fonts/LibreBaskerville-Bold.ttf',\n italic: '/fonts/LibreBaskerville-RegularItalic.ttf',\n boldItalic: '/fonts/LibreBaskerville-BoldItalic.ttf',\n },\n 'Crimson Text': {\n regular: '/fonts/CrimsonText-Regular.ttf',\n bold: '/fonts/CrimsonText-Bold.ttf',\n italic: '/fonts/CrimsonText-Italic.ttf',\n boldItalic: '/fonts/CrimsonText-BoldItalic.ttf',\n },\n 'DM Serif Display': {\n regular: '/fonts/DMSerifDisplay-Regular.ttf',\n italic: '/fonts/DMSerifDisplay-Italic.ttf',\n },\n 'Libre Franklin': {\n regular: '/fonts/LibreFranklin-Regular.ttf',\n bold: '/fonts/LibreFranklin-Bold.ttf',\n light: '/fonts/LibreFranklin-Light.ttf',\n medium: '/fonts/LibreFranklin-Medium.ttf',\n semibold: '/fonts/LibreFranklin-SemiBold.ttf',\n italic: '/fonts/LibreFranklin-RegularItalic.ttf',\n boldItalic: '/fonts/LibreFranklin-BoldItalic.ttf',\n lightItalic: '/fonts/LibreFranklin-LightItalic.ttf',\n mediumItalic: '/fonts/LibreFranklin-MediumItalic.ttf',\n semiboldItalic: '/fonts/LibreFranklin-SemiBoldItalic.ttf',\n },\n 'Mulish': {\n regular: '/fonts/Mulish-Regular.ttf',\n bold: '/fonts/Mulish-Bold.ttf',\n light: '/fonts/Mulish-Light.ttf',\n medium: '/fonts/Mulish-Medium.ttf',\n semibold: '/fonts/Mulish-SemiBold.ttf',\n italic: '/fonts/Mulish-RegularItalic.ttf',\n boldItalic: '/fonts/Mulish-BoldItalic.ttf',\n lightItalic: '/fonts/Mulish-LightItalic.ttf',\n mediumItalic: '/fonts/Mulish-MediumItalic.ttf',\n semiboldItalic: '/fonts/Mulish-SemiBoldItalic.ttf',\n },\n 'Quicksand': {\n regular: '/fonts/Quicksand-Regular.ttf',\n bold: '/fonts/Quicksand-Bold.ttf',\n light: '/fonts/Quicksand-Light.ttf',\n medium: '/fonts/Quicksand-Medium.ttf',\n semibold: '/fonts/Quicksand-SemiBold.ttf',\n },\n 'Rubik': {\n regular: '/fonts/Rubik-Regular.ttf',\n bold: '/fonts/Rubik-Bold.ttf',\n light: '/fonts/Rubik-Light.ttf',\n medium: '/fonts/Rubik-Medium.ttf',\n semibold: '/fonts/Rubik-SemiBold.ttf',\n italic: '/fonts/Rubik-RegularItalic.ttf',\n boldItalic: '/fonts/Rubik-BoldItalic.ttf',\n lightItalic: '/fonts/Rubik-LightItalic.ttf',\n mediumItalic: '/fonts/Rubik-MediumItalic.ttf',\n semiboldItalic: '/fonts/Rubik-SemiBoldItalic.ttf',\n },\n 'Karla': {\n regular: '/fonts/Karla-Regular.ttf',\n bold: '/fonts/Karla-Bold.ttf',\n light: '/fonts/Karla-Light.ttf',\n medium: '/fonts/Karla-Medium.ttf',\n semibold: '/fonts/Karla-SemiBold.ttf',\n italic: '/fonts/Karla-RegularItalic.ttf',\n boldItalic: '/fonts/Karla-BoldItalic.ttf',\n lightItalic: '/fonts/Karla-LightItalic.ttf',\n mediumItalic: '/fonts/Karla-MediumItalic.ttf',\n semiboldItalic: '/fonts/Karla-SemiBoldItalic.ttf',\n },\n 'Plus Jakarta Sans': {\n regular: '/fonts/PlusJakartaSans-Regular.ttf',\n bold: '/fonts/PlusJakartaSans-Bold.ttf',\n light: '/fonts/PlusJakartaSans-Light.ttf',\n medium: '/fonts/PlusJakartaSans-Medium.ttf',\n semibold: '/fonts/PlusJakartaSans-SemiBold.ttf',\n italic: '/fonts/PlusJakartaSans-RegularItalic.ttf',\n boldItalic: '/fonts/PlusJakartaSans-BoldItalic.ttf',\n lightItalic: '/fonts/PlusJakartaSans-LightItalic.ttf',\n mediumItalic: '/fonts/PlusJakartaSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/PlusJakartaSans-SemiBoldItalic.ttf',\n },\n 'Sora': {\n regular: '/fonts/Sora-Regular.ttf',\n bold: '/fonts/Sora-Bold.ttf',\n light: '/fonts/Sora-Light.ttf',\n medium: '/fonts/Sora-Medium.ttf',\n semibold: '/fonts/Sora-SemiBold.ttf',\n },\n 'Urbanist': {\n regular: '/fonts/Urbanist-Regular.ttf',\n bold: '/fonts/Urbanist-Bold.ttf',\n light: '/fonts/Urbanist-Light.ttf',\n medium: '/fonts/Urbanist-Medium.ttf',\n semibold: '/fonts/Urbanist-SemiBold.ttf',\n italic: '/fonts/Urbanist-RegularItalic.ttf',\n boldItalic: '/fonts/Urbanist-BoldItalic.ttf',\n lightItalic: '/fonts/Urbanist-LightItalic.ttf',\n mediumItalic: '/fonts/Urbanist-MediumItalic.ttf',\n semiboldItalic: '/fonts/Urbanist-SemiBoldItalic.ttf',\n },\n 'Lexend': {\n regular: '/fonts/Lexend-Regular.ttf',\n bold: '/fonts/Lexend-Bold.ttf',\n light: '/fonts/Lexend-Light.ttf',\n medium: '/fonts/Lexend-Medium.ttf',\n semibold: '/fonts/Lexend-SemiBold.ttf',\n },\n 'Albert Sans': {\n regular: '/fonts/AlbertSans-Regular.ttf',\n bold: '/fonts/AlbertSans-Bold.ttf',\n light: '/fonts/AlbertSans-Light.ttf',\n medium: '/fonts/AlbertSans-Medium.ttf',\n semibold: '/fonts/AlbertSans-SemiBold.ttf',\n italic: '/fonts/AlbertSans-RegularItalic.ttf',\n boldItalic: '/fonts/AlbertSans-BoldItalic.ttf',\n lightItalic: '/fonts/AlbertSans-LightItalic.ttf',\n mediumItalic: '/fonts/AlbertSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/AlbertSans-SemiBoldItalic.ttf',\n },\n 'Noto Sans': {\n regular: '/fonts/NotoSans-Regular.ttf',\n bold: '/fonts/NotoSans-Bold.ttf',\n light: '/fonts/NotoSans-Light.ttf',\n medium: '/fonts/NotoSans-Medium.ttf',\n semibold: '/fonts/NotoSans-SemiBold.ttf',\n italic: '/fonts/NotoSans-RegularItalic.ttf',\n boldItalic: '/fonts/NotoSans-BoldItalic.ttf',\n lightItalic: '/fonts/NotoSans-LightItalic.ttf',\n mediumItalic: '/fonts/NotoSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/NotoSans-SemiBoldItalic.ttf',\n },\n 'Cabin': {\n regular: '/fonts/Cabin-Regular.ttf',\n bold: '/fonts/Cabin-Bold.ttf',\n medium: '/fonts/Cabin-Medium.ttf',\n semibold: '/fonts/Cabin-SemiBold.ttf',\n italic: '/fonts/Cabin-RegularItalic.ttf',\n boldItalic: '/fonts/Cabin-BoldItalic.ttf',\n mediumItalic: '/fonts/Cabin-MediumItalic.ttf',\n semiboldItalic: '/fonts/Cabin-SemiBoldItalic.ttf',\n },\n 'Barlow': {\n regular: '/fonts/Barlow-Regular.ttf',\n bold: '/fonts/Barlow-Bold.ttf',\n light: '/fonts/Barlow-Light.ttf',\n medium: '/fonts/Barlow-Medium.ttf',\n semibold: '/fonts/Barlow-SemiBold.ttf',\n italic: '/fonts/Barlow-Italic.ttf',\n boldItalic: '/fonts/Barlow-BoldItalic.ttf',\n },\n 'Josefin Sans': {\n regular: '/fonts/JosefinSans-Regular.ttf',\n bold: '/fonts/JosefinSans-Bold.ttf',\n light: '/fonts/JosefinSans-Light.ttf',\n medium: '/fonts/JosefinSans-Medium.ttf',\n semibold: '/fonts/JosefinSans-SemiBold.ttf',\n italic: '/fonts/JosefinSans-RegularItalic.ttf',\n boldItalic: '/fonts/JosefinSans-BoldItalic.ttf',\n lightItalic: '/fonts/JosefinSans-LightItalic.ttf',\n mediumItalic: '/fonts/JosefinSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/JosefinSans-SemiBoldItalic.ttf',\n },\n 'Archivo': {\n regular: '/fonts/Archivo-Regular.ttf',\n bold: '/fonts/Archivo-Bold.ttf',\n light: '/fonts/Archivo-Light.ttf',\n medium: '/fonts/Archivo-Medium.ttf',\n semibold: '/fonts/Archivo-SemiBold.ttf',\n italic: '/fonts/Archivo-RegularItalic.ttf',\n boldItalic: '/fonts/Archivo-BoldItalic.ttf',\n lightItalic: '/fonts/Archivo-LightItalic.ttf',\n mediumItalic: '/fonts/Archivo-MediumItalic.ttf',\n semiboldItalic: '/fonts/Archivo-SemiBoldItalic.ttf',\n },\n 'Overpass': {\n regular: '/fonts/Overpass-Regular.ttf',\n bold: '/fonts/Overpass-Bold.ttf',\n light: '/fonts/Overpass-Light.ttf',\n medium: '/fonts/Overpass-Medium.ttf',\n semibold: '/fonts/Overpass-SemiBold.ttf',\n italic: '/fonts/Overpass-RegularItalic.ttf',\n boldItalic: '/fonts/Overpass-BoldItalic.ttf',\n lightItalic: '/fonts/Overpass-LightItalic.ttf',\n mediumItalic: '/fonts/Overpass-MediumItalic.ttf',\n semiboldItalic: '/fonts/Overpass-SemiBoldItalic.ttf',\n },\n 'Exo 2': {\n regular: '/fonts/Exo2-Regular.ttf',\n bold: '/fonts/Exo2-Bold.ttf',\n light: '/fonts/Exo2-Light.ttf',\n medium: '/fonts/Exo2-Medium.ttf',\n semibold: '/fonts/Exo2-SemiBold.ttf',\n italic: '/fonts/Exo2-RegularItalic.ttf',\n boldItalic: '/fonts/Exo2-BoldItalic.ttf',\n lightItalic: '/fonts/Exo2-LightItalic.ttf',\n mediumItalic: '/fonts/Exo2-MediumItalic.ttf',\n semiboldItalic: '/fonts/Exo2-SemiBoldItalic.ttf',\n },\n 'Roboto Mono': {\n regular: '/fonts/RobotoMono-Regular.ttf',\n bold: '/fonts/RobotoMono-Bold.ttf',\n light: '/fonts/RobotoMono-Light.ttf',\n medium: '/fonts/RobotoMono-Medium.ttf',\n semibold: '/fonts/RobotoMono-SemiBold.ttf',\n italic: '/fonts/RobotoMono-RegularItalic.ttf',\n boldItalic: '/fonts/RobotoMono-BoldItalic.ttf',\n lightItalic: '/fonts/RobotoMono-LightItalic.ttf',\n mediumItalic: '/fonts/RobotoMono-MediumItalic.ttf',\n semiboldItalic: '/fonts/RobotoMono-SemiBoldItalic.ttf',\n },\n 'Fira Code': {\n regular: '/fonts/FiraCode-Regular.ttf',\n bold: '/fonts/FiraCode-Bold.ttf',\n light: '/fonts/FiraCode-Light.ttf',\n medium: '/fonts/FiraCode-Medium.ttf',\n semibold: '/fonts/FiraCode-SemiBold.ttf',\n },\n 'JetBrains Mono': {\n regular: '/fonts/JetBrainsMono-Regular.ttf',\n bold: '/fonts/JetBrainsMono-Bold.ttf',\n light: '/fonts/JetBrainsMono-Light.ttf',\n medium: '/fonts/JetBrainsMono-Medium.ttf',\n semibold: '/fonts/JetBrainsMono-SemiBold.ttf',\n italic: '/fonts/JetBrainsMono-RegularItalic.ttf',\n boldItalic: '/fonts/JetBrainsMono-BoldItalic.ttf',\n lightItalic: '/fonts/JetBrainsMono-LightItalic.ttf',\n mediumItalic: '/fonts/JetBrainsMono-MediumItalic.ttf',\n semiboldItalic: '/fonts/JetBrainsMono-SemiBoldItalic.ttf',\n },\n 'Source Code Pro': {\n regular: '/fonts/SourceCodePro-Regular.ttf',\n bold: '/fonts/SourceCodePro-Bold.ttf',\n light: '/fonts/SourceCodePro-Light.ttf',\n medium: '/fonts/SourceCodePro-Medium.ttf',\n semibold: '/fonts/SourceCodePro-SemiBold.ttf',\n italic: '/fonts/SourceCodePro-RegularItalic.ttf',\n boldItalic: '/fonts/SourceCodePro-BoldItalic.ttf',\n lightItalic: '/fonts/SourceCodePro-LightItalic.ttf',\n mediumItalic: '/fonts/SourceCodePro-MediumItalic.ttf',\n semiboldItalic: '/fonts/SourceCodePro-SemiBoldItalic.ttf',\n },\n 'IBM Plex Mono': {\n regular: '/fonts/IBMPlexMono-Regular.ttf',\n bold: '/fonts/IBMPlexMono-Bold.ttf',\n },\n 'Space Mono': {\n regular: '/fonts/SpaceMono-Regular.ttf',\n bold: '/fonts/SpaceMono-Bold.ttf',\n italic: '/fonts/SpaceMono-Italic.ttf',\n boldItalic: '/fonts/SpaceMono-BoldItalic.ttf',\n },\n 'Sacramento': { regular: '/fonts/Sacramento-Regular.ttf' },\n 'Alex Brush': { regular: '/fonts/AlexBrush-Regular.ttf' },\n 'Allura': { regular: '/fonts/Allura-Regular.ttf' },\n 'Caveat': {\n regular: '/fonts/Caveat-Regular.ttf',\n bold: '/fonts/Caveat-Bold.ttf',\n medium: '/fonts/Caveat-Medium.ttf',\n semibold: '/fonts/Caveat-SemiBold.ttf',\n },\n 'Lobster': { regular: '/fonts/Lobster-Regular.ttf' },\n 'Comfortaa': {\n regular: '/fonts/Comfortaa-Regular.ttf',\n bold: '/fonts/Comfortaa-Bold.ttf',\n light: '/fonts/Comfortaa-Light.ttf',\n medium: '/fonts/Comfortaa-Medium.ttf',\n semibold: '/fonts/Comfortaa-SemiBold.ttf',\n },\n 'Anton': { regular: '/fonts/Anton-Regular.ttf' },\n 'Teko': {\n regular: '/fonts/Teko-Regular.ttf',\n bold: '/fonts/Teko-Bold.ttf',\n light: '/fonts/Teko-Light.ttf',\n medium: '/fonts/Teko-Medium.ttf',\n semibold: '/fonts/Teko-SemiBold.ttf',\n },\n // ── Indic Script Fallback Fonts ──\n 'Noto Sans Devanagari': {\n regular: '/fonts/NotoSansDevanagari-Regular.ttf',\n bold: '/fonts/NotoSansDevanagari-Bold.ttf',\n light: '/fonts/NotoSansDevanagari-Light.ttf',\n medium: '/fonts/NotoSansDevanagari-Medium.ttf',\n semibold: '/fonts/NotoSansDevanagari-SemiBold.ttf',\n },\n 'Hind': {\n regular: '/fonts/Hind-Regular.ttf',\n bold: '/fonts/Hind-Bold.ttf',\n light: '/fonts/Hind-Light.ttf',\n medium: '/fonts/Hind-Medium.ttf',\n semibold: '/fonts/Hind-SemiBold.ttf',\n },\n // ── Math / Operator Symbol Fallback ──\n // Carries glyphs that NotoSans-Regular's Latin subset is missing\n // (≠ ≤ ≥ ≈ ∞ → ← × ÷ ∑ √ ∈ ∀ ∃ etc.). Used as a tertiary fallback\n // ONLY for chars classified as 'math' that the main font + Noto Sans\n // both lack.\n 'Noto Sans Math': {\n regular: '/fonts/NotoSansMath-Regular.ttf',\n },\n};\n\n// Convert font file to Base64\nconst fontToBase64 = async (url: string): Promise<string> => {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch font: ${response.statusText}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n \n // Convert ArrayBuffer to Base64\n const bytes = new Uint8Array(arrayBuffer);\n if (!isJsPdfEmbeddableTrueType(bytes)) {\n throw new Error(`Font is not a jsPDF-compatible TrueType file: ${url}`);\n }\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n};\n\nfunction isJsPdfEmbeddableTrueType(bytes: Uint8Array): boolean {\n if (bytes.length < 12) return false;\n const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);\n if (signature !== '\\x00\\x01\\x00\\x00' && signature !== 'true') return false;\n\n const u16 = (offset: number) => (bytes[offset] << 8) | bytes[offset + 1];\n const u32 = (offset: number) => ((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) >>> 0;\n const tableCount = u16(4);\n for (let i = 0; i < tableCount; i++) {\n const recordOffset = 12 + i * 16;\n if (recordOffset + 16 > bytes.length) return false;\n const tag = String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]);\n if (tag !== 'cmap') continue;\n const cmapOffset = u32(recordOffset + 8);\n const cmapLength = u32(recordOffset + 12);\n if (cmapOffset + Math.min(cmapLength, 4) > bytes.length) return false;\n const subtables = u16(cmapOffset + 2);\n for (let j = 0; j < subtables; j++) {\n const encOffset = cmapOffset + 4 + j * 8;\n if (encOffset + 8 > bytes.length) return false;\n const platform = u16(encOffset);\n const encoding = u16(encOffset + 2);\n if (platform === 0 || (platform === 3 && (encoding === 1 || encoding === 10))) return true;\n }\n return false;\n }\n return false;\n}\n\nfunction extractSupportedCodePointsFromTtf(bytes: Uint8Array): Set<number> {\n const supported = new Set<number>();\n if (bytes.length < 12) return supported;\n const u16 = (offset: number) => (bytes[offset] << 8) | bytes[offset + 1];\n const i16 = (offset: number) => {\n const value = u16(offset);\n return value & 0x8000 ? value - 0x10000 : value;\n };\n const u32 = (offset: number) => ((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) >>> 0;\n const tableCount = u16(4);\n let cmapOffset = 0;\n for (let i = 0; i < tableCount; i++) {\n const recordOffset = 12 + i * 16;\n if (recordOffset + 16 > bytes.length) return supported;\n if (String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]) === 'cmap') {\n cmapOffset = u32(recordOffset + 8);\n break;\n }\n }\n if (!cmapOffset || cmapOffset + 4 > bytes.length) return supported;\n const subtables = u16(cmapOffset + 2);\n const candidates: Array<{ format: number; offset: number; score: number }> = [];\n for (let j = 0; j < subtables; j++) {\n const encOffset = cmapOffset + 4 + j * 8;\n if (encOffset + 8 > bytes.length) continue;\n const platform = u16(encOffset);\n const encoding = u16(encOffset + 2);\n const subOffset = cmapOffset + u32(encOffset + 4);\n if (subOffset + 2 > bytes.length) continue;\n const format = u16(subOffset);\n const score = format === 12 ? 40 : format === 4 ? 30 : 0;\n if (score) candidates.push({ format, offset: subOffset, score: score + (platform === 3 && encoding === 10 ? 2 : platform === 0 ? 1 : 0) });\n }\n candidates.sort((a, b) => b.score - a.score);\n const best = candidates[0];\n if (!best) return supported;\n if (best.format === 12 && best.offset + 16 <= bytes.length) {\n const nGroups = u32(best.offset + 12);\n for (let i = 0; i < nGroups; i++) {\n const off = best.offset + 16 + i * 12;\n if (off + 12 > bytes.length) break;\n const start = u32(off);\n const end = u32(off + 4);\n for (let cp = start; cp <= end && cp <= 0x10FFFF; cp++) supported.add(cp);\n }\n } else if (best.format === 4 && best.offset + 14 <= bytes.length) {\n const segCount = u16(best.offset + 6) / 2;\n const endCodes = best.offset + 14;\n const startCodes = endCodes + segCount * 2 + 2;\n const idDeltas = startCodes + segCount * 2;\n const idRangeOffsets = idDeltas + segCount * 2;\n for (let i = 0; i < segCount; i++) {\n const start = u16(startCodes + i * 2);\n const end = u16(endCodes + i * 2);\n const delta = i16(idDeltas + i * 2);\n const rangeOffset = u16(idRangeOffsets + i * 2);\n for (let cp = start; cp <= end && cp !== 0xFFFF; cp++) {\n if (rangeOffset === 0) {\n if (((cp + delta) & 0xffff) !== 0) supported.add(cp);\n } else {\n const glyphOffset = idRangeOffsets + i * 2 + rangeOffset + (cp - start) * 2;\n if (glyphOffset + 2 <= bytes.length && u16(glyphOffset) !== 0) supported.add(cp);\n }\n }\n }\n }\n return supported;\n}\n\nfunction base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\n// Get jsPDF-compatible font name (sanitized - no spaces)\nexport const getJsPDFFontName = (fontName: string): string => {\n return fontName.replace(/\\s+/g, '');\n};\n\n// Weight → file key and fallback order for resolving TTF path (normal style)\nconst WEIGHT_TO_KEYS: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['light', 'regular'],\n 400: ['regular'],\n 500: ['medium', 'regular'],\n 600: ['semibold', 'bold', 'regular'],\n 700: ['bold', 'regular'],\n};\n\n// Weight → file key and fallback order for resolving TTF path (italic style)\nconst WEIGHT_TO_ITALIC_KEYS: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['lightItalic', 'italic', 'light', 'regular'],\n 400: ['italic', 'regular'],\n 500: ['mediumItalic', 'italic', 'medium', 'regular'],\n 600: ['semiboldItalic', 'boldItalic', 'italic', 'semibold', 'bold', 'regular'],\n 700: ['boldItalic', 'italic', 'bold', 'regular'],\n};\n\nfunction getFontPathForWeight(fontFiles: FontWeightFiles, resolvedWeight: number, isItalic = false): string {\n const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[resolvedWeight] : WEIGHT_TO_KEYS[resolvedWeight];\n if (!keys) return fontFiles.regular;\n for (const k of keys) {\n const path = fontFiles[k];\n if (path) return path;\n }\n return fontFiles.regular;\n}\n\n/**\n * True when the path resolved by getFontPathForWeight is actually the file for\n * the requested (weight, italic) — not a fallback (e.g. resolving Bold to\n * Regular because the family has no Bold file). Used so we can avoid\n * registering Regular bytes under a \"Bold\" name (which makes jsPDF render\n * inline bold spans in regular weight).\n */\nfunction isExactWeightItalicMatch(\n fontFiles: FontWeightFiles,\n resolvedWeight: number,\n isItalic: boolean,\n resolvedPath: string,\n): boolean {\n const exactKey: keyof FontWeightFiles | null = isItalic\n ? resolvedWeight === 300 ? 'lightItalic'\n : resolvedWeight === 500 ? 'mediumItalic'\n : resolvedWeight === 600 ? 'semiboldItalic'\n : resolvedWeight === 700 ? 'boldItalic'\n : 'italic'\n : resolvedWeight === 300 ? 'light'\n : resolvedWeight === 500 ? 'medium'\n : resolvedWeight === 600 ? 'semibold'\n : resolvedWeight === 700 ? 'bold'\n : 'regular';\n return !!exactKey && fontFiles[exactKey] === resolvedPath;\n}\n\n/** Check if the resolved path is actually an italic-specific file */\nfunction isItalicPath(fontFiles: FontWeightFiles, path: string): boolean {\n return path === fontFiles.italic ||\n path === fontFiles.boldItalic ||\n path === fontFiles.lightItalic ||\n path === fontFiles.mediumItalic ||\n path === fontFiles.semiboldItalic;\n}\n\n// Returns the jsPDF font name used when embedding; includes italic suffix when applicable\nexport const getEmbeddedJsPDFFontName = (fontName: string, weight: number, isItalic = false): string => {\n const resolved = resolveFontWeight(weight);\n const label = FONT_WEIGHT_LABELS[resolved];\n const italicSuffix = isItalic ? 'Italic' : '';\n return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;\n};\n\n// Load and embed a font into jsPDF from local TTF files (one jsPDF font per weight+style, style always \"normal\")\nexport const embedFont = async (\n pdf: any,\n fontName: string,\n weight: number = 400,\n isItalic = false,\n): Promise<boolean> => {\n const fontFiles = FONT_FILES[fontName];\n if (!fontFiles) {\n console.warn(`Font ${fontName} not found in local fonts`);\n return false;\n }\n\n const resolvedWeight = resolveFontWeight(weight);\n const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);\n if (!fontPath) return false;\n\n // If the local family lacks a TTF for this exact (weight, italic) and would\n // fall back to Regular, refuse — let embedFontWithGoogleFallback fetch a\n // real variant from Google Fonts / Fontshare. Registering Regular bytes\n // under e.g. \"DMSerifDisplay-Bold\" makes jsPDF render bold spans in\n // regular weight, breaking inline bold/italic in selectable PDFs.\n if (!isExactWeightItalicMatch(fontFiles, resolvedWeight, isItalic, fontPath)) {\n return false;\n }\n\n const label = FONT_WEIGHT_LABELS[resolvedWeight];\n const italicSuffix = isItalic ? 'Italic' : '';\n const cacheKey = `${fontName}-${resolvedWeight}${isItalic ? '-italic' : ''}`;\n const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, isItalic);\n\n try {\n let base64Font = fontCache.get(cacheKey);\n if (!base64Font) {\n const response = await fetch(fontPath);\n if (!response.ok) throw new Error(`Failed to fetch font: ${response.statusText}`);\n const arrayBuffer = await response.arrayBuffer();\n const bytes = new Uint8Array(arrayBuffer);\n if (!isJsPdfEmbeddableTrueType(bytes)) throw new Error(`Font is not a jsPDF-compatible TrueType file: ${fontPath}`);\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n base64Font = btoa(binary);\n fontCache.set(cacheKey, base64Font);\n } else if (!registeredVariantCoverage.has(variantKey(fontName, resolvedWeight, isItalic))) {\n // The registry is reset per PDF export, but `fontCache` persists across\n // exports. Rebuild glyph coverage directly from the cached TTF bytes;\n // otherwise supported glyphs like Karla's `≠` are treated as missing and\n // incorrectly rewritten to Noto Sans Math in selectable PDFs.\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(base64Font)));\n }\n\n const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;\n pdf.addFileToVFS(fileName, base64Font);\n pdf.addFont(fileName, jsPdfFontName, 'normal');\n if (fontName !== jsPdfFontName) {\n try {\n pdf.addFont(fileName, fontName, 'normal');\n } catch {\n // Ignore duplicate alias registration; svg2pdf only needs one successful alias.\n }\n }\n registeredFamilies.add(fontName);\n registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));\n return true;\n } catch (error) {\n console.error(`Failed to embed font ${fontName} (weight ${weight}, italic=${isItalic}):`, error);\n return false;\n }\n};\n\n// Pre-load all font weights into cache (can be called at app start for faster PDF export)\nexport const preloadFonts = async (): Promise<void> => {\n const loadPromises: Promise<void>[] = [];\n const weights = [300, 400, 500, 600, 700] as const;\n\n for (const [fontName, files] of Object.entries(FONT_FILES)) {\n for (const w of weights) {\n // Normal\n const path = getFontPathForWeight(files as FontWeightFiles, w);\n if (path) {\n const cacheKey = `${fontName}-${w}`;\n loadPromises.push(\n fontToBase64(path)\n .then(base64 => { fontCache.set(cacheKey, base64); })\n .catch(err => console.warn(`Failed to preload ${fontName} weight ${w}:`, err))\n );\n }\n // Italic\n const italicPath = getFontPathForWeight(files as FontWeightFiles, w, true);\n if (italicPath && italicPath !== path) {\n const cacheKeyItalic = `${fontName}-${w}-italic`;\n loadPromises.push(\n fontToBase64(italicPath)\n .then(base64 => { fontCache.set(cacheKeyItalic, base64); })\n .catch(err => console.warn(`Failed to preload ${fontName} weight ${w} italic:`, err))\n );\n }\n }\n }\n\n await Promise.all(loadPromises);\n};\n\n// Check if a font is available locally\nexport const isFontAvailable = (fontName: string): boolean => {\n return fontName in FONT_FILES;\n};\n\n// Check if a font has an italic variant for the given weight\nexport const hasItalicVariant = (fontName: string, weight: number = 400): boolean => {\n const files = FONT_FILES[fontName];\n if (!files) return false;\n const resolvedWeight = resolveFontWeight(weight);\n const normalPath = getFontPathForWeight(files, resolvedWeight, false);\n const italicPath = getFontPathForWeight(files, resolvedWeight, true);\n return italicPath !== normalPath && isItalicPath(files, italicPath);\n};\n\n// Get all available font names\nexport const getAvailableFonts = (): string[] => {\n return Object.keys(FONT_FILES);\n};\n\n/**\n * Get available font weights for a given font family.\n * Returns only weights that have a dedicated TTF file (not fallbacks).\n */\nexport const getAvailableWeights = (fontFamily: string): number[] => {\n const files = FONT_FILES[fontFamily];\n if (!files) {\n // Non-local font (Google Fonts / Fontshare). The PDF embedder\n // (`fetchGoogleFontTTF` / `fetchFontshareTTF`) can fetch any standard\n // weight on-demand via the proxy, and the canvas CSS loader requests\n // [300,400,500,600,700] up-front in `loadGoogleFont`. So expose the\n // full standard ladder for most families, except for known\n // single-weight categories where Google only publishes weight 400.\n try {\n const entry = _findFontEntry(fontFamily);\n if (entry?.weights && entry.weights.length > 0) return entry.weights;\n const SINGLE_WEIGHT_CATEGORIES = new Set([\n 'Display', 'Decorative', 'Blackletter', 'Handwriting',\n ]);\n // Multi-weight handwriting/display exceptions worth surfacing.\n const MULTI_WEIGHT_OVERRIDES = new Set([\n 'Caveat', 'Comfortaa', 'Fredoka', 'Kalam', 'Patrick Hand',\n 'Amatic SC', 'Architects Daughter', 'Indie Flower', 'Permanent Marker',\n 'Lobster Two', 'Oswald', 'Bebas Neue',\n ]);\n if (entry && SINGLE_WEIGHT_CATEGORIES.has(entry.category) && !MULTI_WEIGHT_OVERRIDES.has(fontFamily)) {\n return [400];\n }\n } catch { /* ignore */ }\n return [300, 400, 500, 600, 700];\n }\n\n const weights: number[] = [];\n if (files.light) weights.push(300);\n // regular always exists\n weights.push(400);\n if (files.medium) weights.push(500);\n if (files.semibold) weights.push(600);\n if (files.bold) weights.push(700);\n\n return weights;\n};\n\n/**\n * Check if a font has any italic variant at all.\n */\nexport const hasAnyItalicVariant = (fontFamily: string): boolean => {\n const files = FONT_FILES[fontFamily];\n if (!files) return false;\n return !!(files.italic || files.boldItalic || files.lightItalic || files.mediumItalic || files.semiboldItalic);\n};\n\n// ═══════════════════════════════════════════════════════════════\n// Google Fonts dynamic TTF fetching (parity with EC2 server)\n// ═══════════════════════════════════════════════════════════════\n\n/** Fetch a TTF (as base64) for any Google Font. Caches per (family, weight, style). */\nexport async function fetchGoogleFontTTF(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n): Promise<string | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontCache.has(cacheKey)) return fontCache.get(cacheKey)!;\n const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);\n if (googleFontNotFound.has(notFoundKey)) return null;\n // Try the server-side proxy first — it reliably returns TTF since the edge\n // function can spoof a legacy UA. Direct browser fetch is unreliable because\n // sec-ch-ua client hints override our custom User-Agent.\n const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, 'google');\n if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {\n fontBytesCache.set(cacheKey, proxyBytes);\n let binary = '';\n for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n }\n if (resolveFontProxyUrl()) return null;\n try {\n const ital = isItalic ? '1' : '0';\n const cssUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(\n fontFamily,\n )}:ital,wght@${ital},${weight}&display=swap`;\n // The User-Agent below tricks Google Fonts into returning legacy TTF (not WOFF2),\n // matching what the EC2 server does so jsPDF can consume it.\n const cssRes = await fetch(cssUrl, {\n headers: {\n 'User-Agent':\n 'Mozilla/5.0 (Linux; U; Android 2.2; en-us) AppleWebKit/533.1 (KHTML, like Gecko)',\n },\n });\n if (!cssRes.ok) {\n if (cssRes.status === 400 || cssRes.status === 404) googleFontNotFound.add(notFoundKey);\n return null;\n }\n const css = await cssRes.text();\n const urlMatch = css.match(/url\\(([^)]+)\\)\\s+format\\(['\"]?truetype['\"]?\\)/i)\n || css.match(/url\\(([^)]+)\\)/);\n if (!urlMatch) return null;\n const ttfUrl = urlMatch[1].replace(/['\"]/g, '');\n googleFontUrlCache.set(cacheKey, ttfUrl);\n const ttfRes = await fetch(ttfUrl);\n if (!ttfRes.ok) return null;\n const buf = await ttfRes.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isJsPdfEmbeddableTrueType(bytes)) {\n console.warn(`[pdfFonts] Google Fonts returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);\n return null;\n }\n fontBytesCache.set(cacheKey, bytes);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n } catch (err) {\n console.warn(`[pdfFonts] fetchGoogleFontTTF failed for ${fontFamily} (${weight}):`, err);\n return null;\n }\n}\n\n/** Get raw TTF bytes for a Google Font (used by opentype.js / HarfBuzz). */\nexport async function getGoogleFontBytes(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n): Promise<Uint8Array | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey)!;\n await fetchGoogleFontTTF(fontFamily, weight, isItalic);\n return fontBytesCache.get(cacheKey) || null;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Fontshare dynamic TTF fetching (Satoshi, Clash Display, etc.)\n// ═══════════════════════════════════════════════════════════════\n\nconst fontshareNotFound: Set<string> = new Set();\n\n/** Convert a font family display name to the slug Fontshare's API expects. */\nfunction toFontshareSlug(family: string): string {\n return family.trim().toLowerCase().replace(/\\s+/g, '-');\n}\n\n/**\n * Fetch a TTF (as base64) for a Fontshare family. Mirrors `fetchGoogleFontTTF`:\n * pulls the CSS for the requested weight/style, picks the `format('truetype')`\n * URL, downloads the bytes, validates, and caches under the same key shape used\n * for Google Fonts so all downstream consumers work without changes.\n */\nexport async function fetchFontshareTTF(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n slug?: string,\n): Promise<string | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontCache.has(cacheKey)) return fontCache.get(cacheKey)!;\n const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);\n if (fontshareNotFound.has(notFoundKey)) return null;\n const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, 'fontshare');\n if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {\n fontBytesCache.set(cacheKey, proxyBytes);\n let binary = '';\n for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n }\n if (resolveFontProxyUrl()) return null;\n const finalSlug = slug || toFontshareSlug(fontFamily);\n try {\n const styleSuffix = isItalic ? 'i' : '';\n const cssUrl = `https://api.fontshare.com/v2/css?f[]=${finalSlug}@${weight}${styleSuffix}&display=swap`;\n const cssRes = await fetch(cssUrl);\n if (!cssRes.ok) {\n if (cssRes.status === 400 || cssRes.status === 404) fontshareNotFound.add(notFoundKey);\n return null;\n }\n const css = await cssRes.text();\n // Fontshare CSS includes woff2/woff/ttf; pick truetype explicitly.\n const ttMatch = css.match(/url\\(([^)]+)\\)\\s+format\\(['\"]?truetype['\"]?\\)/i);\n if (!ttMatch) {\n fontshareNotFound.add(notFoundKey);\n return null;\n }\n let ttfUrl = ttMatch[1].replace(/['\"]/g, '').trim();\n if (ttfUrl.startsWith('//')) ttfUrl = `https:${ttfUrl}`;\n const ttfRes = await fetch(ttfUrl);\n if (!ttfRes.ok) return null;\n const buf = await ttfRes.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isJsPdfEmbeddableTrueType(bytes)) {\n console.warn(`[pdfFonts] Fontshare returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);\n return null;\n }\n fontBytesCache.set(cacheKey, bytes);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n } catch (err) {\n console.warn(`[pdfFonts] fetchFontshareTTF failed for ${fontFamily} (${weight}):`, err);\n return null;\n }\n}\n\n/** Get raw TTF bytes for a Fontshare font (used by opentype.js / HarfBuzz). */\nexport async function getFontshareFontBytes(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n slug?: string,\n): Promise<Uint8Array | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey)!;\n await fetchFontshareTTF(fontFamily, weight, isItalic, slug);\n return fontBytesCache.get(cacheKey) || null;\n}\n\n/**\n * Embed a font into jsPDF — local TTF if available, otherwise Google Fonts.\n * Returns true on success. Registers under the SAME jsPDF font name as\n * `getEmbeddedJsPDFFontName(...)` so SVG rewriting matches.\n */\nexport const embedFontWithGoogleFallback = async (\n pdf: any,\n fontName: string,\n weight: number = 400,\n isItalic = false,\n): Promise<boolean> => {\n // 1. Local first\n if (FONT_FILES[fontName]) {\n const ok = await embedFont(pdf, fontName, weight, isItalic);\n if (ok) return true;\n }\n\n // Family short-circuit: if base 400-regular missed on every CDN already,\n // skip the variant ladder entirely. Saves 6–8 wasted edge-function calls\n // per missing family (massive DevTools spam reduction + faster export).\n if (familyNotOnAnyCdn.has(fontName)) return false;\n\n // 2. Try the requested variant first on Fontshare, then Google. Many\n // decorative families on Google Fonts and Fontshare ship a SINGLE\n // weight (e.g. Pacifico, Frijole, Stardom only at 400). The canvas\n // fakes bold/semibold via synthetic-bold rendering — the PDF must do\n // the same: when the requested weight is unavailable, fall back\n // through a weight ladder so the family still embeds with its real\n // glyphs and svg2pdf can match by family. Without this fallback,\n // bold display fonts silently substitute Helvetica/Times in the PDF.\n const resolved = resolveFontWeight(weight);\n const weightLadder: number[] = [resolved];\n for (const w of [400, 500, 700, 600, 300]) {\n if (!weightLadder.includes(w)) weightLadder.push(w);\n }\n\n const tryFetch = async (w: number, italic: boolean): Promise<string | null> => {\n const fs = await fetchFontshareTTF(fontName, w, italic);\n if (fs) return fs;\n const g = await fetchGoogleFontTTF(fontName, w, italic);\n return g;\n };\n\n let b64: string | null = null;\n let usedItalic = isItalic;\n let usedWeight = resolved;\n for (const w of weightLadder) {\n b64 = await tryFetch(w, isItalic);\n if (b64) { usedWeight = w; break; }\n }\n // If italic was requested but no italic variant exists at any weight,\n // fall back to upright bytes so the family still renders. svg2pdf will\n // skew via the existing synthetic-italic transform path in the rewriter.\n if (!b64 && isItalic) {\n for (const w of weightLadder) {\n b64 = await tryFetch(w, false);\n if (b64) { usedItalic = false; usedWeight = w; break; }\n }\n }\n if (!b64) {\n // Both CDNs missed for this variant. If the base 400-regular also failed\n // for both (meaning the family doesn't exist anywhere), seed the family\n // short-circuit so subsequent variant requests skip the ladder.\n if (\n !familyConfirmedOnSomeCdn.has(fontName) &&\n proxyNotFound.has(proxyKey(fontName, 400, false, 'google')) &&\n proxyNotFound.has(proxyKey(fontName, 400, false, 'fontshare'))\n ) {\n familyNotOnAnyCdn.add(fontName);\n persistCaches();\n }\n // For italic requests, do NOT silently register upright bytes under the\n // italic variant key — that previously caused inline italic spans to\n // render in upright glyphs in the PDF. Instead we let\n // `resolveBestRegisteredVariant` (in the SVG rewriter) fall back to a\n // lighter italic weight that actually carries italic glyphs, with\n // synthetic bold (stroke) applied for the weight delta.\n return false;\n }\n // Register the bytes under the ACTUAL weight whose glyphs we fetched.\n // This is critical for visual parity with the canvas: when the requested\n // weight (e.g. 700) is not available and we fell back to 400, the SVG\n // rewriter's `resolveBestRegisteredVariant` will return weight=400, and\n // `needsSyntheticBold(700, 400)` will trigger the stroke-based synthetic\n // bold path — matching what the browser does on <canvas> for\n // single-weight families like Pacifico/Stardom/Frijole.\n return registerJsPdfFont(pdf, fontName, usedWeight, usedItalic, b64);\n};\n\n/** Register a base64 TTF inside jsPDF under the canonical embedded name + alias. */\nfunction registerJsPdfFont(\n pdf: any,\n fontName: string,\n resolvedWeight: number,\n isItalic: boolean,\n base64: string,\n): boolean {\n const label = FONT_WEIGHT_LABELS[resolvedWeight];\n const italicSuffix = isItalic ? 'Italic' : '';\n const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, resolvedWeight, isItalic);\n const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;\n try {\n try {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));\n } catch {\n // Coverage is an optimization for choosing fallbacks; font registration can still proceed.\n }\n pdf.addFileToVFS(fileName, base64);\n pdf.addFont(fileName, jsPdfFontName, 'normal');\n if (fontName !== jsPdfFontName) {\n try {\n pdf.addFont(fileName, fontName, 'normal');\n } catch {\n /* duplicate alias; ignore */\n }\n }\n registeredFamilies.add(fontName);\n registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));\n return true;\n } catch (err) {\n console.warn(`[pdfFonts] registerJsPdfFont failed for ${fontName}:`, err);\n return false;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Latin → Devanagari font sibling mapping\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Map of Latin Google Fonts → their Devanagari sibling family on Google Fonts.\n * When a user picks a Latin font and types Hindi, we use the matching Devanagari\n * family for path conversion so the visual style is preserved (instead of always\n * falling back to Hind). Sourced from Google's own family pairings.\n */\nexport const LATIN_TO_DEVANAGARI: Record<string, string> = {\n // Direct Devanagari subsets — same family carries both scripts\n 'Poppins': 'Poppins',\n 'Noto Sans': 'Noto Sans Devanagari',\n 'Noto Serif': 'Noto Serif Devanagari',\n 'Hind': 'Hind',\n 'Mukta': 'Mukta',\n\n // Curated visual matches (Google's own recommendations)\n 'Montserrat': 'Mukta',\n 'Open Sans': 'Mukta',\n 'Lato': 'Mukta',\n 'Roboto': 'Mukta',\n 'Inter': 'Mukta',\n 'Nunito': 'Mukta',\n 'Source Sans Pro': 'Mukta',\n 'Work Sans': 'Mukta',\n 'DM Sans': 'Mukta',\n 'Outfit': 'Mukta',\n 'Figtree': 'Mukta',\n 'Manrope': 'Mukta',\n 'Plus Jakarta Sans': 'Mukta',\n 'Sora': 'Mukta',\n 'Urbanist': 'Mukta',\n 'Lexend': 'Mukta',\n 'Albert Sans': 'Mukta',\n 'Cabin': 'Mukta',\n 'Karla': 'Mukta',\n 'Mulish': 'Mukta',\n 'Rubik': 'Mukta',\n 'Quicksand': 'Mukta',\n 'Libre Franklin': 'Mukta',\n 'Barlow': 'Mukta',\n 'Archivo': 'Mukta',\n 'Overpass': 'Mukta',\n 'Josefin Sans': 'Mukta',\n 'Exo 2': 'Mukta',\n 'Space Grotesk': 'Mukta',\n\n // Display / heavy\n 'Oswald': 'Teko',\n 'Bebas Neue': 'Teko',\n 'Anton': 'Teko',\n 'Teko': 'Teko',\n 'League Spartan': 'Teko',\n\n // Serifs → Tiro Devanagari Hindi (a refined Devanagari serif)\n 'Playfair Display': 'Tiro Devanagari Hindi',\n 'Merriweather': 'Tiro Devanagari Hindi',\n 'Lora': 'Tiro Devanagari Hindi',\n 'EB Garamond': 'Tiro Devanagari Hindi',\n 'Libre Baskerville': 'Tiro Devanagari Hindi',\n 'Crimson Text': 'Tiro Devanagari Hindi',\n 'DM Serif Display': 'Tiro Devanagari Sanskrit',\n 'Abril Fatface': 'Tiro Devanagari Sanskrit',\n\n // Handwriting → Kalam (the only serious Devanagari handwriting family on GF)\n 'Dancing Script': 'Kalam',\n 'Pacifico': 'Kalam',\n 'Great Vibes': 'Kalam',\n 'Sacramento': 'Kalam',\n 'Alex Brush': 'Kalam',\n 'Allura': 'Kalam',\n 'Caveat': 'Kalam',\n 'Lobster': 'Kalam',\n 'Comfortaa': 'Mukta',\n\n // Monospace → there's no proper Devanagari mono; fall back to Mukta\n 'Roboto Mono': 'Mukta',\n 'Fira Code': 'Mukta',\n 'JetBrains Mono': 'Mukta',\n 'Source Code Pro': 'Mukta',\n 'IBM Plex Mono': 'Mukta',\n 'Space Mono': 'Mukta',\n};\n\n/** Pick the best Devanagari family for a given Latin font (returns FONT_FALLBACK_DEVANAGARI as last resort). */\nexport function resolveDevanagariSibling(latinFont: string | null | undefined): string {\n if (!latinFont) return FONT_FALLBACK_DEVANAGARI;\n return LATIN_TO_DEVANAGARI[latinFont] || FONT_FALLBACK_DEVANAGARI;\n}\n"],"names":[],"mappings":"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"}
@@ -8,7 +8,8 @@ const familyNotOnAnyCdn = /* @__PURE__ */ new Set();
8
8
  const familyConfirmedOnSomeCdn = /* @__PURE__ */ new Set();
9
9
  const proxyKey = (family, weight, isItalic, source) => `${source}|${family}|${weight}|${isItalic ? "i" : "n"}`;
10
10
  const LS_KEY = "pdfFonts.negCache.v1";
11
- const LS_VERSION = 1;
11
+ const LS_VERSION = 2;
12
+ const familyProbedWeights = /* @__PURE__ */ new Map();
12
13
  function loadPersistedCaches() {
13
14
  try {
14
15
  if (typeof localStorage === "undefined") return;
@@ -19,6 +20,13 @@ function loadPersistedCaches() {
19
20
  (obj.proxyNotFound || []).forEach((k) => proxyNotFound.add(k));
20
21
  (obj.familyNotOnAnyCdn || []).forEach((k) => familyNotOnAnyCdn.add(k));
21
22
  (obj.familyConfirmedOnSomeCdn || []).forEach((k) => familyConfirmedOnSomeCdn.add(k));
23
+ if (obj.familyProbedWeights && typeof obj.familyProbedWeights === "object") {
24
+ for (const [k, v] of Object.entries(obj.familyProbedWeights)) {
25
+ if (Array.isArray(v) && v.every((n) => typeof n === "number")) {
26
+ familyProbedWeights.set(k, v);
27
+ }
28
+ }
29
+ }
22
30
  } catch {
23
31
  }
24
32
  }
@@ -33,7 +41,8 @@ function persistCaches() {
33
41
  v: LS_VERSION,
34
42
  proxyNotFound: Array.from(proxyNotFound),
35
43
  familyNotOnAnyCdn: Array.from(familyNotOnAnyCdn),
36
- familyConfirmedOnSomeCdn: Array.from(familyConfirmedOnSomeCdn)
44
+ familyConfirmedOnSomeCdn: Array.from(familyConfirmedOnSomeCdn),
45
+ familyProbedWeights: Object.fromEntries(familyProbedWeights)
37
46
  }));
38
47
  } catch {
39
48
  }
@@ -1128,4 +1137,4 @@ export {
1128
1137
  resolveDevanagariSibling,
1129
1138
  resolveFontWeight
1130
1139
  };
1131
- //# sourceMappingURL=pdfFonts-b3_bv7F0.js.map
1140
+ //# sourceMappingURL=pdfFonts-DhEaMTZl.js.map