@nifrajs/web 0.1.0-alpha.1
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 +21 -0
- package/README.md +18 -0
- package/css-modules.d.ts +34 -0
- package/dist/build.d.ts +110 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +238 -0
- package/dist/build.js.map +1 -0
- package/dist/client.d.ts +32 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +204 -0
- package/dist/client.js.map +1 -0
- package/dist/deferred.d.ts +90 -0
- package/dist/deferred.d.ts.map +1 -0
- package/dist/deferred.js +310 -0
- package/dist/deferred.js.map +1 -0
- package/dist/dev-error.d.ts +17 -0
- package/dist/dev-error.d.ts.map +1 -0
- package/dist/dev-error.js +59 -0
- package/dist/dev-error.js.map +1 -0
- package/dist/dev.d.ts +25 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +83 -0
- package/dist/dev.js.map +1 -0
- package/dist/draft.d.ts +58 -0
- package/dist/draft.d.ts.map +1 -0
- package/dist/draft.js +55 -0
- package/dist/draft.js.map +1 -0
- package/dist/fonts-google.d.ts +109 -0
- package/dist/fonts-google.d.ts.map +1 -0
- package/dist/fonts-google.js +291 -0
- package/dist/fonts-google.js.map +1 -0
- package/dist/fonts.d.ts +67 -0
- package/dist/fonts.d.ts.map +1 -0
- package/dist/fonts.js +103 -0
- package/dist/fonts.js.map +1 -0
- package/dist/fs.d.ts +10 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +24 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +784 -0
- package/dist/index.js.map +1 -0
- package/dist/islands.d.ts +37 -0
- package/dist/islands.d.ts.map +1 -0
- package/dist/islands.js +107 -0
- package/dist/islands.js.map +1 -0
- package/dist/isr.d.ts +154 -0
- package/dist/isr.d.ts.map +1 -0
- package/dist/isr.js +331 -0
- package/dist/isr.js.map +1 -0
- package/dist/manifest.d.ts +178 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +213 -0
- package/dist/manifest.js.map +1 -0
- package/dist/plugins/css-modules.d.ts +40 -0
- package/dist/plugins/css-modules.d.ts.map +1 -0
- package/dist/plugins/css-modules.js +0 -0
- package/dist/plugins/css-modules.js.map +1 -0
- package/dist/plugins/kit.d.ts +44 -0
- package/dist/plugins/kit.d.ts.map +1 -0
- package/dist/plugins/kit.js +105 -0
- package/dist/plugins/kit.js.map +1 -0
- package/dist/plugins/scss.d.ts +27 -0
- package/dist/plugins/scss.d.ts.map +1 -0
- package/dist/plugins/scss.js +78 -0
- package/dist/plugins/scss.js.map +1 -0
- package/dist/prerender.d.ts +77 -0
- package/dist/prerender.d.ts.map +1 -0
- package/dist/prerender.js +139 -0
- package/dist/prerender.js.map +1 -0
- package/dist/query.d.ts +62 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +184 -0
- package/dist/query.js.map +1 -0
- package/dist/router.d.ts +169 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +531 -0
- package/dist/router.js.map +1 -0
- package/dist/vite.d.ts +49 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +144 -0
- package/dist/vite.js.map +1 -0
- package/package.json +127 -0
- package/src/build.ts +375 -0
- package/src/client.ts +218 -0
- package/src/deferred.ts +339 -0
- package/src/dev-error.ts +62 -0
- package/src/dev.ts +108 -0
- package/src/draft.ts +82 -0
- package/src/fonts-google.ts +397 -0
- package/src/fonts.ts +147 -0
- package/src/fs.ts +26 -0
- package/src/index.ts +1202 -0
- package/src/islands.ts +121 -0
- package/src/isr.ts +461 -0
- package/src/manifest.ts +366 -0
- package/src/plugins/css-modules.ts +0 -0
- package/src/plugins/kit.ts +123 -0
- package/src/plugins/scss.ts +108 -0
- package/src/prerender.ts +209 -0
- package/src/query.ts +250 -0
- package/src/router.ts +676 -0
- package/src/vite.ts +212 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time Google Fonts automation — the `next/font/google` equivalent. At **build time** (never on
|
|
3
|
+
* the request path) it: builds the Google Fonts CSS2 URL, downloads the stylesheet, parses the
|
|
4
|
+
* `@font-face` rules, downloads each `.woff2`, content-hashes it, writes it next to your assets, and
|
|
5
|
+
* hands back a **self-hosted** `@font-face` stylesheet + the matching `<link rel="preload">`s. The
|
|
6
|
+
* result is identical to dropping the files in yourself and calling {@link fontFace} — no runtime CDN
|
|
7
|
+
* hotlink, no layout shift, hashed filenames for immutable caching.
|
|
8
|
+
*
|
|
9
|
+
* // fonts.build.ts — run once at build time (e.g. a prebuild step)
|
|
10
|
+
* import { loadGoogleFont } from "@nifrajs/web/fonts"
|
|
11
|
+
* const inter = await loadGoogleFont(
|
|
12
|
+
* { family: "Inter", weights: [400, 700], subsets: ["latin"] },
|
|
13
|
+
* { outDir: "public/fonts" }, // → public/fonts/inter-latin-normal-400-<hash>.woff2
|
|
14
|
+
* )
|
|
15
|
+
* await Bun.write("app/fonts.css", inter.css) // import this stylesheet from your app
|
|
16
|
+
* // inter.preloads → spread into a root layout's `meta.link`
|
|
17
|
+
*
|
|
18
|
+
* Security: this fetches remote content and writes it to disk, so every input is validated and the
|
|
19
|
+
* font-file host is **allowlisted to `fonts.gstatic.com` over https** — a tampered/MITM'd stylesheet
|
|
20
|
+
* cannot make the build fetch an arbitrary URL (SSRF) or write an attacker-chosen blob. Downloads are
|
|
21
|
+
* size-capped. Filenames are derived only from validated tokens + a content hash (no path traversal).
|
|
22
|
+
*/
|
|
23
|
+
import { writeFile as fsWriteFile, mkdir } from "node:fs/promises";
|
|
24
|
+
import { dirname, join } from "node:path";
|
|
25
|
+
import { fontFace, fontPreload } from "./fonts.js";
|
|
26
|
+
const CSS2_ENDPOINT = "https://fonts.googleapis.com/css2";
|
|
27
|
+
/** Only this host, only over https, may supply a font file we download + write to disk. The SSRF gate:
|
|
28
|
+
* a tampered stylesheet listing any other `src: url(...)` is rejected, not fetched. */
|
|
29
|
+
const ALLOWED_FONT_HOSTS = new Set(["fonts.gstatic.com"]);
|
|
30
|
+
/** A modern desktop-Chrome UA so Google serves `woff2` (it falls back to bulky `ttf` for unknown UAs). */
|
|
31
|
+
const WOFF2_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
32
|
+
const DEFAULT_MAX_FONT_BYTES = 5 * 1024 * 1024;
|
|
33
|
+
const MAX_CSS_BYTES = 512 * 1024;
|
|
34
|
+
const MAX_TEXT_LEN = 2048;
|
|
35
|
+
const VALID_DISPLAY = new Set([
|
|
36
|
+
"auto",
|
|
37
|
+
"block",
|
|
38
|
+
"swap",
|
|
39
|
+
"fallback",
|
|
40
|
+
"optional",
|
|
41
|
+
]);
|
|
42
|
+
/** `true` iff `raw` is an `https://fonts.gstatic.com/…` URL — the only host we'll download from. */
|
|
43
|
+
export function isAllowedFontUrl(raw) {
|
|
44
|
+
let url;
|
|
45
|
+
try {
|
|
46
|
+
url = new URL(raw);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return url.protocol === "https:" && ALLOWED_FONT_HOSTS.has(url.hostname);
|
|
52
|
+
}
|
|
53
|
+
/** Validate a family name (letters/digits/spaces only). It goes into both a URL and a filename, so a
|
|
54
|
+
* strict allowlist closes injection + path-traversal at the source. */
|
|
55
|
+
function validateFamily(family) {
|
|
56
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9 ]{0,62}$/.test(family)) {
|
|
57
|
+
throw new Error(`loadGoogleFont: invalid family ${JSON.stringify(family)} (letters, digits, and spaces only)`);
|
|
58
|
+
}
|
|
59
|
+
return family;
|
|
60
|
+
}
|
|
61
|
+
/** Normalize a weight to the token Google expects: `400`, `"700"`, `normal`→`400`, `bold`→`700`, or a
|
|
62
|
+
* variable range `"100 900"`. Rejects anything else (these land in the request URL). */
|
|
63
|
+
function normalizeWeight(weight) {
|
|
64
|
+
if (typeof weight === "number") {
|
|
65
|
+
if (!Number.isInteger(weight) || weight < 1 || weight > 1000) {
|
|
66
|
+
throw new Error(`loadGoogleFont: invalid weight ${weight} (1–1000)`);
|
|
67
|
+
}
|
|
68
|
+
return String(weight);
|
|
69
|
+
}
|
|
70
|
+
const w = weight.trim();
|
|
71
|
+
if (w === "normal")
|
|
72
|
+
return "400";
|
|
73
|
+
if (w === "bold")
|
|
74
|
+
return "700";
|
|
75
|
+
// A single numeric weight, or a variable range like "100 900".
|
|
76
|
+
if (/^\d{1,4}$/.test(w) || /^\d{1,4} \d{1,4}$/.test(w))
|
|
77
|
+
return w;
|
|
78
|
+
throw new Error(`loadGoogleFont: invalid weight ${JSON.stringify(weight)}`);
|
|
79
|
+
}
|
|
80
|
+
function validateSubset(subset) {
|
|
81
|
+
if (!/^[a-z0-9-]{1,32}$/.test(subset)) {
|
|
82
|
+
throw new Error(`loadGoogleFont: invalid subset ${JSON.stringify(subset)}`);
|
|
83
|
+
}
|
|
84
|
+
return subset;
|
|
85
|
+
}
|
|
86
|
+
/** Build the Google Fonts CSS2 request URL. Pure + fully validated, so it's safe to feed a dynamic
|
|
87
|
+
* family/weights/text. Exported for advanced callers who fetch + parse the stylesheet themselves. */
|
|
88
|
+
export function googleFontsCssUrl(options) {
|
|
89
|
+
const family = validateFamily(options.family);
|
|
90
|
+
const styles = options.styles ?? ["normal"];
|
|
91
|
+
for (const s of styles) {
|
|
92
|
+
if (s !== "normal" && s !== "italic") {
|
|
93
|
+
throw new Error(`loadGoogleFont: invalid style ${JSON.stringify(s)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const display = options.display ?? "swap";
|
|
97
|
+
if (!VALID_DISPLAY.has(display)) {
|
|
98
|
+
throw new Error(`loadGoogleFont: invalid display ${JSON.stringify(display)}`);
|
|
99
|
+
}
|
|
100
|
+
// De-dupe + sort weights numerically (variable ranges sort by their lower bound).
|
|
101
|
+
const weights = [...new Set((options.weights ?? [400]).map(normalizeWeight))].sort((a, b) => Number.parseInt(a, 10) - Number.parseInt(b, 10));
|
|
102
|
+
const hasItalic = styles.includes("italic");
|
|
103
|
+
const hasNormal = styles.includes("normal") || !hasItalic;
|
|
104
|
+
// CSS2 wants spaces in the family as `+`; the `:`, `@`, `,`, `;` axis syntax stays literal.
|
|
105
|
+
const familyName = encodeURIComponent(family).replace(/%20/g, "+");
|
|
106
|
+
let axis;
|
|
107
|
+
if (hasItalic) {
|
|
108
|
+
// `ital,wght@` with tuples; all normal (ital=0) tuples must precede italic (ital=1).
|
|
109
|
+
const tuples = [];
|
|
110
|
+
if (hasNormal)
|
|
111
|
+
for (const w of weights)
|
|
112
|
+
tuples.push(`0,${w}`);
|
|
113
|
+
for (const w of weights)
|
|
114
|
+
tuples.push(`1,${w}`);
|
|
115
|
+
axis = `ital,wght@${tuples.join(";")}`;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
axis = `wght@${weights.join(";")}`;
|
|
119
|
+
}
|
|
120
|
+
const params = [`family=${familyName}:${axis}`, `display=${display}`];
|
|
121
|
+
if (options.text !== undefined) {
|
|
122
|
+
if (options.text.length > MAX_TEXT_LEN) {
|
|
123
|
+
throw new Error(`loadGoogleFont: text exceeds ${MAX_TEXT_LEN} chars`);
|
|
124
|
+
}
|
|
125
|
+
if (options.text.length > 0)
|
|
126
|
+
params.push(`text=${encodeURIComponent(options.text)}`);
|
|
127
|
+
}
|
|
128
|
+
return `${CSS2_ENDPOINT}?${params.join("&")}`;
|
|
129
|
+
}
|
|
130
|
+
const FACE_RE = /(?:\/\*\s*([^*]+?)\s*\*\/\s*)?@font-face\s*\{([^}]*)\}/g;
|
|
131
|
+
const SRC_RE = /url\(\s*(['"]?)([^'")]+)\1\s*\)(?:\s*format\(\s*(['"]?)([^'")]+)\3\s*\))?/g;
|
|
132
|
+
function declOf(body, prop) {
|
|
133
|
+
const m = body.match(new RegExp(`${prop}\\s*:\\s*([^;]+);`, "i"));
|
|
134
|
+
return m?.[1]?.trim();
|
|
135
|
+
}
|
|
136
|
+
/** Parse Google's stylesheet into structured faces, capturing the `/* subset */` label that precedes
|
|
137
|
+
* each `@font-face`. Pure — exported so callers can run their own download/write pipeline. */
|
|
138
|
+
export function parseGoogleFontCss(css) {
|
|
139
|
+
const faces = [];
|
|
140
|
+
for (const match of css.matchAll(FACE_RE)) {
|
|
141
|
+
const subset = (match[1] ?? "").trim() || "default";
|
|
142
|
+
const body = match[2] ?? "";
|
|
143
|
+
const familyRaw = declOf(body, "font-family");
|
|
144
|
+
if (familyRaw === undefined)
|
|
145
|
+
continue;
|
|
146
|
+
const family = familyRaw.replace(/^['"]|['"]$/g, "");
|
|
147
|
+
const src = [];
|
|
148
|
+
for (const s of body.matchAll(SRC_RE)) {
|
|
149
|
+
const url = s[2];
|
|
150
|
+
if (url === undefined)
|
|
151
|
+
continue;
|
|
152
|
+
src.push(s[4] === undefined ? { url } : { url, format: s[4] });
|
|
153
|
+
}
|
|
154
|
+
if (src.length === 0)
|
|
155
|
+
continue;
|
|
156
|
+
const unicodeRange = declOf(body, "unicode-range");
|
|
157
|
+
faces.push({
|
|
158
|
+
family,
|
|
159
|
+
style: declOf(body, "font-style") ?? "normal",
|
|
160
|
+
weight: declOf(body, "font-weight") ?? "400",
|
|
161
|
+
subset,
|
|
162
|
+
...(unicodeRange === undefined ? {} : { unicodeRange }),
|
|
163
|
+
src,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return faces;
|
|
167
|
+
}
|
|
168
|
+
/** First 16 hex chars of the SHA-256 of the bytes — a content hash for an immutable, cache-busting
|
|
169
|
+
* filename. Web Crypto, so it runs identically on Bun/Node/edge build hosts. `Uint8Array<ArrayBuffer>`
|
|
170
|
+
* (not the generic `ArrayBufferLike`) to satisfy WebCrypto's `BufferSource` under TS 5.7+ generics. */
|
|
171
|
+
async function contentHash(bytes) {
|
|
172
|
+
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
173
|
+
let hex = "";
|
|
174
|
+
for (const b of new Uint8Array(digest))
|
|
175
|
+
hex += b.toString(16).padStart(2, "0");
|
|
176
|
+
return hex.slice(0, 16);
|
|
177
|
+
}
|
|
178
|
+
/** Lowercase a validated token into a filename-safe slug. */
|
|
179
|
+
const slug = (s) => s
|
|
180
|
+
.toLowerCase()
|
|
181
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
182
|
+
.replace(/^-+|-+$/g, "");
|
|
183
|
+
/** Host of a URL for error messages — we never echo the full untrusted URL+path. */
|
|
184
|
+
const hostOf = (raw) => {
|
|
185
|
+
try {
|
|
186
|
+
return new URL(raw).host;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return "<invalid-url>";
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
/** Fetch with a hard byte ceiling. Checks the advertised `Content-Length` first (cheap reject), then
|
|
193
|
+
* re-checks the materialized body (a lying header can't smuggle a larger payload past us). */
|
|
194
|
+
async function fetchBounded(fetchImpl, url, maxBytes, headers) {
|
|
195
|
+
const res = await fetchImpl(url, headers ? { headers } : {});
|
|
196
|
+
if (!res.ok) {
|
|
197
|
+
throw new Error(`loadGoogleFont: fetch failed (${res.status}) from ${hostOf(url)}`);
|
|
198
|
+
}
|
|
199
|
+
const advertised = Number(res.headers.get("content-length"));
|
|
200
|
+
if (Number.isFinite(advertised) && advertised > maxBytes) {
|
|
201
|
+
throw new Error(`loadGoogleFont: response from ${hostOf(url)} exceeds ${maxBytes} bytes`);
|
|
202
|
+
}
|
|
203
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
204
|
+
if (bytes.byteLength > maxBytes) {
|
|
205
|
+
throw new Error(`loadGoogleFont: response from ${hostOf(url)} exceeds ${maxBytes} bytes`);
|
|
206
|
+
}
|
|
207
|
+
return bytes;
|
|
208
|
+
}
|
|
209
|
+
const defaultWriteFile = async (path, bytes) => {
|
|
210
|
+
await mkdir(dirname(path), { recursive: true });
|
|
211
|
+
await fsWriteFile(path, bytes);
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Download a Google font, self-host it, and return a CLS-safe `@font-face` stylesheet + preloads.
|
|
215
|
+
* See the module header for the full flow and security model. I/O (`fetch`, `writeFile`) is injectable
|
|
216
|
+
* so this is unit-testable without the network.
|
|
217
|
+
*/
|
|
218
|
+
export async function loadGoogleFont(options, io) {
|
|
219
|
+
const family = validateFamily(options.family);
|
|
220
|
+
const fetchImpl = io.fetch ?? fetch;
|
|
221
|
+
const writeFile = io.writeFile ?? defaultWriteFile;
|
|
222
|
+
const publicPath = (io.publicPath ?? "/fonts").replace(/\/+$/, "");
|
|
223
|
+
const maxBytes = io.maxBytesPerFile ?? DEFAULT_MAX_FONT_BYTES;
|
|
224
|
+
const wantedSubsets = options.subsets?.map(validateSubset);
|
|
225
|
+
const cssUrl = googleFontsCssUrl(options);
|
|
226
|
+
const cssBytes = await fetchBounded(fetchImpl, cssUrl, MAX_CSS_BYTES, { "user-agent": WOFF2_UA });
|
|
227
|
+
const css = new TextDecoder().decode(cssBytes);
|
|
228
|
+
let faces = parseGoogleFontCss(css);
|
|
229
|
+
if (faces.length === 0) {
|
|
230
|
+
throw new Error(`loadGoogleFont: Google returned no @font-face rules for ${JSON.stringify(family)}`);
|
|
231
|
+
}
|
|
232
|
+
// Filter to requested named subsets — but only when not glyph-subsetting (text mode labels faces
|
|
233
|
+
// `[0]`, `[1]`, … which carry no subset name).
|
|
234
|
+
if (wantedSubsets && wantedSubsets.length > 0 && options.text === undefined) {
|
|
235
|
+
faces = faces.filter((f) => wantedSubsets.includes(f.subset));
|
|
236
|
+
if (faces.length === 0) {
|
|
237
|
+
throw new Error(`loadGoogleFont: no faces for subsets [${wantedSubsets.join(", ")}]`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const assets = [];
|
|
241
|
+
const rules = [];
|
|
242
|
+
const preloads = [];
|
|
243
|
+
for (const face of faces) {
|
|
244
|
+
// Prefer woff2; the CSS2 endpoint with a Chrome UA only ever returns woff2, but be defensive.
|
|
245
|
+
const source = face.src.find((s) => s.format === "woff2") ?? face.src[0];
|
|
246
|
+
if (!source)
|
|
247
|
+
continue;
|
|
248
|
+
if (!isAllowedFontUrl(source.url)) {
|
|
249
|
+
throw new Error(`loadGoogleFont: refusing to download a font from a non-Google host (${hostOf(source.url)}); ` +
|
|
250
|
+
"the stylesheet may be tampered with");
|
|
251
|
+
}
|
|
252
|
+
const bytes = await fetchBounded(fetchImpl, source.url, maxBytes);
|
|
253
|
+
const hash = await contentHash(bytes);
|
|
254
|
+
const style = face.style === "italic" ? "italic" : "normal";
|
|
255
|
+
const fileName = `${slug(family)}-${slug(face.subset)}-${style}-${face.weight.replace(/\s+/g, "_")}-${hash}.woff2`;
|
|
256
|
+
const path = join(io.outDir, fileName);
|
|
257
|
+
await writeFile(path, bytes);
|
|
258
|
+
const href = `${publicPath}/${fileName}`;
|
|
259
|
+
assets.push({
|
|
260
|
+
fileName,
|
|
261
|
+
href,
|
|
262
|
+
sourceUrl: source.url,
|
|
263
|
+
bytes,
|
|
264
|
+
subset: face.subset,
|
|
265
|
+
weight: face.weight,
|
|
266
|
+
style,
|
|
267
|
+
});
|
|
268
|
+
rules.push(fontFace({
|
|
269
|
+
family,
|
|
270
|
+
src: [{ url: href, format: "woff2" }],
|
|
271
|
+
weight: face.weight,
|
|
272
|
+
style,
|
|
273
|
+
display: options.display ?? "swap",
|
|
274
|
+
...(face.unicodeRange === undefined ? {} : { unicodeRange: face.unicodeRange }),
|
|
275
|
+
...(options.sizeAdjust === undefined ? {} : { sizeAdjust: options.sizeAdjust }),
|
|
276
|
+
...(options.ascentOverride === undefined ? {} : { ascentOverride: options.ascentOverride }),
|
|
277
|
+
...(options.descentOverride === undefined
|
|
278
|
+
? {}
|
|
279
|
+
: { descentOverride: options.descentOverride }),
|
|
280
|
+
...(options.lineGapOverride === undefined
|
|
281
|
+
? {}
|
|
282
|
+
: { lineGapOverride: options.lineGapOverride }),
|
|
283
|
+
}));
|
|
284
|
+
preloads.push(fontPreload({ href }));
|
|
285
|
+
}
|
|
286
|
+
if (assets.length === 0) {
|
|
287
|
+
throw new Error(`loadGoogleFont: no downloadable woff2 sources for ${JSON.stringify(family)}`);
|
|
288
|
+
}
|
|
289
|
+
return { family, css: rules.join("\n\n"), assets, preloads };
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=fonts-google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts-google.js","sourceRoot":"","sources":["../src/fonts-google.ts"],"names":[],"mappings":"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"}
|
package/dist/fonts.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Font optimization primitives — generate a **CLS-safe `@font-face`** rule and the matching
|
|
3
|
+
* **preload `<link>`** for a self-hosted font. The two fixes that matter most (the ones `next/font`
|
|
4
|
+
* automates) are right here: `font-display: swap` (text paints immediately, no invisible-text FOIT)
|
|
5
|
+
* plus a preload so the file downloads with the document, and optional metric overrides
|
|
6
|
+
* (`size-adjust`/`ascent-override`/…) so swapping from the fallback to the web font doesn't shift layout.
|
|
7
|
+
*
|
|
8
|
+
* Self-host the file (drop a `.woff2` in your assets — never hotlink Google's CDN), then:
|
|
9
|
+
*
|
|
10
|
+
* // fonts.css (imported by your app — the CSS pipeline bundles + links it)
|
|
11
|
+
* import { fontFace } from "@nifrajs/web"
|
|
12
|
+
* export default fontFace({ family: "Inter", src: [{ url: "/fonts/inter.woff2" }], weight: "100 900" })
|
|
13
|
+
*
|
|
14
|
+
* // a root layout's meta — becomes a <link rel="preload" as="font"> in <head>
|
|
15
|
+
* export const meta = { link: [fontPreload({ href: "/fonts/inter.woff2" })] }
|
|
16
|
+
*/
|
|
17
|
+
/** `font-display` strategy. `swap` (the default here) paints fallback text immediately, then swaps. */
|
|
18
|
+
export type FontDisplay = "auto" | "block" | "swap" | "fallback" | "optional";
|
|
19
|
+
export interface FontSource {
|
|
20
|
+
/** URL of the self-hosted font file. */
|
|
21
|
+
readonly url: string;
|
|
22
|
+
/** `format()` hint (`woff2`, `woff`, `truetype`, …). Inferred from the URL extension when omitted. */
|
|
23
|
+
readonly format?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface FontFace {
|
|
26
|
+
readonly family: string;
|
|
27
|
+
/** One or more sources (best format first; the browser picks the first it supports). */
|
|
28
|
+
readonly src: readonly FontSource[];
|
|
29
|
+
/** `400`, `"700"`, or a variable-font range like `"100 900"`. */
|
|
30
|
+
readonly weight?: number | string;
|
|
31
|
+
readonly style?: "normal" | "italic" | "oblique";
|
|
32
|
+
/** Defaults to `"swap"` (no flash of invisible text). */
|
|
33
|
+
readonly display?: FontDisplay;
|
|
34
|
+
/** Restrict the glyphs this face covers, e.g. `"U+0000-00FF"` — lets the browser skip the download
|
|
35
|
+
* for pages without those characters. */
|
|
36
|
+
readonly unicodeRange?: string;
|
|
37
|
+
/** Metric overrides that eliminate layout shift when the fallback swaps to the web font (the
|
|
38
|
+
* `next/font` technique). e.g. `sizeAdjust: "105%"`, `ascentOverride: "90%"`. */
|
|
39
|
+
readonly sizeAdjust?: string;
|
|
40
|
+
readonly ascentOverride?: string;
|
|
41
|
+
readonly descentOverride?: string;
|
|
42
|
+
readonly lineGapOverride?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build a single `@font-face` CSS rule. Defaults to `font-display: swap`; infers each source's
|
|
46
|
+
* `format()` from its extension. All values are CSS-escaped, so a dynamic family/URL can't inject CSS.
|
|
47
|
+
* Put the result in a stylesheet your app imports (nifra's CSS pipeline bundles + links it).
|
|
48
|
+
*/
|
|
49
|
+
export declare function fontFace(face: FontFace): string;
|
|
50
|
+
export interface FontPreloadInput {
|
|
51
|
+
/** URL of the self-hosted font file to preload. */
|
|
52
|
+
readonly href: string;
|
|
53
|
+
/** MIME type (`font/woff2`, …). Inferred from the extension when omitted. */
|
|
54
|
+
readonly type?: string;
|
|
55
|
+
/** `crossorigin` mode — defaults to `"anonymous"`. Fonts are always fetched in CORS mode, and a
|
|
56
|
+
* preload whose `crossorigin` doesn't match the actual fetch is **wasted** (downloaded twice), so
|
|
57
|
+
* this is on by default. */
|
|
58
|
+
readonly crossOrigin?: "anonymous" | "use-credentials";
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build a font preload as a `<link>` attribute set for a route/layout's `meta.link` — nifra injects it
|
|
62
|
+
* into `<head>` (`<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous">`). Values are
|
|
63
|
+
* escaped at injection by the head renderer. Preloading the font file removes a render-blocking round
|
|
64
|
+
* trip (the browser would otherwise discover the font only after parsing the CSS).
|
|
65
|
+
*/
|
|
66
|
+
export declare function fontPreload(input: FontPreloadInput): Record<string, string>;
|
|
67
|
+
//# sourceMappingURL=fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../src/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,uGAAuG;AACvG,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAA;AAE7E,MAAM,WAAW,UAAU;IACzB,wCAAwC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,sGAAsG;IACtG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,wFAAwF;IACxF,QAAQ,CAAC,GAAG,EAAE,SAAS,UAAU,EAAE,CAAA;IACnC,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;IAChD,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAA;IAC9B;6CACyC;IACzC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B;qFACiF;IACjF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAwCD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CA4B/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB;;gCAE4B;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAA;CACvD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS3E"}
|
package/dist/fonts.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Font optimization primitives — generate a **CLS-safe `@font-face`** rule and the matching
|
|
3
|
+
* **preload `<link>`** for a self-hosted font. The two fixes that matter most (the ones `next/font`
|
|
4
|
+
* automates) are right here: `font-display: swap` (text paints immediately, no invisible-text FOIT)
|
|
5
|
+
* plus a preload so the file downloads with the document, and optional metric overrides
|
|
6
|
+
* (`size-adjust`/`ascent-override`/…) so swapping from the fallback to the web font doesn't shift layout.
|
|
7
|
+
*
|
|
8
|
+
* Self-host the file (drop a `.woff2` in your assets — never hotlink Google's CDN), then:
|
|
9
|
+
*
|
|
10
|
+
* // fonts.css (imported by your app — the CSS pipeline bundles + links it)
|
|
11
|
+
* import { fontFace } from "@nifrajs/web"
|
|
12
|
+
* export default fontFace({ family: "Inter", src: [{ url: "/fonts/inter.woff2" }], weight: "100 900" })
|
|
13
|
+
*
|
|
14
|
+
* // a root layout's meta — becomes a <link rel="preload" as="font"> in <head>
|
|
15
|
+
* export const meta = { link: [fontPreload({ href: "/fonts/inter.woff2" })] }
|
|
16
|
+
*/
|
|
17
|
+
const FORMAT_BY_EXT = {
|
|
18
|
+
woff2: "woff2",
|
|
19
|
+
woff: "woff",
|
|
20
|
+
ttf: "truetype",
|
|
21
|
+
otf: "opentype",
|
|
22
|
+
eot: "embedded-opentype",
|
|
23
|
+
svg: "svg",
|
|
24
|
+
};
|
|
25
|
+
const MIME_BY_EXT = {
|
|
26
|
+
woff2: "font/woff2",
|
|
27
|
+
woff: "font/woff",
|
|
28
|
+
ttf: "font/ttf",
|
|
29
|
+
otf: "font/otf",
|
|
30
|
+
};
|
|
31
|
+
/** Lowercased file extension of a URL, ignoring any `?query`/`#hash`. */
|
|
32
|
+
function extOf(url) {
|
|
33
|
+
const clean = url.split(/[?#]/, 1)[0] ?? url;
|
|
34
|
+
const dot = clean.lastIndexOf(".");
|
|
35
|
+
return dot === -1 ? "" : clean.slice(dot + 1).toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
/** Escape a value placed inside a double-quoted CSS string (`font-family`, `url("…")`, `format("…")`):
|
|
38
|
+
* neutralize the quote, the escape char, and newlines so a value can't break out of the declaration. */
|
|
39
|
+
function cssQuoted(value) {
|
|
40
|
+
return value.replace(/[\\"]/g, "\\$&").replace(/[\r\n]+/g, " ");
|
|
41
|
+
}
|
|
42
|
+
/** Sanitize an **unquoted** CSS token value (`font-weight`, `unicode-range`, `size-adjust`, …): drop the
|
|
43
|
+
* characters that could end the declaration or the rule and inject more CSS. */
|
|
44
|
+
function cssToken(value) {
|
|
45
|
+
return value
|
|
46
|
+
.replace(/[;{}<>]/g, "")
|
|
47
|
+
.replace(/[\r\n]+/g, " ")
|
|
48
|
+
.trim();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Build a single `@font-face` CSS rule. Defaults to `font-display: swap`; infers each source's
|
|
52
|
+
* `format()` from its extension. All values are CSS-escaped, so a dynamic family/URL can't inject CSS.
|
|
53
|
+
* Put the result in a stylesheet your app imports (nifra's CSS pipeline bundles + links it).
|
|
54
|
+
*/
|
|
55
|
+
export function fontFace(face) {
|
|
56
|
+
if (face.src.length === 0) {
|
|
57
|
+
throw new Error("fontFace: `src` needs at least one source");
|
|
58
|
+
}
|
|
59
|
+
const src = face.src
|
|
60
|
+
.map((source) => {
|
|
61
|
+
const format = source.format ?? FORMAT_BY_EXT[extOf(source.url)];
|
|
62
|
+
const formatPart = format === undefined ? "" : ` format("${cssQuoted(format)}")`;
|
|
63
|
+
return `url("${cssQuoted(source.url)}")${formatPart}`;
|
|
64
|
+
})
|
|
65
|
+
.join(", ");
|
|
66
|
+
const declarations = [
|
|
67
|
+
`font-family: "${cssQuoted(face.family)}"`,
|
|
68
|
+
`src: ${src}`,
|
|
69
|
+
`font-display: ${face.display ?? "swap"}`,
|
|
70
|
+
];
|
|
71
|
+
if (face.weight !== undefined)
|
|
72
|
+
declarations.push(`font-weight: ${cssToken(String(face.weight))}`);
|
|
73
|
+
if (face.style !== undefined)
|
|
74
|
+
declarations.push(`font-style: ${face.style}`);
|
|
75
|
+
if (face.unicodeRange !== undefined)
|
|
76
|
+
declarations.push(`unicode-range: ${cssToken(face.unicodeRange)}`);
|
|
77
|
+
if (face.sizeAdjust !== undefined)
|
|
78
|
+
declarations.push(`size-adjust: ${cssToken(face.sizeAdjust)}`);
|
|
79
|
+
if (face.ascentOverride !== undefined)
|
|
80
|
+
declarations.push(`ascent-override: ${cssToken(face.ascentOverride)}`);
|
|
81
|
+
if (face.descentOverride !== undefined)
|
|
82
|
+
declarations.push(`descent-override: ${cssToken(face.descentOverride)}`);
|
|
83
|
+
if (face.lineGapOverride !== undefined)
|
|
84
|
+
declarations.push(`line-gap-override: ${cssToken(face.lineGapOverride)}`);
|
|
85
|
+
return `@font-face {\n ${declarations.join(";\n ")};\n}`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Build a font preload as a `<link>` attribute set for a route/layout's `meta.link` — nifra injects it
|
|
89
|
+
* into `<head>` (`<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous">`). Values are
|
|
90
|
+
* escaped at injection by the head renderer. Preloading the font file removes a render-blocking round
|
|
91
|
+
* trip (the browser would otherwise discover the font only after parsing the CSS).
|
|
92
|
+
*/
|
|
93
|
+
export function fontPreload(input) {
|
|
94
|
+
const type = input.type ?? MIME_BY_EXT[extOf(input.href)];
|
|
95
|
+
return {
|
|
96
|
+
rel: "preload",
|
|
97
|
+
as: "font",
|
|
98
|
+
href: input.href,
|
|
99
|
+
...(type === undefined ? {} : { type }),
|
|
100
|
+
crossorigin: input.crossOrigin ?? "anonymous",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=fonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.js","sourceRoot":"","sources":["../src/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAgCH,MAAM,aAAa,GAAqC;IACtD,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,KAAK;CACX,CAAA;AAED,MAAM,WAAW,GAAqC;IACpD,KAAK,EAAE,YAAY;IACnB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,UAAU;CAChB,CAAA;AAED,yEAAyE;AACzE,SAAS,KAAK,CAAC,GAAW;IACxB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;IAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAClC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;AAC7D,CAAC;AAED;wGACwG;AACxG,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;AACjE,CAAC;AAED;gFACgF;AAChF,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,KAAK;SACT,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,IAAI,EAAE,CAAA;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAc;IACrC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG;SACjB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QAChE,MAAM,UAAU,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,SAAS,CAAC,MAAM,CAAC,IAAI,CAAA;QAChF,OAAO,QAAQ,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,UAAU,EAAE,CAAA;IACvD,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;IACb,MAAM,YAAY,GAAG;QACnB,iBAAiB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;QAC1C,QAAQ,GAAG,EAAE;QACb,iBAAiB,IAAI,CAAC,OAAO,IAAI,MAAM,EAAE;KAC1C,CAAA;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,YAAY,CAAC,IAAI,CAAC,gBAAgB,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAA;IACjG,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,YAAY,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;IAC5E,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;QACjC,YAAY,CAAC,IAAI,CAAC,kBAAkB,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IACpE,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;QAAE,YAAY,CAAC,IAAI,CAAC,gBAAgB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IACjG,IAAI,IAAI,CAAC,cAAc,KAAK,SAAS;QACnC,YAAY,CAAC,IAAI,CAAC,oBAAoB,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;IACxE,IAAI,IAAI,CAAC,eAAe,KAAK,SAAS;QACpC,YAAY,CAAC,IAAI,CAAC,qBAAqB,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;IAC1E,IAAI,IAAI,CAAC,eAAe,KAAK,SAAS;QACpC,YAAY,CAAC,IAAI,CAAC,sBAAsB,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;IAC3E,OAAO,mBAAmB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;AAC5D,CAAC;AAaD;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IACzD,OAAO;QACL,GAAG,EAAE,SAAS;QACd,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,WAAW;KAC9C,CAAA;AACH,CAAC"}
|
package/dist/fs.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Manifest } from "./manifest.js";
|
|
2
|
+
/** Options for {@link discoverRoutes}. */
|
|
3
|
+
export interface DiscoverRoutesOptions {
|
|
4
|
+
/** Appended (as `?<importQuery>`) to each route's dynamic import — the dev server sets a
|
|
5
|
+
* changing value to bust Bun's module cache so SSR picks up edited route files. */
|
|
6
|
+
readonly importQuery?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Scan a `routes/` directory (recursively) and build the route manifest. */
|
|
9
|
+
export declare function discoverRoutes(dir: string, options?: DiscoverRoutesOptions): Manifest;
|
|
10
|
+
//# sourceMappingURL=fs.d.ts.map
|
package/dist/fs.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiB,KAAK,QAAQ,EAAoB,MAAM,eAAe,CAAA;AAE9E,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC;uFACmF;IACnF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,QAAQ,CASzF"}
|
package/dist/fs.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* @nifrajs/web/fs — filesystem route discovery. Separated from the main entry so `app.fetch`
|
|
11
|
+
* (and the rest of @nifrajs/web) stays fs-free + edge-portable: this runs at build/startup
|
|
12
|
+
* only. It scans a routes dir and feeds the pure `buildManifest`.
|
|
13
|
+
*/
|
|
14
|
+
import { readdirSync } from "node:fs";
|
|
15
|
+
import { buildManifest } from "./manifest.js";
|
|
16
|
+
/** Scan a `routes/` directory (recursively) and build the route manifest. */
|
|
17
|
+
export function discoverRoutes(dir, options = {}) {
|
|
18
|
+
const files = readdirSync(dir, { recursive: true })
|
|
19
|
+
.map((file) => file.replaceAll("\\", "/")) // normalize Windows separators
|
|
20
|
+
.filter((file) => /\.(tsx|jsx|svelte|vue|mdx)$/.test(file));
|
|
21
|
+
const query = options.importQuery ? `?${options.importQuery}` : "";
|
|
22
|
+
return buildManifest(files, (file) => () => import(__rewriteRelativeImportExtension(`${dir}/${file}${query}`)));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=fs.js.map
|
package/dist/fs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":";;;;;;;;AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,aAAa,EAAmC,MAAM,eAAe,CAAA;AAS9E,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,UAAiC,EAAE;IAC7E,MAAM,KAAK,GAAI,WAAW,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAc;SAC9D,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,+BAA+B;SACzE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAClE,OAAO,aAAa,CAClB,KAAK,EACL,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,kCAAC,GAAG,GAAG,IAAI,IAAI,GAAG,KAAK,EAAE,EAAyB,CACzE,CAAA;AACH,CAAC"}
|