@bagelink/blox 1.12.22 → 1.12.25

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.
Files changed (59) hide show
  1. package/dist/CmsPageView.vue.d.ts.map +1 -1
  2. package/dist/PreviewApp-C2T03Jm9.cjs +4 -0
  3. package/dist/PreviewApp-CmThrLvv.js +4 -0
  4. package/dist/PreviewApp.vue.d.ts.map +1 -1
  5. package/dist/PreviewApp.vue_vue_type_style_index_0_lang-B0N5QbfS.js +157 -0
  6. package/dist/PreviewApp.vue_vue_type_style_index_0_lang-BTuE4GmT.cjs +156 -0
  7. package/dist/api/index.d.ts.map +1 -1
  8. package/dist/bridge.d.ts +1 -0
  9. package/dist/bridge.d.ts.map +1 -1
  10. package/dist/core-C3Iu5qa2.js +460 -0
  11. package/dist/core-_fnHoEZN.cjs +459 -0
  12. package/dist/core.d.ts.map +1 -1
  13. package/dist/createBloxApp.d.ts +107 -0
  14. package/dist/createBloxApp.d.ts.map +1 -0
  15. package/dist/defineBlock.d.ts +2 -0
  16. package/dist/defineBlock.d.ts.map +1 -1
  17. package/dist/index.cjs +79 -585
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.mjs +78 -583
  21. package/dist/{prerender-6jE_obPj.cjs → prerender-Bi7YtzSp.cjs} +246 -6
  22. package/dist/prerender-D3Q4jKXm.js +522 -0
  23. package/dist/schema.d.ts +2 -0
  24. package/dist/schema.d.ts.map +1 -1
  25. package/dist/ssg/cli.cjs +48 -5
  26. package/dist/ssg/cli.mjs +48 -5
  27. package/dist/ssg/client.cjs +50 -3
  28. package/dist/ssg/client.d.ts +2 -1
  29. package/dist/ssg/client.d.ts.map +1 -1
  30. package/dist/ssg/client.mjs +49 -2
  31. package/dist/ssg/cms-routes.d.ts +21 -4
  32. package/dist/ssg/cms-routes.d.ts.map +1 -1
  33. package/dist/ssg/collection-cache.d.ts +53 -0
  34. package/dist/ssg/collection-cache.d.ts.map +1 -0
  35. package/dist/ssg/constants.d.ts +4 -0
  36. package/dist/ssg/constants.d.ts.map +1 -1
  37. package/dist/ssg/createSSREntry.d.ts +73 -0
  38. package/dist/ssg/createSSREntry.d.ts.map +1 -0
  39. package/dist/ssg/index.cjs +138 -6
  40. package/dist/ssg/index.d.ts +10 -3
  41. package/dist/ssg/index.d.ts.map +1 -1
  42. package/dist/ssg/index.mjs +124 -12
  43. package/dist/ssg/prerender.d.ts +19 -1
  44. package/dist/ssg/prerender.d.ts.map +1 -1
  45. package/dist/ssg/render-resolved-page.d.ts +13 -3
  46. package/dist/ssg/render-resolved-page.d.ts.map +1 -1
  47. package/dist/ssg/seo.d.ts +66 -0
  48. package/dist/ssg/seo.d.ts.map +1 -0
  49. package/dist/style.css +20 -0
  50. package/dist/vite-plugin.cjs +142 -3
  51. package/dist/vite-plugin.d.ts +22 -21
  52. package/dist/vite-plugin.d.ts.map +1 -1
  53. package/dist/vite-plugin.mjs +142 -3
  54. package/package.json +4 -1
  55. package/dist/PreviewApp-BZNzZkit.js +0 -4
  56. package/dist/PreviewApp-C1WvJWI4.cjs +0 -4
  57. package/dist/constants-BIbQhd3z.js +0 -4
  58. package/dist/constants-fZvybj0k.cjs +0 -3
  59. package/dist/prerender-DYmDaqcz.js +0 -282
package/dist/ssg/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import process from "node:process";
3
- import { p as polyfillBloxSsgGlobals, f as fetchCmsPrerenderPaths, a as prerender } from "../prerender-DYmDaqcz.js";
3
+ import { p as polyfillBloxSsgGlobals, f as fetchCmsSiteData, a as prerender } from "../prerender-D3Q4jKXm.js";
4
4
  async function resolveApiBase(mode) {
5
5
  if (process.env.BAGELINK_API_URL != null && process.env.BAGELINK_API_URL !== "") {
6
6
  return { apiBase: process.env.BAGELINK_API_URL };
@@ -29,6 +29,7 @@ async function resolveApiBase(mode) {
29
29
  return { apiBase: "https://localhost:8000" };
30
30
  }
31
31
  async function main() {
32
+ var _a;
32
33
  const argv = process.argv.slice(2);
33
34
  const extraPaths = [];
34
35
  let crawl = false;
@@ -71,11 +72,47 @@ Environment:
71
72
  const websiteName = process.env.WEBSITE_NAME ?? configWebsiteName ?? "default";
72
73
  console.log(`Fetching routes from ${apiBase} (mode: ${mode}, site: ${websiteName})…`);
73
74
  let paths = [];
75
+ let website = null;
76
+ let websiteId = "";
77
+ let redirects = [];
78
+ const collections = {};
74
79
  try {
75
- paths = await fetchCmsPrerenderPaths(apiBase, websiteName);
80
+ const siteData = await fetchCmsSiteData(apiBase, websiteName);
81
+ paths = siteData.paths;
82
+ website = siteData.website;
83
+ websiteId = siteData.websiteId;
84
+ redirects = siteData.redirects;
76
85
  console.log(` Found ${paths.length} CMS routes`);
86
+ if (redirects.length > 0) console.log(` Found ${redirects.length} redirects`);
87
+ const allCollectionRefs = [...siteData.collections];
88
+ const extraCollections = (_a = process.env.BLOX_SSG_COLLECTIONS) == null ? void 0 : _a.trim();
89
+ if (extraCollections) {
90
+ for (const entry of extraCollections.split(",")) {
91
+ const parts = entry.trim().split("/");
92
+ if (parts.length === 2 && parts[0] && parts[1]) {
93
+ const already = allCollectionRefs.some((r) => r.store === parts[0] && r.collection === parts[1]);
94
+ if (!already) allCollectionRefs.push({ store: parts[0], collection: parts[1] });
95
+ }
96
+ }
97
+ }
98
+ if (allCollectionRefs.length > 0) {
99
+ console.log(` Pre-fetching ${allCollectionRefs.length} datastore collection(s)…`);
100
+ for (const ref of allCollectionRefs) {
101
+ try {
102
+ const url = `${apiBase}/datastore/${ref.store}/collections/${ref.collection}?limit=500`;
103
+ const res = await fetch(url);
104
+ const data = await res.json();
105
+ const items = Array.isArray(data) ? data : data.data ?? [];
106
+ const key = `${ref.store}/${ref.collection}`;
107
+ collections[key] = items;
108
+ console.log(` ${key}: ${items.length} items`);
109
+ } catch (e) {
110
+ console.warn(` Failed to fetch ${ref.store}/${ref.collection}: ${e.message}`);
111
+ }
112
+ }
113
+ }
77
114
  } catch (err) {
78
- console.error(" Failed to fetch CMS routes:", err.message);
115
+ console.error(" Failed to fetch CMS data:", err.message);
79
116
  paths = ["/"];
80
117
  }
81
118
  for (const p of extraPaths) {
@@ -91,7 +128,11 @@ Environment:
91
128
  crawl,
92
129
  excludePaths,
93
130
  maxPages: 5e3,
94
- mode: "file"
131
+ mode: "file",
132
+ website,
133
+ websiteId,
134
+ redirects,
135
+ collections
95
136
  });
96
137
  const elapsed = ((Date.now() - startTime) / 1e3).toFixed(2);
97
138
  console.log(`
@@ -114,7 +155,9 @@ ${"=".repeat(60)}`);
114
155
  if (result.failures.length > 10) {
115
156
  console.log(` ... and ${result.failures.length - 10} more`);
116
157
  }
117
- process.exitCode = 1;
158
+ if (result.rendered.length === 0) {
159
+ process.exitCode = 1;
160
+ }
118
161
  }
119
162
  } catch (err) {
120
163
  console.error("Fatal error:", err);
@@ -1,7 +1,49 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const constants = require("../constants-fZvybj0k.cjs");
4
- function installBloxStateCache(globalKey = constants.BLOX_STATE_WINDOW_KEY) {
3
+ const BLOX_STATE_WINDOW_KEY = "__BLOX_STATE__";
4
+ const BLOX_COLLECTIONS_WINDOW_KEY = "__BLOX_COLLECTIONS__";
5
+ const BLOX_WEBSITE_ID_WINDOW_KEY = "__BLOX_WEBSITE_ID__";
6
+ let _cache = null;
7
+ function readCache() {
8
+ if (_cache != null) return _cache;
9
+ if (typeof window === "undefined") return null;
10
+ const raw = window[BLOX_COLLECTIONS_WINDOW_KEY];
11
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
12
+ _cache = raw;
13
+ return _cache;
14
+ }
15
+ return null;
16
+ }
17
+ function getCollectionCache() {
18
+ return readCache();
19
+ }
20
+ function getEmbeddedWebsiteId() {
21
+ if (typeof window === "undefined") return "";
22
+ const id = window[BLOX_WEBSITE_ID_WINDOW_KEY];
23
+ return typeof id === "string" ? id : "";
24
+ }
25
+ function installCollectionCache() {
26
+ const cache = readCache();
27
+ if (!cache || Object.keys(cache).length === 0) return null;
28
+ return (config) => {
29
+ if (config.method && config.method.toLowerCase() !== "get") return config;
30
+ const url = config.url ?? "";
31
+ const match = url.match(/\/datastore\/([^/?]+)\/collections\/([^/?]+)/);
32
+ if (!match) return config;
33
+ const key = `${match[1]}/${match[2]}`;
34
+ if (cache[key] == null) return config;
35
+ const items = cache[key];
36
+ config.adapter = () => Promise.resolve({
37
+ data: items,
38
+ status: 200,
39
+ statusText: "OK",
40
+ headers: { "content-type": "application/json", "x-blox-cache": "hit" },
41
+ config
42
+ });
43
+ return config;
44
+ };
45
+ }
46
+ function installBloxStateCache(globalKey = BLOX_STATE_WINDOW_KEY) {
5
47
  if (typeof window === "undefined") return;
6
48
  const state = window[globalKey];
7
49
  if (!state || typeof state !== "object" || Object.keys(state).length === 0) return;
@@ -26,5 +68,10 @@ function installBloxStateCache(globalKey = constants.BLOX_STATE_WINDOW_KEY) {
26
68
  return originalFetch(input, init);
27
69
  };
28
70
  }
29
- exports.BLOX_STATE_WINDOW_KEY = constants.BLOX_STATE_WINDOW_KEY;
71
+ exports.BLOX_COLLECTIONS_WINDOW_KEY = BLOX_COLLECTIONS_WINDOW_KEY;
72
+ exports.BLOX_STATE_WINDOW_KEY = BLOX_STATE_WINDOW_KEY;
73
+ exports.BLOX_WEBSITE_ID_WINDOW_KEY = BLOX_WEBSITE_ID_WINDOW_KEY;
74
+ exports.getCollectionCache = getCollectionCache;
75
+ exports.getEmbeddedWebsiteId = getEmbeddedWebsiteId;
30
76
  exports.installBloxStateCache = installBloxStateCache;
77
+ exports.installCollectionCache = installCollectionCache;
@@ -1,9 +1,10 @@
1
+ export { getCollectionCache, getEmbeddedWebsiteId, installCollectionCache } from './collection-cache';
1
2
  /**
2
3
  * @bagelink/blox/ssg/client — browser-safe SSG utilities.
3
4
  *
4
5
  * Use this import in client entry files (main.ts / entry-client.ts).
5
6
  * It does NOT pull in Node.js modules (fs, path, url, happy-dom).
6
7
  */
7
- export { BLOX_STATE_WINDOW_KEY } from './constants';
8
+ export { BLOX_COLLECTIONS_WINDOW_KEY, BLOX_STATE_WINDOW_KEY, BLOX_WEBSITE_ID_WINDOW_KEY } from './constants';
8
9
  export { installBloxStateCache } from './state-cache';
9
10
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ssg/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ssg/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AACrG;;;;;GAKG;AACH,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA"}
@@ -1,4 +1,46 @@
1
- import { B as BLOX_STATE_WINDOW_KEY } from "../constants-BIbQhd3z.js";
1
+ const BLOX_STATE_WINDOW_KEY = "__BLOX_STATE__";
2
+ const BLOX_COLLECTIONS_WINDOW_KEY = "__BLOX_COLLECTIONS__";
3
+ const BLOX_WEBSITE_ID_WINDOW_KEY = "__BLOX_WEBSITE_ID__";
4
+ let _cache = null;
5
+ function readCache() {
6
+ if (_cache != null) return _cache;
7
+ if (typeof window === "undefined") return null;
8
+ const raw = window[BLOX_COLLECTIONS_WINDOW_KEY];
9
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
10
+ _cache = raw;
11
+ return _cache;
12
+ }
13
+ return null;
14
+ }
15
+ function getCollectionCache() {
16
+ return readCache();
17
+ }
18
+ function getEmbeddedWebsiteId() {
19
+ if (typeof window === "undefined") return "";
20
+ const id = window[BLOX_WEBSITE_ID_WINDOW_KEY];
21
+ return typeof id === "string" ? id : "";
22
+ }
23
+ function installCollectionCache() {
24
+ const cache = readCache();
25
+ if (!cache || Object.keys(cache).length === 0) return null;
26
+ return (config) => {
27
+ if (config.method && config.method.toLowerCase() !== "get") return config;
28
+ const url = config.url ?? "";
29
+ const match = url.match(/\/datastore\/([^/?]+)\/collections\/([^/?]+)/);
30
+ if (!match) return config;
31
+ const key = `${match[1]}/${match[2]}`;
32
+ if (cache[key] == null) return config;
33
+ const items = cache[key];
34
+ config.adapter = () => Promise.resolve({
35
+ data: items,
36
+ status: 200,
37
+ statusText: "OK",
38
+ headers: { "content-type": "application/json", "x-blox-cache": "hit" },
39
+ config
40
+ });
41
+ return config;
42
+ };
43
+ }
2
44
  function installBloxStateCache(globalKey = BLOX_STATE_WINDOW_KEY) {
3
45
  if (typeof window === "undefined") return;
4
46
  const state = window[globalKey];
@@ -25,6 +67,11 @@ function installBloxStateCache(globalKey = BLOX_STATE_WINDOW_KEY) {
25
67
  };
26
68
  }
27
69
  export {
70
+ BLOX_COLLECTIONS_WINDOW_KEY,
28
71
  BLOX_STATE_WINDOW_KEY,
29
- installBloxStateCache
72
+ BLOX_WEBSITE_ID_WINDOW_KEY,
73
+ getCollectionCache,
74
+ getEmbeddedWebsiteId,
75
+ installBloxStateCache,
76
+ installCollectionCache
30
77
  };
@@ -1,8 +1,25 @@
1
+ import { WebsiteRead } from '../api/types';
2
+ import { RedirectEntry } from './seo';
3
+ /** A datastore collection reference discovered from page data_bindings. */
4
+ export interface CollectionRef {
5
+ store: string;
6
+ collection: string;
7
+ }
8
+ export interface CmsSiteData {
9
+ websiteId: string;
10
+ website: WebsiteRead;
11
+ paths: string[];
12
+ redirects: RedirectEntry[];
13
+ /** Datastore collections referenced by any page's data_bindings. */
14
+ collections: CollectionRef[];
15
+ }
1
16
  /**
2
- * Collect prerender paths from the Bagelink CMS.
3
- *
4
- * Static slugs are returned as-is. Template pages (e.g. `/blog/:slug`) are
5
- * expanded into concrete paths using their `data_bindings` + the datastore.
17
+ * Fetch everything the SSG needs from the CMS in one go:
18
+ * website settings, page routes, and redirects.
19
+ */
20
+ export declare function fetchCmsSiteData(apiBase: string, websiteName: string): Promise<CmsSiteData>;
21
+ /**
22
+ * Legacy compat: fetch only prerender paths (no website/redirect data).
6
23
  */
7
24
  export declare function fetchCmsPrerenderPaths(apiBase: string, websiteName: string): Promise<string[]>;
8
25
  //# sourceMappingURL=cms-routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cms-routes.d.ts","sourceRoot":"","sources":["../../src/ssg/cms-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAqDnB"}
1
+ {"version":3,"file":"cms-routes.d.ts","sourceRoot":"","sources":["../../src/ssg/cms-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAY1C,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,WAAW,CAAA;IACpB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,SAAS,EAAE,aAAa,EAAE,CAAA;IAC1B,oEAAoE;IACpE,WAAW,EAAE,aAAa,EAAE,CAAA;CAC5B;AAMD;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,CAwCtB;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAGnB"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Pre-fetched collection cache for zero-fetch client hydration.
3
+ *
4
+ * During SSG, `blox-ssg` embeds pre-fetched datastore collections as
5
+ * `window.__BLOX_COLLECTIONS__ = { "store/collection": [...items] }`.
6
+ *
7
+ * This module provides:
8
+ * 1. `installCollectionCache()` — returns an axios request interceptor
9
+ * that short-circuits matching datastore GET requests with cached data.
10
+ * 2. `getCollectionCache()` — direct access to the cache for manual use.
11
+ *
12
+ * Usage in client entry (main.ts):
13
+ *
14
+ * ```ts
15
+ * import { installCollectionCache } from '@bagelink/blox/ssg/client'
16
+ * import { axios } from '@shared/api'
17
+ *
18
+ * const interceptor = installCollectionCache()
19
+ * if (interceptor) axios.interceptors.request.use(interceptor)
20
+ * ```
21
+ */
22
+ type CollectionCacheMap = Record<string, unknown[]>;
23
+ /**
24
+ * Get direct access to the pre-fetched collections cache.
25
+ * Returns null if not available (e.g. page wasn't pre-rendered).
26
+ */
27
+ export declare function getCollectionCache(): CollectionCacheMap | null;
28
+ /**
29
+ * Get the pre-embedded website ID (avoids GET /cms/websites on client).
30
+ * Returns empty string if not available.
31
+ */
32
+ export declare function getEmbeddedWebsiteId(): string;
33
+ /**
34
+ * Install collection cache and return an axios request interceptor.
35
+ *
36
+ * The interceptor matches `GET /datastore/{store}/collections/{name}` requests
37
+ * and returns the cached data as a fulfilled promise (zero network).
38
+ *
39
+ * Returns `null` if no cache is available (page wasn't pre-rendered).
40
+ */
41
+ export declare function installCollectionCache(): ((config: AxiosLikeConfig) => AxiosLikeConfig) | null;
42
+ /**
43
+ * Minimal axios config shape — avoids importing axios as a dependency.
44
+ * Only the fields we need for interception.
45
+ */
46
+ interface AxiosLikeConfig {
47
+ url?: string;
48
+ method?: string;
49
+ adapter?: (config: AxiosLikeConfig) => Promise<unknown>;
50
+ [key: string]: unknown;
51
+ }
52
+ export {};
53
+ //# sourceMappingURL=collection-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-cache.d.ts","sourceRoot":"","sources":["../../src/ssg/collection-cache.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;AAenD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,kBAAkB,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,IAAI,CAAC,CAAC,MAAM,EAAE,eAAe,KAAK,eAAe,CAAC,GAAG,IAAI,CA+B9F;AAED;;;GAGG;AACH,UAAU,eAAe;IACxB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACvD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB"}
@@ -1,3 +1,7 @@
1
1
  /** Global key for embedded prerender payload (must match client interceptor). */
2
2
  export declare const BLOX_STATE_WINDOW_KEY: "__BLOX_STATE__";
3
+ /** Global key for pre-fetched datastore collections (keyed by "store/collection"). */
4
+ export declare const BLOX_COLLECTIONS_WINDOW_KEY: "__BLOX_COLLECTIONS__";
5
+ /** Global key for the pre-resolved website ID (avoids GET /cms/websites on client). */
6
+ export declare const BLOX_WEBSITE_ID_WINDOW_KEY: "__BLOX_WEBSITE_ID__";
3
7
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/ssg/constants.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,EAAG,gBAAyB,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/ssg/constants.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,EAAG,gBAAyB,CAAA;AAE9D,sFAAsF;AACtF,eAAO,MAAM,2BAA2B,EAAG,sBAA+B,CAAA;AAE1E,uFAAuF;AACvF,eAAO,MAAM,0BAA0B,EAAG,qBAA8B,CAAA"}
@@ -0,0 +1,73 @@
1
+ import { Component } from 'vue';
2
+ import { Router } from 'vue-router';
3
+ import { BlockModule } from '../defineBlock';
4
+ import { RenderContext, RenderResult } from './prerender';
5
+ export interface CreateBloxSSREntryOptions {
6
+ /** Root Vue component (App.vue). */
7
+ rootComponent: Component;
8
+ /**
9
+ * Router factory. Must return a fresh router for each render call.
10
+ * @param mode - 'web' for client, 'memory' for SSR
11
+ * @param url - initial URL (only for 'memory' mode)
12
+ */
13
+ createRouter: (mode: 'web' | 'memory', url?: string) => Router;
14
+ /**
15
+ * Block SFC modules — same format as `createBloxApp`.
16
+ * Use `import.meta.glob('./components/blocks/*.vue', { eager: true })`.
17
+ */
18
+ modules: BlockModule[] | Record<string, BlockModule>;
19
+ /** CMS website name. */
20
+ websiteName: string;
21
+ /** Datastore store identifier. */
22
+ store: string;
23
+ /** API base URL for SSR fetches. @default process.env.BAGELINK_API_URL ?? 'https://api.bagel.to' */
24
+ apiBase?: string;
25
+ /** Default locale. @default 'en' */
26
+ locale?: string;
27
+ /** Supported locales. @default [locale] */
28
+ supportedLocales?: string[];
29
+ /**
30
+ * Extra Vue plugins to install on the SSR app.
31
+ * Typically `[BagelVue]` from `@bagelink/vue`.
32
+ */
33
+ plugins?: Array<import('vue').Plugin | [import('vue').Plugin, ...unknown[]]>;
34
+ /**
35
+ * Global components to register.
36
+ * Typically `{ RouterWrapper }` from `@bagelink/vue`.
37
+ */
38
+ globalComponents?: Record<string, Component>;
39
+ }
40
+ export interface BloxSSREntry {
41
+ render: (url: string, ctx: RenderContext) => Promise<RenderResult>;
42
+ }
43
+ /**
44
+ * Factory that produces the `{ render }` export for `main.server.ts`.
45
+ *
46
+ * Encapsulates all SSR boilerplate:
47
+ * - Website ID resolution
48
+ * - CMS page data fetching
49
+ * - Vue SSR app creation with Blox + Pinia
50
+ * - `renderBloxSsgPage()` call with full context passthrough
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * import { createBloxSSREntry } from '@bagelink/blox/ssg'
55
+ * import { BagelVue, RouterWrapper } from '@bagelink/vue'
56
+ * import App from './App.vue'
57
+ * import { createRouter } from './router'
58
+ *
59
+ * const blocks = import.meta.glob('./components/blocks/*.vue', { eager: true })
60
+ *
61
+ * export const { render } = createBloxSSREntry({
62
+ * rootComponent: App,
63
+ * createRouter,
64
+ * modules: Object.values(blocks),
65
+ * websiteName: 'cylogic',
66
+ * store: 'cylogic',
67
+ * plugins: [BagelVue],
68
+ * globalComponents: { RouterWrapper },
69
+ * })
70
+ * ```
71
+ */
72
+ export declare function createBloxSSREntry(options: CreateBloxSSREntryOptions): BloxSSREntry;
73
+ //# sourceMappingURL=createSSREntry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSSREntry.d.ts","sourceRoot":"","sources":["../../src/ssg/createSSREntry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAO9D,MAAM,WAAW,yBAAyB;IACzC,oCAAoC;IACpC,aAAa,EAAE,SAAS,CAAA;IACxB;;;;OAIG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAC9D;;;OAGG;IACH,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpD,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,OAAO,KAAK,EAAE,MAAM,GAAG,CAAC,OAAO,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;IAC5E;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CAC5C;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;CAClE;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAqGnF"}
@@ -1,15 +1,42 @@
1
1
  "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
2
24
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const prerender = require("../prerender-6jE_obPj.cjs");
4
- const constants = require("../constants-fZvybj0k.cjs");
25
+ const prerender = require("../prerender-Bi7YtzSp.cjs");
5
26
  const ssg_client = require("./client.cjs");
27
+ const pinia = require("pinia");
28
+ const vue = require("vue");
29
+ const core = require("../core-_fnHoEZN.cjs");
6
30
  async function renderBloxSsgPage(options) {
7
31
  const {
8
32
  url,
9
33
  resolvedData,
10
34
  renderToString,
11
35
  createAppForUrl,
12
- stateWindowKey = constants.BLOX_STATE_WINDOW_KEY
36
+ stateWindowKey = ssg_client.BLOX_STATE_WINDOW_KEY,
37
+ website = null,
38
+ websiteId = "",
39
+ collections
13
40
  } = options;
14
41
  const g = globalThis;
15
42
  const prevState = g[stateWindowKey];
@@ -21,8 +48,18 @@ async function renderBloxSsgPage(options) {
21
48
  await router.push(url);
22
49
  await router.isReady();
23
50
  const html = await renderToString(app);
24
- const head = resolvedData != null ? `<script>window[${JSON.stringify(stateWindowKey)}]=${JSON.stringify({ [url]: resolvedData })};${"<"}/script>` : "";
25
- return { html, head };
51
+ const stateScript = resolvedData != null ? `<script>window[${JSON.stringify(stateWindowKey)}]=${JSON.stringify({ [url]: resolvedData })};${"<"}/script>` : "";
52
+ const collectionsScript = collections && Object.keys(collections).length > 0 ? `<script>window[${JSON.stringify(ssg_client.BLOX_COLLECTIONS_WINDOW_KEY)}]=${JSON.stringify(collections)};${"<"}/script>` : "";
53
+ const websiteIdScript = websiteId ? `<script>window[${JSON.stringify(ssg_client.BLOX_WEBSITE_ID_WINDOW_KEY)}]=${JSON.stringify(websiteId)};${"<"}/script>` : "";
54
+ const head = prerender.buildPageHead({
55
+ url,
56
+ resolvedData,
57
+ website,
58
+ stateScript: [stateScript, collectionsScript, websiteIdScript].filter(Boolean).join("\n")
59
+ });
60
+ const lang = (website == null ? void 0 : website.default_locale) || "en";
61
+ const htmlAttrs = `lang="${lang}"`;
62
+ return { html, head, htmlAttrs };
26
63
  } finally {
27
64
  if (prevState !== void 0) {
28
65
  g[stateWindowKey] = prevState;
@@ -31,9 +68,104 @@ async function renderBloxSsgPage(options) {
31
68
  }
32
69
  }
33
70
  }
71
+ let _websiteId = null;
72
+ function createBloxSSREntry(options) {
73
+ var _a;
74
+ const {
75
+ rootComponent,
76
+ createRouter,
77
+ modules,
78
+ websiteName,
79
+ store,
80
+ locale = "en",
81
+ supportedLocales = [locale],
82
+ plugins = [],
83
+ globalComponents = {}
84
+ } = options;
85
+ const apiBase = options.apiBase ?? (typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.BAGELINK_API_URL : void 0) ?? "https://api.bagel.to";
86
+ async function getWebsiteId() {
87
+ if (_websiteId) return _websiteId;
88
+ const res = await fetch(`${apiBase}/cms/websites`);
89
+ const data = await res.json();
90
+ const sites = Array.isArray(data) ? data : (data == null ? void 0 : data.data) ?? [];
91
+ const site = sites.find((s) => s.name === websiteName);
92
+ if (!(site == null ? void 0 : site.id)) throw new Error(`Website "${websiteName}" not found`);
93
+ _websiteId = site.id;
94
+ return _websiteId;
95
+ }
96
+ async function fetchResolvedPage(urlPath) {
97
+ const websiteId = await getWebsiteId();
98
+ const url = `${apiBase}/cms/websites/${websiteId}/resolve-path?path=${encodeURIComponent(urlPath)}&locale=${locale}`;
99
+ const res = await fetch(url);
100
+ if (!res.ok) throw new Error(`resolve-path ${res.status}: ${urlPath}`);
101
+ return res.json();
102
+ }
103
+ function buildApp(url) {
104
+ const router = createRouter("memory", url);
105
+ const app = vue.createSSRApp(rootComponent);
106
+ const pinia$1 = pinia.createPinia();
107
+ pinia$1.use(({ store: s }) => {
108
+ s.router = vue.markRaw(router);
109
+ });
110
+ const blox = core.createBlox({
111
+ modules,
112
+ websiteName,
113
+ store,
114
+ defaultLocale: locale,
115
+ supportedLocales,
116
+ router
117
+ });
118
+ for (const plugin of plugins) {
119
+ if (Array.isArray(plugin)) {
120
+ const [p, ...args] = plugin;
121
+ app.use(p, ...args);
122
+ } else {
123
+ app.use(plugin);
124
+ }
125
+ }
126
+ blox.install(app, {});
127
+ app.use(pinia$1);
128
+ app.use(router);
129
+ for (const [name, comp] of Object.entries(globalComponents)) {
130
+ app.component(name, comp);
131
+ }
132
+ return { app, router };
133
+ }
134
+ async function render(url, ctx) {
135
+ let resolvedData = null;
136
+ try {
137
+ resolvedData = await fetchResolvedPage(url);
138
+ } catch (e) {
139
+ console.warn(`[prerender] Could not resolve: ${url} — ${e.message}`);
140
+ }
141
+ const { renderToString } = await import("vue/server-renderer");
142
+ return renderBloxSsgPage({
143
+ url,
144
+ resolvedData,
145
+ renderToString,
146
+ createAppForUrl: buildApp,
147
+ website: ctx.website,
148
+ websiteId: ctx.websiteId,
149
+ collections: ctx.collections
150
+ });
151
+ }
152
+ return { render };
153
+ }
154
+ exports.buildPageHead = prerender.buildPageHead;
155
+ exports.buildSiteHead = prerender.buildSiteHead;
34
156
  exports.fetchCmsPrerenderPaths = prerender.fetchCmsPrerenderPaths;
157
+ exports.fetchCmsSiteData = prerender.fetchCmsSiteData;
158
+ exports.generateNetlifyRedirects = prerender.generateNetlifyRedirects;
159
+ exports.generateRobotsTxt = prerender.generateRobotsTxt;
160
+ exports.generateSitemapXml = prerender.generateSitemapXml;
35
161
  exports.polyfillBloxSsgGlobals = prerender.polyfillBloxSsgGlobals;
36
162
  exports.prerender = prerender.prerender;
37
- exports.BLOX_STATE_WINDOW_KEY = constants.BLOX_STATE_WINDOW_KEY;
163
+ exports.BLOX_COLLECTIONS_WINDOW_KEY = ssg_client.BLOX_COLLECTIONS_WINDOW_KEY;
164
+ exports.BLOX_STATE_WINDOW_KEY = ssg_client.BLOX_STATE_WINDOW_KEY;
165
+ exports.BLOX_WEBSITE_ID_WINDOW_KEY = ssg_client.BLOX_WEBSITE_ID_WINDOW_KEY;
166
+ exports.getCollectionCache = ssg_client.getCollectionCache;
167
+ exports.getEmbeddedWebsiteId = ssg_client.getEmbeddedWebsiteId;
38
168
  exports.installBloxStateCache = ssg_client.installBloxStateCache;
169
+ exports.installCollectionCache = ssg_client.installCollectionCache;
170
+ exports.createBloxSSREntry = createBloxSSREntry;
39
171
  exports.renderBloxSsgPage = renderBloxSsgPage;
@@ -1,19 +1,26 @@
1
- export { fetchCmsPrerenderPaths } from './cms-routes';
1
+ export { fetchCmsPrerenderPaths, fetchCmsSiteData } from './cms-routes';
2
+ export type { CmsSiteData, CollectionRef } from './cms-routes';
3
+ export { getCollectionCache, getEmbeddedWebsiteId, installCollectionCache } from './collection-cache';
2
4
  /**
3
5
  * @bagelink/blox/ssg — Static Site Generation helpers for Blox CMS sites.
4
6
  *
5
7
  * Provides everything needed to prerender a Vue + Blox app at build time:
6
8
  * - Browser global polyfills for Node.js
7
9
  * - CMS route discovery (including template page expansion via data_bindings)
8
- * - Double-render page renderer with state embedding
10
+ * - Page renderer with state embedding and full SEO head
9
11
  * - Client-side fetch interceptor for zero-API-call hydration
10
12
  * - Full prerender orchestrator with crawl support
13
+ * - SEO asset generation (sitemap.xml, robots.txt, _redirects)
11
14
  */
12
- export { BLOX_STATE_WINDOW_KEY } from './constants';
15
+ export { BLOX_COLLECTIONS_WINDOW_KEY, BLOX_STATE_WINDOW_KEY, BLOX_WEBSITE_ID_WINDOW_KEY } from './constants';
16
+ export { createBloxSSREntry } from './createSSREntry';
17
+ export type { BloxSSREntry, CreateBloxSSREntryOptions } from './createSSREntry';
13
18
  export { polyfillBloxSsgGlobals } from './polyfill-node';
14
19
  export { prerender } from './prerender';
15
20
  export type { PrerenderOptions, PrerenderResult, RenderContext, RenderResult } from './prerender';
16
21
  export { renderBloxSsgPage } from './render-resolved-page';
17
22
  export type { BloxSsgRouterLike } from './render-resolved-page';
23
+ export { buildPageHead, buildSiteHead, generateNetlifyRedirects, generateRobotsTxt, generateSitemapXml } from './seo';
24
+ export type { RedirectEntry, SeoPageData, WebsiteMeta } from './seo';
18
25
  export { installBloxStateCache } from './state-cache';
19
26
  //# 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,MAAM,cAAc,CAAA;AACrD;;;;;;;;;GASG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,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,qBAAqB,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ssg/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACvE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AACrG;;;;;;;;;;GAUG;AACH,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAC5G,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,MAAM,OAAO,CAAA;AACrH,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA"}