@bagelink/blox 1.15.647 → 1.15.651

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.
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const PreviewApp_vue_vue_type_style_index_0_lang = require("./PreviewApp.vue_vue_type_style_index_0_lang-DuF7jSt7.cjs");
3
+ const PreviewApp_vue_vue_type_style_index_0_lang = require("./PreviewApp.vue_vue_type_style_index_0_lang-CRaNO3wo.cjs");
4
4
  exports.default = PreviewApp_vue_vue_type_style_index_0_lang._sfc_main;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "./PreviewApp.vue_vue_type_style_index_0_lang-0cUPU_L_.js";
1
+ import { _ as _sfc_main } from "./PreviewApp.vue_vue_type_style_index_0_lang-BzGw32LW.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, inject, ref, h, provide, onMounted, onUnmounted, openBlock, createElementBlock, createVNode, unref, nextTick } from "vue";
2
- import { d as BLOX_REGISTRY_KEY, r as resolveBlockProps, u as useLocale, e as BLOX_RUNTIME_KEY } from "./appRuntime-Sl40toxn.js";
2
+ import { d as BLOX_REGISTRY_KEY, r as resolveBlockProps, u as useLocale, e as BLOX_RUNTIME_KEY } from "./appRuntime-BKUaccqq.js";
3
3
  function sendToEditor(msg) {
4
4
  window.parent.postMessage(cloneForPostMessage(msg), "*");
5
5
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  const vue = require("vue");
3
- const appRuntime = require("./appRuntime-Bh3LdYXU.cjs");
3
+ const appRuntime = require("./appRuntime-Cay272e9.cjs");
4
4
  function sendToEditor(msg) {
5
5
  window.parent.postMessage(cloneForPostMessage(msg), "*");
6
6
  }
@@ -869,7 +869,7 @@ class BloxInstance {
869
869
  router.addRoute({
870
870
  path: "/_blox_preview",
871
871
  name: BLOX_PREVIEW_ROUTE_NAME,
872
- component: () => import("./PreviewApp-C-0zfTwq.js"),
872
+ component: () => import("./PreviewApp-hLsU5HKs.js"),
873
873
  beforeEnter: () => typeof window === "undefined" || window.parent !== window ? true : "/"
874
874
  });
875
875
  }
@@ -1218,7 +1218,7 @@ function installBloxRuntime(options) {
1218
1218
  setup,
1219
1219
  adminEdit,
1220
1220
  contentFallback = false,
1221
- navigation = "spa",
1221
+ navigation = "document",
1222
1222
  api,
1223
1223
  localeState: localeState2
1224
1224
  } = options;
@@ -870,7 +870,7 @@ class BloxInstance {
870
870
  router.addRoute({
871
871
  path: "/_blox_preview",
872
872
  name: BLOX_PREVIEW_ROUTE_NAME,
873
- component: () => Promise.resolve().then(() => require("./PreviewApp-BD5RzRZO.cjs")),
873
+ component: () => Promise.resolve().then(() => require("./PreviewApp-7BXiNjwg.cjs")),
874
874
  beforeEnter: () => typeof window === "undefined" || window.parent !== window ? true : "/"
875
875
  });
876
876
  }
@@ -1219,7 +1219,7 @@ function installBloxRuntime(options) {
1219
1219
  setup,
1220
1220
  adminEdit,
1221
1221
  contentFallback = false,
1222
- navigation = "spa",
1222
+ navigation = "document",
1223
1223
  api,
1224
1224
  localeState: localeState2
1225
1225
  } = options;
@@ -18,6 +18,11 @@ export interface InstallBloxRuntimeOptions {
18
18
  setup?: (app: App) => void;
19
19
  adminEdit?: BloxAdminConfig;
20
20
  contentFallback?: boolean;
21
+ /**
22
+ * CMS navigation mode. @default 'document' — matches `createBloxSSREntry`,
23
+ * which prerenders every route as its own static page. Only opt into `spa`
24
+ * when the API is reachable from the site origin.
25
+ */
21
26
  navigation?: 'document' | 'spa';
22
27
  api: BloxApiClient;
23
28
  localeState: BloxLocaleState;
@@ -1 +1 @@
1
- {"version":3,"file":"appRuntime.d.ts","sourceRoot":"","sources":["../src/appRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAG9D,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;AAGtD,MAAM,WAAW,yBAAyB;IACzC,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpD,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;IAChD,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC5C,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAA;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,UAAU,CAAC,EAAE,UAAU,GAAG,KAAK,CAAA;IAC/B,GAAG,EAAE,aAAa,CAAA;IAClB,WAAW,EAAE,eAAe,CAAA;CAC5B;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAwDnF"}
1
+ {"version":3,"file":"appRuntime.d.ts","sourceRoot":"","sources":["../src/appRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAG9D,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;AAGtD,MAAM,WAAW,yBAAyB;IACzC,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpD,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;IAChD,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC5C,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAA;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,KAAK,CAAA;IAC/B,GAAG,EAAE,aAAa,CAAA;IAClB,WAAW,EAAE,eAAe,CAAA;CAC5B;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAwDnF"}
@@ -64,7 +64,16 @@ export interface CreateBloxAppOptions {
64
64
  * plausible: 'auctentic2.netlify.app'
65
65
  */
66
66
  plausible?: string | PlausibleOptions;
67
- /** CMS navigation mode. Marketing sites should use `document`. @default 'spa' */
67
+ /**
68
+ * CMS navigation mode. @default 'document'
69
+ *
70
+ * `document` (default) lets the browser navigate between prerendered pages —
71
+ * correct for Blox sites because `blox-ssg` emits one static HTML file per
72
+ * route and the host serves no API. `spa` routes on the client and fetches
73
+ * `/blox/websites/<id>/resolve-path` for any page without an embedded
74
+ * payload, which only works when the API is reachable from the site origin —
75
+ * opt in to it deliberately.
76
+ */
68
77
  navigation?: 'document' | 'spa';
69
78
  /** Opt-in admin "edit this page" button configuration. */
70
79
  adminEdit?: BloxOptions['adminEdit'];
@@ -1 +1 @@
1
- {"version":3,"file":"createBloxApp.d.ts","sourceRoot":"","sources":["../src/createBloxApp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAWhD,MAAM,WAAW,oBAAoB;IACpC,oCAAoC;IACpC,aAAa,EAAE,SAAS,CAAA;IACxB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpD,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;IAClD;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;IAChD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC5C;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1B;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAA;IACrC,iFAAiF;IACjF,UAAU,CAAC,EAAE,UAAU,GAAG,KAAK,CAAA;IAC/B,0DAA0D;IAC1D,SAAS,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAA;IACpC,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAChC,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAoCvE;AAED,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,YAAY,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA4I1E"}
1
+ {"version":3,"file":"createBloxApp.d.ts","sourceRoot":"","sources":["../src/createBloxApp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAWhD,MAAM,WAAW,oBAAoB;IACpC,oCAAoC;IACpC,aAAa,EAAE,SAAS,CAAA;IACxB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpD,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;IAClD;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;IAChD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC5C;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1B;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAA;IACrC;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,KAAK,CAAA;IAC/B,0DAA0D;IAC1D,SAAS,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAA;IACpC,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAChC,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAoCvE;AAED,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,YAAY,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA4I1E"}
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const index = require("./index-DUjEj7ts.cjs");
4
- const PreviewApp_vue_vue_type_style_index_0_lang = require("./PreviewApp.vue_vue_type_style_index_0_lang-DuF7jSt7.cjs");
5
- const appRuntime = require("./appRuntime-Bh3LdYXU.cjs");
4
+ const PreviewApp_vue_vue_type_style_index_0_lang = require("./PreviewApp.vue_vue_type_style_index_0_lang-CRaNO3wo.cjs");
5
+ const appRuntime = require("./appRuntime-Cay272e9.cjs");
6
6
  const vue = require("vue");
7
7
  const ssg_client = require("./client-AoDTJJXJ.cjs");
8
8
  const vueRouter = require("vue-router");
@@ -272,7 +272,7 @@ function createBloxApp(options) {
272
272
  globalComponents = {},
273
273
  setup: userSetup,
274
274
  plausible,
275
- navigation = "spa",
275
+ navigation = "document",
276
276
  adminEdit,
277
277
  chunkLoadRecovery = true
278
278
  } = options;
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { useBloxApi, getItemBySlug, getItemById, provideBloxApi } from "./index-I81QTzv-.js";
2
2
  import { configureApi, createBloxApi, getCollectionResolver, getWebsiteId, getWebsiteIdSync, listItems, resolvePath, setApiOrigin, setCollectionResolver } from "./index-I81QTzv-.js";
3
- import { _, P, s, a } from "./PreviewApp.vue_vue_type_style_index_0_lang-0cUPU_L_.js";
4
- import { f as BLOX_LOCALE_STRATEGY_KEY, u as useLocale, n as normalizeLink, e as BLOX_RUNTIME_KEY, g as useSeo, h as getRegistryData, j as getContentRoute, p as provideBloxData, b as provideBloxLocale, i as installBloxRuntime, s as setActiveLocale, k as installSmartLinks, l as consumePendingLocaleSwitch } from "./appRuntime-Sl40toxn.js";
5
- import { _ as _2, m, o, q, t, v, w, x, y, P as P2, z, A, c, a as a2, C, D, E, F, G, H, I, J, K, L, M, r, N, O, Q, R } from "./appRuntime-Sl40toxn.js";
3
+ import { _, P, s, a } from "./PreviewApp.vue_vue_type_style_index_0_lang-BzGw32LW.js";
4
+ import { f as BLOX_LOCALE_STRATEGY_KEY, u as useLocale, n as normalizeLink, e as BLOX_RUNTIME_KEY, g as useSeo, h as getRegistryData, j as getContentRoute, p as provideBloxData, b as provideBloxLocale, i as installBloxRuntime, s as setActiveLocale, k as installSmartLinks, l as consumePendingLocaleSwitch } from "./appRuntime-BKUaccqq.js";
5
+ import { _ as _2, m, o, q, t, v, w, x, y, P as P2, z, A, c, a as a2, C, D, E, F, G, H, I, J, K, L, M, r, N, O, Q, R } from "./appRuntime-BKUaccqq.js";
6
6
  import { defineComponent, resolveComponent, openBlock, createBlock, withCtx, Transition, resolveDynamicComponent, inject, ref, watch, onMounted, onUnmounted, computed, onServerPrefetch, toValue, h, Suspense, createSSRApp, createApp } from "vue";
7
7
  import { r as readBloxHydration } from "./client-Ce9fRCGH.js";
8
8
  import { useRouter, useRoute } from "vue-router";
@@ -272,7 +272,7 @@ function createBloxApp(options) {
272
272
  globalComponents = {},
273
273
  setup: userSetup,
274
274
  plausible,
275
- navigation = "spa",
275
+ navigation = "document",
276
276
  adminEdit,
277
277
  chunkLoadRecovery = true
278
278
  } = options;
@@ -26,7 +26,7 @@ const node_child_process = require("node:child_process");
26
26
  const os = require("node:os");
27
27
  const path = require("node:path");
28
28
  const process = require("node:process");
29
- const llmArtifacts = require("./validate-output-CGCpqI7T.cjs");
29
+ const llmArtifacts = require("./validate-output-DUqTdLHI.cjs");
30
30
  const AUTO_SHARD_CAP = Number(process.env.BLOX_SSG_SHARD_CAP) || 6;
31
31
  const PREFETCH_BUDGET = Number(process.env.BLOX_SSG_PREFETCH_BUDGET) || 24;
32
32
  const SEQUENTIAL_SHARDS = process.env.BLOX_SSG_SEQUENTIAL === "1";
@@ -166,7 +166,7 @@ async function runSharded(opts) {
166
166
  }
167
167
  if (process.env.BLOX_SSG_LLM !== "0") {
168
168
  try {
169
- const { mergeLlmParts } = await Promise.resolve().then(() => require("./validate-output-CGCpqI7T.cjs")).then((n) => n.llmArtifacts);
169
+ const { mergeLlmParts } = await Promise.resolve().then(() => require("./validate-output-DUqTdLHI.cjs")).then((n) => n.llmArtifacts);
170
170
  const mergeWebsite = website;
171
171
  const partFiles = Array.from({ length: total }, (_, i) => path.join(llmPartsDir, `part.${i}.json`));
172
172
  const { pages } = await mergeLlmParts({
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import process from "node:process";
5
- import { f as fetchCmsSiteData, g as generateSitemapArtifacts } from "./validate-output-CBUyK03E.js";
5
+ import { f as fetchCmsSiteData, g as generateSitemapArtifacts } from "./validate-output-DcEQIZns.js";
6
6
  const AUTO_SHARD_CAP = Number(process.env.BLOX_SSG_SHARD_CAP) || 6;
7
7
  const PREFETCH_BUDGET = Number(process.env.BLOX_SSG_PREFETCH_BUDGET) || 24;
8
8
  const SEQUENTIAL_SHARDS = process.env.BLOX_SSG_SEQUENTIAL === "1";
@@ -142,7 +142,7 @@ async function runSharded(opts) {
142
142
  }
143
143
  if (process.env.BLOX_SSG_LLM !== "0") {
144
144
  try {
145
- const { mergeLlmParts } = await import("./validate-output-CBUyK03E.js").then((n) => n.A);
145
+ const { mergeLlmParts } = await import("./validate-output-DcEQIZns.js").then((n) => n.C);
146
146
  const mergeWebsite = website;
147
147
  const partFiles = Array.from({ length: total }, (_, i) => path.join(llmPartsDir, `part.${i}.json`));
148
148
  const { pages } = await mergeLlmParts({
package/dist/ssg/cli.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  const process = require("node:process");
4
4
  const fs = require("node:fs/promises");
5
5
  const ssg_buildGrant = require("./build-grant.cjs");
6
- const llmArtifacts = require("../validate-output-CGCpqI7T.cjs");
6
+ const llmArtifacts = require("../validate-output-DUqTdLHI.cjs");
7
7
  function installFetchTimeout() {
8
8
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
9
9
  const original = globalThis.fetch;
@@ -58,6 +58,7 @@ async function main() {
58
58
  let routesCmd = "";
59
59
  let siteDataFile = "";
60
60
  let validateOutDir = "";
61
+ let validateOutput = process.env.BLOX_SSG_VALIDATE !== "0";
61
62
  const passthroughArgs = [];
62
63
  const excludePaths = ["/_blox_preview"];
63
64
  for (const a of argv) {
@@ -77,6 +78,8 @@ async function main() {
77
78
  validateOutDir = "dist";
78
79
  } else if (a.startsWith("--validate=")) {
79
80
  validateOutDir = a.slice("--validate=".length);
81
+ } else if (a === "--no-validate") {
82
+ validateOutput = false;
80
83
  } else if (a.startsWith("--shard=")) {
81
84
  const [i, n] = a.slice("--shard=".length).split("/").map(Number);
82
85
  if (Number.isInteger(i) && Number.isInteger(n) && n > 0 && i >= 0 && i < n) {
@@ -101,7 +104,10 @@ Options:
101
104
  --shard=<i/n> (internal) Render only this shard's slice — set by --shards.
102
105
  --routes-cmd=<cmd> Shell command whose stdout (whitespace-separated) is the
103
106
  route list. For router-driven sites with no CMS pages.
104
- --validate[=dir] Validate generated SSG assets (default directory: dist).
107
+ --validate[=dir] Validate generated SSG assets (default directory: dist)
108
+ and exit without prerendering.
109
+ --no-validate Skip the automatic output validation a normal build runs.
110
+ (Also: BLOX_SSG_VALIDATE=0.)
105
111
  --help, -h Show this help
106
112
 
107
113
  Environment:
@@ -141,7 +147,7 @@ Environment:
141
147
  if (shardsOpt !== null || routesCmd) {
142
148
  const { apiBase: apiBase2, websiteName: configWebsiteName2 } = await resolveApiBase(mode);
143
149
  const websiteName2 = process.env.WEBSITE_NAME ?? configWebsiteName2 ?? "default";
144
- const { runSharded } = await Promise.resolve().then(() => require("../shard-runner-BoSrSIzQ.cjs"));
150
+ const { runSharded } = await Promise.resolve().then(() => require("../shard-runner-CTCqpTrW.cjs"));
145
151
  const code = await runSharded({
146
152
  shards: shardsOpt ?? "auto",
147
153
  mode,
@@ -280,6 +286,10 @@ ${"=".repeat(60)}`);
280
286
  process.exitCode = 1;
281
287
  }
282
288
  }
289
+ if (validateOutput && shardTotal === 1) {
290
+ await llmArtifacts.validateInternalLinks("dist");
291
+ console.log("[blox-ssg] validated internal links");
292
+ }
283
293
  if (productionBuild && shardTotal === 1) {
284
294
  const uploadWebsiteId = ((_b = process.env.BLOX_WEBSITE_ID) == null ? void 0 : _b.trim()) || websiteId;
285
295
  const manifestExists = await fs.stat("dist/.blox-manifest.json").then(() => true, () => false);
package/dist/ssg/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import process from "node:process";
3
3
  import fs from "node:fs/promises";
4
4
  import { resolveBloxBuildGrant } from "./build-grant.mjs";
5
- import { v as validateSsgOutput, u as uploadBloxManifest, p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, b as buildCollectionResolver, a as prerender } from "../validate-output-CBUyK03E.js";
5
+ import { v as validateSsgOutput, u as uploadBloxManifest, p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, b as buildCollectionResolver, a as prerender, c as validateInternalLinks } from "../validate-output-DcEQIZns.js";
6
6
  function installFetchTimeout() {
7
7
  const ms = Number(process.env.BLOX_SSG_FETCH_TIMEOUT_MS) || 2e4;
8
8
  const original = globalThis.fetch;
@@ -57,6 +57,7 @@ async function main() {
57
57
  let routesCmd = "";
58
58
  let siteDataFile = "";
59
59
  let validateOutDir = "";
60
+ let validateOutput = process.env.BLOX_SSG_VALIDATE !== "0";
60
61
  const passthroughArgs = [];
61
62
  const excludePaths = ["/_blox_preview"];
62
63
  for (const a of argv) {
@@ -76,6 +77,8 @@ async function main() {
76
77
  validateOutDir = "dist";
77
78
  } else if (a.startsWith("--validate=")) {
78
79
  validateOutDir = a.slice("--validate=".length);
80
+ } else if (a === "--no-validate") {
81
+ validateOutput = false;
79
82
  } else if (a.startsWith("--shard=")) {
80
83
  const [i, n] = a.slice("--shard=".length).split("/").map(Number);
81
84
  if (Number.isInteger(i) && Number.isInteger(n) && n > 0 && i >= 0 && i < n) {
@@ -100,7 +103,10 @@ Options:
100
103
  --shard=<i/n> (internal) Render only this shard's slice — set by --shards.
101
104
  --routes-cmd=<cmd> Shell command whose stdout (whitespace-separated) is the
102
105
  route list. For router-driven sites with no CMS pages.
103
- --validate[=dir] Validate generated SSG assets (default directory: dist).
106
+ --validate[=dir] Validate generated SSG assets (default directory: dist)
107
+ and exit without prerendering.
108
+ --no-validate Skip the automatic output validation a normal build runs.
109
+ (Also: BLOX_SSG_VALIDATE=0.)
104
110
  --help, -h Show this help
105
111
 
106
112
  Environment:
@@ -140,7 +146,7 @@ Environment:
140
146
  if (shardsOpt !== null || routesCmd) {
141
147
  const { apiBase: apiBase2, websiteName: configWebsiteName2 } = await resolveApiBase(mode);
142
148
  const websiteName2 = process.env.WEBSITE_NAME ?? configWebsiteName2 ?? "default";
143
- const { runSharded } = await import("../shard-runner-A_vfoOw0.js");
149
+ const { runSharded } = await import("../shard-runner-PsawGL3I.js");
144
150
  const code = await runSharded({
145
151
  shards: shardsOpt ?? "auto",
146
152
  mode,
@@ -279,6 +285,10 @@ ${"=".repeat(60)}`);
279
285
  process.exitCode = 1;
280
286
  }
281
287
  }
288
+ if (validateOutput && shardTotal === 1) {
289
+ await validateInternalLinks("dist");
290
+ console.log("[blox-ssg] validated internal links");
291
+ }
282
292
  if (productionBuild && shardTotal === 1) {
283
293
  const uploadWebsiteId = ((_b = process.env.BLOX_WEBSITE_ID) == null ? void 0 : _b.trim()) || websiteId;
284
294
  const manifestExists = await fs.stat("dist/.blox-manifest.json").then(() => true, () => false);
@@ -22,11 +22,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
25
- const llmArtifacts = require("../validate-output-CGCpqI7T.cjs");
25
+ const llmArtifacts = require("../validate-output-DUqTdLHI.cjs");
26
26
  const ssg_buildGrant = require("./build-grant.cjs");
27
27
  const ssg_client = require("../client-AoDTJJXJ.cjs");
28
28
  const vue = require("vue");
29
- const appRuntime = require("../appRuntime-Bh3LdYXU.cjs");
29
+ const appRuntime = require("../appRuntime-Cay272e9.cjs");
30
30
  const index = require("../index-DUjEj7ts.cjs");
31
31
  async function renderBloxSsgPage(options) {
32
32
  var _a, _b, _c, _d;
@@ -445,6 +445,7 @@ exports.prerender = llmArtifacts.prerender;
445
445
  exports.resolveManifestProvenance = llmArtifacts.resolveManifestProvenance;
446
446
  exports.splitSitemapPathsByLocale = llmArtifacts.splitSitemapPathsByLocale;
447
447
  exports.uploadBloxManifest = llmArtifacts.uploadBloxManifest;
448
+ exports.validateInternalLinks = llmArtifacts.validateInternalLinks;
448
449
  exports.validateSsgOutput = llmArtifacts.validateSsgOutput;
449
450
  exports.parseBloxBuildGrantBody = ssg_buildGrant.parseBloxBuildGrantBody;
450
451
  exports.resolveBloxBuildGrant = ssg_buildGrant.resolveBloxBuildGrant;
@@ -31,6 +31,6 @@ export { buildJsonLd, extractPageText, generateLlmsFullTxt, generateLlmsTxt, mer
31
31
  export type { LlmArtifactsConfig, LlmPageEntry } from './llm-artifacts';
32
32
  export { resolveManifestProvenance, uploadBloxManifest } from './manifest-upload';
33
33
  export type { ManifestProvenance, ManifestUpload } from './manifest-upload';
34
- export { validateSsgOutput } from './validate-output';
34
+ export { validateInternalLinks, validateSsgOutput } from './validate-output';
35
35
  export type { ValidateSsgOutputOptions } from './validate-output';
36
36
  //# 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,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAA;AACrH,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAC9E,YAAY,EAAE,cAAc,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAA;AACjF,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAC9D;;;;;;;;;;GAUG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAClG,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAC9F,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,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,wBAAwB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,OAAO,CAAA;AACxO,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AACtF,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,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
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ssg/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAA;AACrH,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAC9E,YAAY,EAAE,cAAc,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAA;AACjF,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAC9D;;;;;;;;;;GAUG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAClG,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAC9F,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,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,wBAAwB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,OAAO,CAAA;AACxO,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AACtF,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,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACjF,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAC3E,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC5E,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA"}
@@ -1,9 +1,9 @@
1
- import { c as buildPageHead, d as primaryContextEntry, e as buildJsonLd, h as extractPageText, B as BloxBuildResponseError, i as bloxBuildJson } from "../validate-output-CBUyK03E.js";
2
- import { j, k, f, l, m, n, o, g, q, r, s, t, w, x, p, a, y, z, u, v } from "../validate-output-CBUyK03E.js";
1
+ import { d as buildPageHead, e as primaryContextEntry, h as buildJsonLd, i as extractPageText, B as BloxBuildResponseError, j as bloxBuildJson } from "../validate-output-DcEQIZns.js";
2
+ import { k, l, f, m, n, o, q, g, r, s, t, w, x, y, p, a, z, A, u, c, v } from "../validate-output-DcEQIZns.js";
3
3
  import { parseBloxBuildGrantBody, resolveBloxBuildGrant } from "./build-grant.mjs";
4
4
  import { a as BLOX_HYDRATION_WINDOW_KEY } from "../client-Ce9fRCGH.js";
5
5
  import { createSSRApp, h, Suspense } from "vue";
6
- import { c as collectBloxData, a as collectBloxSeo, p as provideBloxData, b as provideBloxLocale, B as BLOX_SSR_ROUTE_STATE_KEY, i as installBloxRuntime, s as setActiveLocale } from "../appRuntime-Sl40toxn.js";
6
+ import { c as collectBloxData, a as collectBloxSeo, p as provideBloxData, b as provideBloxLocale, B as BLOX_SSR_ROUTE_STATE_KEY, i as installBloxRuntime, s as setActiveLocale } from "../appRuntime-BKUaccqq.js";
7
7
  import { provideBloxApi, getCollectionResolver } from "../index-I81QTzv-.js";
8
8
  async function renderBloxSsgPage(options) {
9
9
  var _a, _b, _c, _d;
@@ -402,34 +402,35 @@ export {
402
402
  BLOX_HYDRATION_WINDOW_KEY,
403
403
  BloxBuildResponseError,
404
404
  bloxBuildJson,
405
- j as bloxBuildRequest,
405
+ k as bloxBuildRequest,
406
406
  buildJsonLd,
407
407
  buildPageHead,
408
- k as buildSiteHead,
408
+ l as buildSiteHead,
409
409
  createBloxSSREntry,
410
410
  extractPageText,
411
411
  f as fetchCmsSiteData,
412
412
  fetchDatastoreSnapshot,
413
- l as generateLlmsFullTxt,
414
- m as generateLlmsTxt,
415
- n as generateNetlifyRedirects,
416
- o as generateRobotsTxt,
413
+ m as generateLlmsFullTxt,
414
+ n as generateLlmsTxt,
415
+ o as generateNetlifyRedirects,
416
+ q as generateRobotsTxt,
417
417
  g as generateSitemapArtifacts,
418
- q as generateSitemapIndexXml,
419
- r as generateSitemapXml,
420
- s as getBloxBuildRequestOptions,
421
- t as getSiteIconFlags,
422
- w as localeSitemapPath,
423
- x as mergeLlmParts,
418
+ r as generateSitemapIndexXml,
419
+ s as generateSitemapXml,
420
+ t as getBloxBuildRequestOptions,
421
+ w as getSiteIconFlags,
422
+ x as localeSitemapPath,
423
+ y as mergeLlmParts,
424
424
  parseBloxBuildGrantBody,
425
425
  p as polyfillBloxSsgGlobals,
426
426
  a as prerender,
427
427
  querySnapshotRows,
428
428
  renderBloxSsgPage,
429
429
  resolveBloxBuildGrant,
430
- y as resolveManifestProvenance,
430
+ z as resolveManifestProvenance,
431
431
  snapshotRows,
432
- z as splitSitemapPathsByLocale,
432
+ A as splitSitemapPathsByLocale,
433
433
  u as uploadBloxManifest,
434
+ c as validateInternalLinks,
434
435
  v as validateSsgOutput
435
436
  };
@@ -1,6 +1,24 @@
1
+ /**
2
+ * Fail when any prerendered page contains a relative internal link.
3
+ *
4
+ * A prerendered site is a tree of static files, so `<a href="contact">` on
5
+ * `/about` resolves to `/about/contact` for the browser — navigation silently
6
+ * breaks. This is the one check a normal build runs automatically (see
7
+ * `cli.ts`); the fuller `validateSsgOutput` stays opt-in via `--validate`.
8
+ */
9
+ export declare function validateInternalLinks(outDir: string): Promise<void>;
1
10
  export interface ValidateSsgOutputOptions {
2
11
  outDir: string;
3
12
  requireFiles?: string[];
13
+ /**
14
+ * Fail when a prerendered page contains a relative internal link.
15
+ *
16
+ * A prerendered site is a tree of static files, so `<a href="contact">` on
17
+ * `/about` resolves to `/about/contact` for the browser. That silently
18
+ * breaks navigation and hides a router/base misconfiguration — catch it at
19
+ * build time. @default true
20
+ */
21
+ checkInternalLinks?: boolean;
4
22
  }
5
23
  export declare function validateSsgOutput(options: ValidateSsgOutputOptions): Promise<void>;
6
24
  //# sourceMappingURL=validate-output.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"validate-output.d.ts","sourceRoot":"","sources":["../../src/ssg/validate-output.ts"],"names":[],"mappings":"AASA;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBzE;AAED,MAAM,WAAW,wBAAwB;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAOD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DxF"}
@@ -1320,9 +1320,29 @@ const sitemapIndexEntry = /<sitemap>\s*<loc>[^<]+<\/loc>/gm;
1320
1320
  const sitemapLoc = /<loc>([^<]+)<\/loc>/;
1321
1321
  const loadingShell = /class=["'][^"']*\bblox-initial-loading\b/;
1322
1322
  const embeddedCmsState = /\b__BLOX_HYDRATION__\b/;
1323
+ async function validateInternalLinks(outDir) {
1324
+ const root = path.resolve(outDir);
1325
+ const failures = [];
1326
+ for (const file of await collectHtmlFiles(root)) {
1327
+ const name = path.relative(root, file);
1328
+ const html = await fs.readFile(file, "utf8");
1329
+ for (const href of relativeInternalLinks(html)) {
1330
+ failures.push(
1331
+ `${name}: relative internal link "${href}" — resolves against this page (e.g. "/about" + "contact" → "/about/contact"). Use a root-relative path ("/contact") or an absolute URL.`
1332
+ );
1333
+ }
1334
+ }
1335
+ if (failures.length) {
1336
+ throw new Error(`Invalid Blox SSG output:
1337
+ ${failures.map((item) => ` - ${item}`).join("\n")}`);
1338
+ }
1339
+ }
1340
+ const anchorHref = /<a\b[^>]*\shref=["']([^"']*)["']/gi;
1341
+ const ABSOLUTE_OR_SPECIAL = /^(?:[a-z][a-z0-9+.-]*:|\/\/|\/|#|\?|$)/i;
1323
1342
  async function validateSsgOutput(options) {
1324
1343
  const outDir = path.resolve(options.outDir);
1325
1344
  const failures = [];
1345
+ const checkInternalLinks = options.checkInternalLinks ?? true;
1326
1346
  const requiredFiles = options.requireFiles ?? [
1327
1347
  "robots.txt",
1328
1348
  "_redirects",
@@ -1344,6 +1364,13 @@ async function validateSsgOutput(options) {
1344
1364
  if (loadingShell.test(html) && !embeddedCmsState.test(html)) {
1345
1365
  failures.push(`${name}: contains only the Blox loading shell`);
1346
1366
  }
1367
+ if (checkInternalLinks) {
1368
+ for (const href of relativeInternalLinks(html)) {
1369
+ failures.push(
1370
+ `${name}: relative internal link "${href}" — resolves against this page (e.g. "/about" + "contact" → "/about/contact"). Use a root-relative path ("/contact") or an absolute URL.`
1371
+ );
1372
+ }
1373
+ }
1347
1374
  }
1348
1375
  if (!htmlFiles.length) failures.push("output contains no HTML files");
1349
1376
  if (!hydratedFiles) failures.push("output contains no prerendered Blox hydration state");
@@ -1368,6 +1395,16 @@ async function validateSsgOutput(options) {
1368
1395
  ${failures.map((item) => ` - ${item}`).join("\n")}`);
1369
1396
  }
1370
1397
  }
1398
+ function relativeInternalLinks(html) {
1399
+ var _a;
1400
+ const found = /* @__PURE__ */ new Set();
1401
+ for (const match of html.matchAll(anchorHref)) {
1402
+ const href = ((_a = match[1]) == null ? void 0 : _a.trim()) ?? "";
1403
+ if (ABSOLUTE_OR_SPECIAL.test(href)) continue;
1404
+ found.add(href);
1405
+ }
1406
+ return [...found];
1407
+ }
1371
1408
  async function collectHtmlFiles(directory) {
1372
1409
  const entries = await fs.readdir(directory, { withFileTypes: true });
1373
1410
  const files = await Promise.all(entries.map(async (entry) => {
@@ -1431,4 +1468,5 @@ exports.primaryContextEntry = primaryContextEntry;
1431
1468
  exports.resolveManifestProvenance = resolveManifestProvenance;
1432
1469
  exports.splitSitemapPathsByLocale = splitSitemapPathsByLocale;
1433
1470
  exports.uploadBloxManifest = uploadBloxManifest;
1471
+ exports.validateInternalLinks = validateInternalLinks;
1434
1472
  exports.validateSsgOutput = validateSsgOutput;
@@ -1297,9 +1297,29 @@ const sitemapIndexEntry = /<sitemap>\s*<loc>[^<]+<\/loc>/gm;
1297
1297
  const sitemapLoc = /<loc>([^<]+)<\/loc>/;
1298
1298
  const loadingShell = /class=["'][^"']*\bblox-initial-loading\b/;
1299
1299
  const embeddedCmsState = /\b__BLOX_HYDRATION__\b/;
1300
+ async function validateInternalLinks(outDir) {
1301
+ const root = path.resolve(outDir);
1302
+ const failures = [];
1303
+ for (const file of await collectHtmlFiles(root)) {
1304
+ const name = path.relative(root, file);
1305
+ const html = await fs.readFile(file, "utf8");
1306
+ for (const href of relativeInternalLinks(html)) {
1307
+ failures.push(
1308
+ `${name}: relative internal link "${href}" — resolves against this page (e.g. "/about" + "contact" → "/about/contact"). Use a root-relative path ("/contact") or an absolute URL.`
1309
+ );
1310
+ }
1311
+ }
1312
+ if (failures.length) {
1313
+ throw new Error(`Invalid Blox SSG output:
1314
+ ${failures.map((item) => ` - ${item}`).join("\n")}`);
1315
+ }
1316
+ }
1317
+ const anchorHref = /<a\b[^>]*\shref=["']([^"']*)["']/gi;
1318
+ const ABSOLUTE_OR_SPECIAL = /^(?:[a-z][a-z0-9+.-]*:|\/\/|\/|#|\?|$)/i;
1300
1319
  async function validateSsgOutput(options) {
1301
1320
  const outDir = path.resolve(options.outDir);
1302
1321
  const failures = [];
1322
+ const checkInternalLinks = options.checkInternalLinks ?? true;
1303
1323
  const requiredFiles = options.requireFiles ?? [
1304
1324
  "robots.txt",
1305
1325
  "_redirects",
@@ -1321,6 +1341,13 @@ async function validateSsgOutput(options) {
1321
1341
  if (loadingShell.test(html) && !embeddedCmsState.test(html)) {
1322
1342
  failures.push(`${name}: contains only the Blox loading shell`);
1323
1343
  }
1344
+ if (checkInternalLinks) {
1345
+ for (const href of relativeInternalLinks(html)) {
1346
+ failures.push(
1347
+ `${name}: relative internal link "${href}" — resolves against this page (e.g. "/about" + "contact" → "/about/contact"). Use a root-relative path ("/contact") or an absolute URL.`
1348
+ );
1349
+ }
1350
+ }
1324
1351
  }
1325
1352
  if (!htmlFiles.length) failures.push("output contains no HTML files");
1326
1353
  if (!hydratedFiles) failures.push("output contains no prerendered Blox hydration state");
@@ -1345,6 +1372,16 @@ async function validateSsgOutput(options) {
1345
1372
  ${failures.map((item) => ` - ${item}`).join("\n")}`);
1346
1373
  }
1347
1374
  }
1375
+ function relativeInternalLinks(html) {
1376
+ var _a;
1377
+ const found = /* @__PURE__ */ new Set();
1378
+ for (const match of html.matchAll(anchorHref)) {
1379
+ const href = ((_a = match[1]) == null ? void 0 : _a.trim()) ?? "";
1380
+ if (ABSOLUTE_OR_SPECIAL.test(href)) continue;
1381
+ found.add(href);
1382
+ }
1383
+ return [...found];
1384
+ }
1348
1385
  async function collectHtmlFiles(directory) {
1349
1386
  const entries = await fs.readdir(directory, { withFileTypes: true });
1350
1387
  const files = await Promise.all(entries.map(async (entry) => {
@@ -1382,32 +1419,33 @@ async function validateSitemap(outDir, content) {
1382
1419
  return failures;
1383
1420
  }
1384
1421
  export {
1385
- llmArtifacts as A,
1422
+ splitSitemapPathsByLocale as A,
1386
1423
  BloxBuildResponseError as B,
1424
+ llmArtifacts as C,
1387
1425
  prerender as a,
1388
1426
  buildCollectionResolver as b,
1389
- buildPageHead as c,
1390
- primaryContextEntry as d,
1391
- buildJsonLd as e,
1427
+ validateInternalLinks as c,
1428
+ buildPageHead as d,
1429
+ primaryContextEntry as e,
1392
1430
  fetchCmsSiteData as f,
1393
1431
  generateSitemapArtifacts as g,
1394
- extractPageText as h,
1395
- bloxBuildJson as i,
1396
- bloxBuildRequest as j,
1397
- buildSiteHead as k,
1398
- generateLlmsFullTxt as l,
1399
- generateLlmsTxt as m,
1400
- generateNetlifyRedirects as n,
1401
- generateRobotsTxt as o,
1432
+ buildJsonLd as h,
1433
+ extractPageText as i,
1434
+ bloxBuildJson as j,
1435
+ bloxBuildRequest as k,
1436
+ buildSiteHead as l,
1437
+ generateLlmsFullTxt as m,
1438
+ generateLlmsTxt as n,
1439
+ generateNetlifyRedirects as o,
1402
1440
  polyfillBloxSsgGlobals as p,
1403
- generateSitemapIndexXml as q,
1404
- generateSitemapXml as r,
1405
- getBloxBuildRequestOptions as s,
1406
- getSiteIconFlags as t,
1441
+ generateRobotsTxt as q,
1442
+ generateSitemapIndexXml as r,
1443
+ generateSitemapXml as s,
1444
+ getBloxBuildRequestOptions as t,
1407
1445
  uploadBloxManifest as u,
1408
1446
  validateSsgOutput as v,
1409
- localeSitemapPath as w,
1410
- mergeLlmParts as x,
1411
- resolveManifestProvenance as y,
1412
- splitSitemapPathsByLocale as z
1447
+ getSiteIconFlags as w,
1448
+ localeSitemapPath as x,
1449
+ mergeLlmParts as y,
1450
+ resolveManifestProvenance as z
1413
1451
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/blox",
3
3
  "type": "module",
4
- "version": "1.15.647",
4
+ "version": "1.15.651",
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",