@stackbox/cms 0.0.4 → 0.0.5
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.
- package/dist/blocks.d.ts +18 -0
- package/dist/blocks.d.ts.map +1 -0
- package/dist/blocks.js +25 -0
- package/dist/blocks.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/link.d.ts +10 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +128 -0
- package/dist/link.js.map +1 -0
- package/dist/modules/blog/module.d.ts +20 -0
- package/dist/modules/blog/module.d.ts.map +1 -0
- package/dist/modules/blog/module.js +52 -0
- package/dist/modules/blog/module.js.map +1 -0
- package/dist/modules/blog/posts.d.ts +15 -0
- package/dist/modules/blog/posts.d.ts.map +1 -0
- package/dist/modules/blog/posts.js +46 -0
- package/dist/modules/blog/posts.js.map +1 -0
- package/dist/modules.d.ts +18 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +25 -0
- package/dist/modules.js.map +1 -0
- package/dist/pages.d.ts +55 -0
- package/dist/pages.d.ts.map +1 -0
- package/dist/pages.js +85 -0
- package/dist/pages.js.map +1 -0
- package/dist/plugins/blog/index.d.ts +20 -0
- package/dist/plugins/blog/index.d.ts.map +1 -0
- package/dist/plugins/blog/index.js +52 -0
- package/dist/plugins/blog/index.js.map +1 -0
- package/dist/plugins/blog/module.d.ts +20 -0
- package/dist/plugins/blog/module.d.ts.map +1 -0
- package/dist/plugins/blog/module.js +52 -0
- package/dist/plugins/blog/module.js.map +1 -0
- package/dist/plugins/blog/plugin.d.ts +20 -0
- package/dist/plugins/blog/plugin.d.ts.map +1 -0
- package/dist/plugins/blog/plugin.js +52 -0
- package/dist/plugins/blog/plugin.js.map +1 -0
- package/dist/plugins/blog/posts.d.ts +15 -0
- package/dist/plugins/blog/posts.d.ts.map +1 -0
- package/dist/plugins/blog/posts.js +46 -0
- package/dist/plugins/blog/posts.js.map +1 -0
- package/dist/plugins/random-quote/index.d.ts +12 -0
- package/dist/plugins/random-quote/index.d.ts.map +1 -0
- package/dist/plugins/random-quote/index.js +21 -0
- package/dist/plugins/random-quote/index.js.map +1 -0
- package/dist/plugins/random-quote/module.d.ts +9 -0
- package/dist/plugins/random-quote/module.d.ts.map +1 -0
- package/dist/plugins/random-quote/module.js +31 -0
- package/dist/plugins/random-quote/module.js.map +1 -0
- package/dist/plugins/random-quote/plugin.d.ts +8 -0
- package/dist/plugins/random-quote/plugin.d.ts.map +1 -0
- package/dist/plugins/random-quote/plugin.js +31 -0
- package/dist/plugins/random-quote/plugin.js.map +1 -0
- package/dist/plugins/random-quote/public_assets/quotes.json +230 -0
- package/dist/plugins/random-quote/quotes.json +230 -0
- package/dist/public/_sb/plugins/random-quote/quotes.json +230 -0
- package/dist/render-head.d.ts +7 -0
- package/dist/render-head.d.ts.map +1 -0
- package/dist/render-head.js +27 -0
- package/dist/render-head.js.map +1 -0
- package/dist/render-page.d.ts +6 -0
- package/dist/render-page.d.ts.map +1 -0
- package/dist/render-page.js +30 -0
- package/dist/render-page.js.map +1 -0
- package/dist/routing.d.ts +3 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +11 -0
- package/dist/routing.js.map +1 -0
- package/dist/site.d.ts +21 -0
- package/dist/site.d.ts.map +1 -0
- package/dist/site.js +102 -0
- package/dist/site.js.map +1 -0
- package/dist/slot-content.d.ts +30 -0
- package/dist/slot-content.d.ts.map +1 -0
- package/dist/slot-content.js +34 -0
- package/dist/slot-content.js.map +1 -0
- package/dist/slot-handle.d.ts +32 -0
- package/dist/slot-handle.d.ts.map +1 -0
- package/dist/slot-handle.js +68 -0
- package/dist/slot-handle.js.map +1 -0
- package/dist/stackbox/context.d.ts +52 -0
- package/dist/stackbox/context.d.ts.map +1 -0
- package/dist/stackbox/context.js +165 -0
- package/dist/stackbox/context.js.map +1 -0
- package/dist/templates.d.ts +63 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +106 -0
- package/dist/templates.js.map +1 -0
- package/package.json +7 -2
- package/.claude/settings.local.json +0 -8
- package/scripts/copy-plugin-assets.mjs +0 -30
- package/src/blocks.ts +0 -58
- package/src/index.ts +0 -67
- package/src/link.ts +0 -158
- package/src/pages.ts +0 -198
- package/src/render-head.ts +0 -32
- package/src/render-page.ts +0 -51
- package/src/routing.ts +0 -14
- package/src/site.ts +0 -160
- package/src/slot-content.ts +0 -77
- package/src/slot-handle.ts +0 -131
- package/src/stackbox/context.ts +0 -257
- package/src/templates.ts +0 -230
- package/test/async-render.test.ts +0 -103
- package/test/blog.test.ts +0 -93
- package/test/fetch-routing.test.ts +0 -76
- package/test/plugin-assets.test.ts +0 -80
- package/test/random-quote.test.ts +0 -55
- package/test/stackbox-context.test.ts +0 -44
- package/tsconfig.json +0 -20
|
@@ -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,EAAE,MAAM,YAAY,CAAC;AAE3C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB,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,6 @@
|
|
|
1
|
+
import { type SitePage } from "./pages.js";
|
|
2
|
+
import type { SiteConfig } from "./site.js";
|
|
3
|
+
import type { Stackbox } from "./stackbox/context.js";
|
|
4
|
+
export { RenderError } from "./slot-handle.js";
|
|
5
|
+
export declare function renderPage(page: SitePage, siteConfig: SiteConfig, ctx?: Stackbox.Context): Promise<string>;
|
|
6
|
+
//# 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":"AACA,OAAO,EACL,KAAK,QAAQ,EAId,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAKtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAa/C,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,UAAU,EAAE,UAAU,EACtB,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAO,GACrB,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
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) {
|
|
16
|
+
validateRequiredSlots(page);
|
|
17
|
+
const renderCtx = { siteConfig, ctx };
|
|
18
|
+
const slots = buildPageSlots(page, renderCtx);
|
|
19
|
+
const head = renderStandardHead({
|
|
20
|
+
title: page.template.formatPageTitle(page.title),
|
|
21
|
+
meta: page.meta,
|
|
22
|
+
});
|
|
23
|
+
return renderAsync(page.template.render({
|
|
24
|
+
head,
|
|
25
|
+
siteConfig,
|
|
26
|
+
page: toPageRenderView(page),
|
|
27
|
+
slots,
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
//# 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,EAGL,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAe,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,SAAS,qBAAqB,CAAC,IAAc;IAC3C,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,IAAc,EACd,UAAsB,EACtB,GAAsB;IAEtB,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAE5B,MAAM,SAAS,GAAkB,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;IAErD,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,OAAO,WAAW,CAChB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnB,IAAI;QACJ,UAAU;QACV,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC;QAC5B,KAAK;KACN,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -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"}
|
package/dist/routing.js
ADDED
|
@@ -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,21 @@
|
|
|
1
|
+
import type { SitePage } from "./pages.js";
|
|
2
|
+
export type SiteConfig<T extends Record<string, unknown> = Record<string, unknown>> = {
|
|
3
|
+
readonly __kind: "siteConfig";
|
|
4
|
+
readonly config: T;
|
|
5
|
+
};
|
|
6
|
+
export type Site<T extends Record<string, unknown> = Record<string, unknown>> = {
|
|
7
|
+
readonly __kind: "site";
|
|
8
|
+
readonly siteConfig: SiteConfig<T>;
|
|
9
|
+
readonly pages: readonly SitePage[];
|
|
10
|
+
fetch(request: globalThis.Request, env?: Record<string, unknown>): Promise<globalThis.Response>;
|
|
11
|
+
};
|
|
12
|
+
export declare class SiteError extends Error {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare function createSiteConfig<T extends Record<string, unknown>>(config: T): SiteConfig<T>;
|
|
16
|
+
export declare function isSiteConfig(value: unknown): value is SiteConfig;
|
|
17
|
+
export declare function createSite<T extends Record<string, unknown>>(siteConfig: SiteConfig<T>, options: {
|
|
18
|
+
pages: [SitePage, ...SitePage[]];
|
|
19
|
+
}): Site<T>;
|
|
20
|
+
export declare function isSite(value: unknown): value is Site;
|
|
21
|
+
//# sourceMappingURL=site.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAO3C,MAAM,MAAM,UAAU,CACpB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IACzD;IACF,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,CACd,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IACzD;IACF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,KAAK,CACH,OAAO,EAAE,UAAU,CAAC,OAAO,EAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;CACjC,CAAC;AAEF,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,UAAU,CAAC,CAAC,CAAC,CAMf;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAShE;AAwBD,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1D,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EACzB,OAAO,EAAE;IAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAA;CAAE,GAC5C,IAAI,CAAC,CAAC,CAAC,CA4DT;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CASpD"}
|
package/dist/site.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { isPage } from "./pages.js";
|
|
2
|
+
import { renderPage } from "./render-page.js";
|
|
3
|
+
import { servePluginAsset } from "./link.js";
|
|
4
|
+
import { normalizePathname } from "./routing.js";
|
|
5
|
+
import { createContext } from "./stackbox/context.js";
|
|
6
|
+
export class SiteError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "SiteError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function validateConfigObject(config, label) {
|
|
13
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
14
|
+
throw new SiteError(`${label}: config must be a non-null object`);
|
|
15
|
+
}
|
|
16
|
+
if (Object.keys(config).length === 0) {
|
|
17
|
+
throw new SiteError(`${label}: config must not be empty`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function createSiteConfig(config) {
|
|
21
|
+
validateConfigObject(config, "createSiteConfig(config)");
|
|
22
|
+
return {
|
|
23
|
+
__kind: "siteConfig",
|
|
24
|
+
config,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function isSiteConfig(value) {
|
|
28
|
+
return (typeof value === "object" &&
|
|
29
|
+
value !== null &&
|
|
30
|
+
value.__kind === "siteConfig" &&
|
|
31
|
+
typeof value.config === "object" &&
|
|
32
|
+
value.config !== null &&
|
|
33
|
+
!Array.isArray(value.config));
|
|
34
|
+
}
|
|
35
|
+
function assertUniquePaths(pages) {
|
|
36
|
+
const seen = new Map();
|
|
37
|
+
for (const page of pages) {
|
|
38
|
+
const existing = seen.get(page.path);
|
|
39
|
+
if (existing) {
|
|
40
|
+
throw new SiteError(`duplicate page path "${page.path}" (${existing} and ${page.title})`);
|
|
41
|
+
}
|
|
42
|
+
seen.set(page.path, page.title);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function buildPageMap(pages) {
|
|
46
|
+
const map = new Map();
|
|
47
|
+
for (const page of pages) {
|
|
48
|
+
map.set(normalizePathname(page.path), page);
|
|
49
|
+
}
|
|
50
|
+
return map;
|
|
51
|
+
}
|
|
52
|
+
export function createSite(siteConfig, options) {
|
|
53
|
+
if (!isSiteConfig(siteConfig)) {
|
|
54
|
+
throw new SiteError("createSite(siteConfig, options): siteConfig must be from createSiteConfig()");
|
|
55
|
+
}
|
|
56
|
+
const { pages } = options;
|
|
57
|
+
if (!Array.isArray(pages) || pages.length === 0) {
|
|
58
|
+
throw new SiteError("createSite(siteConfig, options): pages must be a non-empty array");
|
|
59
|
+
}
|
|
60
|
+
for (const page of pages) {
|
|
61
|
+
if (!isPage(page)) {
|
|
62
|
+
throw new SiteError("createSite(siteConfig, options): every page must be from createPage()");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
assertUniquePaths(pages);
|
|
66
|
+
const pageMap = buildPageMap(pages);
|
|
67
|
+
return {
|
|
68
|
+
__kind: "site",
|
|
69
|
+
siteConfig,
|
|
70
|
+
pages,
|
|
71
|
+
async fetch(request, env = {}) {
|
|
72
|
+
const ctx = createContext(request, env);
|
|
73
|
+
const method = ctx.req.method;
|
|
74
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
75
|
+
return ctx.res.text("Method Not Allowed", { status: 405 });
|
|
76
|
+
}
|
|
77
|
+
const pathname = normalizePathname(ctx.req.url.pathname);
|
|
78
|
+
const pluginAsset = servePluginAsset(pathname, method);
|
|
79
|
+
if (pluginAsset) {
|
|
80
|
+
return pluginAsset;
|
|
81
|
+
}
|
|
82
|
+
const page = pageMap.get(pathname);
|
|
83
|
+
if (!page) {
|
|
84
|
+
return ctx.res.notFound();
|
|
85
|
+
}
|
|
86
|
+
const html = await renderPage(page, siteConfig, ctx);
|
|
87
|
+
if (method === "HEAD") {
|
|
88
|
+
return ctx.res.html("", { status: 200 });
|
|
89
|
+
}
|
|
90
|
+
return ctx.res.html(html);
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export function isSite(value) {
|
|
95
|
+
return (typeof value === "object" &&
|
|
96
|
+
value !== null &&
|
|
97
|
+
value.__kind === "site" &&
|
|
98
|
+
isSiteConfig(value.siteConfig) &&
|
|
99
|
+
Array.isArray(value.pages) &&
|
|
100
|
+
typeof value.fetch === "function");
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=site.js.map
|
package/dist/site.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AACA,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,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAqBtD,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,KAAoB,CAAC,MAAM,KAAK,YAAY;QAC7C,OAAQ,KAAoB,CAAC,MAAM,KAAK,QAAQ;QAC/C,KAAoB,CAAC,MAAM,KAAK,IAAI;QACrC,CAAC,KAAK,CAAC,OAAO,CAAE,KAAoB,CAAC,MAAM,CAAC,CAC7C,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAiB;IAC1C,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,KAA0B;IAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,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,MAAM,UAAU,UAAU,CACxB,UAAyB,EACzB,OAA6C;IAE7C,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,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAEzB,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAEpC,OAAO;QACL,MAAM,EAAE,MAAe;QACvB,UAAU;QACV,KAAK;QACL,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;YAE9B,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,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAEzD,MAAM,WAAW,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACvD,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,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC5B,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;YAErD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3C,CAAC;YAED,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAAc,CAAC,MAAM,KAAK,MAAM;QACjC,YAAY,CAAE,KAAc,CAAC,UAAU,CAAC;QACxC,KAAK,CAAC,OAAO,CAAE,KAAc,CAAC,KAAK,CAAC;QACpC,OAAQ,KAAc,CAAC,KAAK,KAAK,UAAU,CAC5C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import { type Block } from "./blocks.js";
|
|
3
|
+
import type { SlotDefinition, SlotNamesFrom } from "./templates.js";
|
|
4
|
+
export type DefaultSlotContent = Block | string;
|
|
5
|
+
/** Accepts any block or HTML string (default slot content). */
|
|
6
|
+
export declare const anySlotContentSchema: z.ZodType<DefaultSlotContent>;
|
|
7
|
+
/** Accepts only HTML strings. */
|
|
8
|
+
export declare const stringSlotContentSchema: z.ZodString;
|
|
9
|
+
/** Accepts only CMS blocks. */
|
|
10
|
+
export declare const blockSlotContentSchema: z.ZodType<Block>;
|
|
11
|
+
export type SlotContentFromDefinition<D extends SlotDefinition> = D extends {
|
|
12
|
+
options: {
|
|
13
|
+
schema: infer Schema extends z.ZodTypeAny;
|
|
14
|
+
};
|
|
15
|
+
} ? z.input<Schema> : DefaultSlotContent;
|
|
16
|
+
export type PageSlotsInput<S extends readonly SlotDefinition[], Required extends string> = {
|
|
17
|
+
[K in Required]: SlotContentFromDefinition<Extract<S[number], {
|
|
18
|
+
name: K;
|
|
19
|
+
}>>[];
|
|
20
|
+
} & Partial<{
|
|
21
|
+
[K in Exclude<SlotNamesFrom<S>, Required>]: SlotContentFromDefinition<Extract<S[number], {
|
|
22
|
+
name: K;
|
|
23
|
+
}>>[];
|
|
24
|
+
}>;
|
|
25
|
+
export declare function validateSlotContentItem(slotName: string, item: unknown, schema: z.ZodTypeAny | undefined): void;
|
|
26
|
+
export declare class SlotContentValidationError extends Error {
|
|
27
|
+
constructor(slotName: string, message: string);
|
|
28
|
+
}
|
|
29
|
+
export declare function slotHasContent(items: unknown[]): boolean;
|
|
30
|
+
//# 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;AAE7B,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAG7D,CAAC;AAEH,iCAAiC;AACjC,eAAO,MAAM,uBAAuB,aAAe,CAAC;AAEpD,+BAA+B;AAC/B,eAAO,MAAM,sBAAsB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAEnD,CAAC;AAEF,MAAM,MAAM,yBAAyB,CAAC,CAAC,SAAS,cAAc,IAC5D,CAAC,SAAS;IAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,MAAM,SAAS,CAAC,CAAC,UAAU,CAAA;KAAE,CAAA;CAAE,GAChE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GACf,kBAAkB,CAAC;AAEzB,MAAM,MAAM,cAAc,CACxB,CAAC,SAAS,SAAS,cAAc,EAAE,EACnC,QAAQ,SAAS,MAAM,IACrB;KACD,CAAC,IAAI,QAAQ,GAAG,yBAAyB,CACxC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAChC,EAAE;CACJ,GAAG,OAAO,CAAC;KACT,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,yBAAyB,CACnE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAChC,EAAE;CACJ,CAAC,CAAC;AAEH,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,EAAc,MAAM,aAAa,CAAC;AAKlD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAkC,GAAG,CAAC,KAAK,CAAC;IAC3E,GAAG,CAAC,MAAM,EAAE;IACZ,GAAG,CAAC,MAAM,CAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;CAC7C,CAAC,CAAC;AAEH,iCAAiC;AACjC,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAqB,GAAG,CAAC,MAAM,CAChE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAC1B,CAAC;AAoBF,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,32 @@
|
|
|
1
|
+
import { html, type HSHtml } from "@hyperspan/html";
|
|
2
|
+
import type { z } from "zod";
|
|
3
|
+
import type { SitePage, RenderContext } from "./pages.js";
|
|
4
|
+
import { type DefaultSlotContent, type SlotContentFromDefinition } from "./slot-content.js";
|
|
5
|
+
import type { SlotDefinition, SlotNamesFrom } from "./templates.js";
|
|
6
|
+
export declare class RenderError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
export declare const SLOT_SENTINEL_PREFIX = "<!--__STACKBOX_SLOT__:";
|
|
10
|
+
export declare function slotSentinel(name: string): string;
|
|
11
|
+
type HtmlSafe = ReturnType<typeof html.raw>;
|
|
12
|
+
export type { HSHtml } from "@hyperspan/html";
|
|
13
|
+
export type SlotRenderValue = HSHtml | HtmlSafe | Promise<HSHtml>;
|
|
14
|
+
export type Slot<TContent = DefaultSlotContent, D extends SlotDefinition = SlotDefinition> = {
|
|
15
|
+
readonly name: D["name"];
|
|
16
|
+
readonly definition: D;
|
|
17
|
+
readonly content: readonly TContent[];
|
|
18
|
+
render(): SlotRenderValue;
|
|
19
|
+
};
|
|
20
|
+
export type TemplateSlotsFrom<S extends readonly SlotDefinition[]> = {
|
|
21
|
+
[K in SlotNamesFrom<S>]: Slot<SlotContentFromDefinition<Extract<S[number], {
|
|
22
|
+
name: K;
|
|
23
|
+
}>>, Extract<S[number], {
|
|
24
|
+
name: K;
|
|
25
|
+
}>>;
|
|
26
|
+
};
|
|
27
|
+
export declare function renderSlotContent(slotName: string, items: readonly unknown[], ctx: RenderContext, schema: z.ZodTypeAny | undefined): Promise<HSHtml>;
|
|
28
|
+
export declare function createStubSlot<D extends SlotDefinition>(definition: D): Slot<DefaultSlotContent, D>;
|
|
29
|
+
export declare function createPageSlot<D extends SlotDefinition>(definition: D, content: readonly SlotContentFromDefinition<D>[], ctx: RenderContext): Slot<SlotContentFromDefinition<D>, D>;
|
|
30
|
+
export declare function buildStubSlots<S extends readonly SlotDefinition[]>(definitions: S): TemplateSlotsFrom<S>;
|
|
31
|
+
export declare function buildPageSlots(page: SitePage, ctx: RenderContext): Record<string, Slot>;
|
|
32
|
+
//# 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,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAE/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,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;AAED,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5C,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAElE,MAAM,MAAM,IAAI,CACd,QAAQ,GAAG,kBAAkB,EAC7B,CAAC,SAAS,cAAc,GAAG,cAAc,IACvC;IACF,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IACtC,MAAM,IAAI,eAAe,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,SAAS,cAAc,EAAE,IAAI;KAClE,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAC3B,yBAAyB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC,EAC1D,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAChC;CACF,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,CAAC,CAAC,UAAU,GAAG,SAAS,GAC/B,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAED,wBAAgB,cAAc,CAC5B,CAAC,SAAS,cAAc,EACxB,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAS5C;AAED,wBAAgB,cAAc,CAC5B,CAAC,SAAS,cAAc,EAExB,UAAU,EAAE,CAAC,EACb,OAAO,EAAE,SAAS,yBAAyB,CAAC,CAAC,CAAC,EAAE,EAChD,GAAG,EAAE,aAAa,GACjB,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAUvC;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,SAAS,cAAc,EAAE,EAChE,WAAW,EAAE,CAAC,GACb,iBAAiB,CAAC,CAAC,CAAC,CAQtB;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,aAAa,GACjB,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAUtB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { html } from "@hyperspan/html";
|
|
2
|
+
import { isBlock } from "./blocks.js";
|
|
3
|
+
import { validateSlotContentItem, } from "./slot-content.js";
|
|
4
|
+
export class RenderError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "RenderError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export const SLOT_SENTINEL_PREFIX = "<!--__STACKBOX_SLOT__:";
|
|
11
|
+
export function slotSentinel(name) {
|
|
12
|
+
return `${SLOT_SENTINEL_PREFIX}${name}-->`;
|
|
13
|
+
}
|
|
14
|
+
export function renderSlotContent(slotName, items, ctx, schema) {
|
|
15
|
+
return Promise.all(items.map(async (item) => {
|
|
16
|
+
try {
|
|
17
|
+
validateSlotContentItem(slotName, item, schema);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new RenderError(err instanceof Error ? err.message : String(err));
|
|
21
|
+
}
|
|
22
|
+
if (typeof item === "string") {
|
|
23
|
+
return html.raw(item);
|
|
24
|
+
}
|
|
25
|
+
if (isBlock(item)) {
|
|
26
|
+
return item.render(ctx);
|
|
27
|
+
}
|
|
28
|
+
throw new RenderError("invalid slot content; expected block or HTML string");
|
|
29
|
+
})).then((chunks) => html `${chunks}`);
|
|
30
|
+
}
|
|
31
|
+
export function createStubSlot(definition) {
|
|
32
|
+
return {
|
|
33
|
+
name: definition.name,
|
|
34
|
+
definition,
|
|
35
|
+
content: [],
|
|
36
|
+
render() {
|
|
37
|
+
return html.raw(slotSentinel(definition.name));
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function createPageSlot(definition, content, ctx) {
|
|
42
|
+
const schema = definition.options?.schema;
|
|
43
|
+
return {
|
|
44
|
+
name: definition.name,
|
|
45
|
+
definition,
|
|
46
|
+
content,
|
|
47
|
+
render() {
|
|
48
|
+
return renderSlotContent(definition.name, content, ctx, schema);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function buildStubSlots(definitions) {
|
|
53
|
+
const slots = {};
|
|
54
|
+
for (const def of definitions) {
|
|
55
|
+
slots[def.name] = createStubSlot(def);
|
|
56
|
+
}
|
|
57
|
+
return slots;
|
|
58
|
+
}
|
|
59
|
+
export function buildPageSlots(page, ctx) {
|
|
60
|
+
const slots = {};
|
|
61
|
+
const definitions = page.template.__definitions ?? [];
|
|
62
|
+
for (const def of definitions) {
|
|
63
|
+
const content = page.slots[def.name] ?? [];
|
|
64
|
+
slots[def.name] = createPageSlot(def, content, ctx);
|
|
65
|
+
}
|
|
66
|
+
return slots;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=slot-handle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-handle.js","sourceRoot":"","sources":["../src/slot-handle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare namespace Stackbox {
|
|
2
|
+
type CookieOptions = {
|
|
3
|
+
maxAge?: number;
|
|
4
|
+
domain?: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
expires?: Date;
|
|
7
|
+
httpOnly?: boolean;
|
|
8
|
+
secure?: boolean;
|
|
9
|
+
sameSite?: "lax" | "strict" | true;
|
|
10
|
+
};
|
|
11
|
+
type Cookies = {
|
|
12
|
+
_req: globalThis.Request;
|
|
13
|
+
_responseHeaders: Headers | undefined;
|
|
14
|
+
_parsedCookies: Record<string, string>;
|
|
15
|
+
_encrypt: ((str: string) => string) | undefined;
|
|
16
|
+
_decrypt: ((str: string) => string) | undefined;
|
|
17
|
+
get: (name: string) => string | undefined;
|
|
18
|
+
set: (name: string, value: string, options?: CookieOptions) => void;
|
|
19
|
+
delete: (name: string) => void;
|
|
20
|
+
};
|
|
21
|
+
type Request = {
|
|
22
|
+
url: URL;
|
|
23
|
+
raw: globalThis.Request;
|
|
24
|
+
method: string;
|
|
25
|
+
headers: Headers;
|
|
26
|
+
query: URLSearchParams;
|
|
27
|
+
cookies: Cookies;
|
|
28
|
+
text: () => Promise<string>;
|
|
29
|
+
json: <T = unknown>() => Promise<T>;
|
|
30
|
+
formData: () => Promise<FormData>;
|
|
31
|
+
urlencoded: () => Promise<URLSearchParams>;
|
|
32
|
+
};
|
|
33
|
+
type Response = {
|
|
34
|
+
cookies: Cookies;
|
|
35
|
+
headers: Headers;
|
|
36
|
+
status: number | undefined;
|
|
37
|
+
html: (html: string, options?: ResponseInit) => Promise<globalThis.Response>;
|
|
38
|
+
json: (json: unknown, options?: ResponseInit) => Promise<globalThis.Response>;
|
|
39
|
+
text: (text: string, options?: ResponseInit) => Promise<globalThis.Response>;
|
|
40
|
+
redirect: (url: string, options?: ResponseInit) => Promise<globalThis.Response>;
|
|
41
|
+
error: (error: Error, options?: ResponseInit) => Promise<globalThis.Response>;
|
|
42
|
+
notFound: (options?: ResponseInit) => Promise<globalThis.Response>;
|
|
43
|
+
merge: (response: globalThis.Response) => Promise<globalThis.Response>;
|
|
44
|
+
};
|
|
45
|
+
interface Context<TEnv extends Record<string, unknown> = Record<string, unknown>> {
|
|
46
|
+
env: TEnv;
|
|
47
|
+
req: Request;
|
|
48
|
+
res: Response;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export declare function createContext<TEnv extends Record<string, unknown> = Record<string, unknown>>(raw: globalThis.Request, env?: TEnv): Stackbox.Context<TEnv>;
|
|
52
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/stackbox/context.ts"],"names":[],"mappings":"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"}
|