@bagelink/blox 1.15.673 → 1.15.674

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.
@@ -26,7 +26,7 @@ const node_child_process = require("node:child_process");
26
26
  const os = require("node:os");
27
27
  const path = require("node:path");
28
28
  const process = require("node:process");
29
- const llmArtifacts = require("./validate-output-CWWWtrI-.cjs");
29
+ const llmArtifacts = require("./validate-output-gJ1f8o9z.cjs");
30
30
  const AUTO_SHARD_CAP = Number(process.env.BLOX_SSG_SHARD_CAP) || 6;
31
31
  const PREFETCH_BUDGET = Number(process.env.BLOX_SSG_PREFETCH_BUDGET) || 24;
32
32
  const SEQUENTIAL_SHARDS = process.env.BLOX_SSG_SEQUENTIAL === "1";
@@ -166,7 +166,7 @@ async function runSharded(opts) {
166
166
  }
167
167
  if (process.env.BLOX_SSG_LLM !== "0") {
168
168
  try {
169
- const { mergeLlmParts } = await Promise.resolve().then(() => require("./validate-output-CWWWtrI-.cjs")).then((n) => n.llmArtifacts);
169
+ const { mergeLlmParts } = await Promise.resolve().then(() => require("./validate-output-gJ1f8o9z.cjs")).then((n) => n.llmArtifacts);
170
170
  const mergeWebsite = website;
171
171
  const partFiles = Array.from({ length: total }, (_, i) => path.join(llmPartsDir, `part.${i}.json`));
172
172
  const { pages } = await mergeLlmParts({
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import process from "node:process";
5
- import { f as fetchCmsSiteData, g as generateSitemapArtifacts } from "./validate-output-BK5OVQ7Y.js";
5
+ import { f as fetchCmsSiteData, g as generateSitemapArtifacts } from "./validate-output-CJiiZxtm.js";
6
6
  const AUTO_SHARD_CAP = Number(process.env.BLOX_SSG_SHARD_CAP) || 6;
7
7
  const PREFETCH_BUDGET = Number(process.env.BLOX_SSG_PREFETCH_BUDGET) || 24;
8
8
  const SEQUENTIAL_SHARDS = process.env.BLOX_SSG_SEQUENTIAL === "1";
@@ -142,7 +142,7 @@ async function runSharded(opts) {
142
142
  }
143
143
  if (process.env.BLOX_SSG_LLM !== "0") {
144
144
  try {
145
- const { mergeLlmParts } = await import("./validate-output-BK5OVQ7Y.js").then((n) => n.C);
145
+ const { mergeLlmParts } = await import("./validate-output-CJiiZxtm.js").then((n) => n.C);
146
146
  const mergeWebsite = website;
147
147
  const partFiles = Array.from({ length: total }, (_, i) => path.join(llmPartsDir, `part.${i}.json`));
148
148
  const { pages } = await mergeLlmParts({
package/dist/ssg/cli.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  const process = require("node:process");
4
4
  const fs = require("node:fs/promises");
5
5
  const ssg_buildGrant = require("./build-grant.cjs");
6
- const llmArtifacts = require("../validate-output-CWWWtrI-.cjs");
6
+ const llmArtifacts = require("../validate-output-gJ1f8o9z.cjs");
7
7
  function installFetchTimeout() {
8
8
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
9
9
  const original = globalThis.fetch;
@@ -147,7 +147,7 @@ Environment:
147
147
  if (shardsOpt !== null || routesCmd) {
148
148
  const { apiBase: apiBase2, websiteName: configWebsiteName2 } = await resolveApiBase(mode);
149
149
  const websiteName2 = process.env.WEBSITE_NAME ?? configWebsiteName2 ?? "default";
150
- const { runSharded } = await Promise.resolve().then(() => require("../shard-runner-C1yhyjvs.cjs"));
150
+ const { runSharded } = await Promise.resolve().then(() => require("../shard-runner-DEmn6Lgi.cjs"));
151
151
  const code = await runSharded({
152
152
  shards: shardsOpt ?? "auto",
153
153
  mode,
package/dist/ssg/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import process from "node:process";
3
3
  import fs from "node:fs/promises";
4
4
  import { resolveBloxBuildGrant } from "./build-grant.mjs";
5
- import { v as validateSsgOutput, u as uploadBloxManifest, p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, b as buildCollectionResolver, a as prerender, c as validateInternalLinks } from "../validate-output-BK5OVQ7Y.js";
5
+ import { v as validateSsgOutput, u as uploadBloxManifest, p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, b as buildCollectionResolver, a as prerender, c as validateInternalLinks } from "../validate-output-CJiiZxtm.js";
6
6
  function installFetchTimeout() {
7
7
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
8
8
  const original = globalThis.fetch;
@@ -146,7 +146,7 @@ Environment:
146
146
  if (shardsOpt !== null || routesCmd) {
147
147
  const { apiBase: apiBase2, websiteName: configWebsiteName2 } = await resolveApiBase(mode);
148
148
  const websiteName2 = process.env.WEBSITE_NAME ?? configWebsiteName2 ?? "default";
149
- const { runSharded } = await import("../shard-runner-esdE7BT1.js");
149
+ const { runSharded } = await import("../shard-runner-tnSCxMng.js");
150
150
  const code = await runSharded({
151
151
  shards: shardsOpt ?? "auto",
152
152
  mode,
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
25
- const llmArtifacts = require("../validate-output-CWWWtrI-.cjs");
25
+ const llmArtifacts = require("../validate-output-gJ1f8o9z.cjs");
26
26
  const ssg_buildGrant = require("./build-grant.cjs");
27
27
  const ssg_client = require("../client-AoDTJJXJ.cjs");
28
28
  const vue = require("vue");
@@ -1,5 +1,5 @@
1
- import { d as buildPageHead, e as primaryContextEntry, h as buildJsonLd, i as extractPageText, B as BloxBuildResponseError, j as bloxBuildJson } from "../validate-output-BK5OVQ7Y.js";
2
- import { k, l, f, m, n, o, q, g, r, s, t, w, x, y, p, a, z, A, u, c, v } from "../validate-output-BK5OVQ7Y.js";
1
+ import { d as buildPageHead, e as primaryContextEntry, h as buildJsonLd, i as extractPageText, B as BloxBuildResponseError, j as bloxBuildJson } from "../validate-output-CJiiZxtm.js";
2
+ import { k, l, f, m, n, o, q, g, r, s, t, w, x, y, p, a, z, A, u, c, v } from "../validate-output-CJiiZxtm.js";
3
3
  import { parseBloxBuildGrantBody, resolveBloxBuildGrant } from "./build-grant.mjs";
4
4
  import { a as BLOX_HYDRATION_WINDOW_KEY } from "../client-Ce9fRCGH.js";
5
5
  import { createSSRApp, h, Suspense } from "vue";
@@ -99,6 +99,17 @@ export declare function prerender({ root, clientOutDir, serverEntry, paths, craw
99
99
  * prefetch (render resolves inline). Default 8.
100
100
  */
101
101
  resolvePrefetchConcurrency, appPaths, includeRoot, routePartsFile, mode, website, websiteId, redirects, llm, }?: PrerenderOptions): Promise<PrerenderResult>;
102
+ /**
103
+ * Collect `<link rel="preload">` tags for the web fonts a page is likely to use.
104
+ *
105
+ * Fonts are usually split into many `@font-face` blocks — one per `unicode-range`
106
+ * subset (latin, latin-ext, cyrillic, greek, vietnamese…) and per weight. Only one
107
+ * subset per (family, weight, style) is ever needed for a given page, so preloading
108
+ * every URL makes the browser fetch megabytes of subsets it will never render,
109
+ * competing with the LCP resource. Prefer the Latin subset of each face and skip
110
+ * the rest; browsers still fetch any other subset on demand via `unicode-range`.
111
+ */
112
+ export declare function discoverFontPreloads(clientOutDir: string): Promise<string>;
102
113
  export declare function injectIntoTemplate(template: string, head: string, appHtml: string, fontPreloads: string, htmlAttrs?: string, teleports?: Record<string, string>): string;
103
114
  export declare function injectTeleports(html: string, teleports: Record<string, string>): string;
104
115
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"prerender.d.ts","sourceRoot":"","sources":["../../src/ssg/prerender.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prerender.d.ts","sourceRoot":"","sources":["../../src/ssg/prerender.ts"],"names":[],"mappings":"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"}
@@ -1256,7 +1256,56 @@ function makeExcludeChecker(excludePaths) {
1256
1256
  return false;
1257
1257
  };
1258
1258
  }
1259
+ const FONT_FACE_RE = /@font-face\s*\{([^}]*)\}/g;
1260
+ const SRC_URL_RE = /url\(\s*(["']?)([^"')\s]+\.woff2)\1\s*\)/;
1261
+ const LATIN_CODE_POINT = 65;
1262
+ function rangeCoversLatin(range) {
1263
+ for (const part of range.split(",")) {
1264
+ const token = part.trim().replace(/^U\+/i, "");
1265
+ if (!token) continue;
1266
+ const [start, end] = token.split("-");
1267
+ const lo = Number.parseInt(start, 16);
1268
+ const hi = end ? Number.parseInt(end, 16) : lo;
1269
+ if (!Number.isFinite(lo) || !Number.isFinite(hi)) continue;
1270
+ if (LATIN_CODE_POINT >= lo && LATIN_CODE_POINT <= hi) return true;
1271
+ }
1272
+ return false;
1273
+ }
1274
+ const CSS_IMPORT_RE = /@import\s+(?:url\(\s*)?["']?(?:https?:)?\/\/([^"')\s]+)["']?\s*\)?/g;
1275
+ async function cssImportHints(cssFiles) {
1276
+ const origins = /* @__PURE__ */ new Set();
1277
+ const imported = [];
1278
+ for (const file of cssFiles) {
1279
+ let css = "";
1280
+ try {
1281
+ css = await fs.readFile(file, "utf8");
1282
+ } catch {
1283
+ continue;
1284
+ }
1285
+ for (const [, rest] of css.matchAll(CSS_IMPORT_RE)) {
1286
+ if (!rest) continue;
1287
+ const href = rest.startsWith("http") ? rest : `https://${rest}`;
1288
+ const isFontCss = /fonts\.googleapis\.com|font-awesome|material-symbols/i.test(href);
1289
+ if (!isFontCss) continue;
1290
+ if (imported.includes(href)) continue;
1291
+ imported.push(href);
1292
+ try {
1293
+ origins.add(new URL(href).origin);
1294
+ } catch {
1295
+ }
1296
+ }
1297
+ }
1298
+ const tags = [];
1299
+ for (const origin of origins) {
1300
+ tags.push(`<link rel="preconnect" href="${origin}" crossorigin>`);
1301
+ }
1302
+ for (const href of imported) {
1303
+ tags.push(`<link rel="preload" as="style" href="${href}">`);
1304
+ }
1305
+ return tags;
1306
+ }
1259
1307
  async function discoverFontPreloads(clientOutDir) {
1308
+ var _a, _b, _c, _d, _e;
1260
1309
  const assetsDir = path.join(clientOutDir, "assets");
1261
1310
  let cssFiles = [];
1262
1311
  try {
@@ -1265,15 +1314,42 @@ async function discoverFontPreloads(clientOutDir) {
1265
1314
  } catch {
1266
1315
  return "";
1267
1316
  }
1268
- const seen = /* @__PURE__ */ new Set();
1269
- const woff2Re = /url\((["']?)(https?:\/\/[^"')]+\.woff2)\1\)/g;
1317
+ const groups = /* @__PURE__ */ new Map();
1270
1318
  for (const file of cssFiles) {
1271
1319
  const css = await fs.readFile(file, "utf8");
1272
- for (const [, , url] of css.matchAll(woff2Re)) {
1273
- if (url !== "") seen.add(url);
1320
+ for (const [, body] of css.matchAll(FONT_FACE_RE)) {
1321
+ const src = SRC_URL_RE.exec(body ?? "");
1322
+ const url = src == null ? void 0 : src[2];
1323
+ if (!url) continue;
1324
+ if (!/^(https?:\/\/|\/)/.test(url)) continue;
1325
+ const family = (((_a = /font-family\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _a[1]) ?? "").trim().replace(/^["']|["']$/g, "");
1326
+ const style = (((_b = /font-style\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _b[1]) ?? "normal").trim();
1327
+ const weight = (((_c = /font-weight\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _c[1]) ?? "400").trim();
1328
+ const rangeRaw = (_e = (_d = /unicode-range\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _d[1]) == null ? void 0 : _e.trim();
1329
+ const key = `${family}|${style}|${weight}`;
1330
+ const list = groups.get(key) ?? [];
1331
+ if (list.some((candidate) => candidate.url === url)) continue;
1332
+ list.push({
1333
+ family,
1334
+ style,
1335
+ weight,
1336
+ url,
1337
+ hasRange: Boolean(rangeRaw),
1338
+ coversLatin: rangeRaw ? rangeCoversLatin(rangeRaw) : true
1339
+ });
1340
+ groups.set(key, list);
1274
1341
  }
1275
1342
  }
1276
- return [...seen].map((href) => `<link rel="preload" as="font" type="font/woff2" crossorigin href="${href}">`).join("\n");
1343
+ const picked = [];
1344
+ const seen = /* @__PURE__ */ new Set();
1345
+ for (const candidates of groups.values()) {
1346
+ const choice = candidates.find((candidate) => candidate.coversLatin) ?? (candidates.every((candidate) => candidate.hasRange) ? void 0 : candidates[0]);
1347
+ if (!choice || seen.has(choice.url)) continue;
1348
+ seen.add(choice.url);
1349
+ picked.push(choice.url);
1350
+ }
1351
+ const fontTags = picked.map((href) => `<link rel="preload" as="font" type="font/woff2" crossorigin href="${href}">`);
1352
+ return [...await cssImportHints(cssFiles), ...fontTags].join("\n");
1277
1353
  }
1278
1354
  function injectIntoTemplate(template, head, appHtml, fontPreloads, htmlAttrs = "", teleports = {}) {
1279
1355
  let out = template;
@@ -1279,7 +1279,56 @@ function makeExcludeChecker(excludePaths) {
1279
1279
  return false;
1280
1280
  };
1281
1281
  }
1282
+ const FONT_FACE_RE = /@font-face\s*\{([^}]*)\}/g;
1283
+ const SRC_URL_RE = /url\(\s*(["']?)([^"')\s]+\.woff2)\1\s*\)/;
1284
+ const LATIN_CODE_POINT = 65;
1285
+ function rangeCoversLatin(range) {
1286
+ for (const part of range.split(",")) {
1287
+ const token = part.trim().replace(/^U\+/i, "");
1288
+ if (!token) continue;
1289
+ const [start, end] = token.split("-");
1290
+ const lo = Number.parseInt(start, 16);
1291
+ const hi = end ? Number.parseInt(end, 16) : lo;
1292
+ if (!Number.isFinite(lo) || !Number.isFinite(hi)) continue;
1293
+ if (LATIN_CODE_POINT >= lo && LATIN_CODE_POINT <= hi) return true;
1294
+ }
1295
+ return false;
1296
+ }
1297
+ const CSS_IMPORT_RE = /@import\s+(?:url\(\s*)?["']?(?:https?:)?\/\/([^"')\s]+)["']?\s*\)?/g;
1298
+ async function cssImportHints(cssFiles) {
1299
+ const origins = /* @__PURE__ */ new Set();
1300
+ const imported = [];
1301
+ for (const file of cssFiles) {
1302
+ let css = "";
1303
+ try {
1304
+ css = await fs.readFile(file, "utf8");
1305
+ } catch {
1306
+ continue;
1307
+ }
1308
+ for (const [, rest] of css.matchAll(CSS_IMPORT_RE)) {
1309
+ if (!rest) continue;
1310
+ const href = rest.startsWith("http") ? rest : `https://${rest}`;
1311
+ const isFontCss = /fonts\.googleapis\.com|font-awesome|material-symbols/i.test(href);
1312
+ if (!isFontCss) continue;
1313
+ if (imported.includes(href)) continue;
1314
+ imported.push(href);
1315
+ try {
1316
+ origins.add(new URL(href).origin);
1317
+ } catch {
1318
+ }
1319
+ }
1320
+ }
1321
+ const tags = [];
1322
+ for (const origin of origins) {
1323
+ tags.push(`<link rel="preconnect" href="${origin}" crossorigin>`);
1324
+ }
1325
+ for (const href of imported) {
1326
+ tags.push(`<link rel="preload" as="style" href="${href}">`);
1327
+ }
1328
+ return tags;
1329
+ }
1282
1330
  async function discoverFontPreloads(clientOutDir) {
1331
+ var _a, _b, _c, _d, _e;
1283
1332
  const assetsDir = path.join(clientOutDir, "assets");
1284
1333
  let cssFiles = [];
1285
1334
  try {
@@ -1288,15 +1337,42 @@ async function discoverFontPreloads(clientOutDir) {
1288
1337
  } catch {
1289
1338
  return "";
1290
1339
  }
1291
- const seen = /* @__PURE__ */ new Set();
1292
- const woff2Re = /url\((["']?)(https?:\/\/[^"')]+\.woff2)\1\)/g;
1340
+ const groups = /* @__PURE__ */ new Map();
1293
1341
  for (const file of cssFiles) {
1294
1342
  const css = await fs.readFile(file, "utf8");
1295
- for (const [, , url] of css.matchAll(woff2Re)) {
1296
- if (url !== "") seen.add(url);
1343
+ for (const [, body] of css.matchAll(FONT_FACE_RE)) {
1344
+ const src = SRC_URL_RE.exec(body ?? "");
1345
+ const url = src == null ? void 0 : src[2];
1346
+ if (!url) continue;
1347
+ if (!/^(https?:\/\/|\/)/.test(url)) continue;
1348
+ const family = (((_a = /font-family\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _a[1]) ?? "").trim().replace(/^["']|["']$/g, "");
1349
+ const style = (((_b = /font-style\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _b[1]) ?? "normal").trim();
1350
+ const weight = (((_c = /font-weight\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _c[1]) ?? "400").trim();
1351
+ const rangeRaw = (_e = (_d = /unicode-range\s*:\s*([^;]+)/i.exec(body)) == null ? void 0 : _d[1]) == null ? void 0 : _e.trim();
1352
+ const key = `${family}|${style}|${weight}`;
1353
+ const list = groups.get(key) ?? [];
1354
+ if (list.some((candidate) => candidate.url === url)) continue;
1355
+ list.push({
1356
+ family,
1357
+ style,
1358
+ weight,
1359
+ url,
1360
+ hasRange: Boolean(rangeRaw),
1361
+ coversLatin: rangeRaw ? rangeCoversLatin(rangeRaw) : true
1362
+ });
1363
+ groups.set(key, list);
1297
1364
  }
1298
1365
  }
1299
- return [...seen].map((href) => `<link rel="preload" as="font" type="font/woff2" crossorigin href="${href}">`).join("\n");
1366
+ const picked = [];
1367
+ const seen = /* @__PURE__ */ new Set();
1368
+ for (const candidates of groups.values()) {
1369
+ const choice = candidates.find((candidate) => candidate.coversLatin) ?? (candidates.every((candidate) => candidate.hasRange) ? void 0 : candidates[0]);
1370
+ if (!choice || seen.has(choice.url)) continue;
1371
+ seen.add(choice.url);
1372
+ picked.push(choice.url);
1373
+ }
1374
+ const fontTags = picked.map((href) => `<link rel="preload" as="font" type="font/woff2" crossorigin href="${href}">`);
1375
+ return [...await cssImportHints(cssFiles), ...fontTags].join("\n");
1300
1376
  }
1301
1377
  function injectIntoTemplate(template, head, appHtml, fontPreloads, htmlAttrs = "", teleports = {}) {
1302
1378
  let out = template;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/blox",
3
3
  "type": "module",
4
- "version": "1.15.673",
4
+ "version": "1.15.674",
5
5
  "description": "Blox page builder library for drag-and-drop page building and static data management",
6
6
  "author": {
7
7
  "name": "Bagel Studio",