@we8/cms 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/README.md +78 -0
  2. package/dist/auth/auth.d.ts +87 -0
  3. package/dist/auth/auth.d.ts.map +1 -0
  4. package/dist/auth/auth.js +90 -0
  5. package/dist/auth/auth.js.map +1 -0
  6. package/dist/auth/routes.admin.d.ts +22 -0
  7. package/dist/auth/routes.admin.d.ts.map +1 -0
  8. package/dist/auth/routes.admin.js +106 -0
  9. package/dist/auth/routes.admin.js.map +1 -0
  10. package/dist/auth/schema.d.ts +1395 -0
  11. package/dist/auth/schema.d.ts.map +1 -0
  12. package/dist/auth/schema.js +76 -0
  13. package/dist/auth/schema.js.map +1 -0
  14. package/dist/env.d.ts +64 -0
  15. package/dist/env.d.ts.map +1 -0
  16. package/dist/env.js +48 -0
  17. package/dist/env.js.map +1 -0
  18. package/dist/index.d.ts +22 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +170 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/keys/middleware.d.ts +54 -0
  23. package/dist/keys/middleware.d.ts.map +1 -0
  24. package/dist/keys/middleware.js +84 -0
  25. package/dist/keys/middleware.js.map +1 -0
  26. package/dist/keys/routes.admin.d.ts +16 -0
  27. package/dist/keys/routes.admin.d.ts.map +1 -0
  28. package/dist/keys/routes.admin.js +34 -0
  29. package/dist/keys/routes.admin.js.map +1 -0
  30. package/dist/keys/service.d.ts +36 -0
  31. package/dist/keys/service.d.ts.map +1 -0
  32. package/dist/keys/service.js +120 -0
  33. package/dist/keys/service.js.map +1 -0
  34. package/dist/lib/bots.d.ts +24 -0
  35. package/dist/lib/bots.d.ts.map +1 -0
  36. package/dist/lib/bots.js +79 -0
  37. package/dist/lib/bots.js.map +1 -0
  38. package/dist/lib/email.d.ts +62 -0
  39. package/dist/lib/email.d.ts.map +1 -0
  40. package/dist/lib/email.js +64 -0
  41. package/dist/lib/email.js.map +1 -0
  42. package/dist/lib/errors.d.ts +12 -0
  43. package/dist/lib/errors.d.ts.map +1 -0
  44. package/dist/lib/errors.js +23 -0
  45. package/dist/lib/errors.js.map +1 -0
  46. package/dist/lib/notify.d.ts +20 -0
  47. package/dist/lib/notify.d.ts.map +1 -0
  48. package/dist/lib/notify.js +60 -0
  49. package/dist/lib/notify.js.map +1 -0
  50. package/dist/lib/retention.d.ts +15 -0
  51. package/dist/lib/retention.d.ts.map +1 -0
  52. package/dist/lib/retention.js +40 -0
  53. package/dist/lib/retention.js.map +1 -0
  54. package/dist/lib/sanitize.d.ts +14 -0
  55. package/dist/lib/sanitize.d.ts.map +1 -0
  56. package/dist/lib/sanitize.js +145 -0
  57. package/dist/lib/sanitize.js.map +1 -0
  58. package/dist/lib/turnstile.d.ts +7 -0
  59. package/dist/lib/turnstile.d.ts.map +1 -0
  60. package/dist/lib/turnstile.js +32 -0
  61. package/dist/lib/turnstile.js.map +1 -0
  62. package/dist/lib/validate.d.ts +11 -0
  63. package/dist/lib/validate.d.ts.map +1 -0
  64. package/dist/lib/validate.js +22 -0
  65. package/dist/lib/validate.js.map +1 -0
  66. package/dist/lib/word-count.d.ts +7 -0
  67. package/dist/lib/word-count.d.ts.map +1 -0
  68. package/dist/lib/word-count.js +14 -0
  69. package/dist/lib/word-count.js.map +1 -0
  70. package/dist/middleware/auth.d.ts +46 -0
  71. package/dist/middleware/auth.d.ts.map +1 -0
  72. package/dist/middleware/auth.js +60 -0
  73. package/dist/middleware/auth.js.map +1 -0
  74. package/dist/middleware/cors.d.ts +33 -0
  75. package/dist/middleware/cors.d.ts.map +1 -0
  76. package/dist/middleware/cors.js +55 -0
  77. package/dist/middleware/cors.js.map +1 -0
  78. package/dist/middleware/module-gate.d.ts +11 -0
  79. package/dist/middleware/module-gate.d.ts.map +1 -0
  80. package/dist/middleware/module-gate.js +18 -0
  81. package/dist/middleware/module-gate.js.map +1 -0
  82. package/dist/middleware/rate-limit.d.ts +13 -0
  83. package/dist/middleware/rate-limit.d.ts.map +1 -0
  84. package/dist/middleware/rate-limit.js +30 -0
  85. package/dist/middleware/rate-limit.js.map +1 -0
  86. package/dist/middleware/request-id.d.ts +8 -0
  87. package/dist/middleware/request-id.d.ts.map +1 -0
  88. package/dist/middleware/request-id.js +11 -0
  89. package/dist/middleware/request-id.js.map +1 -0
  90. package/dist/modules/aeo/checks.d.ts +41 -0
  91. package/dist/modules/aeo/checks.d.ts.map +1 -0
  92. package/dist/modules/aeo/checks.js +127 -0
  93. package/dist/modules/aeo/checks.js.map +1 -0
  94. package/dist/modules/aeo/llms.d.ts +24 -0
  95. package/dist/modules/aeo/llms.d.ts.map +1 -0
  96. package/dist/modules/aeo/llms.js +92 -0
  97. package/dist/modules/aeo/llms.js.map +1 -0
  98. package/dist/modules/aeo/routes.admin.d.ts +12 -0
  99. package/dist/modules/aeo/routes.admin.d.ts.map +1 -0
  100. package/dist/modules/aeo/routes.admin.js +37 -0
  101. package/dist/modules/aeo/routes.admin.js.map +1 -0
  102. package/dist/modules/analytics/db.d.ts +24 -0
  103. package/dist/modules/analytics/db.d.ts.map +1 -0
  104. package/dist/modules/analytics/db.js +24 -0
  105. package/dist/modules/analytics/db.js.map +1 -0
  106. package/dist/modules/analytics/routes.admin.d.ts +6 -0
  107. package/dist/modules/analytics/routes.admin.d.ts.map +1 -0
  108. package/dist/modules/analytics/routes.admin.js +21 -0
  109. package/dist/modules/analytics/routes.admin.js.map +1 -0
  110. package/dist/modules/analytics/routes.public.d.ts +6 -0
  111. package/dist/modules/analytics/routes.public.d.ts.map +1 -0
  112. package/dist/modules/analytics/routes.public.js +33 -0
  113. package/dist/modules/analytics/routes.public.js.map +1 -0
  114. package/dist/modules/analytics/service.d.ts +16 -0
  115. package/dist/modules/analytics/service.d.ts.map +1 -0
  116. package/dist/modules/analytics/service.js +148 -0
  117. package/dist/modules/analytics/service.js.map +1 -0
  118. package/dist/modules/authors/routes.admin.d.ts +6 -0
  119. package/dist/modules/authors/routes.admin.d.ts.map +1 -0
  120. package/dist/modules/authors/routes.admin.js +29 -0
  121. package/dist/modules/authors/routes.admin.js.map +1 -0
  122. package/dist/modules/authors/routes.public.d.ts +6 -0
  123. package/dist/modules/authors/routes.public.d.ts.map +1 -0
  124. package/dist/modules/authors/routes.public.js +11 -0
  125. package/dist/modules/authors/routes.public.js.map +1 -0
  126. package/dist/modules/authors/service.d.ts +26 -0
  127. package/dist/modules/authors/service.d.ts.map +1 -0
  128. package/dist/modules/authors/service.js +116 -0
  129. package/dist/modules/authors/service.js.map +1 -0
  130. package/dist/modules/content/db.d.ts +127 -0
  131. package/dist/modules/content/db.d.ts.map +1 -0
  132. package/dist/modules/content/db.js +203 -0
  133. package/dist/modules/content/db.js.map +1 -0
  134. package/dist/modules/content/publish.d.ts +38 -0
  135. package/dist/modules/content/publish.d.ts.map +1 -0
  136. package/dist/modules/content/publish.js +184 -0
  137. package/dist/modules/content/publish.js.map +1 -0
  138. package/dist/modules/content/routes.admin.d.ts +8 -0
  139. package/dist/modules/content/routes.admin.d.ts.map +1 -0
  140. package/dist/modules/content/routes.admin.js +122 -0
  141. package/dist/modules/content/routes.admin.js.map +1 -0
  142. package/dist/modules/content/routes.public.d.ts +6 -0
  143. package/dist/modules/content/routes.public.d.ts.map +1 -0
  144. package/dist/modules/content/routes.public.js +56 -0
  145. package/dist/modules/content/routes.public.js.map +1 -0
  146. package/dist/modules/content/service.d.ts +137 -0
  147. package/dist/modules/content/service.d.ts.map +1 -0
  148. package/dist/modules/content/service.js +348 -0
  149. package/dist/modules/content/service.js.map +1 -0
  150. package/dist/modules/forms/db.d.ts +42 -0
  151. package/dist/modules/forms/db.d.ts.map +1 -0
  152. package/dist/modules/forms/db.js +62 -0
  153. package/dist/modules/forms/db.js.map +1 -0
  154. package/dist/modules/forms/forms-routes.admin.d.ts +6 -0
  155. package/dist/modules/forms/forms-routes.admin.d.ts.map +1 -0
  156. package/dist/modules/forms/forms-routes.admin.js +37 -0
  157. package/dist/modules/forms/forms-routes.admin.js.map +1 -0
  158. package/dist/modules/forms/forms-service.d.ts +18 -0
  159. package/dist/modules/forms/forms-service.d.ts.map +1 -0
  160. package/dist/modules/forms/forms-service.js +121 -0
  161. package/dist/modules/forms/forms-service.js.map +1 -0
  162. package/dist/modules/forms/routes.public.d.ts +6 -0
  163. package/dist/modules/forms/routes.public.d.ts.map +1 -0
  164. package/dist/modules/forms/routes.public.js +41 -0
  165. package/dist/modules/forms/routes.public.js.map +1 -0
  166. package/dist/modules/forms/submissions-routes.admin.d.ts +6 -0
  167. package/dist/modules/forms/submissions-routes.admin.d.ts.map +1 -0
  168. package/dist/modules/forms/submissions-routes.admin.js +46 -0
  169. package/dist/modules/forms/submissions-routes.admin.js.map +1 -0
  170. package/dist/modules/forms/submissions-service.d.ts +45 -0
  171. package/dist/modules/forms/submissions-service.d.ts.map +1 -0
  172. package/dist/modules/forms/submissions-service.js +174 -0
  173. package/dist/modules/forms/submissions-service.js.map +1 -0
  174. package/dist/modules/media/db.d.ts +15 -0
  175. package/dist/modules/media/db.d.ts.map +1 -0
  176. package/dist/modules/media/db.js +24 -0
  177. package/dist/modules/media/db.js.map +1 -0
  178. package/dist/modules/media/routes.admin.d.ts +6 -0
  179. package/dist/modules/media/routes.admin.d.ts.map +1 -0
  180. package/dist/modules/media/routes.admin.js +30 -0
  181. package/dist/modules/media/routes.admin.js.map +1 -0
  182. package/dist/modules/media/routes.public.d.ts +6 -0
  183. package/dist/modules/media/routes.public.d.ts.map +1 -0
  184. package/dist/modules/media/routes.public.js +35 -0
  185. package/dist/modules/media/routes.public.js.map +1 -0
  186. package/dist/modules/media/service.d.ts +32 -0
  187. package/dist/modules/media/service.d.ts.map +1 -0
  188. package/dist/modules/media/service.js +99 -0
  189. package/dist/modules/media/service.js.map +1 -0
  190. package/dist/modules/openapi/spec.d.ts +21 -0
  191. package/dist/modules/openapi/spec.d.ts.map +1 -0
  192. package/dist/modules/openapi/spec.js +468 -0
  193. package/dist/modules/openapi/spec.js.map +1 -0
  194. package/dist/modules/seo/jsonld.d.ts +25 -0
  195. package/dist/modules/seo/jsonld.d.ts.map +1 -0
  196. package/dist/modules/seo/jsonld.js +67 -0
  197. package/dist/modules/seo/jsonld.js.map +1 -0
  198. package/dist/modules/seo/routes.public.d.ts +6 -0
  199. package/dist/modules/seo/routes.public.d.ts.map +1 -0
  200. package/dist/modules/seo/routes.public.js +39 -0
  201. package/dist/modules/seo/routes.public.js.map +1 -0
  202. package/dist/modules/seo/sitemap.d.ts +3 -0
  203. package/dist/modules/seo/sitemap.d.ts.map +1 -0
  204. package/dist/modules/seo/sitemap.js +39 -0
  205. package/dist/modules/seo/sitemap.js.map +1 -0
  206. package/dist/modules/settings/routes.admin.d.ts +12 -0
  207. package/dist/modules/settings/routes.admin.d.ts.map +1 -0
  208. package/dist/modules/settings/routes.admin.js +27 -0
  209. package/dist/modules/settings/routes.admin.js.map +1 -0
  210. package/dist/modules/site-documents/routes.admin.d.ts +10 -0
  211. package/dist/modules/site-documents/routes.admin.d.ts.map +1 -0
  212. package/dist/modules/site-documents/routes.admin.js +29 -0
  213. package/dist/modules/site-documents/routes.admin.js.map +1 -0
  214. package/dist/modules/site-documents/routes.public.d.ts +6 -0
  215. package/dist/modules/site-documents/routes.public.d.ts.map +1 -0
  216. package/dist/modules/site-documents/routes.public.js +16 -0
  217. package/dist/modules/site-documents/routes.public.js.map +1 -0
  218. package/dist/modules/site-documents/service.d.ts +11 -0
  219. package/dist/modules/site-documents/service.d.ts.map +1 -0
  220. package/dist/modules/site-documents/service.js +42 -0
  221. package/dist/modules/site-documents/service.js.map +1 -0
  222. package/dist/modules/webhooks/dispatch.d.ts +14 -0
  223. package/dist/modules/webhooks/dispatch.d.ts.map +1 -0
  224. package/dist/modules/webhooks/dispatch.js +84 -0
  225. package/dist/modules/webhooks/dispatch.js.map +1 -0
  226. package/dist/shared/constants.d.ts +79 -0
  227. package/dist/shared/constants.d.ts.map +1 -0
  228. package/dist/shared/constants.js +89 -0
  229. package/dist/shared/constants.js.map +1 -0
  230. package/dist/shared/envelope.d.ts +37 -0
  231. package/dist/shared/envelope.d.ts.map +1 -0
  232. package/dist/shared/envelope.js +46 -0
  233. package/dist/shared/envelope.js.map +1 -0
  234. package/dist/shared/hash.d.ts +2 -0
  235. package/dist/shared/hash.d.ts.map +1 -0
  236. package/dist/shared/hash.js +8 -0
  237. package/dist/shared/hash.js.map +1 -0
  238. package/dist/shared/index.d.ts +13 -0
  239. package/dist/shared/index.d.ts.map +1 -0
  240. package/dist/shared/index.js +13 -0
  241. package/dist/shared/index.js.map +1 -0
  242. package/dist/shared/schemas/aeo.d.ts +182 -0
  243. package/dist/shared/schemas/aeo.d.ts.map +1 -0
  244. package/dist/shared/schemas/aeo.js +43 -0
  245. package/dist/shared/schemas/aeo.js.map +1 -0
  246. package/dist/shared/schemas/analytics.d.ts +277 -0
  247. package/dist/shared/schemas/analytics.d.ts.map +1 -0
  248. package/dist/shared/schemas/analytics.js +74 -0
  249. package/dist/shared/schemas/analytics.js.map +1 -0
  250. package/dist/shared/schemas/api-key.d.ts +77 -0
  251. package/dist/shared/schemas/api-key.d.ts.map +1 -0
  252. package/dist/shared/schemas/api-key.js +27 -0
  253. package/dist/shared/schemas/api-key.js.map +1 -0
  254. package/dist/shared/schemas/author.d.ts +147 -0
  255. package/dist/shared/schemas/author.d.ts.map +1 -0
  256. package/dist/shared/schemas/author.js +27 -0
  257. package/dist/shared/schemas/author.js.map +1 -0
  258. package/dist/shared/schemas/form.d.ts +341 -0
  259. package/dist/shared/schemas/form.d.ts.map +1 -0
  260. package/dist/shared/schemas/form.js +117 -0
  261. package/dist/shared/schemas/form.js.map +1 -0
  262. package/dist/shared/schemas/index.d.ts +12 -0
  263. package/dist/shared/schemas/index.d.ts.map +1 -0
  264. package/dist/shared/schemas/index.js +12 -0
  265. package/dist/shared/schemas/index.js.map +1 -0
  266. package/dist/shared/schemas/media.d.ts +42 -0
  267. package/dist/shared/schemas/media.d.ts.map +1 -0
  268. package/dist/shared/schemas/media.js +16 -0
  269. package/dist/shared/schemas/media.js.map +1 -0
  270. package/dist/shared/schemas/pagination.d.ts +34 -0
  271. package/dist/shared/schemas/pagination.d.ts.map +1 -0
  272. package/dist/shared/schemas/pagination.js +21 -0
  273. package/dist/shared/schemas/pagination.js.map +1 -0
  274. package/dist/shared/schemas/post.d.ts +862 -0
  275. package/dist/shared/schemas/post.d.ts.map +1 -0
  276. package/dist/shared/schemas/post.js +187 -0
  277. package/dist/shared/schemas/post.js.map +1 -0
  278. package/dist/shared/schemas/settings.d.ts +839 -0
  279. package/dist/shared/schemas/settings.d.ts.map +1 -0
  280. package/dist/shared/schemas/settings.js +202 -0
  281. package/dist/shared/schemas/settings.js.map +1 -0
  282. package/dist/shared/schemas/site-document.d.ts +38 -0
  283. package/dist/shared/schemas/site-document.d.ts.map +1 -0
  284. package/dist/shared/schemas/site-document.js +21 -0
  285. package/dist/shared/schemas/site-document.js.map +1 -0
  286. package/dist/shared/schemas/webhook.d.ts +39 -0
  287. package/dist/shared/schemas/webhook.d.ts.map +1 -0
  288. package/dist/shared/schemas/webhook.js +20 -0
  289. package/dist/shared/schemas/webhook.js.map +1 -0
  290. package/dist/spa.d.ts +9 -0
  291. package/dist/spa.d.ts.map +1 -0
  292. package/dist/spa.js +57 -0
  293. package/dist/spa.js.map +1 -0
  294. package/migrations/0001_settings.sql +39 -0
  295. package/migrations/0002_content.sql +135 -0
  296. package/migrations/0003_forms.sql +35 -0
  297. package/migrations/0004_analytics.sql +42 -0
  298. package/migrations/0005_media.sql +17 -0
  299. package/migrations/0006_site_documents.sql +18 -0
  300. package/migrations/0007_auth.sql +81 -0
  301. package/migrations/0008_api_keys.sql +20 -0
  302. package/package.json +68 -0
  303. package/scripts/bundle-admin.mjs +54 -0
  304. package/seed/local.sql +63 -0
@@ -0,0 +1,468 @@
1
+ import { CONSENT_DECISIONS, POST_TYPES } from '../../shared/index.js';
2
+ /**
3
+ * The we8 public API, described as OpenAPI 3.1.
4
+ *
5
+ * This is the durable, language-agnostic contract: a frontend in any stack
6
+ * calls these endpoints over HTTPS with the site's publishable key. The JS SDK
7
+ * (@we8/client, @we8/astro) is an optional convenience over exactly these
8
+ * routes, never a requirement. Served live at GET /v1/openapi.json so a
9
+ * deployment's API is self-describing, and kept in sync BY HAND with the public
10
+ * routes (the golden-file contract tests pin the actual JSON shapes; this
11
+ * document is the human and tooling facing description of the same surface).
12
+ *
13
+ * It is deliberately the SAME dialect a managed we8 tenant speaks, extended
14
+ * only by what 0.1 adds for AEO, so a site can move between the two without
15
+ * rewriting its frontend.
16
+ *
17
+ * Scope: the PUBLIC, frontend-facing surface only. The admin API (/v1/admin/*,
18
+ * reached with a signed-in session) is not documented here; this spec is what
19
+ * a site owner hands to whoever builds their site.
20
+ */
21
+ export function buildOpenApiSpec(siteUrl) {
22
+ const okEnvelope = (dataProps, required = []) => ({
23
+ type: 'object',
24
+ required: ['ok', ...required],
25
+ properties: { ok: { type: 'boolean', enum: [true] }, ...dataProps },
26
+ });
27
+ return {
28
+ openapi: '3.1.0',
29
+ info: {
30
+ title: 'we8 public API',
31
+ version: '1.0.0',
32
+ description: 'The public content and engagement API for a we8 site. Call it from any ' +
33
+ 'frontend, in any language, over HTTPS with your publishable key in the ' +
34
+ 'X-We8-Key header. Reads are safe with a publishable (pk_) key; the ' +
35
+ 'optional @we8/client SDK is a thin typed wrapper over these same routes.',
36
+ },
37
+ // A standalone deployment IS the API origin: there is no router in front
38
+ // splitting a path prefix off to somewhere else.
39
+ servers: [{ url: siteUrl, description: 'Your CMS' }],
40
+ security: [{ publishableKey: [] }],
41
+ tags: [
42
+ { name: 'content', description: 'Published posts and authors' },
43
+ { name: 'site', description: 'Site identity and documents' },
44
+ { name: 'forms', description: 'Form submissions' },
45
+ { name: 'analytics', description: 'Visit and consent beacons' },
46
+ { name: 'media', description: 'Uploaded media (keyless)' },
47
+ { name: 'aeo', description: 'Answer-engine surfaces' },
48
+ { name: 'meta', description: 'Health and this spec' },
49
+ ],
50
+ paths: {
51
+ '/v1/posts': {
52
+ get: {
53
+ tags: ['content'],
54
+ summary: 'List published posts',
55
+ parameters: [
56
+ { name: 'page', in: 'query', schema: { type: 'integer', minimum: 1, default: 1 } },
57
+ {
58
+ name: 'pageSize',
59
+ in: 'query',
60
+ schema: { type: 'integer', minimum: 1, maximum: 50, default: 20 },
61
+ },
62
+ { name: 'type', in: 'query', schema: { type: 'string', enum: [...POST_TYPES] } },
63
+ { name: 'category', in: 'query', schema: { type: 'string' } },
64
+ { name: 'tag', in: 'query', schema: { type: 'string' } },
65
+ ],
66
+ responses: {
67
+ '200': {
68
+ description: 'A page of published posts.',
69
+ content: {
70
+ 'application/json': {
71
+ schema: okEnvelope({
72
+ items: { type: 'array', items: { $ref: '#/components/schemas/Post' } },
73
+ page: { type: 'integer' },
74
+ pageSize: { type: 'integer' },
75
+ total: { type: 'integer' },
76
+ }),
77
+ },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ },
83
+ '/v1/posts/{slug}': {
84
+ get: {
85
+ tags: ['content'],
86
+ summary: 'Get a published post by slug',
87
+ parameters: [{ name: 'slug', in: 'path', required: true, schema: { type: 'string' } }],
88
+ responses: {
89
+ '200': {
90
+ description: 'The post, its resolved authors, and its JSON-LD.',
91
+ content: {
92
+ 'application/json': {
93
+ schema: okEnvelope({
94
+ post: { $ref: '#/components/schemas/Post' },
95
+ authors: { type: 'array', items: { $ref: '#/components/schemas/Author' } },
96
+ jsonld: { type: 'object', additionalProperties: true },
97
+ }),
98
+ },
99
+ },
100
+ },
101
+ '404': { $ref: '#/components/responses/NotFound' },
102
+ },
103
+ },
104
+ },
105
+ '/v1/posts/{slug}/view': {
106
+ post: {
107
+ tags: ['content'],
108
+ summary: 'Record a view (one per session)',
109
+ parameters: [{ name: 'slug', in: 'path', required: true, schema: { type: 'string' } }],
110
+ requestBody: { $ref: '#/components/requestBodies/SessionId' },
111
+ responses: { '200': { $ref: '#/components/responses/Ok' } },
112
+ },
113
+ },
114
+ '/v1/posts/{slug}/like': {
115
+ post: {
116
+ tags: ['content'],
117
+ summary: 'Toggle a like (one per session)',
118
+ parameters: [{ name: 'slug', in: 'path', required: true, schema: { type: 'string' } }],
119
+ requestBody: { $ref: '#/components/requestBodies/SessionId' },
120
+ responses: {
121
+ '200': {
122
+ description: 'The new like state.',
123
+ content: {
124
+ 'application/json': {
125
+ schema: okEnvelope({
126
+ liked: { type: 'boolean' },
127
+ likeCount: { type: 'integer' },
128
+ }),
129
+ },
130
+ },
131
+ },
132
+ },
133
+ },
134
+ },
135
+ '/v1/authors/{slug}': {
136
+ get: {
137
+ tags: ['content'],
138
+ summary: 'Get an author by slug',
139
+ parameters: [{ name: 'slug', in: 'path', required: true, schema: { type: 'string' } }],
140
+ responses: {
141
+ '200': {
142
+ description: 'The author.',
143
+ content: {
144
+ 'application/json': {
145
+ schema: okEnvelope({ author: { $ref: '#/components/schemas/Author' } }),
146
+ },
147
+ },
148
+ },
149
+ '404': { $ref: '#/components/responses/NotFound' },
150
+ },
151
+ },
152
+ },
153
+ '/v1/site': {
154
+ get: {
155
+ tags: ['site'],
156
+ summary: 'Get site identity and SEO/brand config',
157
+ responses: {
158
+ '200': {
159
+ description: 'The site config.',
160
+ content: {
161
+ 'application/json': {
162
+ schema: okEnvelope({ site: { type: 'object', additionalProperties: true } }),
163
+ },
164
+ },
165
+ },
166
+ },
167
+ },
168
+ },
169
+ '/v1/documents/{kind}': {
170
+ get: {
171
+ tags: ['site'],
172
+ summary: 'Get a site document (design.md or llms.txt)',
173
+ description: 'The llms-txt document doubles as the manual override for GET /llms.txt: ' +
174
+ 'when it has content, that content is served there verbatim.',
175
+ parameters: [
176
+ {
177
+ name: 'kind',
178
+ in: 'path',
179
+ required: true,
180
+ schema: { type: 'string', enum: ['design-md', 'llms-txt'] },
181
+ },
182
+ ],
183
+ responses: {
184
+ '200': {
185
+ description: 'The document.',
186
+ content: {
187
+ 'application/json': {
188
+ schema: okEnvelope({ document: { type: 'object', additionalProperties: true } }),
189
+ },
190
+ },
191
+ },
192
+ '404': { $ref: '#/components/responses/NotFound' },
193
+ },
194
+ },
195
+ },
196
+ '/v1/forms/{formKey}/submissions': {
197
+ post: {
198
+ tags: ['forms'],
199
+ summary: 'Submit a form',
200
+ description: 'Fields are passthrough; email is typical. Honeypot, Turnstile (if the ' +
201
+ 'form enables it), and a short dedupe window are enforced server-side.',
202
+ parameters: [{ name: 'formKey', in: 'path', required: true, schema: { type: 'string' } }],
203
+ requestBody: {
204
+ required: true,
205
+ content: {
206
+ 'application/json': {
207
+ schema: {
208
+ type: 'object',
209
+ properties: {
210
+ email: { type: 'string', format: 'email' },
211
+ name: { type: 'string' },
212
+ message: { type: 'string' },
213
+ sourcePage: { type: 'string' },
214
+ turnstileToken: { type: 'string' },
215
+ },
216
+ additionalProperties: true,
217
+ },
218
+ },
219
+ },
220
+ },
221
+ responses: {
222
+ '200': {
223
+ description: 'Accepted (id is null when the honeypot silently swallowed it).',
224
+ content: {
225
+ 'application/json': {
226
+ schema: okEnvelope({ id: { type: 'string', nullable: true } }),
227
+ },
228
+ },
229
+ },
230
+ },
231
+ },
232
+ },
233
+ '/v1/events/visit': {
234
+ post: {
235
+ tags: ['analytics'],
236
+ summary: 'Record an anonymous page visit',
237
+ requestBody: {
238
+ required: true,
239
+ content: {
240
+ 'application/json': {
241
+ schema: {
242
+ type: 'object',
243
+ required: ['pathname', 'sessionId'],
244
+ properties: {
245
+ pathname: { type: 'string' },
246
+ sessionId: { type: 'string' },
247
+ referrer: { type: 'string' },
248
+ },
249
+ },
250
+ },
251
+ },
252
+ },
253
+ responses: { '200': { $ref: '#/components/responses/Ok' } },
254
+ },
255
+ },
256
+ '/v1/events/consent': {
257
+ post: {
258
+ tags: ['analytics'],
259
+ summary: 'Record a cookie-consent decision',
260
+ requestBody: {
261
+ required: true,
262
+ content: {
263
+ 'application/json': {
264
+ schema: {
265
+ type: 'object',
266
+ required: ['sessionId', 'decision', 'analytics', 'performance'],
267
+ properties: {
268
+ sessionId: { type: 'string' },
269
+ decision: { type: 'string', enum: [...CONSENT_DECISIONS] },
270
+ analytics: { type: 'boolean' },
271
+ performance: { type: 'boolean' },
272
+ },
273
+ },
274
+ },
275
+ },
276
+ },
277
+ responses: { '200': { $ref: '#/components/responses/Ok' } },
278
+ },
279
+ },
280
+ '/v1/media/{key}': {
281
+ get: {
282
+ tags: ['media'],
283
+ summary: 'Fetch an uploaded media object (keyless)',
284
+ security: [],
285
+ parameters: [{ name: 'key', in: 'path', required: true, schema: { type: 'string' } }],
286
+ responses: {
287
+ '200': {
288
+ description: 'The binary object.',
289
+ content: { '*/*': { schema: { type: 'string', format: 'binary' } } },
290
+ },
291
+ '404': { $ref: '#/components/responses/NotFound' },
292
+ },
293
+ },
294
+ },
295
+ '/v1/sitemap.xml': {
296
+ get: {
297
+ tags: ['site'],
298
+ // Keyless: a search crawler cannot present a key, and a sitemap
299
+ // behind one is a sitemap nothing reads.
300
+ summary: 'The sitemap (keyless)',
301
+ security: [],
302
+ responses: {
303
+ '200': { description: 'XML sitemap.', content: { 'application/xml': {} } },
304
+ },
305
+ },
306
+ },
307
+ '/llms.txt': {
308
+ get: {
309
+ tags: ['aeo'],
310
+ summary: 'The llms.txt index of this site (keyless)',
311
+ description: 'Generated from site settings and published content in the llmstxt.org ' +
312
+ 'convention, or served verbatim when the site has authored its own. ' +
313
+ 'Keyless for the same reason as the sitemap: the readers are crawlers. ' +
314
+ 'Returns 404 when the site has turned generation off and authored nothing.',
315
+ security: [],
316
+ responses: {
317
+ '200': { description: 'The document.', content: { 'text/plain': {} } },
318
+ '404': { $ref: '#/components/responses/NotFound' },
319
+ },
320
+ },
321
+ },
322
+ '/v1/health': {
323
+ get: {
324
+ tags: ['meta'],
325
+ summary: 'CMS health and enabled modules (keyless)',
326
+ security: [],
327
+ responses: {
328
+ '200': {
329
+ description: 'Health.',
330
+ content: {
331
+ 'application/json': {
332
+ schema: okEnvelope({
333
+ cmsVersion: { type: 'string' },
334
+ modules: { type: 'object', additionalProperties: { type: 'boolean' } },
335
+ }),
336
+ },
337
+ },
338
+ },
339
+ },
340
+ },
341
+ },
342
+ '/v1/openapi.json': {
343
+ get: {
344
+ tags: ['meta'],
345
+ summary: 'This OpenAPI document (keyless)',
346
+ security: [],
347
+ responses: {
348
+ '200': {
349
+ description: 'The spec.',
350
+ content: { 'application/json': { schema: { type: 'object' } } },
351
+ },
352
+ },
353
+ },
354
+ },
355
+ },
356
+ components: {
357
+ securitySchemes: {
358
+ publishableKey: {
359
+ type: 'apiKey',
360
+ in: 'header',
361
+ name: 'X-We8-Key',
362
+ description: 'Your publishable (pk_) key. Safe to ship in browser code.',
363
+ },
364
+ secretKey: {
365
+ type: 'http',
366
+ scheme: 'bearer',
367
+ description: 'Your secret (sk_) key, as a bearer token. Server-side only, and ' +
368
+ 'accepted anywhere a publishable key is. It does NOT reach the admin ' +
369
+ 'API, which is gated by a signed-in session instead.',
370
+ },
371
+ },
372
+ requestBodies: {
373
+ SessionId: {
374
+ required: true,
375
+ content: {
376
+ 'application/json': {
377
+ schema: {
378
+ type: 'object',
379
+ required: ['sessionId'],
380
+ properties: { sessionId: { type: 'string' } },
381
+ },
382
+ },
383
+ },
384
+ },
385
+ },
386
+ responses: {
387
+ Ok: {
388
+ description: 'Success.',
389
+ content: {
390
+ 'application/json': {
391
+ schema: {
392
+ type: 'object',
393
+ required: ['ok'],
394
+ properties: { ok: { type: 'boolean', enum: [true] } },
395
+ },
396
+ },
397
+ },
398
+ },
399
+ NotFound: {
400
+ description: 'Not found.',
401
+ content: {
402
+ 'application/json': {
403
+ schema: {
404
+ type: 'object',
405
+ required: ['ok', 'error', 'code'],
406
+ properties: {
407
+ ok: { type: 'boolean', enum: [false] },
408
+ error: { type: 'string' },
409
+ code: { type: 'string' },
410
+ },
411
+ },
412
+ },
413
+ },
414
+ },
415
+ },
416
+ schemas: {
417
+ Post: {
418
+ type: 'object',
419
+ description: 'A published post (the frozen current version).',
420
+ properties: {
421
+ id: { type: 'string' },
422
+ postId: { type: 'string' },
423
+ slug: { type: 'string' },
424
+ type: { type: 'string', enum: [...POST_TYPES] },
425
+ title: { type: 'string' },
426
+ excerpt: { type: 'string', nullable: true },
427
+ content: { type: 'string', description: 'Sanitized HTML.' },
428
+ coverImageUrl: { type: 'string', nullable: true },
429
+ category: { type: 'string', nullable: true },
430
+ tags: { type: 'array', items: { type: 'string' } },
431
+ ogTitle: { type: 'string', nullable: true },
432
+ ogDescription: { type: 'string', nullable: true },
433
+ ogImageUrl: { type: 'string', nullable: true },
434
+ answerSummary: {
435
+ type: 'string',
436
+ nullable: true,
437
+ description: 'AEO: the answer this content gives, written to be quoted verbatim.',
438
+ },
439
+ questionHeading: {
440
+ type: 'string',
441
+ nullable: true,
442
+ description: 'AEO: the question this content answers, phrased as a question.',
443
+ },
444
+ authorIds: { type: 'array', items: { type: 'string' } },
445
+ wordCount: { type: 'integer' },
446
+ publishedAt: { type: 'string', nullable: true },
447
+ viewCount: { type: 'integer' },
448
+ likeCount: { type: 'integer' },
449
+ },
450
+ },
451
+ Author: {
452
+ type: 'object',
453
+ properties: {
454
+ id: { type: 'string' },
455
+ slug: { type: 'string' },
456
+ name: { type: 'string' },
457
+ type: { type: 'string' },
458
+ roleTitle: { type: 'string', nullable: true },
459
+ avatarUrl: { type: 'string', nullable: true },
460
+ bio: { type: 'string', nullable: true },
461
+ links: { type: 'array', items: { type: 'object', additionalProperties: true } },
462
+ },
463
+ },
464
+ },
465
+ },
466
+ };
467
+ }
468
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../../../src/modules/openapi/spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { AuthorRecord, PostType, PublisherSettings } from '../../shared/index.js';
2
+ export interface JsonLdPostInput {
3
+ slug: string;
4
+ type: PostType;
5
+ title: string;
6
+ excerpt: string | null;
7
+ ogDescription: string | null;
8
+ coverImageUrl: string | null;
9
+ ogImageUrl: string | null;
10
+ answerSummary: string | null;
11
+ questionHeading: string | null;
12
+ publishedAt: string;
13
+ }
14
+ /**
15
+ * Article-family JSON-LD, authors as Person, publisher from settings.
16
+ *
17
+ * 0.1 adds the AEO half. When the author wrote an answer summary it becomes
18
+ * the `description`, ahead of the excerpt, because the excerpt is a teaser and
19
+ * the summary is the sentence written to be quoted. When there is also a
20
+ * question heading, the page additionally declares a `mainEntity` Question
21
+ * with that answer, which is the structure an answer engine actually reads a
22
+ * question-and-answer page through.
23
+ */
24
+ export declare function buildPostJsonLd(post: JsonLdPostInput, authors: AuthorRecord[], siteUrl: string, postsPathPrefix: string, publisher: PublisherSettings | undefined): Record<string, unknown>;
25
+ //# sourceMappingURL=jsonld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonld.d.ts","sourceRoot":"","sources":["../../../src/modules/seo/jsonld.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAgBD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,MAAM,EAEf,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,iBAAiB,GAAG,SAAS,GACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0CzB"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * schema.org @type per content type: exactly the Article subtypes Google's
3
+ * article structured data supports; everything without a dedicated subtype is
4
+ * a plain Article.
5
+ */
6
+ const SCHEMA_TYPE = {
7
+ blog: 'BlogPosting',
8
+ news: 'NewsArticle',
9
+ article: 'Article',
10
+ research: 'Article',
11
+ whitepaper: 'Article',
12
+ 'case-study': 'Article',
13
+ };
14
+ /**
15
+ * Article-family JSON-LD, authors as Person, publisher from settings.
16
+ *
17
+ * 0.1 adds the AEO half. When the author wrote an answer summary it becomes
18
+ * the `description`, ahead of the excerpt, because the excerpt is a teaser and
19
+ * the summary is the sentence written to be quoted. When there is also a
20
+ * question heading, the page additionally declares a `mainEntity` Question
21
+ * with that answer, which is the structure an answer engine actually reads a
22
+ * question-and-answer page through.
23
+ */
24
+ export function buildPostJsonLd(post, authors, siteUrl,
25
+ // Already RESOLVED via resolveContentPath(post.type, settings); callers own that.
26
+ postsPathPrefix, publisher) {
27
+ const url = `${siteUrl}${postsPathPrefix}/${post.slug}`;
28
+ const description = post.answerSummary ?? post.excerpt ?? post.ogDescription ?? undefined;
29
+ const image = post.ogImageUrl ?? post.coverImageUrl ?? undefined;
30
+ const qa = post.questionHeading && post.answerSummary
31
+ ? {
32
+ mainEntity: {
33
+ '@type': 'Question',
34
+ name: post.questionHeading,
35
+ acceptedAnswer: { '@type': 'Answer', text: post.answerSummary },
36
+ },
37
+ }
38
+ : {};
39
+ return {
40
+ '@context': 'https://schema.org',
41
+ '@type': SCHEMA_TYPE[post.type],
42
+ headline: post.title,
43
+ ...(description ? { description } : {}),
44
+ ...(image ? { image } : {}),
45
+ datePublished: post.publishedAt,
46
+ dateModified: post.publishedAt,
47
+ mainEntityOfPage: url,
48
+ ...qa,
49
+ author: authors.map((author) => ({
50
+ '@type': 'Person',
51
+ name: author.name,
52
+ ...(author.links[0] ? { url: author.links[0].url } : {}),
53
+ })),
54
+ ...(publisher
55
+ ? {
56
+ publisher: {
57
+ '@type': 'Organization',
58
+ name: publisher.name,
59
+ ...(publisher.logoUrl
60
+ ? { logo: { '@type': 'ImageObject', url: publisher.logoUrl } }
61
+ : {}),
62
+ },
63
+ }
64
+ : {}),
65
+ };
66
+ }
67
+ //# sourceMappingURL=jsonld.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonld.js","sourceRoot":"","sources":["../../../src/modules/seo/jsonld.ts"],"names":[],"mappings":"AAeA;;;;GAIG;AACH,MAAM,WAAW,GAA6B;IAC5C,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,SAAS;IACnB,UAAU,EAAE,SAAS;IACrB,YAAY,EAAE,SAAS;CACxB,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAqB,EACrB,OAAuB,EACvB,OAAe;AACf,kFAAkF;AAClF,eAAuB,EACvB,SAAwC;IAExC,MAAM,GAAG,GAAG,GAAG,OAAO,GAAG,eAAe,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,IAAI,SAAS,CAAC;IAC1F,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,aAAa,IAAI,SAAS,CAAC;IACjE,MAAM,EAAE,GACN,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,aAAa;QACxC,CAAC,CAAC;YACE,UAAU,EAAE;gBACV,OAAO,EAAE,UAAU;gBACnB,IAAI,EAAE,IAAI,CAAC,eAAe;gBAC1B,cAAc,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE;aAChE;SACF;QACH,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;QACL,UAAU,EAAE,oBAAoB;QAChC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAC/B,QAAQ,EAAE,IAAI,CAAC,KAAK;QACpB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,aAAa,EAAE,IAAI,CAAC,WAAW;QAC/B,YAAY,EAAE,IAAI,CAAC,WAAW;QAC9B,gBAAgB,EAAE,GAAG;QACrB,GAAG,EAAE;QACL,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC/B,OAAO,EAAE,QAAQ;YACjB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;QACH,GAAG,CAAC,SAAS;YACX,CAAC,CAAC;gBACE,SAAS,EAAE;oBACT,OAAO,EAAE,cAAc;oBACvB,IAAI,EAAE,SAAS,CAAC,IAAI;oBACpB,GAAG,CAAC,SAAS,CAAC,OAAO;wBACnB,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,EAAE,EAAE;wBAC9D,CAAC,CAAC,EAAE,CAAC;iBACR;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { Hono } from 'hono';
2
+ import { type Bindings } from '../../env.js';
3
+ export declare const seoPublicRoutes: Hono<{
4
+ Bindings: Bindings;
5
+ }, import("hono/types").BlankSchema, "/">;
6
+ //# sourceMappingURL=routes.public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.public.d.ts","sourceRoot":"","sources":["../../../src/modules/seo/routes.public.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI1D,eAAO,MAAM,eAAe;cAAwB,QAAQ;yCAAK,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { ok, resolveAllContentPaths } from '../../shared/index.js';
2
+ import { Hono } from 'hono';
3
+ import { getSettings } from '../../env.js';
4
+ import { corsMiddleware } from '../../middleware/cors.js';
5
+ import { buildSitemap } from './sitemap.js';
6
+ export const seoPublicRoutes = new Hono();
7
+ seoPublicRoutes.use('/sitemap.xml', corsMiddleware('publicRead'));
8
+ seoPublicRoutes.get('/sitemap.xml', async (c) => {
9
+ const xml = await buildSitemap(c.env.DB, c.env.SITE_URL);
10
+ return c.body(xml, 200, {
11
+ 'Content-Type': 'application/xml; charset=UTF-8',
12
+ 'Cache-Control': 'public, max-age=900',
13
+ });
14
+ });
15
+ seoPublicRoutes.use('/site', corsMiddleware('publicRead'));
16
+ /**
17
+ * The site's identity card: name, canonical URL, SEO fallbacks, publisher, and
18
+ * the content paths. This only stores and serves; the code-first merge, where
19
+ * a template's own values win and these fill the gaps, lives in @we8/astro.
20
+ * Deliberately NOT module-gated: a template needs it at build time regardless
21
+ * of which modules the site runs. Cached like the sitemap.
22
+ */
23
+ seoPublicRoutes.get('/site', async (c) => {
24
+ const settings = await getSettings(c.env.DB);
25
+ const site = {
26
+ name: settings.publisher?.name ?? null,
27
+ siteUrl: c.env.SITE_URL,
28
+ seo: settings.seo,
29
+ publisher: settings.publisher ?? null,
30
+ postsPathPrefix: settings.postsPathPrefix,
31
+ contentPaths: resolveAllContentPaths(settings),
32
+ // "" (unconfigured, the settings-side clear signal) must never leak as a
33
+ // truthy-looking empty string to templates; null is the honest absence.
34
+ gaMeasurementId: settings.gaMeasurementId || null,
35
+ brand: settings.brand,
36
+ };
37
+ return c.json(ok({ site }), 200, { 'Cache-Control': 'public, max-age=900' });
38
+ });
39
+ //# sourceMappingURL=routes.public.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.public.js","sourceRoot":"","sources":["../../../src/modules/seo/routes.public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,sBAAsB,EAAmB,MAAM,uBAAuB,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAiB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,IAAI,EAA0B,CAAC;AAElE,eAAe,CAAC,GAAG,CAAC,cAAc,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;AAElE,eAAe,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC9C,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzD,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;QACtB,cAAc,EAAE,gCAAgC;QAChD,eAAe,EAAE,qBAAqB;KACvC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;AAE3D;;;;;;GAMG;AACH,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACvC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAe;QACvB,IAAI,EAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,IAAI,IAAI;QACtC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ;QACvB,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,IAAI;QACrC,eAAe,EAAE,QAAQ,CAAC,eAAe;QACzC,YAAY,EAAE,sBAAsB,CAAC,QAAQ,CAAC;QAC9C,yEAAyE;QACzE,wEAAwE;QACxE,eAAe,EAAE,QAAQ,CAAC,eAAe,IAAI,IAAI;QACjD,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAC;IACF,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,qBAAqB,EAAE,CAAC,CAAC;AAC/E,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Published posts (cap 1000, lastmod from published_at) plus the configured static routes. */
2
+ export declare function buildSitemap(db: D1Database, siteUrl: string): Promise<string>;
3
+ //# sourceMappingURL=sitemap.d.ts.map