@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.
@@ -352,16 +352,23 @@ function extractPrimaryContext(contexts) {
352
352
  if (!contexts || typeof contexts !== "object") return empty;
353
353
  const ctx = Object.values(contexts).find((c) => c != null);
354
354
  if (!ctx) return empty;
355
- const str = (key) => {
355
+ const str2 = (key) => {
356
356
  const v = ctx[key];
357
357
  return typeof v === "string" && v.trim() ? v.trim() : null;
358
358
  };
359
359
  return {
360
- title: str("meta_title") || str("title"),
361
- description: str("meta_description") || str("excerpt") || str("description") || str("blurb") || str("summary"),
362
- image: str("og_image") || str("cover_image_url") || str("image_url") || str("image")
360
+ title: str2("meta_title") || str2("title"),
361
+ description: str2("meta_description") || str2("excerpt") || str2("description") || str2("blurb") || str2("summary"),
362
+ image: str2("og_image") || str2("cover_image_url") || str2("image_url") || str2("image")
363
363
  };
364
364
  }
365
+ function primaryContextEntry(contexts) {
366
+ if (!contexts || typeof contexts !== "object") return null;
367
+ for (const [key, ctx] of Object.entries(contexts)) {
368
+ if (ctx != null && typeof ctx === "object") return { key, ctx };
369
+ }
370
+ return null;
371
+ }
365
372
  function esc(s) {
366
373
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
367
374
  }
@@ -373,6 +380,196 @@ function absUrl(value) {
373
380
  if (/^(https?:)?\/\//i.test(v) || v.startsWith("/")) return v;
374
381
  return `${FILES_BASE_URL}/${v.replace(/^\/+/, "")}`;
375
382
  }
383
+ function typeFromContextKey(key) {
384
+ const k = key.replace(/^\$/, "").toLowerCase();
385
+ if (/(post|article|blog|story|news)/.test(k)) return "Article";
386
+ if (/(product|listing|item|sku)/.test(k)) return "Product";
387
+ if (/(event|session|webinar)/.test(k)) return "Event";
388
+ return "WebPage";
389
+ }
390
+ function str(o, ...keys) {
391
+ for (const key of keys) {
392
+ const v = o[key];
393
+ if (typeof v === "string" && v.trim()) return v.trim();
394
+ }
395
+ return void 0;
396
+ }
397
+ function breadcrumbList(url, base, siteName) {
398
+ const segs = url.split("/").filter(Boolean);
399
+ const items = [
400
+ { "@type": "ListItem", "position": 1, "name": siteName || "Home", "item": base || "/" }
401
+ ];
402
+ let acc = "";
403
+ segs.forEach((seg, i) => {
404
+ acc += `/${seg}`;
405
+ items.push({
406
+ "@type": "ListItem",
407
+ "position": i + 2,
408
+ "name": decodeURIComponent(seg).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
409
+ "item": base ? base + acc : acc
410
+ });
411
+ });
412
+ return { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": items };
413
+ }
414
+ function buildJsonLd(options) {
415
+ var _a;
416
+ const { url, page, website, contextKey, context, config } = options;
417
+ const seo = (website == null ? void 0 : website.seo) ?? {};
418
+ const base = (seo.canonical_base_url || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
419
+ const siteName = seo.site_name || void 0;
420
+ const pageUrl = base ? base + url : url;
421
+ const title = (page == null ? void 0 : page.meta_title) || (page == null ? void 0 : page.title) || str(context ?? {}, "meta_title", "title") || seo.default_meta_title;
422
+ const description = (page == null ? void 0 : page.meta_description) || str(context ?? {}, "meta_description", "excerpt", "description", "summary") || seo.default_meta_description;
423
+ const graphs = [];
424
+ const webPage = { "@context": "https://schema.org", "@type": "WebPage", "url": pageUrl };
425
+ if (title) webPage.name = title;
426
+ if (description) webPage.description = description;
427
+ if (siteName) webPage.isPartOf = { "@type": "WebSite", "name": siteName, "url": base || void 0 };
428
+ graphs.push(webPage);
429
+ if (url && url !== "/") graphs.push(breadcrumbList(url, base, siteName));
430
+ if (contextKey && context) {
431
+ const type = ((_a = config == null ? void 0 : config.typeMap) == null ? void 0 : _a[contextKey]) || typeFromContextKey(contextKey);
432
+ const entity = { "@context": "https://schema.org", "@type": type, "url": pageUrl };
433
+ const name = str(context, "title", "name", "meta_title");
434
+ const desc = str(context, "meta_description", "excerpt", "description", "summary", "blurb");
435
+ const image = str(context, "og_image", "cover_image_url", "image_url", "image");
436
+ if (name) entity.name = name;
437
+ if (desc) entity.description = desc;
438
+ if (image) entity.image = image;
439
+ if (type === "Article") {
440
+ if (siteName) entity.publisher = { "@type": "Organization", "name": siteName };
441
+ const date = str(context, "published_at", "created_at", "date");
442
+ if (date) entity.datePublished = date;
443
+ const upd = str(context, "updated_at", "modified_at");
444
+ if (upd) entity.dateModified = upd;
445
+ const author = str(context, "author", "author_name");
446
+ if (author) entity.author = { "@type": "Person", "name": author };
447
+ if (name) {
448
+ entity.headline = name;
449
+ delete entity.name;
450
+ }
451
+ } else if (type === "Product") {
452
+ const price = str(context, "price", "amount");
453
+ const currency = str(context, "currency", "currency_code") || "USD";
454
+ if (price) {
455
+ entity.offers = { "@type": "Offer", "price": price, "priceCurrency": currency, "url": pageUrl };
456
+ }
457
+ const sku = str(context, "sku", "id");
458
+ if (sku) entity.sku = sku;
459
+ } else if (type === "Event") {
460
+ const start = str(context, "start_at", "starts_at", "start_date", "date");
461
+ const end = str(context, "end_at", "ends_at", "end_date");
462
+ if (start) entity.startDate = start;
463
+ if (end) entity.endDate = end;
464
+ const loc = str(context, "location", "venue", "address");
465
+ if (loc) entity.location = { "@type": "Place", "name": loc };
466
+ }
467
+ graphs.push(entity);
468
+ }
469
+ return graphs.map((g) => `<script type="application/ld+json">${JSON.stringify(g)}${"<"}/script>`).join("\n");
470
+ }
471
+ function generateLlmsTxt(options) {
472
+ var _a;
473
+ const { website, pages, config } = options;
474
+ const seo = (website == null ? void 0 : website.seo) ?? {};
475
+ const base = (seo.canonical_base_url || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
476
+ const siteName = seo.site_name || (website == null ? void 0 : website.name) || "Website";
477
+ const summary = seo.default_meta_description;
478
+ const visible = pages.filter((p) => !isPathExcluded(p.url, config == null ? void 0 : config.excludePaths)).sort((a, b) => a.url.localeCompare(b.url));
479
+ const lines = [`# ${siteName}`, ""];
480
+ if (summary) lines.push(`> ${summary}`, "");
481
+ if (config == null ? void 0 : config.intro) lines.push(config.intro.trim(), "");
482
+ const abs = (u) => base ? base + u : u;
483
+ const link = (p) => {
484
+ const label = p.title || p.url;
485
+ const desc = p.description ? `: ${p.description}` : "";
486
+ return `- [${label}](${abs(p.url)})${desc}`;
487
+ };
488
+ const used = /* @__PURE__ */ new Set();
489
+ for (const section of (config == null ? void 0 : config.sections) ?? []) {
490
+ const inSection = visible.filter((p) => p.url.startsWith(section.prefix));
491
+ if (inSection.length === 0) continue;
492
+ lines.push(`## ${section.title}`, "");
493
+ for (const p of inSection) {
494
+ lines.push(link(p));
495
+ used.add(p.url);
496
+ }
497
+ lines.push("");
498
+ }
499
+ const rest = visible.filter((p) => !used.has(p.url));
500
+ if (rest.length > 0) {
501
+ lines.push(((_a = config == null ? void 0 : config.sections) == null ? void 0 : _a.length) ? "## Pages" : "## Pages", "");
502
+ for (const p of rest) lines.push(link(p));
503
+ lines.push("");
504
+ }
505
+ return `${lines.join("\n").trimEnd()}
506
+ `;
507
+ }
508
+ function generateLlmsFullTxt(options) {
509
+ const { website, pages, config } = options;
510
+ const seo = (website == null ? void 0 : website.seo) ?? {};
511
+ const base = (seo.canonical_base_url || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
512
+ const siteName = seo.site_name || (website == null ? void 0 : website.name) || "Website";
513
+ 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));
514
+ const blocks = [`# ${siteName}`, ""];
515
+ for (const p of visible) {
516
+ const abs = base ? base + p.url : p.url;
517
+ blocks.push(`## ${p.title || p.url}`, "", `Source: ${abs}`, "");
518
+ if (p.description) blocks.push(`> ${p.description}`, "");
519
+ blocks.push(p.text.trim(), "", "---", "");
520
+ }
521
+ return `${blocks.join("\n").trimEnd()}
522
+ `;
523
+ }
524
+ function extractPageText(html) {
525
+ if (!html) return "";
526
+ let s = html;
527
+ s = s.replace(/<(script|style|noscript|svg|template)\b[^>]*>[\s\S]*?<\/\1>/gi, " ");
528
+ s = s.replace(/<(nav|header|footer)\b[^>]*>[\s\S]*?<\/\1>/gi, " ");
529
+ 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#### ");
530
+ s = s.replace(/<li\b[^>]*>/gi, "\n- ");
531
+ s = s.replace(/<(\/p|\/div|\/section|\/article|br\s*\/?|\/li|\/h[1-6])>/gi, "\n");
532
+ s = s.replace(/<[^>]+>/g, " ");
533
+ s = s.replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'");
534
+ s = s.split("\n").map((l) => l.replace(/[ \t]+/g, " ").trim()).join("\n");
535
+ s = s.replace(/\n{3,}/g, "\n\n").trim();
536
+ return s;
537
+ }
538
+ function isPathExcluded(path2, patterns) {
539
+ if (!patterns || patterns.length === 0) return false;
540
+ return patterns.some((p) => {
541
+ if (p.endsWith("*")) return path2.startsWith(p.slice(0, -1));
542
+ return path2 === p;
543
+ });
544
+ }
545
+ async function mergeLlmParts(options) {
546
+ const fs2 = await import("node:fs/promises");
547
+ const path2 = await import("node:path");
548
+ const byUrl = /* @__PURE__ */ new Map();
549
+ for (const file of options.partFiles) {
550
+ try {
551
+ const raw = await fs2.readFile(file, "utf8");
552
+ const arr = JSON.parse(raw);
553
+ for (const e of arr) if (e == null ? void 0 : e.url) byUrl.set(e.url, e);
554
+ } catch {
555
+ }
556
+ }
557
+ const pages = [...byUrl.values()];
558
+ const { website, config } = options;
559
+ const llmsTxt = generateLlmsTxt({ website, pages, config });
560
+ await fs2.writeFile(path2.join(options.outDir, "llms.txt"), llmsTxt, "utf8");
561
+ if ((config == null ? void 0 : config.fullText) !== false) {
562
+ const full = generateLlmsFullTxt({ website, pages, config });
563
+ await fs2.writeFile(path2.join(options.outDir, "llms-full.txt"), full, "utf8");
564
+ }
565
+ for (const file of options.partFiles) {
566
+ try {
567
+ await fs2.unlink(file);
568
+ } catch {
569
+ }
570
+ }
571
+ return { pages: pages.length };
572
+ }
376
573
  async function prerender({
377
574
  root = process.cwd(),
378
575
  clientOutDir = "dist/client",
@@ -387,15 +584,20 @@ async function prerender({
387
584
  /**
388
585
  * How many `/resolve-path` prefetches to run in parallel, ahead of the render
389
586
  * pool. Decouples the (I/O-bound) resolve latency from the (CPU-bound) render
390
- * so pages render from an in-memory cache with no per-page round-trip. 0
391
- * disables prefetch (render resolves inline). Default 24.
587
+ * so pages render from an in-memory cache with no per-page round-trip.
588
+ *
589
+ * NOTE: this is PER PROCESS. When running N shards, the *total* load on the
590
+ * API is `N × this`, so keep it modest (a small API saturates ~5-wide). The
591
+ * sharded runner divides a global budget by the shard count. 0 disables
592
+ * prefetch (render resolves inline). Default 8.
392
593
  */
393
- resolvePrefetchConcurrency = 24,
594
+ resolvePrefetchConcurrency = 8,
394
595
  mode = "dir",
395
596
  website = null,
396
597
  websiteId = "",
397
598
  redirects = [],
398
- collections = {}
599
+ collections = {},
600
+ llm = {}
399
601
  } = {}) {
400
602
  var _a, _b;
401
603
  const absRoot = path.resolve(root);
@@ -430,6 +632,8 @@ async function prerender({
430
632
  const rendered = [];
431
633
  const noindexPaths = /* @__PURE__ */ new Set();
432
634
  const lastmod = {};
635
+ const llmPages = [];
636
+ const llmEnabled = llm.enabled !== false;
433
637
  const failures = [];
434
638
  const resolveCache = /* @__PURE__ */ new Map();
435
639
  const prefetch = serverMod.prefetchResolve;
@@ -457,14 +661,16 @@ async function prerender({
457
661
  html,
458
662
  head = "",
459
663
  htmlAttrs = "",
460
- lastmod: pageLastmod
664
+ lastmod: pageLastmod,
665
+ llm: pageLlm
461
666
  } = await serverMod.render(urlPath, {
462
667
  manifest,
463
668
  template,
464
669
  website,
465
670
  websiteId,
466
671
  collections,
467
- resolveCache
672
+ resolveCache,
673
+ llm
468
674
  });
469
675
  const outHtml = injectIntoTemplate(template, head, html, fontPreloads, htmlAttrs);
470
676
  const outfile = outFilePath(absClient, urlPath, mode);
@@ -472,6 +678,7 @@ async function prerender({
472
678
  await fs.writeFile(outfile, outHtml, "utf8");
473
679
  rendered.push(urlPath);
474
680
  if (pageLastmod) lastmod[urlPath] = pageLastmod;
681
+ if (llmEnabled && pageLlm) llmPages.push(pageLlm);
475
682
  if (/<meta[^>]+name=["']robots["'][^>]*noindex/i.test(head)) {
476
683
  noindexPaths.add(urlPath);
477
684
  }
@@ -501,7 +708,8 @@ async function prerender({
501
708
  }
502
709
  }
503
710
  }
504
- const prefetchDone = runResolvePrefetch();
711
+ await runResolvePrefetch().catch(() => {
712
+ });
505
713
  while (queue.length && !stopped && rendered.length < maxPages) {
506
714
  const workers = Array.from(
507
715
  { length: Math.min(concurrency, queue.length) },
@@ -509,8 +717,6 @@ async function prerender({
509
717
  );
510
718
  await Promise.all(workers);
511
719
  }
512
- await prefetchDone.catch(() => {
513
- });
514
720
  const canonicalBase = (((_a = website == null ? void 0 : website.seo) == null ? void 0 : _a.canonical_base_url) || (website == null ? void 0 : website.domain) || "").replace(/\/$/, "");
515
721
  if (writeSharedAssets) {
516
722
  const sitemapPaths = rendered.filter((p) => !noindexPaths.has(p));
@@ -538,6 +744,24 @@ async function prerender({
538
744
  await fs.writeFile(redirectsPath, redirectsContent + existing, "utf8");
539
745
  console.log(` Generated _redirects (${redirects.length} rules)`);
540
746
  }
747
+ if (llmEnabled && llm.writeIndex !== false && llmPages.length > 0) {
748
+ const indexable = llmPages.filter((p) => !noindexPaths.has(p.url));
749
+ const llmsTxt = generateLlmsTxt({ website, pages: indexable, config: llm });
750
+ await fs.writeFile(path.join(absClient, "llms.txt"), llmsTxt, "utf8");
751
+ console.log(` Generated llms.txt (${indexable.length} pages)`);
752
+ if (llm.fullText !== false) {
753
+ const full = generateLlmsFullTxt({ website, pages: indexable, config: llm });
754
+ await fs.writeFile(path.join(absClient, "llms-full.txt"), full, "utf8");
755
+ console.log(" Generated llms-full.txt");
756
+ }
757
+ }
758
+ }
759
+ if (llmEnabled && llm.partsFile && llmPages.length > 0) {
760
+ const indexable = llmPages.filter((p) => !noindexPaths.has(p.url));
761
+ const partPath = path.resolve(absRoot, llm.partsFile);
762
+ await fs.mkdir(path.dirname(partPath), { recursive: true });
763
+ await fs.writeFile(partPath, JSON.stringify(indexable), "utf8");
764
+ console.log(` Wrote ${indexable.length} llm page extract(s) → ${llm.partsFile}`);
541
765
  }
542
766
  return {
543
767
  rendered,
@@ -670,13 +894,19 @@ function discoverInternalLinks(html) {
670
894
  }
671
895
  return [...out];
672
896
  }
897
+ exports.buildJsonLd = buildJsonLd;
673
898
  exports.buildPageHead = buildPageHead;
674
899
  exports.buildSiteHead = buildSiteHead;
900
+ exports.extractPageText = extractPageText;
675
901
  exports.fetchCmsPrerenderPaths = fetchCmsPrerenderPaths;
676
902
  exports.fetchCmsSiteData = fetchCmsSiteData;
903
+ exports.generateLlmsFullTxt = generateLlmsFullTxt;
904
+ exports.generateLlmsTxt = generateLlmsTxt;
677
905
  exports.generateNetlifyRedirects = generateNetlifyRedirects;
678
906
  exports.generateRobotsTxt = generateRobotsTxt;
679
907
  exports.generateSitemapXml = generateSitemapXml;
680
908
  exports.getSiteIconFlags = getSiteIconFlags;
909
+ exports.mergeLlmParts = mergeLlmParts;
681
910
  exports.polyfillBloxSsgGlobals = polyfillBloxSsgGlobals;
682
911
  exports.prerender = prerender;
912
+ exports.primaryContextEntry = primaryContextEntry;
package/dist/ssg/cli.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  "use strict";
3
3
  const process = require("node:process");
4
- const prerender = require("../prerender-CD3vMqn6.cjs");
4
+ const prerender = require("../prerender-jcemLPiq.cjs");
5
5
  function installFetchTimeout() {
6
6
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
7
7
  const original = globalThis.fetch;
@@ -47,6 +47,7 @@ async function main() {
47
47
  let mode = "production";
48
48
  let shardIndex = 0;
49
49
  let shardTotal = 1;
50
+ let llmPartsFile = "";
50
51
  const excludePaths = ["/_blox_preview"];
51
52
  for (const a of argv) {
52
53
  if (a === "--crawl") {
@@ -82,6 +83,8 @@ Environment:
82
83
  mode = a.slice("--mode=".length);
83
84
  } else if (a.startsWith("--exclude=")) {
84
85
  excludePaths.push(a.slice("--exclude=".length));
86
+ } else if (a.startsWith("--llm-parts=")) {
87
+ llmPartsFile = a.slice("--llm-parts=".length);
85
88
  } else {
86
89
  extraPaths.push(a);
87
90
  }
@@ -156,6 +159,10 @@ Environment:
156
159
  // Bounded concurrency — configurable so we don't overwhelm a small
157
160
  // staging box. Defaults conservative; bump for beefy prod builds.
158
161
  concurrency: Number(process.env.BLOX_SSG_CONCURRENCY) || 4,
162
+ // Per-process resolve-prefetch parallelism. The sharded runner sets
163
+ // this to (global budget / shard count) so N shards don't collectively
164
+ // hammer a small API. 0 disables prefetch (inline resolve).
165
+ resolvePrefetchConcurrency: process.env.BLOX_SSG_PREFETCH !== void 0 ? Number(process.env.BLOX_SSG_PREFETCH) : 8,
159
166
  mode: "file",
160
167
  // Only shard 0 writes shared, whole-site assets (sitemap/robots/_redirects)
161
168
  // so parallel shards don't race/clobber them.
@@ -163,7 +170,20 @@ Environment:
163
170
  website,
164
171
  websiteId,
165
172
  redirects,
166
- collections
173
+ collections,
174
+ // LLM artifacts (llms.txt, llms-full.txt, per-page JSON-LD). On by
175
+ // default; opt out with BLOX_SSG_LLM=0. Skip the *file* artifacts when
176
+ // sharding (>1 shard) because the writing shard only has its own slice of
177
+ // pages — JSON-LD (per-page, in-head) is still emitted on every shard.
178
+ llm: {
179
+ enabled: process.env.BLOX_SSG_LLM !== "0",
180
+ // llms.txt/full need the FULL page list. Unsharded → write directly.
181
+ // Sharded → each shard writes a part file (via --llm-parts) and the
182
+ // coordinator merges them. Per-page JSON-LD is emitted on every shard.
183
+ writeIndex: shardTotal === 1 && !llmPartsFile,
184
+ partsFile: llmPartsFile || void 0,
185
+ fullText: process.env.BLOX_SSG_LLM_FULL !== "0"
186
+ }
167
187
  });
168
188
  const elapsed = ((Date.now() - startTime) / 1e3).toFixed(2);
169
189
  console.log(`
package/dist/ssg/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import process from "node:process";
3
- import { p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, a as prerender } from "../prerender-FPRGhRSk.js";
3
+ import { p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, a as prerender } from "../prerender-DnqZAE4x.js";
4
4
  function installFetchTimeout() {
5
5
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
6
6
  const original = globalThis.fetch;
@@ -46,6 +46,7 @@ async function main() {
46
46
  let mode = "production";
47
47
  let shardIndex = 0;
48
48
  let shardTotal = 1;
49
+ let llmPartsFile = "";
49
50
  const excludePaths = ["/_blox_preview"];
50
51
  for (const a of argv) {
51
52
  if (a === "--crawl") {
@@ -81,6 +82,8 @@ Environment:
81
82
  mode = a.slice("--mode=".length);
82
83
  } else if (a.startsWith("--exclude=")) {
83
84
  excludePaths.push(a.slice("--exclude=".length));
85
+ } else if (a.startsWith("--llm-parts=")) {
86
+ llmPartsFile = a.slice("--llm-parts=".length);
84
87
  } else {
85
88
  extraPaths.push(a);
86
89
  }
@@ -155,6 +158,10 @@ Environment:
155
158
  // Bounded concurrency — configurable so we don't overwhelm a small
156
159
  // staging box. Defaults conservative; bump for beefy prod builds.
157
160
  concurrency: Number(process.env.BLOX_SSG_CONCURRENCY) || 4,
161
+ // Per-process resolve-prefetch parallelism. The sharded runner sets
162
+ // this to (global budget / shard count) so N shards don't collectively
163
+ // hammer a small API. 0 disables prefetch (inline resolve).
164
+ resolvePrefetchConcurrency: process.env.BLOX_SSG_PREFETCH !== void 0 ? Number(process.env.BLOX_SSG_PREFETCH) : 8,
158
165
  mode: "file",
159
166
  // Only shard 0 writes shared, whole-site assets (sitemap/robots/_redirects)
160
167
  // so parallel shards don't race/clobber them.
@@ -162,7 +169,20 @@ Environment:
162
169
  website,
163
170
  websiteId,
164
171
  redirects,
165
- collections
172
+ collections,
173
+ // LLM artifacts (llms.txt, llms-full.txt, per-page JSON-LD). On by
174
+ // default; opt out with BLOX_SSG_LLM=0. Skip the *file* artifacts when
175
+ // sharding (>1 shard) because the writing shard only has its own slice of
176
+ // pages — JSON-LD (per-page, in-head) is still emitted on every shard.
177
+ llm: {
178
+ enabled: process.env.BLOX_SSG_LLM !== "0",
179
+ // llms.txt/full need the FULL page list. Unsharded → write directly.
180
+ // Sharded → each shard writes a part file (via --llm-parts) and the
181
+ // coordinator merges them. Per-page JSON-LD is emitted on every shard.
182
+ writeIndex: shardTotal === 1 && !llmPartsFile,
183
+ partsFile: llmPartsFile || void 0,
184
+ fullText: process.env.BLOX_SSG_LLM_FULL !== "0"
185
+ }
166
186
  });
167
187
  const elapsed = ((Date.now() - startTime) / 1e3).toFixed(2);
168
188
  console.log(`
@@ -1 +1 @@
1
- {"version":3,"file":"createSSREntry.d.ts","sourceRoot":"","sources":["../../src/ssg/createSSREntry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAY9D,MAAM,WAAW,yBAAyB;IACzC,oCAAoC;IACpC,aAAa,EAAE,SAAS,CAAA;IACxB;;;;OAIG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAC9D;;;OAGG;IACH,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpD,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,OAAO,KAAK,EAAE,MAAM,GAAG,CAAC,OAAO,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;IAC5E;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CAC5C;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IAClE,0EAA0E;IAC1E,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACnD;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAmLnF"}
1
+ {"version":3,"file":"createSSREntry.d.ts","sourceRoot":"","sources":["../../src/ssg/createSSREntry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAY9D,MAAM,WAAW,yBAAyB;IACzC,oCAAoC;IACpC,aAAa,EAAE,SAAS,CAAA;IACxB;;;;OAIG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAC9D;;;OAGG;IACH,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpD,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,OAAO,KAAK,EAAE,MAAM,GAAG,CAAC,OAAO,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;IAC5E;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CAC5C;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IAClE,0EAA0E;IAC1E,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACnD;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAoLnF"}
@@ -22,12 +22,13 @@ 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 prerender = require("../prerender-CD3vMqn6.cjs");
25
+ const prerender = require("../prerender-jcemLPiq.cjs");
26
26
  const ssg_client = require("./client.cjs");
27
27
  const pinia = require("pinia");
28
28
  const vue = require("vue");
29
29
  const routes = require("../routes-Bgy7bXEP.cjs");
30
30
  async function renderBloxSsgPage(options) {
31
+ var _a, _b, _c;
31
32
  const {
32
33
  url,
33
34
  resolvedData,
@@ -40,7 +41,8 @@ async function renderBloxSsgPage(options) {
40
41
  locale,
41
42
  website = null,
42
43
  websiteId = "",
43
- collections
44
+ collections,
45
+ llm
44
46
  } = options;
45
47
  const g = globalThis;
46
48
  const prevState = g[stateWindowKey];
@@ -59,7 +61,7 @@ async function renderBloxSsgPage(options) {
59
61
  const seoOverride = seoHead && Object.keys(seoHead).length > 0 ? seoHead : void 0;
60
62
  const bloxData = dataRegistry && collectData ? collectData(dataRegistry) : {};
61
63
  const dataScript = Object.keys(bloxData).length > 0 ? `<script>window[${JSON.stringify(routes.BLOX_DATA_WINDOW_KEY)}]=${safeJson(bloxData)};${"<"}/script>` : "";
62
- const head = prerender.buildPageHead({
64
+ let head = prerender.buildPageHead({
63
65
  url,
64
66
  resolvedData,
65
67
  website,
@@ -67,9 +69,35 @@ async function renderBloxSsgPage(options) {
67
69
  override: seoOverride,
68
70
  stateScript: [stateScript, collectionsScript, websiteIdScript, dataScript].filter(Boolean).join("\n")
69
71
  });
72
+ const seoData = resolvedData;
73
+ const primary = prerender.primaryContextEntry(seoData == null ? void 0 : seoData.contexts);
74
+ if ((llm == null ? void 0 : llm.jsonLd) !== false) {
75
+ const jsonLd = prerender.buildJsonLd({
76
+ url,
77
+ page: seoData == null ? void 0 : seoData.page,
78
+ website,
79
+ contextKey: primary == null ? void 0 : primary.key,
80
+ context: primary == null ? void 0 : primary.ctx,
81
+ locale,
82
+ config: llm
83
+ });
84
+ if (jsonLd) head += `
85
+ ${jsonLd}`;
86
+ }
87
+ let llmEntry;
88
+ if ((llm == null ? void 0 : llm.enabled) !== false) {
89
+ const title = (seoOverride == null ? void 0 : seoOverride.title) || ((_a = seoData == null ? void 0 : seoData.page) == null ? void 0 : _a.meta_title) || ((_b = seoData == null ? void 0 : seoData.page) == null ? void 0 : _b.title) || "";
90
+ const description = (seoOverride == null ? void 0 : seoOverride.description) || ((_c = seoData == null ? void 0 : seoData.page) == null ? void 0 : _c.meta_description) || void 0;
91
+ llmEntry = {
92
+ url,
93
+ title,
94
+ description,
95
+ text: (llm == null ? void 0 : llm.fullText) !== false ? prerender.extractPageText(html) : void 0
96
+ };
97
+ }
70
98
  const lang = locale || (website == null ? void 0 : website.default_locale) || "en";
71
99
  const htmlAttrs = `lang="${lang}"`;
72
- return { html, head, htmlAttrs };
100
+ return { html, head, htmlAttrs, llm: llmEntry };
73
101
  } finally {
74
102
  if (prevState !== void 0) {
75
103
  g[stateWindowKey] = prevState;
@@ -190,7 +218,8 @@ function createBloxSSREntry(options) {
190
218
  collectSeo: routes.collectBloxSeo,
191
219
  website: ctx.website,
192
220
  websiteId: ctx.websiteId,
193
- collections: ctx.collections
221
+ collections: ctx.collections,
222
+ llm: ctx.llm
194
223
  });
195
224
  }
196
225
  async function prefetchResolve(url) {
@@ -203,14 +232,19 @@ function createBloxSSREntry(options) {
203
232
  }
204
233
  return { render, prefetchResolve };
205
234
  }
235
+ exports.buildJsonLd = prerender.buildJsonLd;
206
236
  exports.buildPageHead = prerender.buildPageHead;
207
237
  exports.buildSiteHead = prerender.buildSiteHead;
238
+ exports.extractPageText = prerender.extractPageText;
208
239
  exports.fetchCmsPrerenderPaths = prerender.fetchCmsPrerenderPaths;
209
240
  exports.fetchCmsSiteData = prerender.fetchCmsSiteData;
241
+ exports.generateLlmsFullTxt = prerender.generateLlmsFullTxt;
242
+ exports.generateLlmsTxt = prerender.generateLlmsTxt;
210
243
  exports.generateNetlifyRedirects = prerender.generateNetlifyRedirects;
211
244
  exports.generateRobotsTxt = prerender.generateRobotsTxt;
212
245
  exports.generateSitemapXml = prerender.generateSitemapXml;
213
246
  exports.getSiteIconFlags = prerender.getSiteIconFlags;
247
+ exports.mergeLlmParts = prerender.mergeLlmParts;
214
248
  exports.polyfillBloxSsgGlobals = prerender.polyfillBloxSsgGlobals;
215
249
  exports.prerender = prerender.prerender;
216
250
  exports.BLOX_COLLECTIONS_WINDOW_KEY = ssg_client.BLOX_COLLECTIONS_WINDOW_KEY;
@@ -22,5 +22,7 @@ export { renderBloxSsgPage } from './render-resolved-page';
22
22
  export type { BloxSsgRouterLike } from './render-resolved-page';
23
23
  export { buildPageHead, buildSiteHead, generateNetlifyRedirects, generateRobotsTxt, generateSitemapXml, getSiteIconFlags } from './seo';
24
24
  export type { RedirectEntry, SeoPageData } from './seo';
25
+ export { buildJsonLd, extractPageText, generateLlmsFullTxt, generateLlmsTxt, mergeLlmParts } from './llm-artifacts';
26
+ export type { LlmArtifactsConfig, LlmPageEntry } from './llm-artifacts';
25
27
  export { installBloxStateCache } from './state-cache';
26
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ssg/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACvE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AACrG;;;;;;;;;;GAUG;AACH,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAC5J,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACjG,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AACvI,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ssg/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACvE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AACrG;;;;;;;;;;GAUG;AACH,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAC5J,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACjG,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AACvI,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACnH,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA"}