@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,230 @@
1
+ [
2
+ {
3
+ "text": "You can beat 40 scholars with one fact, but you can't beat one idiot with 40 facts.",
4
+ "author": "Rumi"
5
+ },
6
+ {
7
+ "text": "You will observe with concern how long a useful truth may be known and exist before it is generally recieved and practices on",
8
+ "author": "Benjamin Franklin"
9
+ },
10
+ {
11
+ "text": "Life can only be understood backwards; but it must be lived forwards.",
12
+ "author": "Søren Kierkegaard"
13
+ },
14
+ {
15
+ "text": "We are what we repeatedly do. Excellence, then, is not an act, but a habit.",
16
+ "author": "Will Durant"
17
+ },
18
+ {
19
+ "text": "Time has a wonderful way of showing us what really matters.",
20
+ "author": "Margaret Peters"
21
+ },
22
+ {
23
+ "text": "When a person can't find a deep sense of meaning, they distract themselves with pleasure.",
24
+ "author": "Viktor Frankl"
25
+ },
26
+ {
27
+ "text": "To attain knowledge, add things everyday. To attain wisdom, remove things every day.",
28
+ "author": "Lao Tzu"
29
+ },
30
+ {
31
+ "text": "At the end of the day, we can endure much more than we think we can.",
32
+ "author": "Frida Kahlo"
33
+ },
34
+ {
35
+ "text": "People rarely succeed unless they have fun in what they are doing.",
36
+ "author": "Dale Carnegie"
37
+ },
38
+ {
39
+ "text": "If you don't design your own life plan, chances are you'll fall into someone else's plan.",
40
+ "author": "Jim Rohn"
41
+ },
42
+ {
43
+ "text": "Not everything that is faced can be changed, but nothing can be changed until it is faced.",
44
+ "author": "James Baldwin"
45
+ },
46
+ {
47
+ "text": "The surface of the Earth is the shore of the cosmic ocean.",
48
+ "author": "Carl Sagan"
49
+ },
50
+ {
51
+ "text": "I do not feel obliged to believe that that same God who has endowed us with senses, reason, and intellect has intended to forgo their use",
52
+ "author": "Galileo Galilei"
53
+ },
54
+ {
55
+ "text": "In science the authority embodied in the opinion of thousands is not worth a spark of reason in one man.",
56
+ "author": "Galileo Galilei"
57
+ },
58
+ {
59
+ "text": "Mathematics is the language in which God wrote the universe.",
60
+ "author": "Galileo Galilei"
61
+ },
62
+ {
63
+ "text": "Ignorance is preferable to error; and he is less remote from the truth who believes nothing, than he who believes what is wrong.",
64
+ "author": "Thomas Jefferson"
65
+ },
66
+ {
67
+ "text": "The essence of Government is power; and power, lodged as it must be in human hands, will ever be liable to abuse.",
68
+ "author": "James Madison"
69
+ },
70
+ {
71
+ "text": "A workman who wants to do his work well must first prepare his tools.",
72
+ "author": "Confucius"
73
+ },
74
+ {
75
+ "text": "It is only the very wisest and the very stupidest who cannot change.",
76
+ "author": "Confucius"
77
+ },
78
+ {
79
+ "text": "Our wretched species is so made that those who walk on the well-trodden path always throw stones at those who are showing a new road.",
80
+ "author": "Voltaire"
81
+ },
82
+ {
83
+ "text": "I have always thought the actions of men the best interpreters of their thoughts.",
84
+ "author": "John Locke"
85
+ },
86
+ {
87
+ "text": "There are two tragedies in life. One is not to get your heart's desire. The other is to get it.",
88
+ "author": "George Bernard Shaw"
89
+ },
90
+ {
91
+ "text": "Marriage is the only adventure open to the cowardly.",
92
+ "author": "Voltaire"
93
+ },
94
+ {
95
+ "text": "Even the rich are hungry for love, for being cared for, for being wanted, for having someone to call their own.",
96
+ "author": "Mother Teresa"
97
+ },
98
+ {
99
+ "text": "Loneliness and the feeling of being unwanted is the most terrible poverty.",
100
+ "author": "Mother Teresa"
101
+ },
102
+ {
103
+ "text": "To know what life is worth you have to risk it once in a while.",
104
+ "author": "Jean-Paul Sartre"
105
+ },
106
+ {
107
+ "text": "Conformity is the jailer of freedom and the enemy of growth.",
108
+ "author": "John F. Kennedy"
109
+ },
110
+ {
111
+ "text": "Man is not born to solve the problem of the universe, but to find out what he has to do; and to restrain himself within the limits of his comprehension.",
112
+ "author": "Goethe"
113
+ },
114
+ {
115
+ "text": "Love does not dominate, it cultivates. And that is more.",
116
+ "author": "Goethe"
117
+ },
118
+ {
119
+ "text": "He alone is great and happy who fills his own station of independence, and has neither to command nor to obey.",
120
+ "author": "Goethe"
121
+ },
122
+ {
123
+ "text": "If you wish to advance into the infinite, explore the finite in all directions.",
124
+ "author": "Goethe"
125
+ },
126
+ {
127
+ "text": "One ought to hold on to one's heart; for if one lets it go, one soon loses control of the head too.",
128
+ "author": "Friedrich Nietzsche"
129
+ },
130
+ {
131
+ "text": "A faith is a necessity to man. Woe to him who believes nothing.",
132
+ "author": "Victor Hugo"
133
+ },
134
+ {
135
+ "text": "To live a life which is a perpetual falsehood is to suffer unknown tortures.",
136
+ "author": "Victor Hugo"
137
+ },
138
+ {
139
+ "text": "A man may be a fine genius, and yet understand nothing of an art which he has not studied.",
140
+ "author": "Victor Hugo"
141
+ },
142
+ {
143
+ "text": "How much more grievous are the consequences of anger than the causes of it.",
144
+ "author": "Marcus Aurelius"
145
+ },
146
+ {
147
+ "text": "You always own the option of having no opinion. There is never any need to get worked up or to trouble your soul about things you can't control. These things are not asking to be judged by you. Leave them alone.",
148
+ "author": "Marcus Aurelius"
149
+ },
150
+ {
151
+ "text": "It never ceases to amaze me: we all love ourselves more than other people, but care more about their opinions than our own.",
152
+ "author": "Marcus Aurelius"
153
+ },
154
+ {
155
+ "text": "External things are not the problem. It's your assessment of them. Which you can erase right now.",
156
+ "author": "Marcus Aurelius"
157
+ },
158
+ {
159
+ "text": "The man who reads nothing at all is more educated than the man who reads nothing but newspapers.",
160
+ "author": "Thomas Jefferson"
161
+ },
162
+ {
163
+ "text": "Nothing gives one person so much advantage over anohter as to remain always cool and unruffled under all circumstances.",
164
+ "author": "Thomas Jefferson"
165
+ },
166
+ {
167
+ "text": "Doubt is an uncomfortable condition, but certainty is a ridiculous one.",
168
+ "author": "Voltaire"
169
+ },
170
+ {
171
+ "text": "The longer we dwell on our misfortunes, the greater is their power to harm us.",
172
+ "author": "Voltaire"
173
+ },
174
+ {
175
+ "text": "Those who can make you believe absurdities, can make you commit atrocities.",
176
+ "author": "Voltaire"
177
+ },
178
+ {
179
+ "text": "It is dangerous to be right in matters on which the established authorities are wrong.",
180
+ "author": "Voltaire"
181
+ },
182
+ {
183
+ "text": "One can stand anything except a succession of ordinary days.",
184
+ "author": "Goethe"
185
+ },
186
+ {
187
+ "text": "Good times become good memories and bad times become good lessons in life.",
188
+ "author": "Unknown"
189
+ },
190
+ {
191
+ "text": "It's better to have a short life that is full of what you like doing, than a long life spent in a miserable way.",
192
+ "author": "Alan Watts"
193
+ },
194
+ {
195
+ "text": "To have faith is to trust yourself to the water. When you swim you don't grab hold of the water, because if you do you will sink and drown. Instead you relax, and float.",
196
+ "author": "Alan Watts"
197
+ },
198
+ {
199
+ "text": "I've been searching for years for the ideal place. And I've come to the realization that the only way to find it is to be it.",
200
+ "author": "Alan Watts"
201
+ },
202
+ {
203
+ "text": "I would rather be governed by the first 2,000 people in the Boston telephone directory than by the 2,000 people on the faculty of Harvard University.",
204
+ "author": "William F. Buckley Jr."
205
+ },
206
+ {
207
+ "text": "Never confuse education with intelligence, you can have a PhD and still be an idiot.",
208
+ "author": "Richard Feynman"
209
+ },
210
+ {
211
+ "text": "The enemy is anybody who's going to get you killed, no matter which side he's on.",
212
+ "author": "Joseph Heller"
213
+ },
214
+ {
215
+ "text": "People often say motivation doesn't last. Neither does bathing—that's why we recommend it daily.",
216
+ "author": "Zig Ziglar"
217
+ },
218
+ {
219
+ "text": "Live free ot die; death is not the worst of evils.",
220
+ "author": "General John Stark"
221
+ },
222
+ {
223
+ "text": "Equality only exists in theory. Social law can give all men equal rights. Nature will never give them equal faculties.",
224
+ "author": "Napoleon"
225
+ },
226
+ {
227
+ "text": "One who does not want to reason exists as a fanatic; one who ignores how to reason exists as a fool; and one who will not dare to reason exists as a slave.",
228
+ "author": "Carlos Drummond de Andrade"
229
+ }
230
+ ]
@@ -0,0 +1,7 @@
1
+ import { type HSHtml } from "@hyperspan/html";
2
+ import type { PageMeta } from "./pages.js";
3
+ export declare function renderStandardHead(input: {
4
+ title: string;
5
+ meta?: PageMeta;
6
+ }): HSHtml;
7
+ //# sourceMappingURL=render-head.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-head.d.ts","sourceRoot":"","sources":["../src/render-head.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,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,3 @@
1
+ export declare function normalizePathname(pathname: string): string;
2
+ export declare function matchPagePath(pathname: string, pagePath: string): boolean;
3
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET"}
@@ -0,0 +1,11 @@
1
+ export function normalizePathname(pathname) {
2
+ if (pathname === "" || pathname === "/") {
3
+ return "/";
4
+ }
5
+ const trimmed = pathname.replace(/\/+$/, "");
6
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
7
+ }
8
+ export function matchPagePath(pathname, pagePath) {
9
+ return normalizePathname(pathname) === normalizePathname(pagePath);
10
+ }
11
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;QACxC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,QAAgB;IAEhB,OAAO,iBAAiB,CAAC,QAAQ,CAAC,KAAK,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AACrE,CAAC"}
package/dist/site.d.ts ADDED
@@ -0,0 +1,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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"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"}
@@ -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"}