@stackbox/cms 0.0.3 → 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.
Files changed (117) hide show
  1. package/AGENTS.md +87 -0
  2. package/README.md +57 -17
  3. package/dist/blocks.d.ts +18 -0
  4. package/dist/blocks.d.ts.map +1 -0
  5. package/dist/blocks.js +25 -0
  6. package/dist/blocks.js.map +1 -0
  7. package/dist/index.d.ts +12 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +12 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/link.d.ts +10 -0
  12. package/dist/link.d.ts.map +1 -0
  13. package/dist/link.js +128 -0
  14. package/dist/link.js.map +1 -0
  15. package/dist/modules/blog/module.d.ts +20 -0
  16. package/dist/modules/blog/module.d.ts.map +1 -0
  17. package/dist/modules/blog/module.js +52 -0
  18. package/dist/modules/blog/module.js.map +1 -0
  19. package/dist/modules/blog/posts.d.ts +15 -0
  20. package/dist/modules/blog/posts.d.ts.map +1 -0
  21. package/dist/modules/blog/posts.js +46 -0
  22. package/dist/modules/blog/posts.js.map +1 -0
  23. package/dist/modules.d.ts +18 -0
  24. package/dist/modules.d.ts.map +1 -0
  25. package/dist/modules.js +25 -0
  26. package/dist/modules.js.map +1 -0
  27. package/dist/pages.d.ts +55 -0
  28. package/dist/pages.d.ts.map +1 -0
  29. package/dist/pages.js +85 -0
  30. package/dist/pages.js.map +1 -0
  31. package/dist/plugins/blog/index.d.ts +20 -0
  32. package/dist/plugins/blog/index.d.ts.map +1 -0
  33. package/dist/plugins/blog/index.js +52 -0
  34. package/dist/plugins/blog/index.js.map +1 -0
  35. package/dist/plugins/blog/module.d.ts +20 -0
  36. package/dist/plugins/blog/module.d.ts.map +1 -0
  37. package/dist/plugins/blog/module.js +52 -0
  38. package/dist/plugins/blog/module.js.map +1 -0
  39. package/dist/plugins/blog/plugin.d.ts +20 -0
  40. package/dist/plugins/blog/plugin.d.ts.map +1 -0
  41. package/dist/plugins/blog/plugin.js +52 -0
  42. package/dist/plugins/blog/plugin.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/index.d.ts +12 -0
  48. package/dist/plugins/random-quote/index.d.ts.map +1 -0
  49. package/dist/plugins/random-quote/index.js +21 -0
  50. package/dist/plugins/random-quote/index.js.map +1 -0
  51. package/dist/plugins/random-quote/module.d.ts +9 -0
  52. package/dist/plugins/random-quote/module.d.ts.map +1 -0
  53. package/dist/plugins/random-quote/module.js +31 -0
  54. package/dist/plugins/random-quote/module.js.map +1 -0
  55. package/dist/plugins/random-quote/plugin.d.ts +8 -0
  56. package/dist/plugins/random-quote/plugin.d.ts.map +1 -0
  57. package/dist/plugins/random-quote/plugin.js +31 -0
  58. package/dist/plugins/random-quote/plugin.js.map +1 -0
  59. package/dist/plugins/random-quote/public_assets/quotes.json +230 -0
  60. package/dist/plugins/random-quote/quotes.json +230 -0
  61. package/dist/public/_sb/plugins/random-quote/quotes.json +230 -0
  62. package/dist/render-head.d.ts +7 -0
  63. package/dist/render-head.d.ts.map +1 -0
  64. package/dist/render-head.js +27 -0
  65. package/dist/render-head.js.map +1 -0
  66. package/dist/render-page.d.ts +6 -0
  67. package/dist/render-page.d.ts.map +1 -0
  68. package/dist/render-page.js +30 -0
  69. package/dist/render-page.js.map +1 -0
  70. package/dist/routing.d.ts +3 -0
  71. package/dist/routing.d.ts.map +1 -0
  72. package/dist/routing.js +11 -0
  73. package/dist/routing.js.map +1 -0
  74. package/dist/site.d.ts +21 -0
  75. package/dist/site.d.ts.map +1 -0
  76. package/dist/site.js +102 -0
  77. package/dist/site.js.map +1 -0
  78. package/dist/slot-content.d.ts +30 -0
  79. package/dist/slot-content.d.ts.map +1 -0
  80. package/dist/slot-content.js +34 -0
  81. package/dist/slot-content.js.map +1 -0
  82. package/dist/slot-handle.d.ts +32 -0
  83. package/dist/slot-handle.d.ts.map +1 -0
  84. package/dist/slot-handle.js +68 -0
  85. package/dist/slot-handle.js.map +1 -0
  86. package/dist/stackbox/context.d.ts +52 -0
  87. package/dist/stackbox/context.d.ts.map +1 -0
  88. package/dist/stackbox/context.js +165 -0
  89. package/dist/stackbox/context.js.map +1 -0
  90. package/dist/templates.d.ts +63 -0
  91. package/dist/templates.d.ts.map +1 -0
  92. package/dist/templates.js +106 -0
  93. package/dist/templates.js.map +1 -0
  94. package/package.json +19 -6
  95. package/src/plugins/blog/AGENTS.md +131 -0
  96. package/src/plugins/random-quote/AGENTS.md +79 -0
  97. package/src/plugins/random-quote/index.ts +33 -0
  98. package/src/plugins/random-quote/public_assets/quotes.json +230 -0
  99. package/.claude/settings.local.json +0 -8
  100. package/src/index.ts +0 -67
  101. package/src/modules.ts +0 -58
  102. package/src/pages.ts +0 -198
  103. package/src/render-head.ts +0 -32
  104. package/src/render-page.ts +0 -51
  105. package/src/routing.ts +0 -14
  106. package/src/site.ts +0 -153
  107. package/src/slot-content.ts +0 -77
  108. package/src/slot-handle.ts +0 -131
  109. package/src/stackbox/context.ts +0 -257
  110. package/src/templates.ts +0 -230
  111. package/test/async-render.test.ts +0 -103
  112. package/test/blog.test.ts +0 -93
  113. package/test/fetch-routing.test.ts +0 -76
  114. package/test/stackbox-context.test.ts +0 -44
  115. package/tsconfig.json +0 -19
  116. /package/src/{modules/blog/module.ts → plugins/blog/index.ts} +0 -0
  117. /package/src/{modules → plugins}/blog/posts.ts +0 -0
@@ -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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"}
@@ -0,0 +1,165 @@
1
+ function parseCookieHeader(header) {
2
+ const cookies = {};
3
+ for (const part of header.split(";")) {
4
+ const trimmed = part.trim();
5
+ if (!trimmed)
6
+ continue;
7
+ const eq = trimmed.indexOf("=");
8
+ if (eq === -1)
9
+ continue;
10
+ const name = trimmed.slice(0, eq).trim();
11
+ const value = trimmed.slice(eq + 1).trim();
12
+ if (name)
13
+ cookies[name] = decodeURIComponent(value);
14
+ }
15
+ return cookies;
16
+ }
17
+ function serializeCookie(name, value, options) {
18
+ let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
19
+ if (options?.maxAge !== undefined)
20
+ cookie += `; Max-Age=${options.maxAge}`;
21
+ if (options?.domain)
22
+ cookie += `; Domain=${options.domain}`;
23
+ if (options?.path)
24
+ cookie += `; Path=${options.path}`;
25
+ else
26
+ cookie += "; Path=/";
27
+ if (options?.expires)
28
+ cookie += `; Expires=${options.expires.toUTCString()}`;
29
+ if (options?.httpOnly)
30
+ cookie += "; HttpOnly";
31
+ if (options?.secure)
32
+ cookie += "; Secure";
33
+ if (options?.sameSite === true)
34
+ cookie += "; SameSite=Strict";
35
+ else if (options?.sameSite) {
36
+ const s = options.sameSite === "strict" ? "Strict" : "Lax";
37
+ cookie += `; SameSite=${s}`;
38
+ }
39
+ return cookie;
40
+ }
41
+ function createCookies(req, responseHeaders, parsed) {
42
+ return {
43
+ _req: req,
44
+ _responseHeaders: responseHeaders,
45
+ _parsedCookies: parsed,
46
+ _encrypt: undefined,
47
+ _decrypt: undefined,
48
+ get(name) {
49
+ return parsed[name];
50
+ },
51
+ set(name, value, options) {
52
+ if (!responseHeaders)
53
+ return;
54
+ parsed[name] = value;
55
+ responseHeaders.append("Set-Cookie", serializeCookie(name, value, options));
56
+ },
57
+ delete(name) {
58
+ if (!responseHeaders)
59
+ return;
60
+ delete parsed[name];
61
+ responseHeaders.append("Set-Cookie", serializeCookie(name, "", { maxAge: 0, path: "/" }));
62
+ },
63
+ };
64
+ }
65
+ function buildResponse(res, body, init = {}) {
66
+ const headers = new Headers(init.headers);
67
+ res.headers.forEach((value, key) => {
68
+ if (!headers.has(key))
69
+ headers.set(key, value);
70
+ });
71
+ for (const value of res.headers.getSetCookie?.() ?? []) {
72
+ headers.append("Set-Cookie", value);
73
+ }
74
+ if (body !== null && !headers.has("Content-Type") && typeof body === "string") {
75
+ headers.set("Content-Type", "text/plain; charset=utf-8");
76
+ }
77
+ const status = init.status ?? res.status ?? 200;
78
+ return new globalThis.Response(body, { ...init, status, headers });
79
+ }
80
+ function createStackboxResponse(reqCookies) {
81
+ const headers = new Headers();
82
+ const resCookies = createCookies(reqCookies._req, headers, { ...reqCookies._parsedCookies });
83
+ const res = {
84
+ cookies: resCookies,
85
+ headers,
86
+ status: undefined,
87
+ async html(html, options = {}) {
88
+ res.status = options.status ?? 200;
89
+ const outHeaders = new Headers(options.headers);
90
+ if (!outHeaders.has("Content-Type")) {
91
+ outHeaders.set("Content-Type", "text/html; charset=utf-8");
92
+ }
93
+ return buildResponse(res, html, { ...options, headers: outHeaders });
94
+ },
95
+ async json(json, options = {}) {
96
+ res.status = options.status ?? 200;
97
+ const outHeaders = new Headers(options.headers);
98
+ if (!outHeaders.has("Content-Type")) {
99
+ outHeaders.set("Content-Type", "application/json; charset=utf-8");
100
+ }
101
+ return buildResponse(res, JSON.stringify(json), {
102
+ ...options,
103
+ headers: outHeaders,
104
+ });
105
+ },
106
+ async text(text, options = {}) {
107
+ res.status = options.status ?? 200;
108
+ return buildResponse(res, text, options);
109
+ },
110
+ async redirect(url, options = {}) {
111
+ const outHeaders = new Headers(options.headers);
112
+ outHeaders.set("Location", url);
113
+ res.status = options.status ?? 302;
114
+ return buildResponse(res, null, { ...options, headers: outHeaders });
115
+ },
116
+ async error(error, options = {}) {
117
+ res.status = options.status ?? 500;
118
+ return buildResponse(res, error.message, options);
119
+ },
120
+ async notFound(options = {}) {
121
+ res.status = options.status ?? 400 + 4;
122
+ return buildResponse(res, "Not Found", { ...options, status: res.status });
123
+ },
124
+ async merge(response) {
125
+ const merged = new Headers(response.headers);
126
+ res.headers.forEach((value, key) => {
127
+ if (!merged.has(key))
128
+ merged.set(key, value);
129
+ });
130
+ for (const value of res.headers.getSetCookie?.() ?? []) {
131
+ merged.append("Set-Cookie", value);
132
+ }
133
+ return new globalThis.Response(response.body, {
134
+ status: response.status,
135
+ statusText: response.statusText,
136
+ headers: merged,
137
+ });
138
+ },
139
+ };
140
+ return res;
141
+ }
142
+ export function createContext(raw, env = {}) {
143
+ const url = new URL(raw.url);
144
+ const parsed = parseCookieHeader(raw.headers.get("Cookie") ?? "");
145
+ const reqHeaders = new Headers(raw.headers);
146
+ const reqCookies = createCookies(raw, undefined, parsed);
147
+ const req = {
148
+ url,
149
+ raw,
150
+ method: raw.method.toUpperCase(),
151
+ headers: reqHeaders,
152
+ query: url.searchParams,
153
+ cookies: reqCookies,
154
+ text: () => raw.text(),
155
+ json: () => raw.json(),
156
+ formData: () => raw.formData(),
157
+ urlencoded: async () => {
158
+ const text = await raw.text();
159
+ return new URLSearchParams(text);
160
+ },
161
+ };
162
+ const res = createStackboxResponse(reqCookies);
163
+ return { env, req, res };
164
+ }
165
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/stackbox/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { type HSHtml } from "@hyperspan/html";
2
+ import type { z } from "zod";
3
+ import { type SiteConfig } from "./site.js";
4
+ import type { PageRenderView } from "./pages.js";
5
+ import { type TemplateSlotsFrom } from "./slot-handle.js";
6
+ export type SlotOptions = {
7
+ required?: boolean;
8
+ primary?: true;
9
+ schema?: z.ZodTypeAny;
10
+ };
11
+ export type SlotDefinition = {
12
+ name: string;
13
+ options?: SlotOptions;
14
+ };
15
+ export type SlotMeta = {
16
+ isDefault: boolean;
17
+ required: boolean;
18
+ schema?: z.ZodTypeAny;
19
+ };
20
+ export type TemplateRenderContext<S extends readonly SlotDefinition[] = readonly SlotDefinition[]> = {
21
+ head?: HSHtml;
22
+ siteConfig: SiteConfig;
23
+ page: PageRenderView;
24
+ slots: TemplateSlotsFrom<S>;
25
+ };
26
+ /** Widened render signature stored on descriptors at runtime. */
27
+ export type TemplateRenderFn = (ctx: {
28
+ head?: HSHtml;
29
+ siteConfig: SiteConfig;
30
+ page: PageRenderView;
31
+ slots: Record<string, import("./slot-handle.js").Slot>;
32
+ }) => HSHtml;
33
+ export type TemplateDescriptor<Slots extends string = string, RequiredSlots extends Slots = never, Definitions extends readonly SlotDefinition[] = readonly SlotDefinition[]> = {
34
+ readonly __kind: "template";
35
+ siteConfig: SiteConfig;
36
+ formatPageTitle: (title: string) => string;
37
+ render: TemplateRenderFn;
38
+ slots: Record<Slots, SlotMeta>;
39
+ requiredSlots: readonly RequiredSlots[];
40
+ readonly __definitions?: Definitions;
41
+ };
42
+ export type SlotNamesFrom<S extends readonly SlotDefinition[]> = S[number]["name"];
43
+ export type RequiredSlotNamesFrom<S extends readonly SlotDefinition[]> = Extract<S[number], {
44
+ options: {
45
+ required: true;
46
+ };
47
+ } | {
48
+ options: {
49
+ primary: true;
50
+ };
51
+ }>["name"];
52
+ export declare function isTemplate(value: unknown): value is TemplateDescriptor;
53
+ export declare class TemplateBuildError extends Error {
54
+ constructor(message: string);
55
+ }
56
+ export declare function createTemplate<const S extends readonly SlotDefinition[]>(def: {
57
+ siteConfig: SiteConfig;
58
+ slots: S;
59
+ title?: (pageTitle: string, siteConfig: SiteConfig) => string;
60
+ render: (ctx: TemplateRenderContext<S>) => HSHtml;
61
+ }): TemplateDescriptor<SlotNamesFrom<S>, RequiredSlotNamesFrom<S>, S>;
62
+ export type { Slot, TemplateSlotsFrom } from "./slot-handle.js";
63
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,MAAM,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAC/B,CAAC,SAAS,SAAS,cAAc,EAAE,GAAG,SAAS,cAAc,EAAE,IAC7D;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;CAC7B,CAAC;AAEF,iEAAiE;AACjE,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,kBAAkB,EAAE,IAAI,CAAC,CAAC;CACxD,KAAK,MAAM,CAAC;AAEb,MAAM,MAAM,kBAAkB,CAC5B,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,aAAa,SAAS,KAAK,GAAG,KAAK,EACnC,WAAW,SAAS,SAAS,cAAc,EAAE,GAAG,SAAS,cAAc,EAAE,IACvE;IACF,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC/B,aAAa,EAAE,SAAS,aAAa,EAAE,CAAC;IACxC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,SAAS,cAAc,EAAE,IAC3D,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpB,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,SAAS,cAAc,EAAE,IACnE,OAAO,CACL,CAAC,CAAC,MAAM,CAAC,EACT;IAAE,OAAO,EAAE;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,CACjE,CAAC,MAAM,CAAC,CAAC;AAEZ,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAYtE;AAiBD,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAgED,wBAAgB,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,SAAS,cAAc,EAAE,EACtE,GAAG,EAAE;IACH,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC;IAC9D,MAAM,EAAE,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC;CACnD,GACA,kBAAkB,CACnB,aAAa,CAAC,CAAC,CAAC,EAChB,qBAAqB,CAAC,CAAC,CAAC,EACxB,CAAC,CACF,CAmDA;AAED,YAAY,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,106 @@
1
+ import { render } from "@hyperspan/html";
2
+ import { isSiteConfig } from "./site.js";
3
+ import { buildStubSlots, slotSentinel, } from "./slot-handle.js";
4
+ export function isTemplate(value) {
5
+ return (typeof value === "object" &&
6
+ value !== null &&
7
+ value.__kind === "template" &&
8
+ isSiteConfig(value.siteConfig) &&
9
+ typeof value.formatPageTitle === "function" &&
10
+ typeof value.render === "function" &&
11
+ typeof value.slots === "object" &&
12
+ value.slots !== null &&
13
+ Array.isArray(value.requiredSlots));
14
+ }
15
+ function defaultFormatPageTitle(pageTitle, siteConfig) {
16
+ const suffix = siteConfig.config.titleSuffix;
17
+ return typeof suffix === "string" ? pageTitle + suffix : pageTitle;
18
+ }
19
+ export class TemplateBuildError extends Error {
20
+ constructor(message) {
21
+ super(message);
22
+ this.name = "TemplateBuildError";
23
+ }
24
+ }
25
+ function validateSlotDefinitions(definitions) {
26
+ if (definitions.length === 0) {
27
+ throw new TemplateBuildError("template must define at least one slot");
28
+ }
29
+ const entries = [];
30
+ const seen = new Set();
31
+ let primaryCount = 0;
32
+ for (const def of definitions) {
33
+ if (!def.name || def.name.length === 0) {
34
+ throw new TemplateBuildError("slot name must be non-empty");
35
+ }
36
+ if (seen.has(def.name)) {
37
+ throw new TemplateBuildError(`duplicate slot name "${def.name}"`);
38
+ }
39
+ seen.add(def.name);
40
+ const opts = def.options ?? {};
41
+ const isDefault = opts.primary === true;
42
+ if (isDefault) {
43
+ primaryCount++;
44
+ }
45
+ entries.push({
46
+ name: def.name,
47
+ isDefault,
48
+ required: opts.required === true || opts.primary === true,
49
+ schema: opts.schema,
50
+ });
51
+ }
52
+ if (primaryCount !== 1) {
53
+ throw new TemplateBuildError(`exactly one slot must have options.primary: true; found ${primaryCount}`);
54
+ }
55
+ return entries;
56
+ }
57
+ function validateRenderOutput(html, slotNames) {
58
+ for (const name of slotNames) {
59
+ if (!html.includes(slotSentinel(name))) {
60
+ throw new TemplateBuildError(`slot "${name}" must be rendered via slots.${name}.render()`);
61
+ }
62
+ }
63
+ }
64
+ const stubPage = {
65
+ __kind: "page",
66
+ path: "/",
67
+ title: "Template validation",
68
+ };
69
+ export function createTemplate(def) {
70
+ if (!isSiteConfig(def.siteConfig)) {
71
+ throw new TemplateBuildError("createTemplate({ siteConfig }): siteConfig must be from createSiteConfig()");
72
+ }
73
+ const formatPageTitle = def.title
74
+ ? (pageTitle) => def.title(pageTitle, def.siteConfig)
75
+ : (pageTitle) => defaultFormatPageTitle(pageTitle, def.siteConfig);
76
+ const entries = validateSlotDefinitions(def.slots);
77
+ const stubSlots = buildStubSlots(def.slots);
78
+ const validationHtml = render(def.render({
79
+ siteConfig: def.siteConfig,
80
+ page: stubPage,
81
+ slots: stubSlots,
82
+ }));
83
+ validateRenderOutput(validationHtml, entries.map((entry) => entry.name));
84
+ const slots = {};
85
+ const requiredSlots = [];
86
+ for (const entry of entries) {
87
+ slots[entry.name] = {
88
+ isDefault: entry.isDefault,
89
+ required: entry.required,
90
+ schema: entry.schema,
91
+ };
92
+ if (entry.required) {
93
+ requiredSlots.push(entry.name);
94
+ }
95
+ }
96
+ return {
97
+ __kind: "template",
98
+ siteConfig: def.siteConfig,
99
+ formatPageTitle,
100
+ render: def.render,
101
+ slots,
102
+ requiredSlots,
103
+ __definitions: def.slots,
104
+ };
105
+ }
106
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackbox/cms",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Stackbox CMS engine",
5
5
  "type": "module",
6
6
  "license": "BSD-3-Clause",
@@ -12,21 +12,34 @@
12
12
  "type": "git",
13
13
  "url": "git+https://github.com/stackboxcms/cms.git"
14
14
  },
15
+ "files": [
16
+ "dist",
17
+ "AGENTS.md",
18
+ "src/plugins"
19
+ ],
15
20
  "exports": {
16
21
  ".": {
17
22
  "types": "./dist/index.d.ts",
18
23
  "import": "./dist/index.js"
19
24
  },
20
- "./modules/blog": {
21
- "types": "./dist/modules/blog/module.d.ts",
22
- "import": "./dist/modules/blog/module.js"
25
+ "./plugins/blog": {
26
+ "types": "./dist/plugins/blog/index.d.ts",
27
+ "import": "./dist/plugins/blog/index.js"
28
+ },
29
+ "./plugins/random-quote": {
30
+ "types": "./dist/plugins/random-quote/index.d.ts",
31
+ "import": "./dist/plugins/random-quote/index.js"
32
+ },
33
+ "./link": {
34
+ "types": "./dist/link.d.ts",
35
+ "import": "./dist/link.js"
23
36
  }
24
37
  },
25
38
  "scripts": {
26
- "build": "tsc -p tsconfig.json",
39
+ "build": "tsc -p tsconfig.json && node scripts/copy-plugin-assets.mjs",
27
40
  "test": "npm run build && node --import tsx --test test/*.test.ts",
28
41
  "typecheck": "tsc --noEmit -p tsconfig.json",
29
- "prepublishOnly": "npm run build"
42
+ "prepack": "npm run build"
30
43
  },
31
44
  "dependencies": {
32
45
  "@hyperspan/html": "^1.0.3",