@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
package/dist/cache.js ADDED
@@ -0,0 +1,93 @@
1
+ import { isBlock } from "./blocks.js";
2
+ export const DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
3
+ export const MAX_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
4
+ export function createMemoryCache() {
5
+ const store = new Map();
6
+ return {
7
+ get(key) {
8
+ return store.get(key);
9
+ },
10
+ set(key, entry) {
11
+ store.set(key, entry);
12
+ },
13
+ };
14
+ }
15
+ function isCacheBounds(value) {
16
+ return (typeof value === "object" &&
17
+ value !== null &&
18
+ !Array.isArray(value) &&
19
+ ("min" in value || "max" in value));
20
+ }
21
+ export function isCacheConfig(value) {
22
+ if (value === false) {
23
+ return true;
24
+ }
25
+ return isCacheBounds(value);
26
+ }
27
+ function readCacheConfig(value) {
28
+ if (value === undefined) {
29
+ return undefined;
30
+ }
31
+ if (value === false) {
32
+ return false;
33
+ }
34
+ if (isCacheBounds(value)) {
35
+ return value;
36
+ }
37
+ return undefined;
38
+ }
39
+ export function collectPageCacheConfigs(page, siteConfig) {
40
+ const configs = [
41
+ readCacheConfig(page.cache),
42
+ readCacheConfig(siteConfig.config.cache),
43
+ ];
44
+ for (const items of Object.values(page.slots)) {
45
+ if (!items) {
46
+ continue;
47
+ }
48
+ for (const item of items) {
49
+ if (isBlock(item)) {
50
+ configs.push(readCacheConfig(item.cache));
51
+ }
52
+ }
53
+ }
54
+ return configs;
55
+ }
56
+ export function isPageCacheDisabled(configs) {
57
+ return configs.some((config) => config === false);
58
+ }
59
+ export function resolvePageCacheTtlMs(configs) {
60
+ const bounds = configs.filter(isCacheBounds);
61
+ const mins = bounds
62
+ .map((config) => config.min)
63
+ .filter((value) => typeof value === "number" && value >= 0);
64
+ const maxes = bounds
65
+ .map((config) => config.max)
66
+ .filter((value) => typeof value === "number" && value > 0);
67
+ const effectiveMin = mins.length > 0 ? Math.max(...mins) : 0;
68
+ const effectiveMax = maxes.length > 0
69
+ ? Math.min(...maxes, MAX_CACHE_TTL_MS)
70
+ : MAX_CACHE_TTL_MS;
71
+ const raw = maxes.length > 0 ? effectiveMax : DEFAULT_CACHE_TTL_MS;
72
+ const ttl = Math.min(Math.max(raw, effectiveMin), effectiveMax);
73
+ return ttl;
74
+ }
75
+ export function buildPageCacheKey(pathname, search) {
76
+ return `${pathname}${search}`;
77
+ }
78
+ export function cacheControlFresh(ttlMs) {
79
+ const seconds = Math.max(0, Math.floor(ttlMs / 1000));
80
+ return `public, max-age=${seconds}`;
81
+ }
82
+ export function cacheControlStale(ttlMs) {
83
+ const seconds = Math.max(0, Math.floor(ttlMs / 1000));
84
+ return `public, max-age=0, stale-while-revalidate=${seconds}`;
85
+ }
86
+ export function isCacheEntryFresh(entry, now = Date.now()) {
87
+ return entry.expiresAt > now;
88
+ }
89
+ const RENDER_ERROR_MARKER = "[Hyperspan] Render Error";
90
+ export function isSuccessfulRender(html) {
91
+ return !html.includes(RENDER_ERROR_MARKER);
92
+ }
93
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACxD,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEzD,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC/C,OAAO;QACL,GAAG,CAAC,GAAG;YACL,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QACD,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,CACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,IAAiB,EACjB,UAAyB;IAEzB,MAAM,OAAO,GAAmC;QAC9C,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3B,eAAe,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC;KACzC,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgD;IAClF,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAgD;IAEhD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,MAAM;SAChB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC;SAC3B,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;IAE/E,MAAM,KAAK,GAAG,MAAM;SACjB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC;SAC3B,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IAE9E,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,YAAY,GAChB,KAAK,CAAC,MAAM,GAAG,CAAC;QACd,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE,gBAAgB,CAAC;QACtC,CAAC,CAAC,gBAAgB,CAAC;IAEvB,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACnE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;IAEhE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;IACtD,OAAO,mBAAmB,OAAO,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;IACtD,OAAO,6CAA6C,OAAO,EAAE,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAoB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACtE,OAAO,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;AAC/B,CAAC;AAED,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AAEvD,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AAC7C,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { runBuildCli } from "./build.js";
3
+ try {
4
+ const result = await runBuildCli(process.argv);
5
+ const names = result.plugins.length > 0
6
+ ? result.plugins.map((plugin) => plugin.name).join(", ")
7
+ : "(none)";
8
+ console.log(`stackbox-cms build: copied public assets for ${names}`);
9
+ console.log(` outDir ${result.settings.outDir}`);
10
+ console.log(` publicDir ${result.settings.publicDir}`);
11
+ }
12
+ catch (error) {
13
+ console.error(error instanceof Error ? error.message : error);
14
+ process.exitCode = 1;
15
+ }
16
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,IAAI,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,KAAK,GACT,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QACvB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACxD,CAAC,CAAC,QAAQ,CAAC;IACf,OAAO,CAAC,GAAG,CAAC,gDAAgD,KAAK,EAAE,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;AAC1D,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export { html, type HSHtml } from "@hyperspan/html";
2
+ export type { Stackbox } from "./types.js";
3
+ export { buildPageCacheKey, cacheControlFresh, cacheControlStale, collectPageCacheConfigs, createMemoryCache, DEFAULT_CACHE_TTL_MS, isCacheConfig, isCacheEntryFresh, isPageCacheDisabled, isSuccessfulRender, MAX_CACHE_TTL_MS, resolvePageCacheTtlMs, } from "./cache.js";
4
+ export { build, BuildError, loadSiteFromEntry, parseBuildCliArgs, resolveBuildSettings, runBuildCli, } from "./build.js";
5
+ export { createBlock, isBlock, } from "./blocks.js";
6
+ export { createPage, isPage, PageValidationError, toPageRenderView, validateSlotContentItem, } from "./pages.js";
7
+ export { renderStandardHead } from "./render-head.js";
8
+ export { renderPage, RenderError } from "./render-page.js";
9
+ export { matchPagePath, normalizePathname } from "./routing.js";
10
+ export { assertPlugin, copyPluginPrivateAssets, copyRegisteredPluginAssets, createPlugin, isPlugin, PluginError, runRegisteredPluginBuilds, } from "./plugin.js";
11
+ export { createSite, createSiteConfig, isSite, isSiteConfig, SiteError, } from "./site.js";
12
+ export { createContext } from "./stackbox/context.js";
13
+ export { anySlotContentSchema, blockSlotContentSchema, slotHasContent, SlotContentValidationError, stringSlotContentSchema, } from "./slot-content.js";
14
+ export { buildPageSlots, buildStubSlots, renderSlotContent, slotSentinel, SLOT_SENTINEL_PREFIX, } from "./slot-handle.js";
15
+ export { createTemplate, isTemplate, TemplateBuildError, } from "./templates.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,EACL,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,UAAU,EACV,MAAM,EACN,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,0BAA0B,EAC1B,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,MAAM,EACN,YAAY,EACZ,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,UAAU,EACV,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export { html } from "@hyperspan/html";
2
+ export { buildPageCacheKey, cacheControlFresh, cacheControlStale, collectPageCacheConfigs, createMemoryCache, DEFAULT_CACHE_TTL_MS, isCacheConfig, isCacheEntryFresh, isPageCacheDisabled, isSuccessfulRender, MAX_CACHE_TTL_MS, resolvePageCacheTtlMs, } from "./cache.js";
3
+ export { build, BuildError, loadSiteFromEntry, parseBuildCliArgs, resolveBuildSettings, runBuildCli, } from "./build.js";
4
+ export { createBlock, isBlock, } from "./blocks.js";
5
+ export { createPage, isPage, PageValidationError, toPageRenderView, validateSlotContentItem, } from "./pages.js";
6
+ export { renderStandardHead } from "./render-head.js";
7
+ export { renderPage, RenderError } from "./render-page.js";
8
+ export { matchPagePath, normalizePathname } from "./routing.js";
9
+ export { assertPlugin, copyPluginPrivateAssets, copyRegisteredPluginAssets, createPlugin, isPlugin, PluginError, runRegisteredPluginBuilds, } from "./plugin.js";
10
+ export { createSite, createSiteConfig, isSite, isSiteConfig, SiteError, } from "./site.js";
11
+ export { createContext } from "./stackbox/context.js";
12
+ export { anySlotContentSchema, blockSlotContentSchema, slotHasContent, SlotContentValidationError, stringSlotContentSchema, } from "./slot-content.js";
13
+ export { buildPageSlots, buildStubSlots, renderSlotContent, slotSentinel, SLOT_SENTINEL_PREFIX, } from "./slot-handle.js";
14
+ export { createTemplate, isTemplate, TemplateBuildError, } from "./templates.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAe,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,EACL,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,UAAU,EACV,MAAM,EACN,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,0BAA0B,EAC1B,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,MAAM,EACN,YAAY,EACZ,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,UAAU,EACV,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
package/dist/link.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { Stackbox as SB } from "./types.js";
2
+ export declare const PLUGIN_PUBLIC_PREFIX = "/_sb/plugins";
3
+ export declare function pluginAssetPath(pluginName: string, relativePath: string): string;
4
+ export declare function parsePluginAssetRequest(pathname: string): SB.PluginAssetRequest | null;
5
+ export declare function servePluginAsset(pathname: string, method: string, plugins?: readonly SB.Plugin[]): globalThis.Response | null;
6
+ //# sourceMappingURL=link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAGjD,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AA8BnD,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAShF;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,GACf,EAAE,CAAC,kBAAkB,GAAG,IAAI,CAkC9B;AA0BD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,SAAS,EAAE,CAAC,MAAM,EAAO,GACjC,UAAU,CAAC,QAAQ,GAAG,IAAI,CAiC5B"}
package/dist/link.js ADDED
@@ -0,0 +1,121 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join, normalize, sep } from "node:path";
3
+ import { normalizePathname } from "./routing.js";
4
+ export const PLUGIN_PUBLIC_PREFIX = "/_sb/plugins";
5
+ const CONTENT_TYPES = {
6
+ ".css": "text/css; charset=utf-8",
7
+ ".gif": "image/gif",
8
+ ".html": "text/html; charset=utf-8",
9
+ ".jpeg": "image/jpeg",
10
+ ".jpg": "image/jpeg",
11
+ ".js": "text/javascript; charset=utf-8",
12
+ ".json": "application/json; charset=utf-8",
13
+ ".png": "image/png",
14
+ ".svg": "image/svg+xml",
15
+ ".txt": "text/plain; charset=utf-8",
16
+ ".webp": "image/webp",
17
+ ".woff": "font/woff",
18
+ ".woff2": "font/woff2",
19
+ };
20
+ function assertSafeSegment(segment, label) {
21
+ if (!segment ||
22
+ segment === "." ||
23
+ segment === ".." ||
24
+ segment.includes("/") ||
25
+ segment.includes("\\")) {
26
+ throw new Error(`pluginAssetPath: invalid ${label}`);
27
+ }
28
+ }
29
+ export function pluginAssetPath(pluginName, relativePath) {
30
+ assertSafeSegment(pluginName, "plugin name");
31
+ const segments = relativePath
32
+ .split(/[/\\]+/)
33
+ .filter((segment) => segment.length > 0);
34
+ for (const segment of segments) {
35
+ assertSafeSegment(segment, "relative path segment");
36
+ }
37
+ return `${PLUGIN_PUBLIC_PREFIX}/${pluginName}/${segments.join("/")}`;
38
+ }
39
+ export function parsePluginAssetRequest(pathname) {
40
+ const normalized = normalizePathname(pathname);
41
+ const prefix = `${PLUGIN_PUBLIC_PREFIX}/`;
42
+ if (!normalized.startsWith(prefix)) {
43
+ return null;
44
+ }
45
+ const rest = normalized.slice(prefix.length);
46
+ const slash = rest.indexOf("/");
47
+ if (slash <= 0 || slash === rest.length - 1) {
48
+ return null;
49
+ }
50
+ const plugin = rest.slice(0, slash);
51
+ const relativePath = rest.slice(slash + 1);
52
+ if (!plugin ||
53
+ !relativePath ||
54
+ relativePath.includes("..") ||
55
+ relativePath.includes("\\")) {
56
+ return null;
57
+ }
58
+ try {
59
+ assertSafeSegment(plugin, "plugin name");
60
+ for (const segment of relativePath.split("/")) {
61
+ assertSafeSegment(segment, "relative path segment");
62
+ }
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ return { plugin, relativePath };
68
+ }
69
+ function contentTypeForPath(relativePath) {
70
+ const dot = relativePath.lastIndexOf(".");
71
+ if (dot === -1) {
72
+ return "application/octet-stream";
73
+ }
74
+ return CONTENT_TYPES[relativePath.slice(dot).toLowerCase()] ??
75
+ "application/octet-stream";
76
+ }
77
+ function resolveFileInDir(root, relativePath) {
78
+ if (!existsSync(root)) {
79
+ return null;
80
+ }
81
+ const absolute = normalize(join(root, relativePath));
82
+ const rootWithSep = root.endsWith(sep) ? root : `${root}${sep}`;
83
+ if (!absolute.startsWith(rootWithSep)) {
84
+ return null;
85
+ }
86
+ if (!existsSync(absolute)) {
87
+ return null;
88
+ }
89
+ return absolute;
90
+ }
91
+ export function servePluginAsset(pathname, method, plugins = []) {
92
+ const request = parsePluginAssetRequest(pathname);
93
+ if (!request) {
94
+ return null;
95
+ }
96
+ const plugin = plugins.find((entry) => entry.name === request.plugin);
97
+ if (!plugin) {
98
+ return new globalThis.Response("Not Found", { status: 404 });
99
+ }
100
+ const filePath = resolveFileInDir(plugin.publicAssetsDir, request.relativePath);
101
+ if (!filePath) {
102
+ return new globalThis.Response("Not Found", { status: 404 });
103
+ }
104
+ const contentType = contentTypeForPath(request.relativePath);
105
+ if (method === "HEAD") {
106
+ const body = readFileSync(filePath);
107
+ return new globalThis.Response(null, {
108
+ status: 200,
109
+ headers: {
110
+ "content-type": contentType,
111
+ "content-length": String(body.byteLength),
112
+ },
113
+ });
114
+ }
115
+ const body = readFileSync(filePath);
116
+ return new globalThis.Response(body, {
117
+ status: 200,
118
+ headers: { "content-type": contentType },
119
+ });
120
+ }
121
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { RenderContext } from "./pages.js";
2
+ import type { HSHtml } from "@hyperspan/html";
3
+ export type ModuleRenderResult = HSHtml | Promise<HSHtml>;
4
+ export type Module = {
5
+ readonly __kind: "module";
6
+ readonly name: string;
7
+ render(ctx: RenderContext): ModuleRenderResult;
8
+ };
9
+ type ModuleDef<TOptions = undefined> = {
10
+ name: string;
11
+ render(options: TOptions, ctx?: RenderContext): ModuleRenderResult;
12
+ };
13
+ export type ModuleOptionsOf<F> = F extends (options?: infer O) => unknown ? [O] extends [undefined] ? undefined : O : never;
14
+ export type ModuleFactory<TOptions = undefined> = (options?: TOptions) => Module;
15
+ export declare function createModule<TOptions = undefined>(def: ModuleDef<TOptions>): ModuleFactory<TOptions>;
16
+ export declare function isModule(value: unknown): value is Module;
17
+ export {};
18
+ //# sourceMappingURL=modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,kBAAkB,CAAC;CAChD,CAAC;AAEF,KAAK,SAAS,CAAC,QAAQ,GAAG,SAAS,IAAI;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,aAAa,GAAG,kBAAkB,CAAC;CACpE,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,KAAK,OAAO,GACrE,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GACrB,SAAS,GACT,CAAC,GACH,KAAK,CAAC;AAEV,MAAM,MAAM,aAAa,CAAC,QAAQ,GAAG,SAAS,IAAI,CAChD,OAAO,CAAC,EAAE,QAAQ,KACf,MAAM,CAAC;AAQZ,wBAAgB,YAAY,CAAC,QAAQ,GAAG,SAAS,EAC/C,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,GACvB,aAAa,CAAC,QAAQ,CAAC,CAYzB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CASxD"}
@@ -0,0 +1,25 @@
1
+ function validateModuleName(name) {
2
+ if (!name || name.length === 0) {
3
+ throw new Error("createModule(def): name is required");
4
+ }
5
+ }
6
+ export function createModule(def) {
7
+ validateModuleName(def.name);
8
+ if (typeof def.render !== "function") {
9
+ throw new Error("createModule(def): render is required");
10
+ }
11
+ return ((options) => ({
12
+ __kind: "module",
13
+ name: def.name,
14
+ render: (ctx) => def.render(options, ctx),
15
+ }));
16
+ }
17
+ export function isModule(value) {
18
+ return (typeof value === "object" &&
19
+ value !== null &&
20
+ value.__kind === "module" &&
21
+ typeof value.name === "string" &&
22
+ value.name.length > 0 &&
23
+ typeof value.render === "function");
24
+ }
25
+ //# sourceMappingURL=modules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.js","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AA0BA,SAAS,kBAAkB,CAAC,IAAY;IACtC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,GAAwB;IAExB,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,CAAC,OAAkB,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,EAAE,QAAiB;QACzB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,CAAC,GAAkB,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAmB,EAAE,GAAG,CAAC;KACrE,CAAC,CAA4B,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAAgB,CAAC,MAAM,KAAK,QAAQ;QACrC,OAAQ,KAAgB,CAAC,IAAI,KAAK,QAAQ;QACzC,KAAgB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QACjC,OAAQ,KAAgB,CAAC,MAAM,KAAK,UAAU,CAC/C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { Stackbox as SB } from "./types.js";
2
+ export declare function toPageRenderView({ template: _template, slots: _slots, ...view }: SB.SitePage): SB.PageRenderView;
3
+ export declare function isPage(value: unknown): value is SB.Page;
4
+ export declare class PageValidationError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ export declare function createPage(template: SB.TemplateDescriptor<string, string>, def: {
8
+ path: string;
9
+ title: string;
10
+ meta?: SB.PageMeta;
11
+ cache?: SB.CacheConfig;
12
+ source?: string;
13
+ slots: Partial<Record<string, SB.DefaultSlotContent[]>>;
14
+ }): SB.SitePage;
15
+ export declare function createPage<const S extends readonly SB.SlotDefinition[]>(template: SB.TemplateDescriptor<SB.SlotNamesFrom<S>, SB.RequiredSlotNamesFrom<S>, S>, def: {
16
+ path: string;
17
+ title: string;
18
+ meta?: SB.PageMeta;
19
+ cache?: SB.CacheConfig;
20
+ source?: string;
21
+ slots: SB.PageSlotsInput<S, SB.RequiredSlotNamesFrom<S>>;
22
+ }): SB.Page<SB.SlotNamesFrom<S>, SB.RequiredSlotNamesFrom<S>, S>;
23
+ export { validateSlotContentItem } from "./slot-content.js";
24
+ //# sourceMappingURL=pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../src/pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAUjD,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,MAAM,EACb,GAAG,IAAI,EACR,EAAE,EAAE,CAAC,QAAQ,GAAG,EAAE,CAAC,cAAc,CAEjC;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC,IAAI,CAavD;AAED,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AA+CD,wBAAgB,UAAU,CACxB,QAAQ,EAAE,EAAE,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/C,GAAG,EAAE;IACH,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC;IACnB,KAAK,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;CACzD,GACA,EAAE,CAAC,QAAQ,CAAC;AACf,wBAAgB,UAAU,CAAC,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,CAAC,cAAc,EAAE,EACrE,QAAQ,EAAE,EAAE,CAAC,kBAAkB,CAC7B,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EACnB,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAC3B,CAAC,CACF,EACD,GAAG,EAAE;IACH,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC;IACnB,KAAK,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;CAC1D,GACA,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AA+ChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/pages.js ADDED
@@ -0,0 +1,87 @@
1
+ import { isTemplate, } from "./templates.js";
2
+ import { slotHasContent, SlotContentValidationError, validateSlotContentItem, } from "./slot-content.js";
3
+ export function toPageRenderView({ template: _template, slots: _slots, ...view }) {
4
+ return view;
5
+ }
6
+ export function isPage(value) {
7
+ return (typeof value === "object" &&
8
+ value !== null &&
9
+ value.__kind === "page" &&
10
+ typeof value.path === "string" &&
11
+ value.path.length > 0 &&
12
+ isTemplate(value.template) &&
13
+ typeof value.title === "string" &&
14
+ value.title.length > 0 &&
15
+ typeof value.slots === "object" &&
16
+ value.slots !== null);
17
+ }
18
+ export class PageValidationError extends Error {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = "PageValidationError";
22
+ }
23
+ }
24
+ function validatePagePath(path) {
25
+ if (!path || !path.startsWith("/")) {
26
+ throw new PageValidationError('path must start with "/"');
27
+ }
28
+ if (path.includes("..")) {
29
+ throw new PageValidationError("path must not contain '..'");
30
+ }
31
+ const lastSegment = path.split("/").pop() ?? "";
32
+ if (lastSegment.includes(".")) {
33
+ throw new PageValidationError("path must not include a file extension");
34
+ }
35
+ }
36
+ function validatePageSlotContent(template, slots) {
37
+ const templateSlotNames = new Set(Object.keys(template.slots));
38
+ for (const key of Object.keys(slots)) {
39
+ if (!templateSlotNames.has(key)) {
40
+ throw new PageValidationError(`unknown slot "${key}" for this template`);
41
+ }
42
+ const items = slots[key];
43
+ if (!Array.isArray(items)) {
44
+ throw new PageValidationError(`slot "${key}" must be an array of content items`);
45
+ }
46
+ const schema = template.slots[key]?.schema;
47
+ for (const item of items) {
48
+ try {
49
+ validateSlotContentItem(key, item, schema);
50
+ }
51
+ catch (err) {
52
+ if (err instanceof SlotContentValidationError) {
53
+ throw new PageValidationError(err.message);
54
+ }
55
+ throw err;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ export function createPage(template, def) {
61
+ if (!isTemplate(template)) {
62
+ throw new PageValidationError("template must be created with createTemplate()");
63
+ }
64
+ validatePagePath(def.path);
65
+ if (!def.title || def.title.trim().length === 0) {
66
+ throw new PageValidationError("title is required");
67
+ }
68
+ validatePageSlotContent(template, def.slots);
69
+ for (const required of template.requiredSlots) {
70
+ const items = def.slots[required];
71
+ if (!items || items.length === 0 || !slotHasContent(items)) {
72
+ throw new PageValidationError(`required slot "${required}" must have at least one block or non-empty HTML string`);
73
+ }
74
+ }
75
+ return {
76
+ __kind: "page",
77
+ path: def.path,
78
+ template,
79
+ title: def.title,
80
+ meta: def.meta,
81
+ cache: def.cache,
82
+ source: def.source,
83
+ slots: def.slots,
84
+ };
85
+ }
86
+ export { validateSlotContentItem } from "./slot-content.js";
87
+ //# sourceMappingURL=pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../src/pages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Stackbox as SB } from "./types.js";
2
+ export declare class PluginError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare function createPlugin(options: SB.CreatePluginOptions): SB.Plugin;
6
+ export declare function isPlugin(value: unknown): value is SB.Plugin;
7
+ export declare function assertPlugin(value: unknown, label?: string): SB.Plugin;
8
+ /**
9
+ * Copy each registered plugin's private `assets/` next to its compiled entry
10
+ * (`{plugin.root}/assets`). Used by this package's build — not a site public copy.
11
+ */
12
+ export declare function copyPluginPrivateAssets(plugins: readonly SB.Plugin[]): void;
13
+ /**
14
+ * Copy each registered plugin's `public_assets/` to
15
+ * `{publicDir}/_sb/plugins/{name}/`. Only plugins you pass in are copied.
16
+ */
17
+ export declare function copyRegisteredPluginAssets(plugins: readonly SB.Plugin[], publicDir: string): void;
18
+ /**
19
+ * Run each registered plugin's `build` hook (e.g. write sitemap.xml).
20
+ */
21
+ export declare function runRegisteredPluginBuilds(plugins: readonly SB.Plugin[], ctx: SB.PluginBuildContext): Promise<void>;
22
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AA8ED,wBAAgB,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,GAAG,EAAE,CAAC,MAAM,CA2BvE;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC,MAAM,CAiB3D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAW,GAAG,EAAE,CAAC,MAAM,CAOxE;AAaD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,GAAG,IAAI,CAK3E;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,EAC7B,SAAS,EAAE,MAAM,GAChB,IAAI,CAiBN;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,EAC7B,GAAG,EAAE,EAAE,CAAC,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CAOf"}