@stackbox/cms 0.0.4 → 0.1.0

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 (122) hide show
  1. package/README.md +119 -7
  2. package/dist/AGENTS.md +215 -0
  3. package/dist/blocks.d.ts +11 -0
  4. package/dist/blocks.d.ts.map +1 -0
  5. package/dist/blocks.js +27 -0
  6. package/dist/blocks.js.map +1 -0
  7. package/dist/build.d.ts +14 -0
  8. package/dist/build.d.ts.map +1 -0
  9. package/dist/build.js +145 -0
  10. package/dist/build.js.map +1 -0
  11. package/dist/cache.d.ts +14 -0
  12. package/dist/cache.d.ts.map +1 -0
  13. package/dist/cache.js +93 -0
  14. package/dist/cache.js.map +1 -0
  15. package/dist/cli.d.ts +3 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +16 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/index.d.ts +16 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +15 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/link.d.ts +6 -0
  24. package/dist/link.d.ts.map +1 -0
  25. package/dist/link.js +121 -0
  26. package/dist/link.js.map +1 -0
  27. package/dist/modules.d.ts +18 -0
  28. package/dist/modules.d.ts.map +1 -0
  29. package/dist/modules.js +25 -0
  30. package/dist/modules.js.map +1 -0
  31. package/dist/pages.d.ts +24 -0
  32. package/dist/pages.d.ts.map +1 -0
  33. package/dist/pages.js +87 -0
  34. package/dist/pages.js.map +1 -0
  35. package/dist/plugin.d.ts +22 -0
  36. package/dist/plugin.d.ts.map +1 -0
  37. package/dist/plugin.js +155 -0
  38. package/dist/plugin.js.map +1 -0
  39. package/dist/plugins/blog/index.d.ts +21 -0
  40. package/dist/plugins/blog/index.d.ts.map +1 -0
  41. package/dist/plugins/blog/index.js +68 -0
  42. package/dist/plugins/blog/index.js.map +1 -0
  43. package/dist/plugins/blog/posts.d.ts +15 -0
  44. package/dist/plugins/blog/posts.d.ts.map +1 -0
  45. package/dist/plugins/blog/posts.js +46 -0
  46. package/dist/plugins/blog/posts.js.map +1 -0
  47. package/dist/plugins/random-quote/assets/quotes.json +230 -0
  48. package/dist/plugins/random-quote/index.d.ts +14 -0
  49. package/dist/plugins/random-quote/index.d.ts.map +1 -0
  50. package/dist/plugins/random-quote/index.js +35 -0
  51. package/dist/plugins/random-quote/index.js.map +1 -0
  52. package/dist/plugins/sitemap/index.d.ts +14 -0
  53. package/dist/plugins/sitemap/index.d.ts.map +1 -0
  54. package/dist/plugins/sitemap/index.js +119 -0
  55. package/dist/plugins/sitemap/index.js.map +1 -0
  56. package/dist/render-head.d.ts +7 -0
  57. package/dist/render-head.d.ts.map +1 -0
  58. package/dist/render-head.js +27 -0
  59. package/dist/render-head.js.map +1 -0
  60. package/dist/render-page.d.ts +4 -0
  61. package/dist/render-page.d.ts.map +1 -0
  62. package/dist/render-page.js +34 -0
  63. package/dist/render-page.js.map +1 -0
  64. package/dist/routing.d.ts +3 -0
  65. package/dist/routing.d.ts.map +1 -0
  66. package/dist/routing.js +11 -0
  67. package/dist/routing.js.map +1 -0
  68. package/dist/site.d.ts +14 -0
  69. package/dist/site.d.ts.map +1 -0
  70. package/dist/site.js +233 -0
  71. package/dist/site.js.map +1 -0
  72. package/dist/slot-content.d.ts +14 -0
  73. package/dist/slot-content.d.ts.map +1 -0
  74. package/dist/slot-content.js +34 -0
  75. package/dist/slot-content.js.map +1 -0
  76. package/dist/slot-handle.d.ts +14 -0
  77. package/dist/slot-handle.d.ts.map +1 -0
  78. package/dist/slot-handle.js +83 -0
  79. package/dist/slot-handle.js.map +1 -0
  80. package/dist/stackbox/context.d.ts +3 -0
  81. package/dist/stackbox/context.d.ts.map +1 -0
  82. package/dist/stackbox/context.js +165 -0
  83. package/dist/stackbox/context.js.map +1 -0
  84. package/dist/templates.d.ts +13 -0
  85. package/dist/templates.d.ts.map +1 -0
  86. package/dist/templates.js +106 -0
  87. package/dist/templates.js.map +1 -0
  88. package/dist/types.d.ts +277 -0
  89. package/dist/types.d.ts.map +1 -0
  90. package/dist/types.js +2 -0
  91. package/dist/types.js.map +1 -0
  92. package/package.json +18 -3
  93. package/src/plugins/blog/AGENTS.md +5 -1
  94. package/src/plugins/blog/index.ts +22 -5
  95. package/src/plugins/random-quote/AGENTS.md +30 -7
  96. package/src/plugins/random-quote/index.ts +17 -1
  97. package/src/plugins/random-quote/public_assets/widget.css +5 -0
  98. package/src/plugins/sitemap/AGENTS.md +82 -0
  99. package/src/plugins/sitemap/index.ts +156 -0
  100. package/.claude/settings.local.json +0 -8
  101. package/AGENTS.md +0 -87
  102. package/scripts/copy-plugin-assets.mjs +0 -30
  103. package/src/blocks.ts +0 -58
  104. package/src/index.ts +0 -67
  105. package/src/link.ts +0 -158
  106. package/src/pages.ts +0 -198
  107. package/src/render-head.ts +0 -32
  108. package/src/render-page.ts +0 -51
  109. package/src/routing.ts +0 -14
  110. package/src/site.ts +0 -160
  111. package/src/slot-content.ts +0 -77
  112. package/src/slot-handle.ts +0 -131
  113. package/src/stackbox/context.ts +0 -257
  114. package/src/templates.ts +0 -230
  115. package/test/async-render.test.ts +0 -103
  116. package/test/blog.test.ts +0 -93
  117. package/test/fetch-routing.test.ts +0 -76
  118. package/test/plugin-assets.test.ts +0 -80
  119. package/test/random-quote.test.ts +0 -55
  120. package/test/stackbox-context.test.ts +0 -44
  121. package/tsconfig.json +0 -20
  122. /package/src/plugins/random-quote/{public_assets → assets}/quotes.json +0 -0
@@ -0,0 +1,119 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { createPlugin, } from "../../plugin.js";
4
+ import { normalizePathname } from "../../routing.js";
5
+ function resolveBaseUrl(site, options) {
6
+ const raw = options.baseUrl ?? site.siteConfig.config.url;
7
+ if (typeof raw !== "string" || raw.trim().length === 0) {
8
+ throw new Error("sb-sitemap: baseUrl or siteConfig.url is required");
9
+ }
10
+ const url = raw.trim().replace(/\/+$/, "");
11
+ try {
12
+ new URL(url);
13
+ }
14
+ catch {
15
+ throw new Error(`sb-sitemap: invalid base URL "${raw}"`);
16
+ }
17
+ return url;
18
+ }
19
+ function isExcluded(path, options) {
20
+ const normalized = normalizePathname(path);
21
+ if (!options.exclude) {
22
+ return false;
23
+ }
24
+ if (typeof options.exclude === "function") {
25
+ return options.exclude(normalized);
26
+ }
27
+ return options.exclude.some((entry) => normalizePathname(entry) === normalized);
28
+ }
29
+ function isNoindexPage(page) {
30
+ const robots = page.meta?.robots?.toLowerCase() ?? "";
31
+ return robots.includes("noindex");
32
+ }
33
+ export function collectSitemapUrls(site, options = {}) {
34
+ const base = resolveBaseUrl(site, options);
35
+ const locs = new Set();
36
+ for (const page of site.pages) {
37
+ if (isNoindexPage(page)) {
38
+ continue;
39
+ }
40
+ if (isExcluded(page.path, options)) {
41
+ continue;
42
+ }
43
+ locs.add(`${base}${normalizePathname(page.path)}`);
44
+ }
45
+ for (const extra of options.extraUrls ?? []) {
46
+ if (extra.startsWith("http://") || extra.startsWith("https://")) {
47
+ if (!isExcluded(extra, options)) {
48
+ locs.add(extra);
49
+ }
50
+ continue;
51
+ }
52
+ const path = normalizePathname(extra);
53
+ if (!isExcluded(path, options)) {
54
+ locs.add(`${base}${path}`);
55
+ }
56
+ }
57
+ return [...locs].sort();
58
+ }
59
+ function escapeXml(text) {
60
+ return text
61
+ .replace(/&/g, "&")
62
+ .replace(/</g, "&lt;")
63
+ .replace(/>/g, "&gt;")
64
+ .replace(/"/g, "&quot;")
65
+ .replace(/'/g, "&apos;");
66
+ }
67
+ export function renderSitemapXml(site, options = {}) {
68
+ const urls = collectSitemapUrls(site, options);
69
+ const body = urls
70
+ .map((loc) => ` <url>\n <loc>${escapeXml(loc)}</loc>\n </url>`)
71
+ .join("\n");
72
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${body}\n</urlset>\n`;
73
+ }
74
+ function sitemapResponse(request, xml) {
75
+ const headers = { "content-type": "application/xml; charset=utf-8" };
76
+ if (request.method === "HEAD") {
77
+ const bytes = new TextEncoder().encode(xml);
78
+ return new globalThis.Response(null, {
79
+ status: 200,
80
+ headers: { ...headers, "content-length": String(bytes.byteLength) },
81
+ });
82
+ }
83
+ return new globalThis.Response(xml, { status: 200, headers });
84
+ }
85
+ function createSitemapRoutes(ctx, options) {
86
+ return [
87
+ {
88
+ path: "/sitemap.xml",
89
+ fetch(request) {
90
+ const xml = renderSitemapXml(ctx.site, options);
91
+ return sitemapResponse(request, xml);
92
+ },
93
+ },
94
+ ];
95
+ }
96
+ export function createSitemap(options = {}) {
97
+ return createPlugin({
98
+ name: "sb-sitemap",
99
+ description: "Generate sitemap.xml from site pages for search engines and static deploys.",
100
+ version: "1.0.0",
101
+ keywords: [
102
+ "sitemap",
103
+ "sitemap.xml",
104
+ "seo",
105
+ "search engines",
106
+ "xml sitemap",
107
+ ],
108
+ root: import.meta.dirname,
109
+ routes(ctx) {
110
+ return createSitemapRoutes(ctx, options);
111
+ },
112
+ build(ctx) {
113
+ const xml = renderSitemapXml(ctx.site, options);
114
+ writeFileSync(join(ctx.publicDir, "sitemap.xml"), xml, "utf8");
115
+ },
116
+ });
117
+ }
118
+ export default createSitemap();
119
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/sitemap/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type HSHtml } from "@hyperspan/html";
2
+ import type { Stackbox as SB } from "./types.js";
3
+ export declare function renderStandardHead(input: {
4
+ title: string;
5
+ meta?: SB.PageMeta;
6
+ }): HSHtml;
7
+ //# sourceMappingURL=render-head.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-head.d.ts","sourceRoot":"","sources":["../src/render-head.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC;CACpB,GAAG,MAAM,CAyBT"}
@@ -0,0 +1,27 @@
1
+ import { html } from "@hyperspan/html";
2
+ export function renderStandardHead(input) {
3
+ const { title, meta = {} } = input;
4
+ const ogTitle = meta.ogTitle ?? title;
5
+ const ogDescription = meta.ogDescription ?? meta.description;
6
+ return html `<meta charset="utf-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <title>${title}</title>
9
+ ${meta.description
10
+ ? html `<meta name="description" content="${meta.description}">`
11
+ : ""}
12
+ ${meta.robots ? html `<meta name="robots" content="${meta.robots}">` : ""}
13
+ ${meta.canonical
14
+ ? html `<link rel="canonical" href="${meta.canonical}">`
15
+ : ""}
16
+ <meta property="og:title" content="${ogTitle}">
17
+ ${ogDescription
18
+ ? html `<meta property="og:description" content="${ogDescription}">`
19
+ : ""}
20
+ ${meta.ogImage
21
+ ? html `<meta property="og:image" content="${meta.ogImage}">`
22
+ : ""}
23
+ ${meta.twitterCard
24
+ ? html `<meta name="twitter:card" content="${meta.twitterCard}">`
25
+ : ""}`;
26
+ }
27
+ //# sourceMappingURL=render-head.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-head.js","sourceRoot":"","sources":["../src/render-head.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAe,MAAM,iBAAiB,CAAC;AAGpD,MAAM,UAAU,kBAAkB,CAAC,KAGlC;IACC,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,WAAW,CAAC;IAE7D,OAAO,IAAI,CAAA;;WAEF,KAAK;IACZ,IAAI,CAAC,WAAW;QAChB,CAAC,CAAC,IAAI,CAAA,qCAAqC,IAAI,CAAC,WAAW,IAAI;QAC/D,CAAC,CAAC,EAAE;IACJ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA,gCAAgC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE;IACtE,IAAI,CAAC,SAAS;QACd,CAAC,CAAC,IAAI,CAAA,+BAA+B,IAAI,CAAC,SAAS,IAAI;QACvD,CAAC,CAAC,EAAE;uCAC+B,OAAO;IAC1C,aAAa;QACb,CAAC,CAAC,IAAI,CAAA,4CAA4C,aAAa,IAAI;QACnE,CAAC,CAAC,EAAE;IACJ,IAAI,CAAC,OAAO;QACZ,CAAC,CAAC,IAAI,CAAA,sCAAsC,IAAI,CAAC,OAAO,IAAI;QAC5D,CAAC,CAAC,EAAE;IACJ,IAAI,CAAC,WAAW;QAChB,CAAC,CAAC,IAAI,CAAA,sCAAsC,IAAI,CAAC,WAAW,IAAI;QAChE,CAAC,CAAC,EAAE,EAAE,CAAC;AACX,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Stackbox as SB } from "./types.js";
2
+ export { RenderError } from "./slot-handle.js";
3
+ export declare function renderPage(page: SB.SitePage, siteConfig: SB.SiteConfig, ctx?: SB.Context, hooks?: SB.SiteHooks): Promise<string>;
4
+ //# sourceMappingURL=render-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-page.d.ts","sourceRoot":"","sources":["../src/render-page.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAa/C,wBAAsB,UAAU,CAC9B,IAAI,EAAE,EAAE,CAAC,QAAQ,EACjB,UAAU,EAAE,EAAE,CAAC,UAAU,EACzB,GAAG,CAAC,EAAE,EAAE,CAAC,OAAO,EAChB,KAAK,CAAC,EAAE,EAAE,CAAC,SAAS,GACnB,OAAO,CAAC,MAAM,CAAC,CA0BjB"}
@@ -0,0 +1,34 @@
1
+ import { renderAsync } from "@hyperspan/html";
2
+ import { toPageRenderView, PageValidationError, } from "./pages.js";
3
+ import { slotHasContent } from "./slot-content.js";
4
+ import { buildPageSlots } from "./slot-handle.js";
5
+ import { renderStandardHead } from "./render-head.js";
6
+ export { RenderError } from "./slot-handle.js";
7
+ function validateRequiredSlots(page) {
8
+ for (const required of page.template.requiredSlots) {
9
+ const items = page.slots[required];
10
+ if (!items || items.length === 0 || !slotHasContent(items)) {
11
+ throw new PageValidationError(`required slot "${required}" must have at least one block or non-empty HTML string`);
12
+ }
13
+ }
14
+ }
15
+ export async function renderPage(page, siteConfig, ctx, hooks) {
16
+ validateRequiredSlots(page);
17
+ const renderCtx = { siteConfig, ctx, page, hooks };
18
+ const slots = buildPageSlots(page, renderCtx);
19
+ const head = renderStandardHead({
20
+ title: page.template.formatPageTitle(page.title),
21
+ meta: page.meta,
22
+ });
23
+ let html = await renderAsync(page.template.render({
24
+ head,
25
+ siteConfig,
26
+ page: toPageRenderView(page),
27
+ slots,
28
+ }));
29
+ if (hooks?.afterRender) {
30
+ html = await hooks.afterRender(html, { page, ctx });
31
+ }
32
+ return html;
33
+ }
34
+ //# sourceMappingURL=render-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-page.js","sourceRoot":"","sources":["../src/render-page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAe,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,SAAS,qBAAqB,CAAC,IAAiB;IAC9C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAmC,CAAC,CAAC;QAC9D,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,mBAAmB,CAC3B,kBAAkB,QAAQ,yDAAyD,CACpF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAiB,EACjB,UAAyB,EACzB,GAAgB,EAChB,KAAoB;IAEpB,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAE5B,MAAM,SAAS,GAAqB,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAErE,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAE9C,MAAM,IAAI,GAAG,kBAAkB,CAAC;QAC9B,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;QAChD,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CAAC;IAEH,IAAI,IAAI,GAAG,MAAM,WAAW,CAC1B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnB,IAAI;QACJ,UAAU;QACV,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC;QAC5B,KAAK;KACN,CAAC,CACH,CAAC;IAEF,IAAI,KAAK,EAAE,WAAW,EAAE,CAAC;QACvB,IAAI,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function normalizePathname(pathname: string): string;
2
+ export declare function matchPagePath(pathname: string, pagePath: string): boolean;
3
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET"}
@@ -0,0 +1,11 @@
1
+ export function normalizePathname(pathname) {
2
+ if (pathname === "" || pathname === "/") {
3
+ return "/";
4
+ }
5
+ const trimmed = pathname.replace(/\/+$/, "");
6
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
7
+ }
8
+ export function matchPagePath(pathname, pagePath) {
9
+ return normalizePathname(pathname) === normalizePathname(pagePath);
10
+ }
11
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;QACxC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,QAAgB;IAEhB,OAAO,iBAAiB,CAAC,QAAQ,CAAC,KAAK,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AACrE,CAAC"}
package/dist/site.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { Stackbox as SB } from "./types.js";
2
+ export declare class SiteError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare function createSiteConfig<T extends Record<string, unknown>>(config: T): SB.SiteConfig<T>;
6
+ export declare function isSiteConfig(value: unknown): value is SB.SiteConfig;
7
+ export declare function createSite<T extends Record<string, unknown>>(siteConfig: SB.SiteConfig<T>, options: {
8
+ pages: [SB.SitePage, ...SB.SitePage[]];
9
+ plugins?: readonly SB.Plugin[];
10
+ cacheAdapter?: SB.CacheAdapter;
11
+ hooks?: SB.SiteHooks;
12
+ }): SB.Site<T>;
13
+ export declare function isSite(value: unknown): value is SB.Site;
14
+ //# sourceMappingURL=site.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAWD,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,MAAM,EAAE,CAAC,GACR,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAMlB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC,UAAU,CASnE;AA0ED,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1D,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAC5B,OAAO,EAAE;IACP,KAAK,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC;IAC/B,KAAK,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC;CACtB,GACA,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CA6MZ;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC,IAAI,CAUvD"}
package/dist/site.js ADDED
@@ -0,0 +1,233 @@
1
+ import { buildPageCacheKey, cacheControlFresh, cacheControlStale, collectPageCacheConfigs, createMemoryCache, isCacheEntryFresh, isPageCacheDisabled, isSuccessfulRender, resolvePageCacheTtlMs, } from "./cache.js";
2
+ import { isPage } from "./pages.js";
3
+ import { renderPage } from "./render-page.js";
4
+ import { servePluginAsset } from "./link.js";
5
+ import { assertPlugin, } from "./plugin.js";
6
+ import { normalizePathname } from "./routing.js";
7
+ import { createContext } from "./stackbox/context.js";
8
+ export class SiteError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "SiteError";
12
+ }
13
+ }
14
+ function validateConfigObject(config, label) {
15
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
16
+ throw new SiteError(`${label}: config must be a non-null object`);
17
+ }
18
+ if (Object.keys(config).length === 0) {
19
+ throw new SiteError(`${label}: config must not be empty`);
20
+ }
21
+ }
22
+ export function createSiteConfig(config) {
23
+ validateConfigObject(config, "createSiteConfig(config)");
24
+ return {
25
+ __kind: "siteConfig",
26
+ config,
27
+ };
28
+ }
29
+ export function isSiteConfig(value) {
30
+ return (typeof value === "object" &&
31
+ value !== null &&
32
+ value.__kind === "siteConfig" &&
33
+ typeof value.config === "object" &&
34
+ value.config !== null &&
35
+ !Array.isArray(value.config));
36
+ }
37
+ function assertUniquePaths(pages) {
38
+ const seen = new Map();
39
+ for (const page of pages) {
40
+ const existing = seen.get(page.path);
41
+ if (existing) {
42
+ throw new SiteError(`duplicate page path "${page.path}" (${existing} and ${page.title})`);
43
+ }
44
+ seen.set(page.path, page.title);
45
+ }
46
+ }
47
+ function buildPageMap(pages) {
48
+ const map = new Map();
49
+ for (const page of pages) {
50
+ map.set(normalizePathname(page.path), page);
51
+ }
52
+ return map;
53
+ }
54
+ function assertUniquePluginNames(plugins) {
55
+ const seen = new Set();
56
+ for (const plugin of plugins) {
57
+ if (seen.has(plugin.name)) {
58
+ throw new SiteError(`createSite(siteConfig, options): duplicate plugin name "${plugin.name}"`);
59
+ }
60
+ seen.add(plugin.name);
61
+ }
62
+ }
63
+ function collectPluginRoutes(plugins, site, pagePaths) {
64
+ const routes = new Map();
65
+ for (const plugin of plugins) {
66
+ if (!plugin.routes) {
67
+ continue;
68
+ }
69
+ const declared = plugin.routes({ site });
70
+ if (declared instanceof Promise) {
71
+ throw new SiteError(`createSite(siteConfig, options): plugin "${plugin.name}" routes must return synchronously`);
72
+ }
73
+ for (const route of declared) {
74
+ const path = normalizePathname(route.path);
75
+ if (pagePaths.has(path)) {
76
+ throw new SiteError(`createSite(siteConfig, options): plugin route "${path}" conflicts with a page path`);
77
+ }
78
+ if (routes.has(path)) {
79
+ throw new SiteError(`createSite(siteConfig, options): duplicate plugin route "${path}"`);
80
+ }
81
+ routes.set(path, route.fetch);
82
+ }
83
+ }
84
+ return routes;
85
+ }
86
+ export function createSite(siteConfig, options) {
87
+ if (!isSiteConfig(siteConfig)) {
88
+ throw new SiteError("createSite(siteConfig, options): siteConfig must be from createSiteConfig()");
89
+ }
90
+ const { pages } = options;
91
+ if (!Array.isArray(pages) || pages.length === 0) {
92
+ throw new SiteError("createSite(siteConfig, options): pages must be a non-empty array");
93
+ }
94
+ for (const page of pages) {
95
+ if (!isPage(page)) {
96
+ throw new SiteError("createSite(siteConfig, options): every page must be from createPage()");
97
+ }
98
+ }
99
+ const plugins = options.plugins ?? [];
100
+ if (!Array.isArray(plugins)) {
101
+ throw new SiteError("createSite(siteConfig, options): plugins must be an array of createPlugin() results");
102
+ }
103
+ for (const plugin of plugins) {
104
+ try {
105
+ assertPlugin(plugin, "createSite(siteConfig, options)");
106
+ }
107
+ catch (error) {
108
+ throw new SiteError(error instanceof Error ? error.message : String(error));
109
+ }
110
+ }
111
+ assertUniquePluginNames(plugins);
112
+ assertUniquePaths(pages);
113
+ const pageMap = buildPageMap(pages);
114
+ const pagePaths = new Set(pageMap.keys());
115
+ const siteShell = {
116
+ __kind: "site",
117
+ siteConfig,
118
+ pages,
119
+ plugins,
120
+ async fetch() {
121
+ return new globalThis.Response("Site not ready", { status: 500 });
122
+ },
123
+ };
124
+ const pluginRoutes = collectPluginRoutes(plugins, siteShell, pagePaths);
125
+ const cacheAdapter = options.cacheAdapter ?? createMemoryCache();
126
+ const hooks = options.hooks;
127
+ const inFlightRenders = new Map();
128
+ async function applyBeforeResponse(response, request, ctx, page) {
129
+ if (!hooks?.beforeResponse) {
130
+ return response;
131
+ }
132
+ return hooks.beforeResponse(response, { request, page, ctx });
133
+ }
134
+ async function renderAndStore(key, page, ctx, ttlMs) {
135
+ const existing = inFlightRenders.get(key);
136
+ if (existing) {
137
+ return existing;
138
+ }
139
+ const promise = (async () => {
140
+ const html = await renderPage(page, siteConfig, ctx, hooks);
141
+ if (isSuccessfulRender(html)) {
142
+ await cacheAdapter.set(key, {
143
+ html,
144
+ expiresAt: Date.now() + ttlMs,
145
+ });
146
+ }
147
+ return html;
148
+ })();
149
+ inFlightRenders.set(key, promise);
150
+ try {
151
+ return await promise;
152
+ }
153
+ finally {
154
+ if (inFlightRenders.get(key) === promise) {
155
+ inFlightRenders.delete(key);
156
+ }
157
+ }
158
+ }
159
+ function startBackgroundRefresh(key, page, ctx, ttlMs) {
160
+ if (inFlightRenders.has(key)) {
161
+ return;
162
+ }
163
+ void renderAndStore(key, page, ctx, ttlMs).catch(() => {
164
+ // Keep serving the last good HTML on refresh failure.
165
+ });
166
+ }
167
+ async function respondWithHtml(html, method, cacheControl, ctx) {
168
+ const headers = { "Cache-Control": cacheControl };
169
+ if (method === "HEAD") {
170
+ return ctx.res.html("", { status: 200, headers });
171
+ }
172
+ return ctx.res.html(html, { status: 200, headers });
173
+ }
174
+ return {
175
+ __kind: "site",
176
+ siteConfig,
177
+ pages,
178
+ plugins,
179
+ async fetch(request, env = {}) {
180
+ const ctx = createContext(request, env);
181
+ const method = ctx.req.method;
182
+ const pathname = normalizePathname(ctx.req.url.pathname);
183
+ const pluginRoute = pluginRoutes.get(pathname);
184
+ if (pluginRoute) {
185
+ return pluginRoute(request, ctx);
186
+ }
187
+ if (method !== "GET" && method !== "HEAD") {
188
+ return ctx.res.text("Method Not Allowed", { status: 405 });
189
+ }
190
+ const pluginAsset = servePluginAsset(pathname, method, plugins);
191
+ if (pluginAsset) {
192
+ return pluginAsset;
193
+ }
194
+ const page = pageMap.get(pathname);
195
+ if (!page) {
196
+ return applyBeforeResponse(await ctx.res.notFound(), request, ctx);
197
+ }
198
+ const cacheKey = buildPageCacheKey(pathname, ctx.req.url.search);
199
+ const cacheConfigs = collectPageCacheConfigs(page, siteConfig);
200
+ const hookAllowsCache = hooks?.shouldCache
201
+ ? hooks.shouldCache(request)
202
+ : true;
203
+ async function respondForPage(html, cacheControl) {
204
+ return applyBeforeResponse(await respondWithHtml(html, method, cacheControl, ctx), request, ctx, page);
205
+ }
206
+ if (isPageCacheDisabled(cacheConfigs) || !hookAllowsCache) {
207
+ const html = await renderPage(page, siteConfig, ctx, hooks);
208
+ return respondForPage(html, "no-store");
209
+ }
210
+ const ttlMs = resolvePageCacheTtlMs(cacheConfigs);
211
+ const cached = await cacheAdapter.get(cacheKey);
212
+ if (cached && isCacheEntryFresh(cached)) {
213
+ return respondForPage(cached.html, cacheControlFresh(ttlMs));
214
+ }
215
+ if (cached) {
216
+ startBackgroundRefresh(cacheKey, page, ctx, ttlMs);
217
+ return respondForPage(cached.html, cacheControlStale(ttlMs));
218
+ }
219
+ const html = await renderAndStore(cacheKey, page, ctx, ttlMs);
220
+ return respondForPage(html, cacheControlFresh(ttlMs));
221
+ },
222
+ };
223
+ }
224
+ export function isSite(value) {
225
+ return (typeof value === "object" &&
226
+ value !== null &&
227
+ value.__kind === "site" &&
228
+ isSiteConfig(value.siteConfig) &&
229
+ Array.isArray(value.pages) &&
230
+ Array.isArray(value.plugins) &&
231
+ typeof value.fetch === "function");
232
+ }
233
+ //# sourceMappingURL=site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,SAAS,oBAAoB,CAAC,MAAe,EAAE,KAAa;IAC1D,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,oCAAoC,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,4BAA4B,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAAS;IAET,oBAAoB,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IACzD,OAAO;QACL,MAAM,EAAE,YAAqB;QAC7B,MAAM;KACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAAuB,CAAC,MAAM,KAAK,YAAY;QAChD,OAAQ,KAAuB,CAAC,MAAM,KAAK,QAAQ;QAClD,KAAuB,CAAC,MAAM,KAAK,IAAI;QACxC,CAAC,KAAK,CAAC,OAAO,CAAE,KAAuB,CAAC,MAAM,CAAC,CAChD,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAoB;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,IAAI,SAAS,CACjB,wBAAwB,IAAI,CAAC,IAAI,MAAM,QAAQ,QAAQ,IAAI,CAAC,KAAK,GAAG,CACrE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,KAA6B;IACjD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,uBAAuB,CAAC,OAA6B;IAC5D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,SAAS,CACjB,2DAA2D,MAAM,CAAC,IAAI,GAAG,CAC1E,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAC1B,OAA6B,EAC7B,IAAa,EACb,SAA8B;IAE9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmC,CAAC;IAE1D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,IAAI,QAAQ,YAAY,OAAO,EAAE,CAAC;YAChC,MAAM,IAAI,SAAS,CACjB,4CAA4C,MAAM,CAAC,IAAI,oCAAoC,CAC5F,CAAC;QACJ,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,SAAS,CACjB,kDAAkD,IAAI,8BAA8B,CACrF,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,MAAM,IAAI,SAAS,CACjB,4DAA4D,IAAI,GAAG,CACpE,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,UAA4B,EAC5B,OAKC;IAED,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CACjB,6EAA6E,CAC9E,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAC1B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,SAAS,CACjB,kEAAkE,CACnE,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,SAAS,CACjB,uEAAuE,CACxE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,SAAS,CACjB,qFAAqF,CACtF,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,YAAY,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,SAAS,CACjB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;QACJ,CAAC;IACH,CAAC;IACD,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAEjC,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAEzB,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAe;QAC5B,MAAM,EAAE,MAAe;QACvB,UAAU;QACV,KAAK;QACL,OAAO;QACP,KAAK,CAAC,KAAK;YACT,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACpE,CAAC;KACF,CAAC;IAEF,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACxE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,iBAAiB,EAAE,CAAC;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,MAAM,eAAe,GAAG,IAAI,GAAG,EAA2B,CAAC;IAE3D,KAAK,UAAU,mBAAmB,CAChC,QAA6B,EAC7B,OAA2B,EAC3B,GAAqC,EACrC,IAAkB;QAElB,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,CAAC;YAC3B,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,OAAO,KAAK,CAAC,cAAc,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,UAAU,cAAc,CAC3B,GAAW,EACX,IAAiB,EACjB,GAAqC,EACrC,KAAa;QAEb,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YAC1B,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YAC5D,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,MAAM,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE;oBAC1B,IAAI;oBACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;iBAC9B,CAAC,CAAC;YACL,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,EAAE,CAAC;QAEL,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAElC,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC;gBACzC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,sBAAsB,CAC7B,GAAW,EACX,IAAiB,EACjB,GAAqC,EACrC,KAAa;QAEb,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,KAAK,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACpD,sDAAsD;QACxD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,UAAU,eAAe,CAC5B,IAAY,EACZ,MAAc,EACd,YAAoB,EACpB,GAAqC;QAErC,MAAM,OAAO,GAAG,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;QAClD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAe;QACvB,UAAU;QACV,KAAK;QACL,OAAO;QACP,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,GAAG,EAAE;YAC3B,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACxC,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;YAC9B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAEzD,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC/C,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACnC,CAAC;YAED,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC1C,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7D,CAAC;YAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YAChE,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,WAAW,CAAC;YACrB,CAAC;YAED,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAEnC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,mBAAmB,CACxB,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,EACxB,OAAO,EACP,GAAG,CACJ,CAAC;YACJ,CAAC;YAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACjE,MAAM,YAAY,GAAG,uBAAuB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC/D,MAAM,eAAe,GAAG,KAAK,EAAE,WAAW;gBACxC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC;gBAC5B,CAAC,CAAC,IAAI,CAAC;YAET,KAAK,UAAU,cAAc,CAC3B,IAAY,EACZ,YAAoB;gBAEpB,OAAO,mBAAmB,CACxB,MAAM,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,EACtD,OAAO,EACP,GAAG,EACH,IAAI,CACL,CAAC;YACJ,CAAC;YAED,IAAI,mBAAmB,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC1D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;gBAC5D,OAAO,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC1C,CAAC;YAED,MAAM,KAAK,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;YAClD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAEhD,IAAI,MAAM,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;gBACxC,OAAO,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/D,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACX,sBAAsB,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;gBACnD,OAAO,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/D,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YAC9D,OAAO,cAAc,CAAC,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;QACxD,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAAiB,CAAC,MAAM,KAAK,MAAM;QACpC,YAAY,CAAE,KAAiB,CAAC,UAAU,CAAC;QAC3C,KAAK,CAAC,OAAO,CAAE,KAAiB,CAAC,KAAK,CAAC;QACvC,KAAK,CAAC,OAAO,CAAE,KAAiB,CAAC,OAAO,CAAC;QACzC,OAAQ,KAAiB,CAAC,KAAK,KAAK,UAAU,CAC/C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { z } from "zod";
2
+ import type { Stackbox as SB } from "./types.js";
3
+ /** Accepts any block or HTML string (default slot content). */
4
+ export declare const anySlotContentSchema: z.ZodType<SB.DefaultSlotContent>;
5
+ /** Accepts only HTML strings. */
6
+ export declare const stringSlotContentSchema: z.ZodString;
7
+ /** Accepts only CMS blocks. */
8
+ export declare const blockSlotContentSchema: z.ZodType<SB.Block>;
9
+ export declare function validateSlotContentItem(slotName: string, item: unknown, schema: z.ZodTypeAny | undefined): void;
10
+ export declare class SlotContentValidationError extends Error {
11
+ constructor(slotName: string, message: string);
12
+ }
13
+ export declare function slotHasContent(items: unknown[]): boolean;
14
+ //# sourceMappingURL=slot-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot-content.d.ts","sourceRoot":"","sources":["../src/slot-content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAG7B,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAEjD,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,kBAAkB,CAGhE,CAAC;AAEH,iCAAiC;AACjC,eAAO,MAAM,uBAAuB,aAAe,CAAC;AAEpD,+BAA+B;AAC/B,eAAO,MAAM,sBAAsB,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAEtD,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,CAAC,CAAC,UAAU,GAAG,SAAS,GAC/B,IAAI,CAkBN;AAED,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI9C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAMxD"}
@@ -0,0 +1,34 @@
1
+ import { z as zod } from "zod";
2
+ import { isBlock } from "./blocks.js";
3
+ /** Accepts any block or HTML string (default slot content). */
4
+ export const anySlotContentSchema = zod.union([
5
+ zod.string(),
6
+ zod.custom((value) => isBlock(value)),
7
+ ]);
8
+ /** Accepts only HTML strings. */
9
+ export const stringSlotContentSchema = zod.string();
10
+ /** Accepts only CMS blocks. */
11
+ export const blockSlotContentSchema = zod.custom((value) => isBlock(value));
12
+ export function validateSlotContentItem(slotName, item, schema) {
13
+ if (schema) {
14
+ const result = schema.safeParse(item);
15
+ if (!result.success) {
16
+ throw new SlotContentValidationError(slotName, result.error.message);
17
+ }
18
+ return;
19
+ }
20
+ if (typeof item !== "string" && !isBlock(item)) {
21
+ throw new SlotContentValidationError(slotName, "expected block or HTML string");
22
+ }
23
+ }
24
+ export class SlotContentValidationError extends Error {
25
+ constructor(slotName, message) {
26
+ super(`slot "${slotName}" content failed validation: ${message}`);
27
+ this.name = "SlotContentValidationError";
28
+ }
29
+ }
30
+ export function slotHasContent(items) {
31
+ return items.some((item) => isBlock(item) ||
32
+ (typeof item === "string" && item.trim().length > 0));
33
+ }
34
+ //# sourceMappingURL=slot-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot-content.js","sourceRoot":"","sources":["../src/slot-content.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAqC,GAAG,CAAC,KAAK,CAAC;IAC9E,GAAG,CAAC,MAAM,EAAE;IACZ,GAAG,CAAC,MAAM,CAAW,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;CAChD,CAAC,CAAC;AAEH,iCAAiC;AACjC,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAwB,GAAG,CAAC,MAAM,CACnE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAC1B,CAAC;AAEF,MAAM,UAAU,uBAAuB,CACrC,QAAgB,EAChB,IAAa,EACb,MAAgC;IAEhC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,0BAA0B,CAClC,QAAQ,EACR,MAAM,CAAC,KAAK,CAAC,OAAO,CACrB,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,0BAA0B,CAClC,QAAQ,EACR,+BAA+B,CAChC,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD,YAAY,QAAgB,EAAE,OAAe;QAC3C,KAAK,CAAC,SAAS,QAAQ,gCAAgC,OAAO,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,OAAO,KAAK,CAAC,IAAI,CACf,CAAC,IAAI,EAAE,EAAE,CACP,OAAO,CAAC,IAAI,CAAC;QACb,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CACvD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type HSHtml } from "@hyperspan/html";
2
+ import type { z } from "zod";
3
+ import type { Stackbox as SB } from "./types.js";
4
+ export declare class RenderError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ export declare const SLOT_SENTINEL_PREFIX = "<!--__STACKBOX_SLOT__:";
8
+ export declare function slotSentinel(name: string): string;
9
+ export declare function renderSlotContent(slotName: string, items: readonly unknown[], ctx: SB.RenderContext, schema: z.ZodTypeAny | undefined): Promise<HSHtml>;
10
+ export declare function createStubSlot<D extends SB.SlotDefinition>(definition: D): SB.Slot<SB.DefaultSlotContent, D>;
11
+ export declare function createPageSlot<D extends SB.SlotDefinition>(definition: D, content: readonly SB.SlotContentFromDefinition<D>[], ctx: SB.RenderContext): SB.Slot<SB.SlotContentFromDefinition<D>, D>;
12
+ export declare function buildStubSlots<S extends readonly SB.SlotDefinition[]>(definitions: S): SB.TemplateSlotsFrom<S>;
13
+ export declare function buildPageSlots(page: SB.SitePage, ctx: SB.RenderContext): Record<string, SB.Slot>;
14
+ //# sourceMappingURL=slot-handle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot-handle.d.ts","sourceRoot":"","sources":["../src/slot-handle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAKjD,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED,eAAO,MAAM,oBAAoB,2BAA2B,CAAC;AAE7D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AA0BD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,GAAG,EAAE,EAAE,CAAC,aAAa,EACrB,MAAM,EAAE,CAAC,CAAC,UAAU,GAAG,SAAS,GAC/B,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,wBAAgB,cAAc,CAC5B,CAAC,SAAS,EAAE,CAAC,cAAc,EAC3B,UAAU,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC,CASlD;AAED,wBAAgB,cAAc,CAC5B,CAAC,SAAS,EAAE,CAAC,cAAc,EAE3B,UAAU,EAAE,CAAC,EACb,OAAO,EAAE,SAAS,EAAE,CAAC,yBAAyB,CAAC,CAAC,CAAC,EAAE,EACnD,GAAG,EAAE,EAAE,CAAC,aAAa,GACpB,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAU7C;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,SAAS,EAAE,CAAC,cAAc,EAAE,EACnE,WAAW,EAAE,CAAC,GACb,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAQzB;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,EAAE,CAAC,QAAQ,EACjB,GAAG,EAAE,EAAE,CAAC,aAAa,GACpB,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,CAUzB"}