@bagelink/blox 1.15.529 → 1.15.533

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.
@@ -46,6 +46,7 @@ export interface WebsiteSeo {
46
46
  site_name?: string | null;
47
47
  canonical_base_url?: string | null;
48
48
  noindex?: boolean;
49
+ sitemap_split_by_locale?: boolean;
49
50
  favicon_url?: string | null;
50
51
  webclip?: string | null;
51
52
  twitter_site?: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"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"}
@@ -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 generateSitemapXml } from "./prerender-M2VjuOlc.js";
5
+ import { f as fetchCmsSiteData, s as splitSitemapPathsByLocale, l as localeSitemapPath, g as generateSitemapXml, b as generateSitemapIndexXml } from "./validate-output-C-RpYkvf.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
  function resolveShardCount(shards) {
@@ -58,7 +58,7 @@ function runShard(index, total, paths, opts, llmPartsDir, routePartsDir, siteDat
58
58
  });
59
59
  }
60
60
  async function runSharded(opts) {
61
- var _a;
61
+ var _a, _b;
62
62
  const total = resolveShardCount(opts.shards);
63
63
  const fs = await import("node:fs/promises");
64
64
  const paths = [...opts.extraPaths];
@@ -109,7 +109,7 @@ async function runSharded(opts) {
109
109
  }
110
110
  if (process.env.BLOX_SSG_LLM !== "0") {
111
111
  try {
112
- const { mergeLlmParts } = await import("./prerender-M2VjuOlc.js").then((n) => n.v);
112
+ const { mergeLlmParts } = await import("./validate-output-C-RpYkvf.js").then((n) => n.z);
113
113
  const mergeWebsite = website;
114
114
  const partFiles = Array.from({ length: total }, (_, i) => path.join(llmPartsDir, `part.${i}.json`));
115
115
  const { pages } = await mergeLlmParts({
@@ -131,13 +131,38 @@ async function runSharded(opts) {
131
131
  const canonicalBase = (((_a = website.seo) == null ? void 0 : _a.canonical_base_url) || website.domain || "").replace(/\/$/, "");
132
132
  const indexableRoutes = [...byUrl.values()].filter((route) => !route.noindex);
133
133
  if (canonicalBase && indexableRoutes.length > 0) {
134
- await fs.writeFile(path.resolve("dist", "sitemap.xml"), generateSitemapXml({
135
- renderedPaths: indexableRoutes.map((route) => route.url),
136
- canonicalBase,
137
- lastmod: Object.fromEntries(
138
- indexableRoutes.flatMap((route) => route.lastmod ? [[route.url, route.lastmod]] : [])
139
- )
140
- }), "utf8");
134
+ const lastmod = Object.fromEntries(
135
+ indexableRoutes.flatMap((route) => route.lastmod ? [[route.url, route.lastmod]] : [])
136
+ );
137
+ const renderedPaths = indexableRoutes.map((route) => route.url);
138
+ if (((_b = website.seo) == null ? void 0 : _b.sitemap_split_by_locale) !== false) {
139
+ const pathsByLocale = splitSitemapPathsByLocale({
140
+ renderedPaths,
141
+ defaultLocale: website.default_locale,
142
+ supportedLocales: website.supported_locales
143
+ });
144
+ const sitemapPaths = [];
145
+ for (const [locale, localePaths] of pathsByLocale) {
146
+ const sitemapPath = localeSitemapPath(locale);
147
+ await fs.writeFile(path.resolve("dist", sitemapPath.slice(1)), generateSitemapXml({
148
+ renderedPaths: localePaths,
149
+ canonicalBase,
150
+ lastmod
151
+ }), "utf8");
152
+ sitemapPaths.push(sitemapPath);
153
+ }
154
+ await fs.writeFile(
155
+ path.resolve("dist", "sitemap.xml"),
156
+ generateSitemapIndexXml({ canonicalBase, sitemapPaths }),
157
+ "utf8"
158
+ );
159
+ } else {
160
+ await fs.writeFile(path.resolve("dist", "sitemap.xml"), generateSitemapXml({
161
+ renderedPaths,
162
+ canonicalBase,
163
+ lastmod
164
+ }), "utf8");
165
+ }
141
166
  }
142
167
  await fs.rm(routePartsDir, { recursive: true, force: true });
143
168
  await fs.rm(siteDataFile, { force: true }).catch(() => {
@@ -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("./prerender-BKt6NiaM.cjs");
29
+ const llmArtifacts = require("./validate-output-C3NhyFsU.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
  function resolveShardCount(shards) {
@@ -82,7 +82,7 @@ function runShard(index, total, paths, opts, llmPartsDir, routePartsDir, siteDat
82
82
  });
83
83
  }
84
84
  async function runSharded(opts) {
85
- var _a;
85
+ var _a, _b;
86
86
  const total = resolveShardCount(opts.shards);
87
87
  const fs = await import("node:fs/promises");
88
88
  const paths = [...opts.extraPaths];
@@ -133,7 +133,7 @@ async function runSharded(opts) {
133
133
  }
134
134
  if (process.env.BLOX_SSG_LLM !== "0") {
135
135
  try {
136
- const { mergeLlmParts } = await Promise.resolve().then(() => require("./prerender-BKt6NiaM.cjs")).then((n) => n.llmArtifacts);
136
+ const { mergeLlmParts } = await Promise.resolve().then(() => require("./validate-output-C3NhyFsU.cjs")).then((n) => n.llmArtifacts);
137
137
  const mergeWebsite = website;
138
138
  const partFiles = Array.from({ length: total }, (_, i) => path.join(llmPartsDir, `part.${i}.json`));
139
139
  const { pages } = await mergeLlmParts({
@@ -155,13 +155,38 @@ async function runSharded(opts) {
155
155
  const canonicalBase = (((_a = website.seo) == null ? void 0 : _a.canonical_base_url) || website.domain || "").replace(/\/$/, "");
156
156
  const indexableRoutes = [...byUrl.values()].filter((route) => !route.noindex);
157
157
  if (canonicalBase && indexableRoutes.length > 0) {
158
- await fs.writeFile(path.resolve("dist", "sitemap.xml"), llmArtifacts.generateSitemapXml({
159
- renderedPaths: indexableRoutes.map((route) => route.url),
160
- canonicalBase,
161
- lastmod: Object.fromEntries(
162
- indexableRoutes.flatMap((route) => route.lastmod ? [[route.url, route.lastmod]] : [])
163
- )
164
- }), "utf8");
158
+ const lastmod = Object.fromEntries(
159
+ indexableRoutes.flatMap((route) => route.lastmod ? [[route.url, route.lastmod]] : [])
160
+ );
161
+ const renderedPaths = indexableRoutes.map((route) => route.url);
162
+ if (((_b = website.seo) == null ? void 0 : _b.sitemap_split_by_locale) !== false) {
163
+ const pathsByLocale = llmArtifacts.splitSitemapPathsByLocale({
164
+ renderedPaths,
165
+ defaultLocale: website.default_locale,
166
+ supportedLocales: website.supported_locales
167
+ });
168
+ const sitemapPaths = [];
169
+ for (const [locale, localePaths] of pathsByLocale) {
170
+ const sitemapPath = llmArtifacts.localeSitemapPath(locale);
171
+ await fs.writeFile(path.resolve("dist", sitemapPath.slice(1)), llmArtifacts.generateSitemapXml({
172
+ renderedPaths: localePaths,
173
+ canonicalBase,
174
+ lastmod
175
+ }), "utf8");
176
+ sitemapPaths.push(sitemapPath);
177
+ }
178
+ await fs.writeFile(
179
+ path.resolve("dist", "sitemap.xml"),
180
+ llmArtifacts.generateSitemapIndexXml({ canonicalBase, sitemapPaths }),
181
+ "utf8"
182
+ );
183
+ } else {
184
+ await fs.writeFile(path.resolve("dist", "sitemap.xml"), llmArtifacts.generateSitemapXml({
185
+ renderedPaths,
186
+ canonicalBase,
187
+ lastmod
188
+ }), "utf8");
189
+ }
165
190
  }
166
191
  await fs.rm(routePartsDir, { recursive: true, force: true });
167
192
  await fs.rm(siteDataFile, { force: true }).catch(() => {
@@ -7,6 +7,10 @@ export interface BloxBuildRequestOptions {
7
7
  tokenScheme?: string;
8
8
  /** Additional build-only headers. */
9
9
  headers?: HeadersInit;
10
+ /** Total attempts for transient network, 429, and 5xx failures. @default 4 */
11
+ retryAttempts?: number;
12
+ /** Initial retry delay in milliseconds; doubles per attempt. @default 500 */
13
+ retryBaseMs?: number;
10
14
  }
11
15
  export declare class BloxBuildResponseError extends Error {
12
16
  readonly status: number;
@@ -1 +1 @@
1
- {"version":3,"file":"build-request.d.ts","sourceRoot":"","sources":["../../src/ssg/build-request.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACvC,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qCAAqC;IACrC,OAAO,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,qBAAa,sBAAuB,SAAQ,KAAK;aAE/B,MAAM,EAAE,MAAM;aACd,GAAG,EAAE,MAAM;gBADX,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EAC3B,UAAU,EAAE,MAAM;CAKnB;AAMD,uFAAuF;AACvF,wBAAgB,0BAA0B,CACzC,SAAS,GAAE,uBAA4B,GACrC,uBAAuB,CAOzB;AAED,gFAAgF;AAChF,wBAAsB,gBAAgB,CACrC,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,GAAE,WAAgB,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,QAAQ,CAAC,CAWnB;AAED,sEAAsE;AACtE,wBAAsB,aAAa,CAAC,CAAC,EACpC,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,GAAE,WAAgB,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,CAAC,CAAC,CAQZ"}
1
+ {"version":3,"file":"build-request.d.ts","sourceRoot":"","sources":["../../src/ssg/build-request.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACvC,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qCAAqC;IACrC,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,sBAAuB,SAAQ,KAAK;aAE/B,MAAM,EAAE,MAAM;aACd,GAAG,EAAE,MAAM;gBADX,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EAC3B,UAAU,EAAE,MAAM;CAKnB;AAMD,uFAAuF;AACvF,wBAAgB,0BAA0B,CACzC,SAAS,GAAE,uBAA4B,GACrC,uBAAuB,CAWzB;AAMD,gFAAgF;AAChF,wBAAsB,gBAAgB,CACrC,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,GAAE,WAAgB,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,QAAQ,CAAC,CAiCnB;AAED,sEAAsE;AACtE,wBAAsB,aAAa,CAAC,CAAC,EACpC,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,GAAE,WAAgB,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,CAAC,CAAC,CAQZ"}
package/dist/ssg/cli.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  const process = require("node:process");
4
4
  const fs = require("node:fs/promises");
5
- const llmArtifacts = require("../prerender-BKt6NiaM.cjs");
5
+ const llmArtifacts = require("../validate-output-C3NhyFsU.cjs");
6
6
  function installFetchTimeout() {
7
7
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
8
8
  const original = globalThis.fetch;
@@ -56,6 +56,7 @@ async function main() {
56
56
  let shardsOpt = null;
57
57
  let routesCmd = "";
58
58
  let siteDataFile = "";
59
+ let validateOutDir = "";
59
60
  const passthroughArgs = [];
60
61
  const excludePaths = ["/_blox_preview"];
61
62
  for (const a of argv) {
@@ -71,6 +72,10 @@ async function main() {
71
72
  routesCmd = a.slice("--routes-cmd=".length);
72
73
  } else if (a.startsWith("--site-data=")) {
73
74
  siteDataFile = a.slice("--site-data=".length);
75
+ } else if (a === "--validate") {
76
+ validateOutDir = "dist";
77
+ } else if (a.startsWith("--validate=")) {
78
+ validateOutDir = a.slice("--validate=".length);
74
79
  } else if (a.startsWith("--shard=")) {
75
80
  const [i, n] = a.slice("--shard=".length).split("/").map(Number);
76
81
  if (Number.isInteger(i) && Number.isInteger(n) && n > 0 && i >= 0 && i < n) {
@@ -95,6 +100,7 @@ Options:
95
100
  --shard=<i/n> (internal) Render only this shard's slice — set by --shards.
96
101
  --routes-cmd=<cmd> Shell command whose stdout (whitespace-separated) is the
97
102
  route list. For router-driven sites with no CMS pages.
103
+ --validate[=dir] Validate generated SSG assets (default directory: dist).
98
104
  --help, -h Show this help
99
105
 
100
106
  Environment:
@@ -120,10 +126,15 @@ Environment:
120
126
  extraPaths.push(a);
121
127
  }
122
128
  }
129
+ if (validateOutDir) {
130
+ await llmArtifacts.validateSsgOutput({ outDir: validateOutDir });
131
+ console.log(`[blox-ssg] validated output in ${validateOutDir}`);
132
+ return;
133
+ }
123
134
  if (shardsOpt !== null || routesCmd) {
124
135
  const { apiBase: apiBase2, websiteName: configWebsiteName2 } = await resolveApiBase(mode);
125
136
  const websiteName2 = process.env.WEBSITE_NAME ?? configWebsiteName2 ?? "default";
126
- const { runSharded } = await Promise.resolve().then(() => require("../shard-runner-B_obJ3aA.cjs"));
137
+ const { runSharded } = await Promise.resolve().then(() => require("../shard-runner-DTkniXr1.cjs"));
127
138
  const code = await runSharded({
128
139
  shards: shardsOpt ?? "auto",
129
140
  mode,
package/dist/ssg/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  import process from "node:process";
3
3
  import fs from "node:fs/promises";
4
- import { u as uploadBloxManifest, p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, a as prerender } from "../prerender-M2VjuOlc.js";
4
+ import { v as validateSsgOutput, u as uploadBloxManifest, p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, a as prerender } from "../validate-output-C-RpYkvf.js";
5
5
  function installFetchTimeout() {
6
6
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
7
7
  const original = globalThis.fetch;
@@ -55,6 +55,7 @@ async function main() {
55
55
  let shardsOpt = null;
56
56
  let routesCmd = "";
57
57
  let siteDataFile = "";
58
+ let validateOutDir = "";
58
59
  const passthroughArgs = [];
59
60
  const excludePaths = ["/_blox_preview"];
60
61
  for (const a of argv) {
@@ -70,6 +71,10 @@ async function main() {
70
71
  routesCmd = a.slice("--routes-cmd=".length);
71
72
  } else if (a.startsWith("--site-data=")) {
72
73
  siteDataFile = a.slice("--site-data=".length);
74
+ } else if (a === "--validate") {
75
+ validateOutDir = "dist";
76
+ } else if (a.startsWith("--validate=")) {
77
+ validateOutDir = a.slice("--validate=".length);
73
78
  } else if (a.startsWith("--shard=")) {
74
79
  const [i, n] = a.slice("--shard=".length).split("/").map(Number);
75
80
  if (Number.isInteger(i) && Number.isInteger(n) && n > 0 && i >= 0 && i < n) {
@@ -94,6 +99,7 @@ Options:
94
99
  --shard=<i/n> (internal) Render only this shard's slice — set by --shards.
95
100
  --routes-cmd=<cmd> Shell command whose stdout (whitespace-separated) is the
96
101
  route list. For router-driven sites with no CMS pages.
102
+ --validate[=dir] Validate generated SSG assets (default directory: dist).
97
103
  --help, -h Show this help
98
104
 
99
105
  Environment:
@@ -119,10 +125,15 @@ Environment:
119
125
  extraPaths.push(a);
120
126
  }
121
127
  }
128
+ if (validateOutDir) {
129
+ await validateSsgOutput({ outDir: validateOutDir });
130
+ console.log(`[blox-ssg] validated output in ${validateOutDir}`);
131
+ return;
132
+ }
122
133
  if (shardsOpt !== null || routesCmd) {
123
134
  const { apiBase: apiBase2, websiteName: configWebsiteName2 } = await resolveApiBase(mode);
124
135
  const websiteName2 = process.env.WEBSITE_NAME ?? configWebsiteName2 ?? "default";
125
- const { runSharded } = await import("../shard-runner-BrakAYOw.js");
136
+ const { runSharded } = await import("../shard-runner-DFZAHrwJ.js");
126
137
  const code = await runSharded({
127
138
  shards: shardsOpt ?? "auto",
128
139
  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("../prerender-BKt6NiaM.cjs");
25
+ const llmArtifacts = require("../validate-output-C3NhyFsU.cjs");
26
26
  const ssg_client = require("./client.cjs");
27
27
  const pinia = require("pinia");
28
28
  const vue = require("vue");
@@ -268,14 +268,18 @@ exports.generateLlmsFullTxt = llmArtifacts.generateLlmsFullTxt;
268
268
  exports.generateLlmsTxt = llmArtifacts.generateLlmsTxt;
269
269
  exports.generateNetlifyRedirects = llmArtifacts.generateNetlifyRedirects;
270
270
  exports.generateRobotsTxt = llmArtifacts.generateRobotsTxt;
271
+ exports.generateSitemapIndexXml = llmArtifacts.generateSitemapIndexXml;
271
272
  exports.generateSitemapXml = llmArtifacts.generateSitemapXml;
272
273
  exports.getBloxBuildRequestOptions = llmArtifacts.getBloxBuildRequestOptions;
273
274
  exports.getSiteIconFlags = llmArtifacts.getSiteIconFlags;
275
+ exports.localeSitemapPath = llmArtifacts.localeSitemapPath;
274
276
  exports.mergeLlmParts = llmArtifacts.mergeLlmParts;
275
277
  exports.polyfillBloxSsgGlobals = llmArtifacts.polyfillBloxSsgGlobals;
276
278
  exports.prerender = llmArtifacts.prerender;
277
279
  exports.resolveManifestProvenance = llmArtifacts.resolveManifestProvenance;
280
+ exports.splitSitemapPathsByLocale = llmArtifacts.splitSitemapPathsByLocale;
278
281
  exports.uploadBloxManifest = llmArtifacts.uploadBloxManifest;
282
+ exports.validateSsgOutput = llmArtifacts.validateSsgOutput;
279
283
  exports.BLOX_COLLECTIONS_WINDOW_KEY = ssg_client.BLOX_COLLECTIONS_WINDOW_KEY;
280
284
  exports.BLOX_DATA_WINDOW_KEY = ssg_client.BLOX_DATA_WINDOW_KEY;
281
285
  exports.BLOX_PAGE_SEO_WINDOW_KEY = ssg_client.BLOX_PAGE_SEO_WINDOW_KEY;
@@ -22,11 +22,13 @@ export { prerender } from './prerender';
22
22
  export type { PrerenderOptions, PrerenderResult, RenderContext, RenderResult } from './prerender';
23
23
  export { renderBloxSsgPage } from './render-resolved-page';
24
24
  export type { BloxSsgRouterLike } from './render-resolved-page';
25
- export { buildPageHead, buildSiteHead, generateNetlifyRedirects, generateRobotsTxt, generateSitemapXml, getSiteIconFlags } from './seo';
25
+ export { buildPageHead, buildSiteHead, generateNetlifyRedirects, generateRobotsTxt, generateSitemapIndexXml, generateSitemapXml, getSiteIconFlags, localeSitemapPath, splitSitemapPathsByLocale } from './seo';
26
26
  export type { RedirectEntry, SeoPageData } from './seo';
27
27
  export { buildJsonLd, extractPageText, generateLlmsFullTxt, generateLlmsTxt, mergeLlmParts } from './llm-artifacts';
28
28
  export type { LlmArtifactsConfig, LlmPageEntry } from './llm-artifacts';
29
29
  export { installBloxStateCache } from './state-cache';
30
30
  export { resolveManifestProvenance, uploadBloxManifest } from './manifest-upload';
31
31
  export type { ManifestProvenance, ManifestUpload } from './manifest-upload';
32
+ export { validateSsgOutput } from './validate-output';
33
+ export type { ValidateSsgOutputOptions } from './validate-output';
32
34
  //# 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,sBAAsB,EAAE,aAAa,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAA;AACrH,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,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;AACrD,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACjF,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,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,sBAAsB,EAAE,aAAa,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAA;AACrH,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,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,uBAAuB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,OAAO,CAAA;AAC9M,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;AACrD,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACjF,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA"}
@@ -1,5 +1,5 @@
1
- import { b as buildPageHead, c as primaryContextEntry, d as buildJsonLd, e as extractPageText, B as BloxBuildResponseError, h as bloxBuildJson } from "../prerender-M2VjuOlc.js";
2
- import { i, j, k, f, l, m, n, o, g, q, r, s, p, a, t, u } from "../prerender-M2VjuOlc.js";
1
+ import { c as buildPageHead, d as primaryContextEntry, e as buildJsonLd, h as extractPageText, B as BloxBuildResponseError, i as bloxBuildJson } from "../validate-output-C-RpYkvf.js";
2
+ import { j, k, m, f, n, o, q, r, b, g, t, w, l, x, p, a, y, s, u, v } from "../validate-output-C-RpYkvf.js";
3
3
  import { BLOX_STATE_WINDOW_KEY, BLOX_WEBSITE_ID_WINDOW_KEY } from "./client.mjs";
4
4
  import { BLOX_COLLECTIONS_WINDOW_KEY, BLOX_DATA_WINDOW_KEY, BLOX_PAGE_SEO_WINDOW_KEY, getCollectionCache, getEmbeddedWebsiteId, installBloxStateCache, installCollectionCache } from "./client.mjs";
5
5
  import { createPinia } from "pinia";
@@ -241,29 +241,33 @@ export {
241
241
  BLOX_WEBSITE_ID_WINDOW_KEY,
242
242
  BloxBuildResponseError,
243
243
  bloxBuildJson,
244
- i as bloxBuildRequest,
244
+ j as bloxBuildRequest,
245
245
  buildJsonLd,
246
246
  buildPageHead,
247
- j as buildSiteHead,
247
+ k as buildSiteHead,
248
248
  createBloxSSREntry,
249
249
  extractPageText,
250
- k as fetchCmsPrerenderPaths,
250
+ m as fetchCmsPrerenderPaths,
251
251
  f as fetchCmsSiteData,
252
- l as generateLlmsFullTxt,
253
- m as generateLlmsTxt,
254
- n as generateNetlifyRedirects,
255
- o as generateRobotsTxt,
252
+ n as generateLlmsFullTxt,
253
+ o as generateLlmsTxt,
254
+ q as generateNetlifyRedirects,
255
+ r as generateRobotsTxt,
256
+ b as generateSitemapIndexXml,
256
257
  g as generateSitemapXml,
257
- q as getBloxBuildRequestOptions,
258
+ t as getBloxBuildRequestOptions,
258
259
  getCollectionCache,
259
260
  getEmbeddedWebsiteId,
260
- r as getSiteIconFlags,
261
+ w as getSiteIconFlags,
261
262
  installBloxStateCache,
262
263
  installCollectionCache,
263
- s as mergeLlmParts,
264
+ l as localeSitemapPath,
265
+ x as mergeLlmParts,
264
266
  p as polyfillBloxSsgGlobals,
265
267
  a as prerender,
266
268
  renderBloxSsgPage,
267
- t as resolveManifestProvenance,
268
- u as uploadBloxManifest
269
+ y as resolveManifestProvenance,
270
+ s as splitSitemapPathsByLocale,
271
+ u as uploadBloxManifest,
272
+ v as validateSsgOutput
269
273
  };
@@ -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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"}
package/dist/ssg/seo.d.ts CHANGED
@@ -67,6 +67,16 @@ export declare function generateSitemapXml(options: {
67
67
  /** Per-path last-modified ISO timestamps (path → ISO). Emits <lastmod>. */
68
68
  lastmod?: Record<string, string>;
69
69
  }): string;
70
+ export declare function generateSitemapIndexXml(options: {
71
+ canonicalBase: string;
72
+ sitemapPaths: string[];
73
+ }): string;
74
+ export declare function splitSitemapPathsByLocale(options: {
75
+ renderedPaths: string[];
76
+ defaultLocale: string;
77
+ supportedLocales: string[];
78
+ }): Map<string, string[]>;
79
+ export declare function localeSitemapPath(locale: string): string;
70
80
  export declare function generateRobotsTxt(options: {
71
81
  robotsTxt?: string | null;
72
82
  canonicalBase?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"seo.d.ts","sourceRoot":"","sources":["../../src/ssg/seo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"seo.d.ts","sourceRoot":"","sources":["../../src/ssg/seo.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"shard-runner.d.ts","sourceRoot":"","sources":["../../src/ssg/shard-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAWH,MAAM,WAAW,kBAAkB;IAClC,qDAAqD;IACrD,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IACf,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAA;IACnB,iFAAiF;IACjF,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,8FAA8F;IAC9F,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CAClB;AA4ED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsH1E"}
1
+ {"version":3,"file":"shard-runner.d.ts","sourceRoot":"","sources":["../../src/ssg/shard-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAWH,MAAM,WAAW,kBAAkB;IAClC,qDAAqD;IACrD,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IACf,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAA;IACnB,iFAAiF;IACjF,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,8FAA8F;IAC9F,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CAClB;AA4ED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+I1E"}
@@ -0,0 +1,6 @@
1
+ export interface ValidateSsgOutputOptions {
2
+ outDir: string;
3
+ requireFiles?: string[];
4
+ }
5
+ export declare function validateSsgOutput(options: ValidateSsgOutputOptions): Promise<void>;
6
+ //# sourceMappingURL=validate-output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-output.d.ts","sourceRoot":"","sources":["../../src/ssg/validate-output.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,wBAAwB;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDxF"}
@@ -21,9 +21,14 @@ function getBloxBuildRequestOptions(overrides = {}) {
21
21
  token: overrides.token ?? env("BLOX_BUILD_TOKEN"),
22
22
  tokenHeader: overrides.tokenHeader ?? env("BLOX_BUILD_TOKEN_HEADER") ?? "Authorization",
23
23
  tokenScheme: overrides.tokenScheme ?? env("BLOX_BUILD_TOKEN_SCHEME") ?? "Bearer",
24
- headers: overrides.headers
24
+ headers: overrides.headers,
25
+ retryAttempts: overrides.retryAttempts ?? (Number(env("BLOX_BUILD_RETRY_ATTEMPTS")) || 4),
26
+ retryBaseMs: overrides.retryBaseMs ?? (Number(env("BLOX_BUILD_RETRY_MS")) || 500)
25
27
  };
26
28
  }
29
+ function sleep(ms) {
30
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
31
+ }
27
32
  async function bloxBuildRequest(input, init = {}, options = {}) {
28
33
  const config = getBloxBuildRequestOptions(options);
29
34
  const headers = new Headers(config.headers);
@@ -34,7 +39,28 @@ async function bloxBuildRequest(input, init = {}, options = {}) {
34
39
  config.tokenScheme ? `${config.tokenScheme} ${config.token}` : config.token
35
40
  );
36
41
  }
37
- return fetch(input, { ...init, headers });
42
+ const attempts = Math.max(1, config.retryAttempts ?? 4);
43
+ const retryBaseMs = Math.max(0, config.retryBaseMs ?? 500);
44
+ for (let attempt = 1; attempt <= attempts; attempt++) {
45
+ try {
46
+ const response = await fetch(input, { ...init, headers });
47
+ const transient = response.status === 429 || response.status >= 500;
48
+ if (response.ok || !transient || attempt === attempts) return response;
49
+ const delay = retryBaseMs * 2 ** (attempt - 1);
50
+ console.warn(
51
+ `[blox-build] retry ${attempt}/${attempts} after HTTP ${response.status} in ${delay}ms`
52
+ );
53
+ if (delay) await sleep(delay);
54
+ } catch (error) {
55
+ if (attempt === attempts) throw error;
56
+ const delay = retryBaseMs * 2 ** (attempt - 1);
57
+ console.warn(
58
+ `[blox-build] retry ${attempt}/${attempts} after ${error.message} in ${delay}ms`
59
+ );
60
+ if (delay) await sleep(delay);
61
+ }
62
+ }
63
+ throw new Error("Blox build request exhausted retries");
38
64
  }
39
65
  async function bloxBuildJson(input, init = {}, options = {}) {
40
66
  const response = await bloxBuildRequest(input, init, options);
@@ -409,8 +435,9 @@ function generateSitemapXml(options) {
409
435
  const mod = lastmod[p];
410
436
  const modLine = mod ? `
411
437
  <lastmod>${esc(mod)}</lastmod>` : "";
438
+ const loc = p === "/" ? base : base + p;
412
439
  return ` <url>
413
- <loc>${esc(base + p)}</loc>${modLine}
440
+ <loc>${esc(loc)}</loc>${modLine}
414
441
  <changefreq>${changefreq}</changefreq>
415
442
  <priority>${priority}</priority>
416
443
  </url>`;
@@ -421,6 +448,35 @@ ${urls.join("\n")}
421
448
  </urlset>
422
449
  `;
423
450
  }
451
+ function generateSitemapIndexXml(options) {
452
+ const base = options.canonicalBase.replace(/\/$/, "");
453
+ const sitemaps = options.sitemapPaths.map((path2) => ` <sitemap>
454
+ <loc>${esc(base + path2)}</loc>
455
+ </sitemap>`);
456
+ return `<?xml version="1.0" encoding="UTF-8"?>
457
+ <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
458
+ ${sitemaps.join("\n")}
459
+ </sitemapindex>
460
+ `;
461
+ }
462
+ function splitSitemapPathsByLocale(options) {
463
+ const locales = new Set(options.supportedLocales);
464
+ const pathsByLocale = /* @__PURE__ */ new Map();
465
+ for (const path2 of options.renderedPaths) {
466
+ const firstSegment = path2.replace(/^\//, "").split("/")[0];
467
+ const locale = firstSegment && firstSegment !== options.defaultLocale && locales.has(firstSegment) ? firstSegment : options.defaultLocale;
468
+ const paths = pathsByLocale.get(locale) ?? [];
469
+ paths.push(path2);
470
+ pathsByLocale.set(locale, paths);
471
+ }
472
+ return pathsByLocale;
473
+ }
474
+ function localeSitemapPath(locale) {
475
+ if (!/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/.test(locale)) {
476
+ throw new Error(`Invalid sitemap locale: ${locale}`);
477
+ }
478
+ return `/sitemap-${locale}.xml`;
479
+ }
424
480
  function generateRobotsTxt(options) {
425
481
  const { robotsTxt, canonicalBase, noindex } = options;
426
482
  if (noindex) {
@@ -746,7 +802,7 @@ async function prerender({
746
802
  collections = {},
747
803
  llm = {}
748
804
  } = {}) {
749
- var _a, _b;
805
+ var _a, _b, _c;
750
806
  const absRoot = path.resolve(root);
751
807
  const absClient = path.resolve(absRoot, clientOutDir);
752
808
  const absServerEntry = path.resolve(absRoot, serverEntry);
@@ -899,15 +955,43 @@ async function prerender({
899
955
  if (writeSharedAssets) {
900
956
  const sitemapPaths = rendered.filter((p) => !noindexPaths.has(p));
901
957
  if (canonicalBase && sitemapPaths.length > 0) {
902
- const sitemap = generateSitemapXml({ renderedPaths: sitemapPaths, canonicalBase, lastmod });
903
- await fs.writeFile(path.join(absClient, "sitemap.xml"), sitemap, "utf8");
958
+ if (((_b = website == null ? void 0 : website.seo) == null ? void 0 : _b.sitemap_split_by_locale) !== false) {
959
+ const pathsByLocale = splitSitemapPathsByLocale({
960
+ renderedPaths: sitemapPaths,
961
+ defaultLocale: (website == null ? void 0 : website.default_locale) ?? "en",
962
+ supportedLocales: (website == null ? void 0 : website.supported_locales) ?? [(website == null ? void 0 : website.default_locale) ?? "en"]
963
+ });
964
+ const sitemapFiles = [];
965
+ for (const [locale, localePaths] of pathsByLocale) {
966
+ const sitemapPath = localeSitemapPath(locale);
967
+ await fs.writeFile(
968
+ path.join(absClient, sitemapPath.slice(1)),
969
+ generateSitemapXml({ renderedPaths: localePaths, canonicalBase, lastmod }),
970
+ "utf8"
971
+ );
972
+ sitemapFiles.push(sitemapPath);
973
+ }
974
+ await fs.writeFile(
975
+ path.join(absClient, "sitemap.xml"),
976
+ generateSitemapIndexXml({ canonicalBase, sitemapPaths: sitemapFiles }),
977
+ "utf8"
978
+ );
979
+ console.log(` Generated sitemap.xml (${sitemapFiles.length} locales, ${sitemapPaths.length} URLs)`);
980
+ } else {
981
+ await fs.writeFile(
982
+ path.join(absClient, "sitemap.xml"),
983
+ generateSitemapXml({ renderedPaths: sitemapPaths, canonicalBase, lastmod }),
984
+ "utf8"
985
+ );
986
+ console.log(` Generated sitemap.xml (${sitemapPaths.length} URLs)`);
987
+ }
904
988
  const skipped = noindexPaths.size > 0 ? ` (${noindexPaths.size} noindex excluded)` : "";
905
- console.log(` Generated sitemap.xml (${sitemapPaths.length} URLs)${skipped}`);
989
+ if (skipped) console.log(` Sitemap exclusions:${skipped}`);
906
990
  }
907
991
  const robotsTxt = generateRobotsTxt({
908
992
  robotsTxt: website == null ? void 0 : website.robots_txt,
909
993
  canonicalBase,
910
- noindex: (_b = website == null ? void 0 : website.seo) == null ? void 0 : _b.noindex
994
+ noindex: (_c = website == null ? void 0 : website.seo) == null ? void 0 : _c.noindex
911
995
  });
912
996
  await fs.writeFile(path.join(absClient, "robots.txt"), robotsTxt, "utf8");
913
997
  console.log(" Generated robots.txt");
@@ -1087,28 +1171,121 @@ function discoverInternalLinks(html) {
1087
1171
  }
1088
1172
  return [...out];
1089
1173
  }
1174
+ const sitemapUrl = /<url>\s*<loc>[^<]+<\/loc>/m;
1175
+ const sitemapIndexEntry = /<sitemap>\s*<loc>[^<]+<\/loc>/gm;
1176
+ const sitemapLoc = /<loc>([^<]+)<\/loc>/;
1177
+ const loadingShell = /class=["'][^"']*\bblox-initial-loading\b/;
1178
+ const embeddedCmsState = /\b__BLOX_(?:STATE|DATA)__\b/;
1179
+ async function validateSsgOutput(options) {
1180
+ const outDir = path.resolve(options.outDir);
1181
+ const failures = [];
1182
+ const requiredFiles = options.requireFiles ?? [
1183
+ "robots.txt",
1184
+ "_redirects",
1185
+ "sitemap.xml",
1186
+ "llms.txt",
1187
+ "llms-full.txt"
1188
+ ];
1189
+ const htmlFiles = await collectHtmlFiles(outDir);
1190
+ let hydratedFiles = 0;
1191
+ for (const file of htmlFiles) {
1192
+ const name = path.relative(outDir, file);
1193
+ const html = await fs.readFile(file, "utf8");
1194
+ if (embeddedCmsState.test(html)) hydratedFiles += 1;
1195
+ if (!/<title>[^<]+<\/title>/i.test(html)) failures.push(`${name}: missing page title`);
1196
+ if (!/<link\s[^>]*rel=["']canonical["'][^>]*>/i.test(html)) {
1197
+ failures.push(`${name}: missing canonical URL`);
1198
+ }
1199
+ if (!/<html[^>]*\slang=["'][^"']+["']/i.test(html)) failures.push(`${name}: missing html lang`);
1200
+ if (loadingShell.test(html) && !embeddedCmsState.test(html)) {
1201
+ failures.push(`${name}: contains only the Blox loading shell`);
1202
+ }
1203
+ }
1204
+ if (!htmlFiles.length) failures.push("output contains no HTML files");
1205
+ if (!hydratedFiles) failures.push("output contains no prerendered Blox hydration state");
1206
+ for (const required of requiredFiles) {
1207
+ try {
1208
+ const content = await fs.readFile(path.join(outDir, required), "utf8");
1209
+ if (required === "robots.txt" && /^Disallow:\s*\/\s*$/im.test(content)) {
1210
+ failures.push("robots.txt blocks the entire site");
1211
+ }
1212
+ if (required === "llms.txt" && !/^- \[[^\]]+\]\([^)]+\)/m.test(content)) {
1213
+ failures.push("llms.txt contains no page links");
1214
+ }
1215
+ if (required === "sitemap.xml") {
1216
+ failures.push(...await validateSitemap(outDir, content));
1217
+ }
1218
+ } catch {
1219
+ failures.push(`missing ${required}`);
1220
+ }
1221
+ }
1222
+ if (failures.length) {
1223
+ throw new Error(`Invalid Blox SSG output:
1224
+ ${failures.map((item) => ` - ${item}`).join("\n")}`);
1225
+ }
1226
+ }
1227
+ async function collectHtmlFiles(directory) {
1228
+ const entries = await fs.readdir(directory, { withFileTypes: true });
1229
+ const files = await Promise.all(entries.map(async (entry) => {
1230
+ const child = path.join(directory, entry.name);
1231
+ if (entry.isDirectory() && entry.name !== "server") return collectHtmlFiles(child);
1232
+ return entry.isFile() && entry.name.endsWith(".html") ? [child] : [];
1233
+ }));
1234
+ return files.flat();
1235
+ }
1236
+ async function validateSitemap(outDir, content) {
1237
+ var _a;
1238
+ if (sitemapUrl.test(content)) return [];
1239
+ const failures = [];
1240
+ const entries = content.match(sitemapIndexEntry) ?? [];
1241
+ if (!entries.length) return ["sitemap.xml contains neither page URLs nor child sitemaps"];
1242
+ let childUrlCount = 0;
1243
+ for (const entry of entries) {
1244
+ const loc = (_a = entry.match(sitemapLoc)) == null ? void 0 : _a[1];
1245
+ if (!loc) continue;
1246
+ const pathname = new URL(loc).pathname.replace(/^\/+/, "");
1247
+ const childPath = path.resolve(outDir, pathname);
1248
+ if (!childPath.startsWith(`${outDir}${path.sep}`)) {
1249
+ failures.push(`child sitemap escapes output directory: ${pathname}`);
1250
+ continue;
1251
+ }
1252
+ try {
1253
+ const child = await fs.readFile(childPath, "utf8");
1254
+ if (!sitemapUrl.test(child)) failures.push(`${pathname} contains no page URLs`);
1255
+ else childUrlCount += (child.match(/<url>/g) ?? []).length;
1256
+ } catch {
1257
+ failures.push(`missing child sitemap ${pathname}`);
1258
+ }
1259
+ }
1260
+ if (!childUrlCount) failures.push("sitemap index child files contain no page URLs");
1261
+ return failures;
1262
+ }
1090
1263
  export {
1091
1264
  BloxBuildResponseError as B,
1092
1265
  prerender as a,
1093
- buildPageHead as b,
1094
- primaryContextEntry as c,
1095
- buildJsonLd as d,
1096
- extractPageText as e,
1266
+ generateSitemapIndexXml as b,
1267
+ buildPageHead as c,
1268
+ primaryContextEntry as d,
1269
+ buildJsonLd as e,
1097
1270
  fetchCmsSiteData as f,
1098
1271
  generateSitemapXml as g,
1099
- bloxBuildJson as h,
1100
- bloxBuildRequest as i,
1101
- buildSiteHead as j,
1102
- fetchCmsPrerenderPaths as k,
1103
- generateLlmsFullTxt as l,
1104
- generateLlmsTxt as m,
1105
- generateNetlifyRedirects as n,
1106
- generateRobotsTxt as o,
1272
+ extractPageText as h,
1273
+ bloxBuildJson as i,
1274
+ bloxBuildRequest as j,
1275
+ buildSiteHead as k,
1276
+ localeSitemapPath as l,
1277
+ fetchCmsPrerenderPaths as m,
1278
+ generateLlmsFullTxt as n,
1279
+ generateLlmsTxt as o,
1107
1280
  polyfillBloxSsgGlobals as p,
1108
- getBloxBuildRequestOptions as q,
1109
- getSiteIconFlags as r,
1110
- mergeLlmParts as s,
1111
- resolveManifestProvenance as t,
1281
+ generateNetlifyRedirects as q,
1282
+ generateRobotsTxt as r,
1283
+ splitSitemapPathsByLocale as s,
1284
+ getBloxBuildRequestOptions as t,
1112
1285
  uploadBloxManifest as u,
1113
- llmArtifacts as v
1286
+ validateSsgOutput as v,
1287
+ getSiteIconFlags as w,
1288
+ mergeLlmParts as x,
1289
+ resolveManifestProvenance as y,
1290
+ llmArtifacts as z
1114
1291
  };
@@ -44,9 +44,14 @@ function getBloxBuildRequestOptions(overrides = {}) {
44
44
  token: overrides.token ?? env("BLOX_BUILD_TOKEN"),
45
45
  tokenHeader: overrides.tokenHeader ?? env("BLOX_BUILD_TOKEN_HEADER") ?? "Authorization",
46
46
  tokenScheme: overrides.tokenScheme ?? env("BLOX_BUILD_TOKEN_SCHEME") ?? "Bearer",
47
- headers: overrides.headers
47
+ headers: overrides.headers,
48
+ retryAttempts: overrides.retryAttempts ?? (Number(env("BLOX_BUILD_RETRY_ATTEMPTS")) || 4),
49
+ retryBaseMs: overrides.retryBaseMs ?? (Number(env("BLOX_BUILD_RETRY_MS")) || 500)
48
50
  };
49
51
  }
52
+ function sleep(ms) {
53
+ return new Promise((resolve) => setTimeout(resolve, ms));
54
+ }
50
55
  async function bloxBuildRequest(input, init = {}, options = {}) {
51
56
  const config = getBloxBuildRequestOptions(options);
52
57
  const headers = new Headers(config.headers);
@@ -57,7 +62,28 @@ async function bloxBuildRequest(input, init = {}, options = {}) {
57
62
  config.tokenScheme ? `${config.tokenScheme} ${config.token}` : config.token
58
63
  );
59
64
  }
60
- return fetch(input, { ...init, headers });
65
+ const attempts = Math.max(1, config.retryAttempts ?? 4);
66
+ const retryBaseMs = Math.max(0, config.retryBaseMs ?? 500);
67
+ for (let attempt = 1; attempt <= attempts; attempt++) {
68
+ try {
69
+ const response = await fetch(input, { ...init, headers });
70
+ const transient = response.status === 429 || response.status >= 500;
71
+ if (response.ok || !transient || attempt === attempts) return response;
72
+ const delay = retryBaseMs * 2 ** (attempt - 1);
73
+ console.warn(
74
+ `[blox-build] retry ${attempt}/${attempts} after HTTP ${response.status} in ${delay}ms`
75
+ );
76
+ if (delay) await sleep(delay);
77
+ } catch (error) {
78
+ if (attempt === attempts) throw error;
79
+ const delay = retryBaseMs * 2 ** (attempt - 1);
80
+ console.warn(
81
+ `[blox-build] retry ${attempt}/${attempts} after ${error.message} in ${delay}ms`
82
+ );
83
+ if (delay) await sleep(delay);
84
+ }
85
+ }
86
+ throw new Error("Blox build request exhausted retries");
61
87
  }
62
88
  async function bloxBuildJson(input, init = {}, options = {}) {
63
89
  const response = await bloxBuildRequest(input, init, options);
@@ -432,8 +458,9 @@ function generateSitemapXml(options) {
432
458
  const mod = lastmod[p];
433
459
  const modLine = mod ? `
434
460
  <lastmod>${esc(mod)}</lastmod>` : "";
461
+ const loc = p === "/" ? base : base + p;
435
462
  return ` <url>
436
- <loc>${esc(base + p)}</loc>${modLine}
463
+ <loc>${esc(loc)}</loc>${modLine}
437
464
  <changefreq>${changefreq}</changefreq>
438
465
  <priority>${priority}</priority>
439
466
  </url>`;
@@ -444,6 +471,35 @@ ${urls.join("\n")}
444
471
  </urlset>
445
472
  `;
446
473
  }
474
+ function generateSitemapIndexXml(options) {
475
+ const base = options.canonicalBase.replace(/\/$/, "");
476
+ const sitemaps = options.sitemapPaths.map((path2) => ` <sitemap>
477
+ <loc>${esc(base + path2)}</loc>
478
+ </sitemap>`);
479
+ return `<?xml version="1.0" encoding="UTF-8"?>
480
+ <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
481
+ ${sitemaps.join("\n")}
482
+ </sitemapindex>
483
+ `;
484
+ }
485
+ function splitSitemapPathsByLocale(options) {
486
+ const locales = new Set(options.supportedLocales);
487
+ const pathsByLocale = /* @__PURE__ */ new Map();
488
+ for (const path2 of options.renderedPaths) {
489
+ const firstSegment = path2.replace(/^\//, "").split("/")[0];
490
+ const locale = firstSegment && firstSegment !== options.defaultLocale && locales.has(firstSegment) ? firstSegment : options.defaultLocale;
491
+ const paths = pathsByLocale.get(locale) ?? [];
492
+ paths.push(path2);
493
+ pathsByLocale.set(locale, paths);
494
+ }
495
+ return pathsByLocale;
496
+ }
497
+ function localeSitemapPath(locale) {
498
+ if (!/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/.test(locale)) {
499
+ throw new Error(`Invalid sitemap locale: ${locale}`);
500
+ }
501
+ return `/sitemap-${locale}.xml`;
502
+ }
447
503
  function generateRobotsTxt(options) {
448
504
  const { robotsTxt, canonicalBase, noindex } = options;
449
505
  if (noindex) {
@@ -769,7 +825,7 @@ async function prerender({
769
825
  collections = {},
770
826
  llm = {}
771
827
  } = {}) {
772
- var _a, _b;
828
+ var _a, _b, _c;
773
829
  const absRoot = path.resolve(root);
774
830
  const absClient = path.resolve(absRoot, clientOutDir);
775
831
  const absServerEntry = path.resolve(absRoot, serverEntry);
@@ -922,15 +978,43 @@ async function prerender({
922
978
  if (writeSharedAssets) {
923
979
  const sitemapPaths = rendered.filter((p) => !noindexPaths.has(p));
924
980
  if (canonicalBase && sitemapPaths.length > 0) {
925
- const sitemap = generateSitemapXml({ renderedPaths: sitemapPaths, canonicalBase, lastmod });
926
- await fs.writeFile(path.join(absClient, "sitemap.xml"), sitemap, "utf8");
981
+ if (((_b = website == null ? void 0 : website.seo) == null ? void 0 : _b.sitemap_split_by_locale) !== false) {
982
+ const pathsByLocale = splitSitemapPathsByLocale({
983
+ renderedPaths: sitemapPaths,
984
+ defaultLocale: (website == null ? void 0 : website.default_locale) ?? "en",
985
+ supportedLocales: (website == null ? void 0 : website.supported_locales) ?? [(website == null ? void 0 : website.default_locale) ?? "en"]
986
+ });
987
+ const sitemapFiles = [];
988
+ for (const [locale, localePaths] of pathsByLocale) {
989
+ const sitemapPath = localeSitemapPath(locale);
990
+ await fs.writeFile(
991
+ path.join(absClient, sitemapPath.slice(1)),
992
+ generateSitemapXml({ renderedPaths: localePaths, canonicalBase, lastmod }),
993
+ "utf8"
994
+ );
995
+ sitemapFiles.push(sitemapPath);
996
+ }
997
+ await fs.writeFile(
998
+ path.join(absClient, "sitemap.xml"),
999
+ generateSitemapIndexXml({ canonicalBase, sitemapPaths: sitemapFiles }),
1000
+ "utf8"
1001
+ );
1002
+ console.log(` Generated sitemap.xml (${sitemapFiles.length} locales, ${sitemapPaths.length} URLs)`);
1003
+ } else {
1004
+ await fs.writeFile(
1005
+ path.join(absClient, "sitemap.xml"),
1006
+ generateSitemapXml({ renderedPaths: sitemapPaths, canonicalBase, lastmod }),
1007
+ "utf8"
1008
+ );
1009
+ console.log(` Generated sitemap.xml (${sitemapPaths.length} URLs)`);
1010
+ }
927
1011
  const skipped = noindexPaths.size > 0 ? ` (${noindexPaths.size} noindex excluded)` : "";
928
- console.log(` Generated sitemap.xml (${sitemapPaths.length} URLs)${skipped}`);
1012
+ if (skipped) console.log(` Sitemap exclusions:${skipped}`);
929
1013
  }
930
1014
  const robotsTxt = generateRobotsTxt({
931
1015
  robotsTxt: website == null ? void 0 : website.robots_txt,
932
1016
  canonicalBase,
933
- noindex: (_b = website == null ? void 0 : website.seo) == null ? void 0 : _b.noindex
1017
+ noindex: (_c = website == null ? void 0 : website.seo) == null ? void 0 : _c.noindex
934
1018
  });
935
1019
  await fs.writeFile(path.join(absClient, "robots.txt"), robotsTxt, "utf8");
936
1020
  console.log(" Generated robots.txt");
@@ -1110,6 +1194,95 @@ function discoverInternalLinks(html) {
1110
1194
  }
1111
1195
  return [...out];
1112
1196
  }
1197
+ const sitemapUrl = /<url>\s*<loc>[^<]+<\/loc>/m;
1198
+ const sitemapIndexEntry = /<sitemap>\s*<loc>[^<]+<\/loc>/gm;
1199
+ const sitemapLoc = /<loc>([^<]+)<\/loc>/;
1200
+ const loadingShell = /class=["'][^"']*\bblox-initial-loading\b/;
1201
+ const embeddedCmsState = /\b__BLOX_(?:STATE|DATA)__\b/;
1202
+ async function validateSsgOutput(options) {
1203
+ const outDir = path.resolve(options.outDir);
1204
+ const failures = [];
1205
+ const requiredFiles = options.requireFiles ?? [
1206
+ "robots.txt",
1207
+ "_redirects",
1208
+ "sitemap.xml",
1209
+ "llms.txt",
1210
+ "llms-full.txt"
1211
+ ];
1212
+ const htmlFiles = await collectHtmlFiles(outDir);
1213
+ let hydratedFiles = 0;
1214
+ for (const file of htmlFiles) {
1215
+ const name = path.relative(outDir, file);
1216
+ const html = await fs.readFile(file, "utf8");
1217
+ if (embeddedCmsState.test(html)) hydratedFiles += 1;
1218
+ if (!/<title>[^<]+<\/title>/i.test(html)) failures.push(`${name}: missing page title`);
1219
+ if (!/<link\s[^>]*rel=["']canonical["'][^>]*>/i.test(html)) {
1220
+ failures.push(`${name}: missing canonical URL`);
1221
+ }
1222
+ if (!/<html[^>]*\slang=["'][^"']+["']/i.test(html)) failures.push(`${name}: missing html lang`);
1223
+ if (loadingShell.test(html) && !embeddedCmsState.test(html)) {
1224
+ failures.push(`${name}: contains only the Blox loading shell`);
1225
+ }
1226
+ }
1227
+ if (!htmlFiles.length) failures.push("output contains no HTML files");
1228
+ if (!hydratedFiles) failures.push("output contains no prerendered Blox hydration state");
1229
+ for (const required of requiredFiles) {
1230
+ try {
1231
+ const content = await fs.readFile(path.join(outDir, required), "utf8");
1232
+ if (required === "robots.txt" && /^Disallow:\s*\/\s*$/im.test(content)) {
1233
+ failures.push("robots.txt blocks the entire site");
1234
+ }
1235
+ if (required === "llms.txt" && !/^- \[[^\]]+\]\([^)]+\)/m.test(content)) {
1236
+ failures.push("llms.txt contains no page links");
1237
+ }
1238
+ if (required === "sitemap.xml") {
1239
+ failures.push(...await validateSitemap(outDir, content));
1240
+ }
1241
+ } catch {
1242
+ failures.push(`missing ${required}`);
1243
+ }
1244
+ }
1245
+ if (failures.length) {
1246
+ throw new Error(`Invalid Blox SSG output:
1247
+ ${failures.map((item) => ` - ${item}`).join("\n")}`);
1248
+ }
1249
+ }
1250
+ async function collectHtmlFiles(directory) {
1251
+ const entries = await fs.readdir(directory, { withFileTypes: true });
1252
+ const files = await Promise.all(entries.map(async (entry) => {
1253
+ const child = path.join(directory, entry.name);
1254
+ if (entry.isDirectory() && entry.name !== "server") return collectHtmlFiles(child);
1255
+ return entry.isFile() && entry.name.endsWith(".html") ? [child] : [];
1256
+ }));
1257
+ return files.flat();
1258
+ }
1259
+ async function validateSitemap(outDir, content) {
1260
+ var _a;
1261
+ if (sitemapUrl.test(content)) return [];
1262
+ const failures = [];
1263
+ const entries = content.match(sitemapIndexEntry) ?? [];
1264
+ if (!entries.length) return ["sitemap.xml contains neither page URLs nor child sitemaps"];
1265
+ let childUrlCount = 0;
1266
+ for (const entry of entries) {
1267
+ const loc = (_a = entry.match(sitemapLoc)) == null ? void 0 : _a[1];
1268
+ if (!loc) continue;
1269
+ const pathname = new URL(loc).pathname.replace(/^\/+/, "");
1270
+ const childPath = path.resolve(outDir, pathname);
1271
+ if (!childPath.startsWith(`${outDir}${path.sep}`)) {
1272
+ failures.push(`child sitemap escapes output directory: ${pathname}`);
1273
+ continue;
1274
+ }
1275
+ try {
1276
+ const child = await fs.readFile(childPath, "utf8");
1277
+ if (!sitemapUrl.test(child)) failures.push(`${pathname} contains no page URLs`);
1278
+ else childUrlCount += (child.match(/<url>/g) ?? []).length;
1279
+ } catch {
1280
+ failures.push(`missing child sitemap ${pathname}`);
1281
+ }
1282
+ }
1283
+ if (!childUrlCount) failures.push("sitemap index child files contain no page URLs");
1284
+ return failures;
1285
+ }
1113
1286
  exports.BloxBuildResponseError = BloxBuildResponseError;
1114
1287
  exports.bloxBuildJson = bloxBuildJson;
1115
1288
  exports.bloxBuildRequest = bloxBuildRequest;
@@ -1123,13 +1296,17 @@ exports.generateLlmsFullTxt = generateLlmsFullTxt;
1123
1296
  exports.generateLlmsTxt = generateLlmsTxt;
1124
1297
  exports.generateNetlifyRedirects = generateNetlifyRedirects;
1125
1298
  exports.generateRobotsTxt = generateRobotsTxt;
1299
+ exports.generateSitemapIndexXml = generateSitemapIndexXml;
1126
1300
  exports.generateSitemapXml = generateSitemapXml;
1127
1301
  exports.getBloxBuildRequestOptions = getBloxBuildRequestOptions;
1128
1302
  exports.getSiteIconFlags = getSiteIconFlags;
1129
1303
  exports.llmArtifacts = llmArtifacts;
1304
+ exports.localeSitemapPath = localeSitemapPath;
1130
1305
  exports.mergeLlmParts = mergeLlmParts;
1131
1306
  exports.polyfillBloxSsgGlobals = polyfillBloxSsgGlobals;
1132
1307
  exports.prerender = prerender;
1133
1308
  exports.primaryContextEntry = primaryContextEntry;
1134
1309
  exports.resolveManifestProvenance = resolveManifestProvenance;
1310
+ exports.splitSitemapPathsByLocale = splitSitemapPathsByLocale;
1135
1311
  exports.uploadBloxManifest = uploadBloxManifest;
1312
+ exports.validateSsgOutput = validateSsgOutput;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/blox",
3
3
  "type": "module",
4
- "version": "1.15.529",
4
+ "version": "1.15.533",
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",