@bagelink/blox 1.15.228 → 1.15.232
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/dist/{prerender-FPRGhRSk.js → prerender-DnqZAE4x.js} +249 -19
- package/dist/{prerender-CD3vMqn6.cjs → prerender-jcemLPiq.cjs} +243 -13
- package/dist/ssg/cli.cjs +22 -2
- package/dist/ssg/cli.mjs +22 -2
- package/dist/ssg/createSSREntry.d.ts.map +1 -1
- package/dist/ssg/index.cjs +39 -5
- package/dist/ssg/index.d.ts +2 -0
- package/dist/ssg/index.d.ts.map +1 -1
- package/dist/ssg/index.mjs +48 -14
- package/dist/ssg/llm-artifacts.d.ts +107 -0
- package/dist/ssg/llm-artifacts.d.ts.map +1 -0
- package/dist/ssg/prerender.d.ts +14 -3
- package/dist/ssg/prerender.d.ts.map +1 -1
- package/dist/ssg/render-resolved-page.d.ts +4 -0
- package/dist/ssg/render-resolved-page.d.ts.map +1 -1
- package/dist/ssg/seo.d.ts +24 -0
- package/dist/ssg/seo.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -329,16 +329,23 @@ function extractPrimaryContext(contexts) {
|
|
|
329
329
|
if (!contexts || typeof contexts !== "object") return empty;
|
|
330
330
|
const ctx = Object.values(contexts).find((c) => c != null);
|
|
331
331
|
if (!ctx) return empty;
|
|
332
|
-
const
|
|
332
|
+
const str2 = (key) => {
|
|
333
333
|
const v = ctx[key];
|
|
334
334
|
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
335
335
|
};
|
|
336
336
|
return {
|
|
337
|
-
title:
|
|
338
|
-
description:
|
|
339
|
-
image:
|
|
337
|
+
title: str2("meta_title") || str2("title"),
|
|
338
|
+
description: str2("meta_description") || str2("excerpt") || str2("description") || str2("blurb") || str2("summary"),
|
|
339
|
+
image: str2("og_image") || str2("cover_image_url") || str2("image_url") || str2("image")
|
|
340
340
|
};
|
|
341
341
|
}
|
|
342
|
+
function primaryContextEntry(contexts) {
|
|
343
|
+
if (!contexts || typeof contexts !== "object") return null;
|
|
344
|
+
for (const [key, ctx] of Object.entries(contexts)) {
|
|
345
|
+
if (ctx != null && typeof ctx === "object") return { key, ctx };
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
342
349
|
function esc(s) {
|
|
343
350
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
344
351
|
}
|
|
@@ -350,6 +357,196 @@ function absUrl(value) {
|
|
|
350
357
|
if (/^(https?:)?\/\//i.test(v) || v.startsWith("/")) return v;
|
|
351
358
|
return `${FILES_BASE_URL}/${v.replace(/^\/+/, "")}`;
|
|
352
359
|
}
|
|
360
|
+
function typeFromContextKey(key) {
|
|
361
|
+
const k = key.replace(/^\$/, "").toLowerCase();
|
|
362
|
+
if (/(post|article|blog|story|news)/.test(k)) return "Article";
|
|
363
|
+
if (/(product|listing|item|sku)/.test(k)) return "Product";
|
|
364
|
+
if (/(event|session|webinar)/.test(k)) return "Event";
|
|
365
|
+
return "WebPage";
|
|
366
|
+
}
|
|
367
|
+
function str(o, ...keys) {
|
|
368
|
+
for (const key of keys) {
|
|
369
|
+
const v = o[key];
|
|
370
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
371
|
+
}
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
function breadcrumbList(url, base, siteName) {
|
|
375
|
+
const segs = url.split("/").filter(Boolean);
|
|
376
|
+
const items = [
|
|
377
|
+
{ "@type": "ListItem", "position": 1, "name": siteName || "Home", "item": base || "/" }
|
|
378
|
+
];
|
|
379
|
+
let acc = "";
|
|
380
|
+
segs.forEach((seg, i) => {
|
|
381
|
+
acc += `/${seg}`;
|
|
382
|
+
items.push({
|
|
383
|
+
"@type": "ListItem",
|
|
384
|
+
"position": i + 2,
|
|
385
|
+
"name": decodeURIComponent(seg).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
386
|
+
"item": base ? base + acc : acc
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
return { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": items };
|
|
390
|
+
}
|
|
391
|
+
function buildJsonLd(options) {
|
|
392
|
+
var _a;
|
|
393
|
+
const { url, page, website, contextKey, context, config } = options;
|
|
394
|
+
const seo = (website == null ? void 0 : website.seo) ?? {};
|
|
395
|
+
const base = (seo.canonical_base_url || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
|
|
396
|
+
const siteName = seo.site_name || void 0;
|
|
397
|
+
const pageUrl = base ? base + url : url;
|
|
398
|
+
const title = (page == null ? void 0 : page.meta_title) || (page == null ? void 0 : page.title) || str(context ?? {}, "meta_title", "title") || seo.default_meta_title;
|
|
399
|
+
const description = (page == null ? void 0 : page.meta_description) || str(context ?? {}, "meta_description", "excerpt", "description", "summary") || seo.default_meta_description;
|
|
400
|
+
const graphs = [];
|
|
401
|
+
const webPage = { "@context": "https://schema.org", "@type": "WebPage", "url": pageUrl };
|
|
402
|
+
if (title) webPage.name = title;
|
|
403
|
+
if (description) webPage.description = description;
|
|
404
|
+
if (siteName) webPage.isPartOf = { "@type": "WebSite", "name": siteName, "url": base || void 0 };
|
|
405
|
+
graphs.push(webPage);
|
|
406
|
+
if (url && url !== "/") graphs.push(breadcrumbList(url, base, siteName));
|
|
407
|
+
if (contextKey && context) {
|
|
408
|
+
const type = ((_a = config == null ? void 0 : config.typeMap) == null ? void 0 : _a[contextKey]) || typeFromContextKey(contextKey);
|
|
409
|
+
const entity = { "@context": "https://schema.org", "@type": type, "url": pageUrl };
|
|
410
|
+
const name = str(context, "title", "name", "meta_title");
|
|
411
|
+
const desc = str(context, "meta_description", "excerpt", "description", "summary", "blurb");
|
|
412
|
+
const image = str(context, "og_image", "cover_image_url", "image_url", "image");
|
|
413
|
+
if (name) entity.name = name;
|
|
414
|
+
if (desc) entity.description = desc;
|
|
415
|
+
if (image) entity.image = image;
|
|
416
|
+
if (type === "Article") {
|
|
417
|
+
if (siteName) entity.publisher = { "@type": "Organization", "name": siteName };
|
|
418
|
+
const date = str(context, "published_at", "created_at", "date");
|
|
419
|
+
if (date) entity.datePublished = date;
|
|
420
|
+
const upd = str(context, "updated_at", "modified_at");
|
|
421
|
+
if (upd) entity.dateModified = upd;
|
|
422
|
+
const author = str(context, "author", "author_name");
|
|
423
|
+
if (author) entity.author = { "@type": "Person", "name": author };
|
|
424
|
+
if (name) {
|
|
425
|
+
entity.headline = name;
|
|
426
|
+
delete entity.name;
|
|
427
|
+
}
|
|
428
|
+
} else if (type === "Product") {
|
|
429
|
+
const price = str(context, "price", "amount");
|
|
430
|
+
const currency = str(context, "currency", "currency_code") || "USD";
|
|
431
|
+
if (price) {
|
|
432
|
+
entity.offers = { "@type": "Offer", "price": price, "priceCurrency": currency, "url": pageUrl };
|
|
433
|
+
}
|
|
434
|
+
const sku = str(context, "sku", "id");
|
|
435
|
+
if (sku) entity.sku = sku;
|
|
436
|
+
} else if (type === "Event") {
|
|
437
|
+
const start = str(context, "start_at", "starts_at", "start_date", "date");
|
|
438
|
+
const end = str(context, "end_at", "ends_at", "end_date");
|
|
439
|
+
if (start) entity.startDate = start;
|
|
440
|
+
if (end) entity.endDate = end;
|
|
441
|
+
const loc = str(context, "location", "venue", "address");
|
|
442
|
+
if (loc) entity.location = { "@type": "Place", "name": loc };
|
|
443
|
+
}
|
|
444
|
+
graphs.push(entity);
|
|
445
|
+
}
|
|
446
|
+
return graphs.map((g) => `<script type="application/ld+json">${JSON.stringify(g)}${"<"}/script>`).join("\n");
|
|
447
|
+
}
|
|
448
|
+
function generateLlmsTxt(options) {
|
|
449
|
+
var _a;
|
|
450
|
+
const { website, pages, config } = options;
|
|
451
|
+
const seo = (website == null ? void 0 : website.seo) ?? {};
|
|
452
|
+
const base = (seo.canonical_base_url || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
|
|
453
|
+
const siteName = seo.site_name || (website == null ? void 0 : website.name) || "Website";
|
|
454
|
+
const summary = seo.default_meta_description;
|
|
455
|
+
const visible = pages.filter((p) => !isPathExcluded(p.url, config == null ? void 0 : config.excludePaths)).sort((a, b) => a.url.localeCompare(b.url));
|
|
456
|
+
const lines = [`# ${siteName}`, ""];
|
|
457
|
+
if (summary) lines.push(`> ${summary}`, "");
|
|
458
|
+
if (config == null ? void 0 : config.intro) lines.push(config.intro.trim(), "");
|
|
459
|
+
const abs = (u) => base ? base + u : u;
|
|
460
|
+
const link = (p) => {
|
|
461
|
+
const label = p.title || p.url;
|
|
462
|
+
const desc = p.description ? `: ${p.description}` : "";
|
|
463
|
+
return `- [${label}](${abs(p.url)})${desc}`;
|
|
464
|
+
};
|
|
465
|
+
const used = /* @__PURE__ */ new Set();
|
|
466
|
+
for (const section of (config == null ? void 0 : config.sections) ?? []) {
|
|
467
|
+
const inSection = visible.filter((p) => p.url.startsWith(section.prefix));
|
|
468
|
+
if (inSection.length === 0) continue;
|
|
469
|
+
lines.push(`## ${section.title}`, "");
|
|
470
|
+
for (const p of inSection) {
|
|
471
|
+
lines.push(link(p));
|
|
472
|
+
used.add(p.url);
|
|
473
|
+
}
|
|
474
|
+
lines.push("");
|
|
475
|
+
}
|
|
476
|
+
const rest = visible.filter((p) => !used.has(p.url));
|
|
477
|
+
if (rest.length > 0) {
|
|
478
|
+
lines.push(((_a = config == null ? void 0 : config.sections) == null ? void 0 : _a.length) ? "## Pages" : "## Pages", "");
|
|
479
|
+
for (const p of rest) lines.push(link(p));
|
|
480
|
+
lines.push("");
|
|
481
|
+
}
|
|
482
|
+
return `${lines.join("\n").trimEnd()}
|
|
483
|
+
`;
|
|
484
|
+
}
|
|
485
|
+
function generateLlmsFullTxt(options) {
|
|
486
|
+
const { website, pages, config } = options;
|
|
487
|
+
const seo = (website == null ? void 0 : website.seo) ?? {};
|
|
488
|
+
const base = (seo.canonical_base_url || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
|
|
489
|
+
const siteName = seo.site_name || (website == null ? void 0 : website.name) || "Website";
|
|
490
|
+
const visible = pages.filter((p) => !isPathExcluded(p.url, config == null ? void 0 : config.excludePaths)).filter((p) => p.text && p.text.trim()).sort((a, b) => a.url.localeCompare(b.url));
|
|
491
|
+
const blocks = [`# ${siteName}`, ""];
|
|
492
|
+
for (const p of visible) {
|
|
493
|
+
const abs = base ? base + p.url : p.url;
|
|
494
|
+
blocks.push(`## ${p.title || p.url}`, "", `Source: ${abs}`, "");
|
|
495
|
+
if (p.description) blocks.push(`> ${p.description}`, "");
|
|
496
|
+
blocks.push(p.text.trim(), "", "---", "");
|
|
497
|
+
}
|
|
498
|
+
return `${blocks.join("\n").trimEnd()}
|
|
499
|
+
`;
|
|
500
|
+
}
|
|
501
|
+
function extractPageText(html) {
|
|
502
|
+
if (!html) return "";
|
|
503
|
+
let s = html;
|
|
504
|
+
s = s.replace(/<(script|style|noscript|svg|template)\b[^>]*>[\s\S]*?<\/\1>/gi, " ");
|
|
505
|
+
s = s.replace(/<(nav|header|footer)\b[^>]*>[\s\S]*?<\/\1>/gi, " ");
|
|
506
|
+
s = s.replace(/<h1\b[^>]*>/gi, "\n\n# ").replace(/<h2\b[^>]*>/gi, "\n\n## ").replace(/<h3\b[^>]*>/gi, "\n\n### ").replace(/<(h4|h5|h6)\b[^>]*>/gi, "\n\n#### ");
|
|
507
|
+
s = s.replace(/<li\b[^>]*>/gi, "\n- ");
|
|
508
|
+
s = s.replace(/<(\/p|\/div|\/section|\/article|br\s*\/?|\/li|\/h[1-6])>/gi, "\n");
|
|
509
|
+
s = s.replace(/<[^>]+>/g, " ");
|
|
510
|
+
s = s.replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'");
|
|
511
|
+
s = s.split("\n").map((l) => l.replace(/[ \t]+/g, " ").trim()).join("\n");
|
|
512
|
+
s = s.replace(/\n{3,}/g, "\n\n").trim();
|
|
513
|
+
return s;
|
|
514
|
+
}
|
|
515
|
+
function isPathExcluded(path2, patterns) {
|
|
516
|
+
if (!patterns || patterns.length === 0) return false;
|
|
517
|
+
return patterns.some((p) => {
|
|
518
|
+
if (p.endsWith("*")) return path2.startsWith(p.slice(0, -1));
|
|
519
|
+
return path2 === p;
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
async function mergeLlmParts(options) {
|
|
523
|
+
const fs2 = await import("node:fs/promises");
|
|
524
|
+
const path2 = await import("node:path");
|
|
525
|
+
const byUrl = /* @__PURE__ */ new Map();
|
|
526
|
+
for (const file of options.partFiles) {
|
|
527
|
+
try {
|
|
528
|
+
const raw = await fs2.readFile(file, "utf8");
|
|
529
|
+
const arr = JSON.parse(raw);
|
|
530
|
+
for (const e of arr) if (e == null ? void 0 : e.url) byUrl.set(e.url, e);
|
|
531
|
+
} catch {
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const pages = [...byUrl.values()];
|
|
535
|
+
const { website, config } = options;
|
|
536
|
+
const llmsTxt = generateLlmsTxt({ website, pages, config });
|
|
537
|
+
await fs2.writeFile(path2.join(options.outDir, "llms.txt"), llmsTxt, "utf8");
|
|
538
|
+
if ((config == null ? void 0 : config.fullText) !== false) {
|
|
539
|
+
const full = generateLlmsFullTxt({ website, pages, config });
|
|
540
|
+
await fs2.writeFile(path2.join(options.outDir, "llms-full.txt"), full, "utf8");
|
|
541
|
+
}
|
|
542
|
+
for (const file of options.partFiles) {
|
|
543
|
+
try {
|
|
544
|
+
await fs2.unlink(file);
|
|
545
|
+
} catch {
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return { pages: pages.length };
|
|
549
|
+
}
|
|
353
550
|
async function prerender({
|
|
354
551
|
root = process.cwd(),
|
|
355
552
|
clientOutDir = "dist/client",
|
|
@@ -364,15 +561,20 @@ async function prerender({
|
|
|
364
561
|
/**
|
|
365
562
|
* How many `/resolve-path` prefetches to run in parallel, ahead of the render
|
|
366
563
|
* pool. Decouples the (I/O-bound) resolve latency from the (CPU-bound) render
|
|
367
|
-
* so pages render from an in-memory cache with no per-page round-trip.
|
|
368
|
-
*
|
|
564
|
+
* so pages render from an in-memory cache with no per-page round-trip.
|
|
565
|
+
*
|
|
566
|
+
* NOTE: this is PER PROCESS. When running N shards, the *total* load on the
|
|
567
|
+
* API is `N × this`, so keep it modest (a small API saturates ~5-wide). The
|
|
568
|
+
* sharded runner divides a global budget by the shard count. 0 disables
|
|
569
|
+
* prefetch (render resolves inline). Default 8.
|
|
369
570
|
*/
|
|
370
|
-
resolvePrefetchConcurrency =
|
|
571
|
+
resolvePrefetchConcurrency = 8,
|
|
371
572
|
mode = "dir",
|
|
372
573
|
website = null,
|
|
373
574
|
websiteId = "",
|
|
374
575
|
redirects = [],
|
|
375
|
-
collections = {}
|
|
576
|
+
collections = {},
|
|
577
|
+
llm = {}
|
|
376
578
|
} = {}) {
|
|
377
579
|
var _a, _b;
|
|
378
580
|
const absRoot = path.resolve(root);
|
|
@@ -407,6 +609,8 @@ async function prerender({
|
|
|
407
609
|
const rendered = [];
|
|
408
610
|
const noindexPaths = /* @__PURE__ */ new Set();
|
|
409
611
|
const lastmod = {};
|
|
612
|
+
const llmPages = [];
|
|
613
|
+
const llmEnabled = llm.enabled !== false;
|
|
410
614
|
const failures = [];
|
|
411
615
|
const resolveCache = /* @__PURE__ */ new Map();
|
|
412
616
|
const prefetch = serverMod.prefetchResolve;
|
|
@@ -434,14 +638,16 @@ async function prerender({
|
|
|
434
638
|
html,
|
|
435
639
|
head = "",
|
|
436
640
|
htmlAttrs = "",
|
|
437
|
-
lastmod: pageLastmod
|
|
641
|
+
lastmod: pageLastmod,
|
|
642
|
+
llm: pageLlm
|
|
438
643
|
} = await serverMod.render(urlPath, {
|
|
439
644
|
manifest,
|
|
440
645
|
template,
|
|
441
646
|
website,
|
|
442
647
|
websiteId,
|
|
443
648
|
collections,
|
|
444
|
-
resolveCache
|
|
649
|
+
resolveCache,
|
|
650
|
+
llm
|
|
445
651
|
});
|
|
446
652
|
const outHtml = injectIntoTemplate(template, head, html, fontPreloads, htmlAttrs);
|
|
447
653
|
const outfile = outFilePath(absClient, urlPath, mode);
|
|
@@ -449,6 +655,7 @@ async function prerender({
|
|
|
449
655
|
await fs.writeFile(outfile, outHtml, "utf8");
|
|
450
656
|
rendered.push(urlPath);
|
|
451
657
|
if (pageLastmod) lastmod[urlPath] = pageLastmod;
|
|
658
|
+
if (llmEnabled && pageLlm) llmPages.push(pageLlm);
|
|
452
659
|
if (/<meta[^>]+name=["']robots["'][^>]*noindex/i.test(head)) {
|
|
453
660
|
noindexPaths.add(urlPath);
|
|
454
661
|
}
|
|
@@ -478,7 +685,8 @@ async function prerender({
|
|
|
478
685
|
}
|
|
479
686
|
}
|
|
480
687
|
}
|
|
481
|
-
|
|
688
|
+
await runResolvePrefetch().catch(() => {
|
|
689
|
+
});
|
|
482
690
|
while (queue.length && !stopped && rendered.length < maxPages) {
|
|
483
691
|
const workers = Array.from(
|
|
484
692
|
{ length: Math.min(concurrency, queue.length) },
|
|
@@ -486,8 +694,6 @@ async function prerender({
|
|
|
486
694
|
);
|
|
487
695
|
await Promise.all(workers);
|
|
488
696
|
}
|
|
489
|
-
await prefetchDone.catch(() => {
|
|
490
|
-
});
|
|
491
697
|
const canonicalBase = (((_a = website == null ? void 0 : website.seo) == null ? void 0 : _a.canonical_base_url) || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
|
|
492
698
|
if (writeSharedAssets) {
|
|
493
699
|
const sitemapPaths = rendered.filter((p) => !noindexPaths.has(p));
|
|
@@ -515,6 +721,24 @@ async function prerender({
|
|
|
515
721
|
await fs.writeFile(redirectsPath, redirectsContent + existing, "utf8");
|
|
516
722
|
console.log(` Generated _redirects (${redirects.length} rules)`);
|
|
517
723
|
}
|
|
724
|
+
if (llmEnabled && llm.writeIndex !== false && llmPages.length > 0) {
|
|
725
|
+
const indexable = llmPages.filter((p) => !noindexPaths.has(p.url));
|
|
726
|
+
const llmsTxt = generateLlmsTxt({ website, pages: indexable, config: llm });
|
|
727
|
+
await fs.writeFile(path.join(absClient, "llms.txt"), llmsTxt, "utf8");
|
|
728
|
+
console.log(` Generated llms.txt (${indexable.length} pages)`);
|
|
729
|
+
if (llm.fullText !== false) {
|
|
730
|
+
const full = generateLlmsFullTxt({ website, pages: indexable, config: llm });
|
|
731
|
+
await fs.writeFile(path.join(absClient, "llms-full.txt"), full, "utf8");
|
|
732
|
+
console.log(" Generated llms-full.txt");
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (llmEnabled && llm.partsFile && llmPages.length > 0) {
|
|
737
|
+
const indexable = llmPages.filter((p) => !noindexPaths.has(p.url));
|
|
738
|
+
const partPath = path.resolve(absRoot, llm.partsFile);
|
|
739
|
+
await fs.mkdir(path.dirname(partPath), { recursive: true });
|
|
740
|
+
await fs.writeFile(partPath, JSON.stringify(indexable), "utf8");
|
|
741
|
+
console.log(` Wrote ${indexable.length} llm page extract(s) → ${llm.partsFile}`);
|
|
518
742
|
}
|
|
519
743
|
return {
|
|
520
744
|
rendered,
|
|
@@ -650,12 +874,18 @@ function discoverInternalLinks(html) {
|
|
|
650
874
|
export {
|
|
651
875
|
prerender as a,
|
|
652
876
|
buildPageHead as b,
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
877
|
+
primaryContextEntry as c,
|
|
878
|
+
buildJsonLd as d,
|
|
879
|
+
extractPageText as e,
|
|
656
880
|
fetchCmsSiteData as f,
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
881
|
+
buildSiteHead as g,
|
|
882
|
+
fetchCmsPrerenderPaths as h,
|
|
883
|
+
generateLlmsFullTxt as i,
|
|
884
|
+
generateLlmsTxt as j,
|
|
885
|
+
generateNetlifyRedirects as k,
|
|
886
|
+
generateRobotsTxt as l,
|
|
887
|
+
generateSitemapXml as m,
|
|
888
|
+
getSiteIconFlags as n,
|
|
889
|
+
mergeLlmParts as o,
|
|
660
890
|
polyfillBloxSsgGlobals as p
|
|
661
891
|
};
|