@pro-laico/payload-fonts 0.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/LICENSE.md +22 -0
- package/README.md +19 -0
- package/dist/access/authd.d.ts +19 -0
- package/dist/access/authd.d.ts.map +1 -0
- package/dist/access/authd.js +18 -0
- package/dist/access/authd.js.map +1 -0
- package/dist/collections/font.d.ts +29 -0
- package/dist/collections/font.d.ts.map +1 -0
- package/dist/collections/font.js +327 -0
- package/dist/collections/font.js.map +1 -0
- package/dist/collections/fontOptimized.d.ts +20 -0
- package/dist/collections/fontOptimized.d.ts.map +1 -0
- package/dist/collections/fontOptimized.js +111 -0
- package/dist/collections/fontOptimized.js.map +1 -0
- package/dist/collections/fontOriginal.d.ts +25 -0
- package/dist/collections/fontOriginal.d.ts.map +1 -0
- package/dist/collections/fontOriginal.js +49 -0
- package/dist/collections/fontOriginal.js.map +1 -0
- package/dist/components/DevFonts.d.ts +52 -0
- package/dist/components/DevFonts.d.ts.map +1 -0
- package/dist/components/DevFonts.js +75 -0
- package/dist/components/DevFonts.js.map +1 -0
- package/dist/components/admin/FontOriginalUpload.d.ts +15 -0
- package/dist/components/admin/FontOriginalUpload.d.ts.map +1 -0
- package/dist/components/admin/FontOriginalUpload.js +22 -0
- package/dist/components/admin/FontOriginalUpload.js.map +1 -0
- package/dist/components/admin/FontOriginalUpload.scss +9 -0
- package/dist/endpoints/exportFonts.d.ts +49 -0
- package/dist/endpoints/exportFonts.d.ts.map +1 -0
- package/dist/endpoints/exportFonts.js +162 -0
- package/dist/endpoints/exportFonts.js.map +1 -0
- package/dist/extractFonts.d.ts +20 -0
- package/dist/extractFonts.d.ts.map +1 -0
- package/dist/extractFonts.js +18 -0
- package/dist/extractFonts.js.map +1 -0
- package/dist/fields/font.d.ts +14 -0
- package/dist/fields/font.d.ts.map +1 -0
- package/dist/fields/font.js +37 -0
- package/dist/fields/font.js.map +1 -0
- package/dist/globals/fontSet.d.ts +15 -0
- package/dist/globals/fontSet.d.ts.map +1 -0
- package/dist/globals/fontSet.js +25 -0
- package/dist/globals/fontSet.js.map +1 -0
- package/dist/hooks/optimizeFont.d.ts +56 -0
- package/dist/hooks/optimizeFont.d.ts.map +1 -0
- package/dist/hooks/optimizeFont.js +185 -0
- package/dist/hooks/optimizeFont.js.map +1 -0
- package/dist/hooks/optimizeFromOriginals.d.ts +43 -0
- package/dist/hooks/optimizeFromOriginals.d.ts.map +1 -0
- package/dist/hooks/optimizeFromOriginals.js +313 -0
- package/dist/hooks/optimizeFromOriginals.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/activeFonts.d.ts +64 -0
- package/dist/lib/activeFonts.d.ts.map +1 -0
- package/dist/lib/activeFonts.js +139 -0
- package/dist/lib/activeFonts.js.map +1 -0
- package/dist/lib/families.d.ts +38 -0
- package/dist/lib/families.d.ts.map +1 -0
- package/dist/lib/families.js +44 -0
- package/dist/lib/families.js.map +1 -0
- package/dist/lib/mergeConfig.d.ts +28 -0
- package/dist/lib/mergeConfig.d.ts.map +1 -0
- package/dist/lib/mergeConfig.js +73 -0
- package/dist/lib/mergeConfig.js.map +1 -0
- package/dist/lib/refs.d.ts +8 -0
- package/dist/lib/refs.d.ts.map +1 -0
- package/dist/lib/refs.js +11 -0
- package/dist/lib/refs.js.map +1 -0
- package/dist/lib/uploadBytes.d.ts +26 -0
- package/dist/lib/uploadBytes.d.ts.map +1 -0
- package/dist/lib/uploadBytes.js +98 -0
- package/dist/lib/uploadBytes.js.map +1 -0
- package/dist/plugin.d.ts +57 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +93 -0
- package/dist/plugin.js.map +1 -0
- package/dist/scripts/cli.d.ts +3 -0
- package/dist/scripts/cli.d.ts.map +1 -0
- package/dist/scripts/cli.js +13 -0
- package/dist/scripts/cli.js.map +1 -0
- package/dist/scripts/downloadFonts.d.ts +37 -0
- package/dist/scripts/downloadFonts.d.ts.map +1 -0
- package/dist/scripts/downloadFonts.js +216 -0
- package/dist/scripts/downloadFonts.js.map +1 -0
- package/package.json +98 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CollectionConfig } from 'payload';
|
|
2
|
+
/** Default slug for the archival font-original upload collection. */
|
|
3
|
+
export declare const FONT_ORIGINAL_SLUG = "fontOriginal";
|
|
4
|
+
/**
|
|
5
|
+
* Accepted upload mime types for the four web-font formats. OTF/TTF arrive under several
|
|
6
|
+
* different mime strings depending on the OS/browser, so the whitelist covers the common
|
|
7
|
+
* sfnt variants — otherwise a valid `.otf` can be rejected as "MIME Type invalid". Shared by
|
|
8
|
+
* the `Font` collection and this archival one (which stores the untouched original under its
|
|
9
|
+
* own original mime).
|
|
10
|
+
*/
|
|
11
|
+
export declare const FONT_MIME_TYPES: string[];
|
|
12
|
+
/**
|
|
13
|
+
* Upload collection holding the raw, untouched font files editors drop into the `Font`
|
|
14
|
+
* typeface's `upload` fields. It's the archive of truth: the `Font` save hook reads these and
|
|
15
|
+
* subsets each to a served `fontOptimized` WOFF2, so the (lossy, subsetted) output can be
|
|
16
|
+
* re-derived with a different charset later.
|
|
17
|
+
*
|
|
18
|
+
* It carries NO hooks — uploading here is a plain store, which is exactly what lets it be a
|
|
19
|
+
* client-upload (direct-to-Blob) collection in production. Hidden from admin nav; editors only
|
|
20
|
+
* ever interact with it through the `Font` fields.
|
|
21
|
+
*/
|
|
22
|
+
export declare const createFontOriginalCollection: ({ slug }?: {
|
|
23
|
+
slug?: string;
|
|
24
|
+
}) => CollectionConfig;
|
|
25
|
+
//# sourceMappingURL=fontOriginal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fontOriginal.d.ts","sourceRoot":"","sources":["../../src/collections/fontOriginal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAI/C,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,iBAAiB,CAAA;AAEhD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,UAW3B,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,WAA+B;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,KAAG,gBAMnG,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { authd } from "../access/authd.js";
|
|
2
|
+
/** Default slug for the archival font-original upload collection. */ export const FONT_ORIGINAL_SLUG = 'fontOriginal';
|
|
3
|
+
/**
|
|
4
|
+
* Accepted upload mime types for the four web-font formats. OTF/TTF arrive under several
|
|
5
|
+
* different mime strings depending on the OS/browser, so the whitelist covers the common
|
|
6
|
+
* sfnt variants — otherwise a valid `.otf` can be rejected as "MIME Type invalid". Shared by
|
|
7
|
+
* the `Font` collection and this archival one (which stores the untouched original under its
|
|
8
|
+
* own original mime).
|
|
9
|
+
*/ export const FONT_MIME_TYPES = [
|
|
10
|
+
'font/ttf',
|
|
11
|
+
'font/otf',
|
|
12
|
+
'font/woff',
|
|
13
|
+
'font/woff2',
|
|
14
|
+
'font/sfnt',
|
|
15
|
+
'application/font-sfnt',
|
|
16
|
+
'application/vnd.ms-opentype',
|
|
17
|
+
'application/x-font-ttf',
|
|
18
|
+
'application/x-font-otf',
|
|
19
|
+
'application/x-font-truetype'
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Upload collection holding the raw, untouched font files editors drop into the `Font`
|
|
23
|
+
* typeface's `upload` fields. It's the archive of truth: the `Font` save hook reads these and
|
|
24
|
+
* subsets each to a served `fontOptimized` WOFF2, so the (lossy, subsetted) output can be
|
|
25
|
+
* re-derived with a different charset later.
|
|
26
|
+
*
|
|
27
|
+
* It carries NO hooks — uploading here is a plain store, which is exactly what lets it be a
|
|
28
|
+
* client-upload (direct-to-Blob) collection in production. Hidden from admin nav; editors only
|
|
29
|
+
* ever interact with it through the `Font` fields.
|
|
30
|
+
*/ export const createFontOriginalCollection = ({ slug = FONT_ORIGINAL_SLUG } = {})=>({
|
|
31
|
+
slug,
|
|
32
|
+
access: {
|
|
33
|
+
create: authd,
|
|
34
|
+
delete: authd,
|
|
35
|
+
read: authd,
|
|
36
|
+
update: authd
|
|
37
|
+
},
|
|
38
|
+
admin: {
|
|
39
|
+
group: 'Assets',
|
|
40
|
+
hidden: true,
|
|
41
|
+
useAsTitle: 'filename'
|
|
42
|
+
},
|
|
43
|
+
upload: {
|
|
44
|
+
mimeTypes: FONT_MIME_TYPES
|
|
45
|
+
},
|
|
46
|
+
fields: []
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=fontOriginal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/collections/fontOriginal.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport { authd } from '../access/authd'\n\n/** Default slug for the archival font-original upload collection. */\nexport const FONT_ORIGINAL_SLUG = 'fontOriginal'\n\n/**\n * Accepted upload mime types for the four web-font formats. OTF/TTF arrive under several\n * different mime strings depending on the OS/browser, so the whitelist covers the common\n * sfnt variants — otherwise a valid `.otf` can be rejected as \"MIME Type invalid\". Shared by\n * the `Font` collection and this archival one (which stores the untouched original under its\n * own original mime).\n */\nexport const FONT_MIME_TYPES = [\n 'font/ttf',\n 'font/otf',\n 'font/woff',\n 'font/woff2',\n 'font/sfnt',\n 'application/font-sfnt',\n 'application/vnd.ms-opentype',\n 'application/x-font-ttf',\n 'application/x-font-otf',\n 'application/x-font-truetype',\n]\n\n/**\n * Upload collection holding the raw, untouched font files editors drop into the `Font`\n * typeface's `upload` fields. It's the archive of truth: the `Font` save hook reads these and\n * subsets each to a served `fontOptimized` WOFF2, so the (lossy, subsetted) output can be\n * re-derived with a different charset later.\n *\n * It carries NO hooks — uploading here is a plain store, which is exactly what lets it be a\n * client-upload (direct-to-Blob) collection in production. Hidden from admin nav; editors only\n * ever interact with it through the `Font` fields.\n */\nexport const createFontOriginalCollection = ({ slug = FONT_ORIGINAL_SLUG }: { slug?: string } = {}): CollectionConfig => ({\n slug,\n access: { create: authd, delete: authd, read: authd, update: authd },\n admin: { group: 'Assets', hidden: true, useAsTitle: 'filename' },\n upload: { mimeTypes: FONT_MIME_TYPES },\n fields: [],\n})\n"],"names":["authd","FONT_ORIGINAL_SLUG","FONT_MIME_TYPES","createFontOriginalCollection","slug","access","create","delete","read","update","admin","group","hidden","useAsTitle","upload","mimeTypes","fields"],"mappings":"AAEA,SAASA,KAAK,QAAQ,qBAAiB;AAEvC,mEAAmE,GACnE,OAAO,MAAMC,qBAAqB,eAAc;AAEhD;;;;;;CAMC,GACD,OAAO,MAAMC,kBAAkB;IAC7B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAA;AAED;;;;;;;;;CASC,GACD,OAAO,MAAMC,+BAA+B,CAAC,EAAEC,OAAOH,kBAAkB,EAAqB,GAAG,CAAC,CAAC,GAAwB,CAAA;QACxHG;QACAC,QAAQ;YAAEC,QAAQN;YAAOO,QAAQP;YAAOQ,MAAMR;YAAOS,QAAQT;QAAM;QACnEU,OAAO;YAAEC,OAAO;YAAUC,QAAQ;YAAMC,YAAY;QAAW;QAC/DC,QAAQ;YAAEC,WAAWb;QAAgB;QACrCc,QAAQ,EAAE;IACZ,CAAA,EAAE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getPayload } from 'payload';
|
|
2
|
+
import { type FontFamilyConfig } from '../lib/families';
|
|
3
|
+
export interface DevFontsProps {
|
|
4
|
+
/** Your Payload config — the same `@payload-config` import you pass to `getPayload`. */
|
|
5
|
+
config: Parameters<typeof getPayload>[0]['config'];
|
|
6
|
+
/**
|
|
7
|
+
* The generated `next/font/local` definition (`import definitionFonts from '@/app/definition'`).
|
|
8
|
+
* When it already has fonts, this component renders nothing and lets `next/font` take over — so
|
|
9
|
+
* running `generate:fonts` against your dev server lets you preview the exact production path
|
|
10
|
+
* locally. Omit it and DevFonts always renders in dev.
|
|
11
|
+
*/
|
|
12
|
+
definition?: Record<string, {
|
|
13
|
+
variable?: string;
|
|
14
|
+
} | undefined>;
|
|
15
|
+
/** CSS family-variable prefix; must match the download CLI's `cssVariablePrefix`. @default '--font-set' */
|
|
16
|
+
cssVarPrefix?: string;
|
|
17
|
+
/** Slug of the standalone font-selection global. @default 'fontSet' */
|
|
18
|
+
fontSetSlug?: string;
|
|
19
|
+
/** Slug of the optimized (served) upload collection. @default 'fontOptimized' */
|
|
20
|
+
optimizedSlug?: string;
|
|
21
|
+
/** Optional. The family slots are auto-discovered from the `fontSet` global, so you only need this
|
|
22
|
+
* if you set custom per-family `fallback` stacks and want the dev preview to match them. */
|
|
23
|
+
families?: FontFamilyConfig[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* **Development-only** font loading. In production it renders `null` — your app self-hosts fonts
|
|
27
|
+
* with `next/font/local` (the build-time export + `payload-fonts-download` CLI), which keeps the
|
|
28
|
+
* production path stock `next/font`: precise preloading, size-adjusted fallbacks, static assets.
|
|
29
|
+
*
|
|
30
|
+
* In development (`NODE_ENV !== 'production'`) it reads the active `fontSet` selection from Payload
|
|
31
|
+
* and inlines the matching `@font-face` rules + the `--font-set*` family variables, so fonts show up
|
|
32
|
+
* immediately with no build step — change a typeface in the admin, refresh, see it. Because it
|
|
33
|
+
* emits the **same** family variables `next/font` defines in production, your app's
|
|
34
|
+
* `font-family: var(--font-setSans)` resolves identically across environments.
|
|
35
|
+
*
|
|
36
|
+
* Drop it into your root layout alongside the production wiring — each is a no-op in the other
|
|
37
|
+
* environment:
|
|
38
|
+
*
|
|
39
|
+
* ```tsx
|
|
40
|
+
* import config from '@payload-config'
|
|
41
|
+
* import definitionFonts from '@/app/definition'
|
|
42
|
+
* import { extractFonts } from '@pro-laico/payload-fonts'
|
|
43
|
+
* import { DevFonts } from '@pro-laico/payload-fonts/DevFonts'
|
|
44
|
+
*
|
|
45
|
+
* <html className={extractFonts(definitionFonts)}>
|
|
46
|
+
* <head><DevFonts config={config} definition={definitionFonts} /></head>
|
|
47
|
+
* </html>
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function DevFonts({ config, definition, cssVarPrefix, fontSetSlug, optimizedSlug, families, }: DevFontsProps): Promise<React.ReactElement | null>;
|
|
51
|
+
export default DevFonts;
|
|
52
|
+
//# sourceMappingURL=DevFonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevFonts.d.ts","sourceRoot":"","sources":["../../src/components/DevFonts.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAGpC,OAAO,EAAE,KAAK,gBAAgB,EAAuB,MAAM,iBAAiB,CAAA;AAE5E,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,MAAM,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;IAClD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAA;IAC9D,2GAA2G;IAC3G,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;iGAC6F;IAC7F,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,QAAQ,CAAC,EAC7B,MAAM,EACN,UAAU,EACV,YAAY,EACZ,WAAW,EACX,aAAa,EACb,QAAQ,GACT,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CA0BpD;AAED,eAAe,QAAQ,CAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getPayload } from "payload";
|
|
3
|
+
import { extractFonts } from "../extractFonts.js";
|
|
4
|
+
import { buildFontFaceCss, getActiveFontFaces } from "../lib/activeFonts.js";
|
|
5
|
+
import { resolveFontFamilies } from "../lib/families.js";
|
|
6
|
+
/**
|
|
7
|
+
* **Development-only** font loading. In production it renders `null` — your app self-hosts fonts
|
|
8
|
+
* with `next/font/local` (the build-time export + `payload-fonts-download` CLI), which keeps the
|
|
9
|
+
* production path stock `next/font`: precise preloading, size-adjusted fallbacks, static assets.
|
|
10
|
+
*
|
|
11
|
+
* In development (`NODE_ENV !== 'production'`) it reads the active `fontSet` selection from Payload
|
|
12
|
+
* and inlines the matching `@font-face` rules + the `--font-set*` family variables, so fonts show up
|
|
13
|
+
* immediately with no build step — change a typeface in the admin, refresh, see it. Because it
|
|
14
|
+
* emits the **same** family variables `next/font` defines in production, your app's
|
|
15
|
+
* `font-family: var(--font-setSans)` resolves identically across environments.
|
|
16
|
+
*
|
|
17
|
+
* Drop it into your root layout alongside the production wiring — each is a no-op in the other
|
|
18
|
+
* environment:
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import config from '@payload-config'
|
|
22
|
+
* import definitionFonts from '@/app/definition'
|
|
23
|
+
* import { extractFonts } from '@pro-laico/payload-fonts'
|
|
24
|
+
* import { DevFonts } from '@pro-laico/payload-fonts/DevFonts'
|
|
25
|
+
*
|
|
26
|
+
* <html className={extractFonts(definitionFonts)}>
|
|
27
|
+
* <head><DevFonts config={config} definition={definitionFonts} /></head>
|
|
28
|
+
* </html>
|
|
29
|
+
* ```
|
|
30
|
+
*/ export async function DevFonts({ config, definition, cssVarPrefix, fontSetSlug, optimizedSlug, families }) {
|
|
31
|
+
// Production self-hosts via next/font — never touch the runtime path there.
|
|
32
|
+
if (process.env.NODE_ENV === 'production') return null;
|
|
33
|
+
// If the build path already produced fonts, stand down so there's exactly one source of truth
|
|
34
|
+
// (this is how you preview the real production path locally — run `generate:fonts`).
|
|
35
|
+
if (definition && extractFonts(definition)) return null;
|
|
36
|
+
let css = '';
|
|
37
|
+
try {
|
|
38
|
+
// Only resolve `families` when explicitly given (custom fallbacks); otherwise let
|
|
39
|
+
// getActiveFontFaces auto-discover the slots from the global and use the default fallbacks.
|
|
40
|
+
const resolved = families ? resolveFontFamilies(families) : undefined;
|
|
41
|
+
const fallbacks = resolved ? Object.fromEntries(resolved.map((r)=>[
|
|
42
|
+
r.key,
|
|
43
|
+
r.fallback
|
|
44
|
+
])) : undefined;
|
|
45
|
+
const payload = await getPayload({
|
|
46
|
+
config
|
|
47
|
+
});
|
|
48
|
+
const typefaces = await getActiveFontFaces(payload, {
|
|
49
|
+
fontSetSlug,
|
|
50
|
+
optimizedSlug,
|
|
51
|
+
families: resolved?.map((r)=>r.key)
|
|
52
|
+
});
|
|
53
|
+
css = buildFontFaceCss(typefaces, {
|
|
54
|
+
cssVarPrefix,
|
|
55
|
+
optimizedSlug,
|
|
56
|
+
fallbacks
|
|
57
|
+
});
|
|
58
|
+
} catch (err) {
|
|
59
|
+
// No DB / not seeded yet — render nothing rather than throw in the layout, but say why
|
|
60
|
+
// (dev-only component, so the warning never reaches production logs).
|
|
61
|
+
console.warn('[payload-fonts] DevFonts failed to load the active fonts:', err);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (!css) return null;
|
|
65
|
+
// dangerouslySetInnerHTML: server-built CSS from our own data, no user input.
|
|
66
|
+
return /*#__PURE__*/ _jsx("style", {
|
|
67
|
+
"data-payload-fonts-dev": true,
|
|
68
|
+
dangerouslySetInnerHTML: {
|
|
69
|
+
__html: css
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export default DevFonts;
|
|
74
|
+
|
|
75
|
+
//# sourceMappingURL=DevFonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/DevFonts.tsx"],"sourcesContent":["import { getPayload } from 'payload'\nimport { extractFonts } from '../extractFonts'\nimport { buildFontFaceCss, getActiveFontFaces } from '../lib/activeFonts'\nimport { type FontFamilyConfig, resolveFontFamilies } from '../lib/families'\n\nexport interface DevFontsProps {\n /** Your Payload config — the same `@payload-config` import you pass to `getPayload`. */\n config: Parameters<typeof getPayload>[0]['config']\n /**\n * The generated `next/font/local` definition (`import definitionFonts from '@/app/definition'`).\n * When it already has fonts, this component renders nothing and lets `next/font` take over — so\n * running `generate:fonts` against your dev server lets you preview the exact production path\n * locally. Omit it and DevFonts always renders in dev.\n */\n definition?: Record<string, { variable?: string } | undefined>\n /** CSS family-variable prefix; must match the download CLI's `cssVariablePrefix`. @default '--font-set' */\n cssVarPrefix?: string\n /** Slug of the standalone font-selection global. @default 'fontSet' */\n fontSetSlug?: string\n /** Slug of the optimized (served) upload collection. @default 'fontOptimized' */\n optimizedSlug?: string\n /** Optional. The family slots are auto-discovered from the `fontSet` global, so you only need this\n * if you set custom per-family `fallback` stacks and want the dev preview to match them. */\n families?: FontFamilyConfig[]\n}\n\n/**\n * **Development-only** font loading. In production it renders `null` — your app self-hosts fonts\n * with `next/font/local` (the build-time export + `payload-fonts-download` CLI), which keeps the\n * production path stock `next/font`: precise preloading, size-adjusted fallbacks, static assets.\n *\n * In development (`NODE_ENV !== 'production'`) it reads the active `fontSet` selection from Payload\n * and inlines the matching `@font-face` rules + the `--font-set*` family variables, so fonts show up\n * immediately with no build step — change a typeface in the admin, refresh, see it. Because it\n * emits the **same** family variables `next/font` defines in production, your app's\n * `font-family: var(--font-setSans)` resolves identically across environments.\n *\n * Drop it into your root layout alongside the production wiring — each is a no-op in the other\n * environment:\n *\n * ```tsx\n * import config from '@payload-config'\n * import definitionFonts from '@/app/definition'\n * import { extractFonts } from '@pro-laico/payload-fonts'\n * import { DevFonts } from '@pro-laico/payload-fonts/DevFonts'\n *\n * <html className={extractFonts(definitionFonts)}>\n * <head><DevFonts config={config} definition={definitionFonts} /></head>\n * </html>\n * ```\n */\nexport async function DevFonts({\n config,\n definition,\n cssVarPrefix,\n fontSetSlug,\n optimizedSlug,\n families,\n}: DevFontsProps): Promise<React.ReactElement | null> {\n // Production self-hosts via next/font — never touch the runtime path there.\n if (process.env.NODE_ENV === 'production') return null\n // If the build path already produced fonts, stand down so there's exactly one source of truth\n // (this is how you preview the real production path locally — run `generate:fonts`).\n if (definition && extractFonts(definition)) return null\n\n let css = ''\n try {\n // Only resolve `families` when explicitly given (custom fallbacks); otherwise let\n // getActiveFontFaces auto-discover the slots from the global and use the default fallbacks.\n const resolved = families ? resolveFontFamilies(families) : undefined\n const fallbacks = resolved ? Object.fromEntries(resolved.map((r) => [r.key, r.fallback])) : undefined\n const payload = await getPayload({ config })\n const typefaces = await getActiveFontFaces(payload, { fontSetSlug, optimizedSlug, families: resolved?.map((r) => r.key) })\n css = buildFontFaceCss(typefaces, { cssVarPrefix, optimizedSlug, fallbacks })\n } catch (err) {\n // No DB / not seeded yet — render nothing rather than throw in the layout, but say why\n // (dev-only component, so the warning never reaches production logs).\n console.warn('[payload-fonts] DevFonts failed to load the active fonts:', err)\n return null\n }\n if (!css) return null\n\n // dangerouslySetInnerHTML: server-built CSS from our own data, no user input.\n return <style data-payload-fonts-dev dangerouslySetInnerHTML={{ __html: css }} />\n}\n\nexport default DevFonts\n"],"names":["getPayload","extractFonts","buildFontFaceCss","getActiveFontFaces","resolveFontFamilies","DevFonts","config","definition","cssVarPrefix","fontSetSlug","optimizedSlug","families","process","env","NODE_ENV","css","resolved","undefined","fallbacks","Object","fromEntries","map","r","key","fallback","payload","typefaces","err","console","warn","style","data-payload-fonts-dev","dangerouslySetInnerHTML","__html"],"mappings":";AAAA,SAASA,UAAU,QAAQ,UAAS;AACpC,SAASC,YAAY,QAAQ,qBAAiB;AAC9C,SAASC,gBAAgB,EAAEC,kBAAkB,QAAQ,wBAAoB;AACzE,SAAgCC,mBAAmB,QAAQ,qBAAiB;AAuB5E;;;;;;;;;;;;;;;;;;;;;;;;CAwBC,GACD,OAAO,eAAeC,SAAS,EAC7BC,MAAM,EACNC,UAAU,EACVC,YAAY,EACZC,WAAW,EACXC,aAAa,EACbC,QAAQ,EACM;IACd,4EAA4E;IAC5E,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc,OAAO;IAClD,8FAA8F;IAC9F,qFAAqF;IACrF,IAAIP,cAAcN,aAAaM,aAAa,OAAO;IAEnD,IAAIQ,MAAM;IACV,IAAI;QACF,kFAAkF;QAClF,4FAA4F;QAC5F,MAAMC,WAAWL,WAAWP,oBAAoBO,YAAYM;QAC5D,MAAMC,YAAYF,WAAWG,OAAOC,WAAW,CAACJ,SAASK,GAAG,CAAC,CAACC,IAAM;gBAACA,EAAEC,GAAG;gBAAED,EAAEE,QAAQ;aAAC,KAAKP;QAC5F,MAAMQ,UAAU,MAAMzB,WAAW;YAAEM;QAAO;QAC1C,MAAMoB,YAAY,MAAMvB,mBAAmBsB,SAAS;YAAEhB;YAAaC;YAAeC,UAAUK,UAAUK,IAAI,CAACC,IAAMA,EAAEC,GAAG;QAAE;QACxHR,MAAMb,iBAAiBwB,WAAW;YAAElB;YAAcE;YAAeQ;QAAU;IAC7E,EAAE,OAAOS,KAAK;QACZ,uFAAuF;QACvF,sEAAsE;QACtEC,QAAQC,IAAI,CAAC,6DAA6DF;QAC1E,OAAO;IACT;IACA,IAAI,CAACZ,KAAK,OAAO;IAEjB,8EAA8E;IAC9E,qBAAO,KAACe;QAAMC,wBAAsB;QAACC,yBAAyB;YAAEC,QAAQlB;QAAI;;AAC9E;AAEA,eAAeV,SAAQ"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { UploadFieldClientProps } from 'payload';
|
|
2
|
+
import './FontOriginalUpload.scss';
|
|
3
|
+
/**
|
|
4
|
+
* The `fontOriginal` upload slots — Payload's own upload field, but with the "Choose from
|
|
5
|
+
* existing" control hidden (see the sibling stylesheet), so every slot always uploads a FRESH
|
|
6
|
+
* original via "Create New".
|
|
7
|
+
*
|
|
8
|
+
* That enforces one `fontOriginal` per typeface slot — an original is never shared between
|
|
9
|
+
* typefaces — which keeps asset cleanup trivially safe and race-free: a de-referenced or
|
|
10
|
+
* deleted original can always be removed, with no reference count and no concurrent-delete
|
|
11
|
+
* hazard (each typeface owns its own files).
|
|
12
|
+
*/
|
|
13
|
+
export declare const FontOriginalUpload: (props: UploadFieldClientProps) => import("react").JSX.Element;
|
|
14
|
+
export default FontOriginalUpload;
|
|
15
|
+
//# sourceMappingURL=FontOriginalUpload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FontOriginalUpload.d.ts","sourceRoot":"","sources":["../../../src/components/admin/FontOriginalUpload.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAGrD,OAAO,2BAA2B,CAAA;AAElC;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,sBAAsB,gCAI/D,CAAA;AAED,eAAe,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { UploadField } from "@payloadcms/ui";
|
|
4
|
+
import "./FontOriginalUpload.scss";
|
|
5
|
+
/**
|
|
6
|
+
* The `fontOriginal` upload slots — Payload's own upload field, but with the "Choose from
|
|
7
|
+
* existing" control hidden (see the sibling stylesheet), so every slot always uploads a FRESH
|
|
8
|
+
* original via "Create New".
|
|
9
|
+
*
|
|
10
|
+
* That enforces one `fontOriginal` per typeface slot — an original is never shared between
|
|
11
|
+
* typefaces — which keeps asset cleanup trivially safe and race-free: a de-referenced or
|
|
12
|
+
* deleted original can always be removed, with no reference count and no concurrent-delete
|
|
13
|
+
* hazard (each typeface owns its own files).
|
|
14
|
+
*/ export const FontOriginalUpload = (props)=>/*#__PURE__*/ _jsx("div", {
|
|
15
|
+
className: "font-original-upload",
|
|
16
|
+
children: /*#__PURE__*/ _jsx(UploadField, {
|
|
17
|
+
...props
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
export default FontOriginalUpload;
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=FontOriginalUpload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/admin/FontOriginalUpload.tsx"],"sourcesContent":["'use client'\n\nimport type { UploadFieldClientProps } from 'payload'\nimport { UploadField } from '@payloadcms/ui'\n\nimport './FontOriginalUpload.scss'\n\n/**\n * The `fontOriginal` upload slots — Payload's own upload field, but with the \"Choose from\n * existing\" control hidden (see the sibling stylesheet), so every slot always uploads a FRESH\n * original via \"Create New\".\n *\n * That enforces one `fontOriginal` per typeface slot — an original is never shared between\n * typefaces — which keeps asset cleanup trivially safe and race-free: a de-referenced or\n * deleted original can always be removed, with no reference count and no concurrent-delete\n * hazard (each typeface owns its own files).\n */\nexport const FontOriginalUpload = (props: UploadFieldClientProps) => (\n <div className=\"font-original-upload\">\n <UploadField {...props} />\n </div>\n)\n\nexport default FontOriginalUpload\n"],"names":["UploadField","FontOriginalUpload","props","div","className"],"mappings":"AAAA;;AAGA,SAASA,WAAW,QAAQ,iBAAgB;AAE5C,OAAO,4BAA2B;AAElC;;;;;;;;;CASC,GACD,OAAO,MAAMC,qBAAqB,CAACC,sBACjC,KAACC;QAAIC,WAAU;kBACb,cAAA,KAACJ;YAAa,GAAGE,KAAK;;OAEzB;AAED,eAAeD,mBAAkB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Create-only upload: hide the "Choose from existing" toggler and its "or" separator, leaving
|
|
2
|
+
// just "Create New" + drag-and-drop. Each slot therefore uploads a fresh `fontOriginal` that
|
|
3
|
+
// is never shared between typefaces.
|
|
4
|
+
.font-original-upload {
|
|
5
|
+
.upload__listToggler,
|
|
6
|
+
.upload__dropzoneContent__orText {
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Endpoint } from 'payload';
|
|
2
|
+
/** A family key — `sans`/`serif`/`mono`/`display` by default, but any string when customised. */
|
|
3
|
+
type Family = string;
|
|
4
|
+
export interface ExportFontsEndpointOptions {
|
|
5
|
+
/** Mount path under the Payload API route. Default `/fonts/export` (→ `/api/fonts/export`). */
|
|
6
|
+
path?: string;
|
|
7
|
+
/** Slug of the standalone font-selection global. Default `fontSet`. */
|
|
8
|
+
fontSetGlobalSlug?: string;
|
|
9
|
+
/** Slug of the optimized (served) weight-file upload collection. Default `fontOptimized`. */
|
|
10
|
+
fontOptimizedSlug?: string;
|
|
11
|
+
/** Family keys to resolve from the `fontSet` global. Default sans/serif/mono/display. */
|
|
12
|
+
families?: Family[];
|
|
13
|
+
}
|
|
14
|
+
/** A single exported weight file: filename, extension, mime, base64 bytes, and (optional) weight/style.
|
|
15
|
+
* An upright variable file that also carries italics (ital/slnt axes) exports TWICE — once per
|
|
16
|
+
* style, same bytes; the italic entry carries `obliqueAngle` when the italics ride a slnt axis. */
|
|
17
|
+
export type ExportedFont = {
|
|
18
|
+
filename: string;
|
|
19
|
+
extension: string;
|
|
20
|
+
mimeType: string | null;
|
|
21
|
+
data: string;
|
|
22
|
+
weight?: string | null;
|
|
23
|
+
style?: string | null;
|
|
24
|
+
/** For slnt-based italics: the positive CSS `oblique` angle (deg). */
|
|
25
|
+
obliqueAngle?: number | null;
|
|
26
|
+
};
|
|
27
|
+
/** Per-family debug info: is a typeface selected, how many optimized files it has, and how many of
|
|
28
|
+
* those couldn't be read from storage — so an empty export can name its cause per family. */
|
|
29
|
+
export type ExportFamilyDiagnostics = {
|
|
30
|
+
selected: boolean;
|
|
31
|
+
typeface?: string;
|
|
32
|
+
optimizedFiles: number;
|
|
33
|
+
readFailures: number;
|
|
34
|
+
};
|
|
35
|
+
/** JSON returned by the fonts export endpoint — an array of weight files per family.
|
|
36
|
+
* `diagnostics` is additive; older servers omit it. */
|
|
37
|
+
export type ExportFontsResponse = {
|
|
38
|
+
fonts: Partial<Record<Family, ExportedFont[]>>;
|
|
39
|
+
diagnostics?: Partial<Record<Family, ExportFamilyDiagnostics>>;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* `GET /api/fonts/export`. Resolves the active fonts from the `fontSet` global — each family
|
|
43
|
+
* points at ONE `font` typeface — and returns the bytes of that typeface's served
|
|
44
|
+
* `fontOptimized` files so the `payload-fonts-download` CLI can write them for
|
|
45
|
+
* `next/font/local`. Secured by the project's `PAYLOAD_SECRET` (Bearer).
|
|
46
|
+
*/
|
|
47
|
+
export declare const exportFontsEndpoint: (opts?: ExportFontsEndpointOptions) => Endpoint;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=exportFonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exportFonts.d.ts","sourceRoot":"","sources":["../../src/endpoints/exportFonts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,QAAQ,EAAc,MAAM,SAAS,CAAA;AAMnE,iGAAiG;AACjG,KAAK,MAAM,GAAG,MAAM,CAAA;AAGpB,MAAM,WAAW,0BAA0B;IACzC,+FAA+F;IAC/F,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAMD;;oGAEoG;AACpG,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,CAAA;AACD;8FAC8F;AAC9F,MAAM,MAAM,uBAAuB,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAA;AAC5H;wDACwD;AACxD,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAA;CAC/D,CAAA;AAYD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAM,0BAA+B,KAAG,QAoH3E,CAAA"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { refId } from "../lib/refs.js";
|
|
3
|
+
import { DEFAULT_FONT_FAMILIES } from "../lib/families.js";
|
|
4
|
+
import { readUploadBytes } from "../lib/uploadBytes.js";
|
|
5
|
+
const DEFAULT_FAMILY_KEYS = DEFAULT_FONT_FAMILIES.map((r)=>r.key);
|
|
6
|
+
/**
|
|
7
|
+
* Constant-time secret compare. Both sides are sha256-hashed to a fixed 32 bytes first, so the
|
|
8
|
+
* comparison is constant-time regardless of length.
|
|
9
|
+
*/ function secretsMatch(provided, secret) {
|
|
10
|
+
const a = createHash('sha256').update(provided).digest();
|
|
11
|
+
const b = createHash('sha256').update(secret).digest();
|
|
12
|
+
return timingSafeEqual(a, b);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `GET /api/fonts/export`. Resolves the active fonts from the `fontSet` global — each family
|
|
16
|
+
* points at ONE `font` typeface — and returns the bytes of that typeface's served
|
|
17
|
+
* `fontOptimized` files so the `payload-fonts-download` CLI can write them for
|
|
18
|
+
* `next/font/local`. Secured by the project's `PAYLOAD_SECRET` (Bearer).
|
|
19
|
+
*/ export const exportFontsEndpoint = (opts = {})=>{
|
|
20
|
+
const { path: endpointPath = '/fonts/export', fontSetGlobalSlug = 'fontSet', fontOptimizedSlug = 'fontOptimized', families = DEFAULT_FAMILY_KEYS } = opts;
|
|
21
|
+
return {
|
|
22
|
+
path: endpointPath,
|
|
23
|
+
method: 'get',
|
|
24
|
+
handler: async (req)=>{
|
|
25
|
+
const { payload } = req;
|
|
26
|
+
// Compare against the RAW PAYLOAD_SECRET (what the caller sends).
|
|
27
|
+
const secret = process.env.PAYLOAD_SECRET || '';
|
|
28
|
+
const provided = (req.headers.get('authorization') || '').replace(/^Bearer\s+/i, '').trim();
|
|
29
|
+
if (!secret || !provided || !secretsMatch(provided, secret)) {
|
|
30
|
+
return Response.json({
|
|
31
|
+
error: 'Unauthorized'
|
|
32
|
+
}, {
|
|
33
|
+
status: 401
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// Read the active selection from the `fontSet` global. The shared secret is the trust
|
|
37
|
+
// boundary → `overrideAccess: true`.
|
|
38
|
+
let selection;
|
|
39
|
+
try {
|
|
40
|
+
const fontSetGlobal = await payload.findGlobal({
|
|
41
|
+
slug: fontSetGlobalSlug,
|
|
42
|
+
// depth 1 populates each slot's typeface (defaultPopulate: title/family), so the
|
|
43
|
+
// diagnostics can name the selected typeface.
|
|
44
|
+
depth: 1,
|
|
45
|
+
overrideAccess: true
|
|
46
|
+
});
|
|
47
|
+
selection = Object.fromEntries(families.map((family)=>[
|
|
48
|
+
family,
|
|
49
|
+
fontSetGlobal?.[family]
|
|
50
|
+
]));
|
|
51
|
+
} catch {
|
|
52
|
+
// no fontSet global in this project
|
|
53
|
+
}
|
|
54
|
+
const fonts = {};
|
|
55
|
+
const diagnostics = Object.fromEntries(families.map((family)=>[
|
|
56
|
+
family,
|
|
57
|
+
{
|
|
58
|
+
selected: false,
|
|
59
|
+
optimizedFiles: 0,
|
|
60
|
+
readFailures: 0
|
|
61
|
+
}
|
|
62
|
+
]));
|
|
63
|
+
if (selection) {
|
|
64
|
+
// One typeface per family (tolerate a stray array — take the first); fetch every family's
|
|
65
|
+
// served files in a single query grouped by typeface, rather than one round-trip per family.
|
|
66
|
+
const familyIds = families.map((family)=>{
|
|
67
|
+
const ref = (Array.isArray(selection[family]) ? selection[family][0] : selection[family]) ?? null;
|
|
68
|
+
const title = ref && typeof ref === 'object' && typeof ref.title === 'string' ? ref.title : undefined;
|
|
69
|
+
return {
|
|
70
|
+
family,
|
|
71
|
+
id: refId(ref),
|
|
72
|
+
title
|
|
73
|
+
};
|
|
74
|
+
}).filter((r)=>r.id != null);
|
|
75
|
+
const docsByFont = new Map();
|
|
76
|
+
if (familyIds.length) {
|
|
77
|
+
const uniqueIds = [
|
|
78
|
+
...new Set(familyIds.map((r)=>r.id))
|
|
79
|
+
];
|
|
80
|
+
try {
|
|
81
|
+
const res = await payload.find({
|
|
82
|
+
collection: fontOptimizedSlug,
|
|
83
|
+
where: {
|
|
84
|
+
font: {
|
|
85
|
+
in: uniqueIds
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
depth: 0,
|
|
89
|
+
limit: 1000,
|
|
90
|
+
overrideAccess: true
|
|
91
|
+
});
|
|
92
|
+
for (const doc of res.docs){
|
|
93
|
+
const fontId = refId(doc.font);
|
|
94
|
+
if (fontId == null) continue;
|
|
95
|
+
const bucket = docsByFont.get(fontId);
|
|
96
|
+
if (bucket) bucket.push(doc);
|
|
97
|
+
else docsByFont.set(fontId, [
|
|
98
|
+
doc
|
|
99
|
+
]);
|
|
100
|
+
}
|
|
101
|
+
} catch (err) {
|
|
102
|
+
// leave docsByFont empty — the response just carries no fonts
|
|
103
|
+
payload.logger.warn({
|
|
104
|
+
msg: `[payload-fonts] export: could not query ${fontOptimizedSlug}`,
|
|
105
|
+
err
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const { family, id, title } of familyIds){
|
|
110
|
+
const docs = docsByFont.get(id) ?? [];
|
|
111
|
+
const diag = {
|
|
112
|
+
selected: true,
|
|
113
|
+
typeface: title,
|
|
114
|
+
optimizedFiles: docs.length,
|
|
115
|
+
readFailures: 0
|
|
116
|
+
};
|
|
117
|
+
diagnostics[family] = diag;
|
|
118
|
+
// An explicit italic file always wins over synthesizing italics from an ital-capable
|
|
119
|
+
// upright — same rule as `expandItalCapableFaces` on the runtime CSS path.
|
|
120
|
+
const hasExplicitItalic = docs.some((doc)=>doc.style === 'italic');
|
|
121
|
+
const exported = [];
|
|
122
|
+
for (const doc of docs){
|
|
123
|
+
const filename = typeof doc.filename === 'string' ? doc.filename : null;
|
|
124
|
+
const bytes = filename ? await readUploadBytes(payload, fontOptimizedSlug, doc) : null;
|
|
125
|
+
if (!filename || !bytes) {
|
|
126
|
+
diag.readFailures++;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const entry = {
|
|
130
|
+
filename,
|
|
131
|
+
extension: filename.split('.').pop()?.toLowerCase() || 'woff2',
|
|
132
|
+
mimeType: doc.mimeType ?? null,
|
|
133
|
+
data: bytes.toString('base64'),
|
|
134
|
+
weight: doc.weight ?? null,
|
|
135
|
+
style: doc.style ?? null
|
|
136
|
+
};
|
|
137
|
+
exported.push(entry);
|
|
138
|
+
if (doc.style !== 'italic' && doc.italCapable && !hasExplicitItalic) {
|
|
139
|
+
exported.push({
|
|
140
|
+
...entry,
|
|
141
|
+
style: 'italic',
|
|
142
|
+
obliqueAngle: typeof doc.obliqueAngle === 'number' ? doc.obliqueAngle : null
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (exported.length) fonts[family] = exported;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// no-store: the response carries font bytes behind auth.
|
|
150
|
+
return Response.json({
|
|
151
|
+
fonts,
|
|
152
|
+
diagnostics
|
|
153
|
+
}, {
|
|
154
|
+
headers: {
|
|
155
|
+
'Cache-Control': 'no-store'
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=exportFonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/exportFonts.ts"],"sourcesContent":["import { createHash, timingSafeEqual } from 'node:crypto'\n\nimport type { CollectionSlug, Endpoint, GlobalSlug } from 'payload'\n\nimport { refId } from '../lib/refs'\nimport { DEFAULT_FONT_FAMILIES } from '../lib/families'\nimport { readUploadBytes } from '../lib/uploadBytes'\n\n/** A family key — `sans`/`serif`/`mono`/`display` by default, but any string when customised. */\ntype Family = string\nconst DEFAULT_FAMILY_KEYS: Family[] = DEFAULT_FONT_FAMILIES.map((r) => r.key)\n\nexport interface ExportFontsEndpointOptions {\n /** Mount path under the Payload API route. Default `/fonts/export` (→ `/api/fonts/export`). */\n path?: string\n /** Slug of the standalone font-selection global. Default `fontSet`. */\n fontSetGlobalSlug?: string\n /** Slug of the optimized (served) weight-file upload collection. Default `fontOptimized`. */\n fontOptimizedSlug?: string\n /** Family keys to resolve from the `fontSet` global. Default sans/serif/mono/display. */\n families?: Family[]\n}\n\n/** The selected typeface for a family: a populated `font` doc or its id. */\ntype TypefaceRef = { id?: string | number; title?: string | null } | string | number | null\ntype FontSelection = Partial<Record<Family, TypefaceRef | TypefaceRef[]>>\n\n/** A single exported weight file: filename, extension, mime, base64 bytes, and (optional) weight/style.\n * An upright variable file that also carries italics (ital/slnt axes) exports TWICE — once per\n * style, same bytes; the italic entry carries `obliqueAngle` when the italics ride a slnt axis. */\nexport type ExportedFont = {\n filename: string\n extension: string\n mimeType: string | null\n data: string\n weight?: string | null\n style?: string | null\n /** For slnt-based italics: the positive CSS `oblique` angle (deg). */\n obliqueAngle?: number | null\n}\n/** Per-family debug info: is a typeface selected, how many optimized files it has, and how many of\n * those couldn't be read from storage — so an empty export can name its cause per family. */\nexport type ExportFamilyDiagnostics = { selected: boolean; typeface?: string; optimizedFiles: number; readFailures: number }\n/** JSON returned by the fonts export endpoint — an array of weight files per family.\n * `diagnostics` is additive; older servers omit it. */\nexport type ExportFontsResponse = {\n fonts: Partial<Record<Family, ExportedFont[]>>\n diagnostics?: Partial<Record<Family, ExportFamilyDiagnostics>>\n}\n\n/**\n * Constant-time secret compare. Both sides are sha256-hashed to a fixed 32 bytes first, so the\n * comparison is constant-time regardless of length.\n */\nfunction secretsMatch(provided: string, secret: string): boolean {\n const a = createHash('sha256').update(provided).digest()\n const b = createHash('sha256').update(secret).digest()\n return timingSafeEqual(a, b)\n}\n\n/**\n * `GET /api/fonts/export`. Resolves the active fonts from the `fontSet` global — each family\n * points at ONE `font` typeface — and returns the bytes of that typeface's served\n * `fontOptimized` files so the `payload-fonts-download` CLI can write them for\n * `next/font/local`. Secured by the project's `PAYLOAD_SECRET` (Bearer).\n */\nexport const exportFontsEndpoint = (opts: ExportFontsEndpointOptions = {}): Endpoint => {\n const {\n path: endpointPath = '/fonts/export',\n fontSetGlobalSlug = 'fontSet',\n fontOptimizedSlug = 'fontOptimized',\n families = DEFAULT_FAMILY_KEYS,\n } = opts\n\n return {\n path: endpointPath,\n method: 'get',\n handler: async (req) => {\n const { payload } = req\n\n // Compare against the RAW PAYLOAD_SECRET (what the caller sends).\n const secret = process.env.PAYLOAD_SECRET || ''\n const provided = (req.headers.get('authorization') || '').replace(/^Bearer\\s+/i, '').trim()\n if (!secret || !provided || !secretsMatch(provided, secret)) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n // Read the active selection from the `fontSet` global. The shared secret is the trust\n // boundary → `overrideAccess: true`.\n let selection: FontSelection | undefined\n try {\n const fontSetGlobal = (await payload.findGlobal({\n slug: fontSetGlobalSlug as GlobalSlug,\n // depth 1 populates each slot's typeface (defaultPopulate: title/family), so the\n // diagnostics can name the selected typeface.\n depth: 1,\n overrideAccess: true,\n // `as unknown as` — in a project with generated types this resolves to the concrete\n // fontSet interface, which doesn't structurally overlap a string-keyed record.\n })) as unknown as FontSelection\n selection = Object.fromEntries(families.map((family) => [family, fontSetGlobal?.[family]]))\n } catch {\n // no fontSet global in this project\n }\n\n const fonts: Partial<Record<Family, ExportedFont[]>> = {}\n const diagnostics: Partial<Record<Family, ExportFamilyDiagnostics>> = Object.fromEntries(\n families.map((family) => [family, { selected: false, optimizedFiles: 0, readFailures: 0 }]),\n )\n if (selection) {\n // One typeface per family (tolerate a stray array — take the first); fetch every family's\n // served files in a single query grouped by typeface, rather than one round-trip per family.\n const familyIds = families\n .map((family) => {\n const ref = (Array.isArray(selection[family]) ? (selection[family] as TypefaceRef[])[0] : selection[family]) ?? null\n const title = ref && typeof ref === 'object' && typeof ref.title === 'string' ? ref.title : undefined\n return { family, id: refId(ref), title }\n })\n .filter((r): r is { family: Family; id: string | number; title: string | undefined } => r.id != null)\n\n const docsByFont = new Map<string | number, Array<Record<string, unknown>>>()\n if (familyIds.length) {\n const uniqueIds = [...new Set(familyIds.map((r) => r.id))]\n try {\n const res = await payload.find({\n collection: fontOptimizedSlug as CollectionSlug,\n where: { font: { in: uniqueIds } },\n depth: 0,\n limit: 1000,\n overrideAccess: true,\n })\n for (const doc of res.docs as unknown as Array<Record<string, unknown>>) {\n const fontId = refId(doc.font)\n if (fontId == null) continue\n const bucket = docsByFont.get(fontId)\n if (bucket) bucket.push(doc)\n else docsByFont.set(fontId, [doc])\n }\n } catch (err) {\n // leave docsByFont empty — the response just carries no fonts\n payload.logger.warn({ msg: `[payload-fonts] export: could not query ${fontOptimizedSlug}`, err })\n }\n }\n\n for (const { family, id, title } of familyIds) {\n const docs = docsByFont.get(id) ?? []\n const diag = { selected: true, typeface: title, optimizedFiles: docs.length, readFailures: 0 }\n diagnostics[family] = diag\n // An explicit italic file always wins over synthesizing italics from an ital-capable\n // upright — same rule as `expandItalCapableFaces` on the runtime CSS path.\n const hasExplicitItalic = docs.some((doc) => doc.style === 'italic')\n const exported: ExportedFont[] = []\n for (const doc of docs) {\n const filename = typeof doc.filename === 'string' ? doc.filename : null\n const bytes = filename\n ? await readUploadBytes(payload, fontOptimizedSlug, doc as { filename?: string | null; url?: string | null })\n : null\n if (!filename || !bytes) {\n diag.readFailures++\n continue\n }\n const entry: ExportedFont = {\n filename,\n extension: filename.split('.').pop()?.toLowerCase() || 'woff2',\n mimeType: (doc.mimeType as string) ?? null,\n data: bytes.toString('base64'),\n weight: (doc.weight as string) ?? null,\n style: (doc.style as string) ?? null,\n }\n exported.push(entry)\n if (doc.style !== 'italic' && doc.italCapable && !hasExplicitItalic) {\n exported.push({ ...entry, style: 'italic', obliqueAngle: typeof doc.obliqueAngle === 'number' ? doc.obliqueAngle : null })\n }\n }\n if (exported.length) fonts[family] = exported\n }\n }\n\n // no-store: the response carries font bytes behind auth.\n return Response.json({ fonts, diagnostics } satisfies ExportFontsResponse, { headers: { 'Cache-Control': 'no-store' } })\n },\n }\n}\n"],"names":["createHash","timingSafeEqual","refId","DEFAULT_FONT_FAMILIES","readUploadBytes","DEFAULT_FAMILY_KEYS","map","r","key","secretsMatch","provided","secret","a","update","digest","b","exportFontsEndpoint","opts","path","endpointPath","fontSetGlobalSlug","fontOptimizedSlug","families","method","handler","req","payload","process","env","PAYLOAD_SECRET","headers","get","replace","trim","Response","json","error","status","selection","fontSetGlobal","findGlobal","slug","depth","overrideAccess","Object","fromEntries","family","fonts","diagnostics","selected","optimizedFiles","readFailures","familyIds","ref","Array","isArray","title","undefined","id","filter","docsByFont","Map","length","uniqueIds","Set","res","find","collection","where","font","in","limit","doc","docs","fontId","bucket","push","set","err","logger","warn","msg","diag","typeface","hasExplicitItalic","some","style","exported","filename","bytes","entry","extension","split","pop","toLowerCase","mimeType","data","toString","weight","italCapable","obliqueAngle"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The shape `next/font/local` produces for each declared font — only the generated
|
|
2
|
+
* `variable` (its CSS-variable class) is read here. */
|
|
3
|
+
type FontDefinitions = Record<string, {
|
|
4
|
+
variable?: string;
|
|
5
|
+
} | undefined>;
|
|
6
|
+
/**
|
|
7
|
+
* Collect the `next/font/local` CSS-variable classes from a generated `definition.ts` default
|
|
8
|
+
* export into a single space-separated string for the root `<html>` `className`. Returns
|
|
9
|
+
* `undefined` when nothing has been generated yet (e.g. before the download CLI has run), so it
|
|
10
|
+
* drops straight into `className`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* import definitionFonts from '@/app/definition'
|
|
14
|
+
* import { extractFonts } from '@pro-laico/payload-fonts'
|
|
15
|
+
*
|
|
16
|
+
* <html className={extractFonts(definitionFonts)}>
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractFonts(definitionFonts: FontDefinitions): string | undefined;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=extractFonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractFonts.d.ts","sourceRoot":"","sources":["../src/extractFonts.ts"],"names":[],"mappings":"AAAA;wDACwD;AACxD,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAAA;AAExE;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,eAAe,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAMjF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The shape `next/font/local` produces for each declared font — only the generated
|
|
2
|
+
* `variable` (its CSS-variable class) is read here. */ /**
|
|
3
|
+
* Collect the `next/font/local` CSS-variable classes from a generated `definition.ts` default
|
|
4
|
+
* export into a single space-separated string for the root `<html>` `className`. Returns
|
|
5
|
+
* `undefined` when nothing has been generated yet (e.g. before the download CLI has run), so it
|
|
6
|
+
* drops straight into `className`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import definitionFonts from '@/app/definition'
|
|
10
|
+
* import { extractFonts } from '@pro-laico/payload-fonts'
|
|
11
|
+
*
|
|
12
|
+
* <html className={extractFonts(definitionFonts)}>
|
|
13
|
+
*/ export function extractFonts(definitionFonts) {
|
|
14
|
+
const variables = Object.values(definitionFonts).map((font)=>font?.variable).filter(Boolean).join(' ');
|
|
15
|
+
return variables || undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=extractFonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/extractFonts.ts"],"sourcesContent":["/** The shape `next/font/local` produces for each declared font — only the generated\n * `variable` (its CSS-variable class) is read here. */\ntype FontDefinitions = Record<string, { variable?: string } | undefined>\n\n/**\n * Collect the `next/font/local` CSS-variable classes from a generated `definition.ts` default\n * export into a single space-separated string for the root `<html>` `className`. Returns\n * `undefined` when nothing has been generated yet (e.g. before the download CLI has run), so it\n * drops straight into `className`.\n *\n * @example\n * import definitionFonts from '@/app/definition'\n * import { extractFonts } from '@pro-laico/payload-fonts'\n *\n * <html className={extractFonts(definitionFonts)}>\n */\nexport function extractFonts(definitionFonts: FontDefinitions): string | undefined {\n const variables = Object.values(definitionFonts)\n .map((font) => font?.variable)\n .filter(Boolean)\n .join(' ')\n return variables || undefined\n}\n"],"names":["extractFonts","definitionFonts","variables","Object","values","map","font","variable","filter","Boolean","join","undefined"],"mappings":"AAAA;sDACsD,GAGtD;;;;;;;;;;;CAWC,GACD,OAAO,SAASA,aAAaC,eAAgC;IAC3D,MAAMC,YAAYC,OAAOC,MAAM,CAACH,iBAC7BI,GAAG,CAAC,CAACC,OAASA,MAAMC,UACpBC,MAAM,CAACC,SACPC,IAAI,CAAC;IACR,OAAOR,aAAaS;AACtB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Field } from 'payload';
|
|
2
|
+
import { type FontFamilyConfig } from '../lib/families';
|
|
3
|
+
/**
|
|
4
|
+
* The per-family relationship fields for the `fontSet` global — one slot per configured family
|
|
5
|
+
* (`sans / serif / mono / display` by default), pointing at this package's `font` typeface
|
|
6
|
+
* collection and laid out two-per-row. Used by the standalone `fontSet` global
|
|
7
|
+
* (`globals/fontSet.ts`), and exported so a project assembling its own selection surface (a
|
|
8
|
+
* different global, or a group on an existing collection) can reuse the exact same slots.
|
|
9
|
+
*/
|
|
10
|
+
export declare const fontUploadFields: ({ fontSlug, families }?: {
|
|
11
|
+
fontSlug?: string;
|
|
12
|
+
families?: FontFamilyConfig[];
|
|
13
|
+
}) => Field[];
|
|
14
|
+
//# sourceMappingURL=font.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font.d.ts","sourceRoot":"","sources":["../../src/fields/font.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpD,OAAO,EAAE,KAAK,gBAAgB,EAAuB,MAAM,iBAAiB,CAAA;AAE5E;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,yBAAiC;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAAO,KAAG,KAAK,EAqBlI,CAAA"}
|