@htmless/core 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 (435) hide show
  1. package/dist/ai/content-operations.d.ts +26 -0
  2. package/dist/ai/content-operations.d.ts.map +1 -0
  3. package/dist/ai/content-operations.js +75 -0
  4. package/dist/ai/content-operations.js.map +1 -0
  5. package/dist/ai/image-analyzer.d.ts +18 -0
  6. package/dist/ai/image-analyzer.d.ts.map +1 -0
  7. package/dist/ai/image-analyzer.js +457 -0
  8. package/dist/ai/image-analyzer.js.map +1 -0
  9. package/dist/ai/json-to-schema.d.ts +6 -0
  10. package/dist/ai/json-to-schema.d.ts.map +1 -0
  11. package/dist/ai/json-to-schema.js +155 -0
  12. package/dist/ai/json-to-schema.js.map +1 -0
  13. package/dist/ai/schema-generator.d.ts +34 -0
  14. package/dist/ai/schema-generator.d.ts.map +1 -0
  15. package/dist/ai/schema-generator.js +307 -0
  16. package/dist/ai/schema-generator.js.map +1 -0
  17. package/dist/api/cda/assets.d.ts +4 -0
  18. package/dist/api/cda/assets.d.ts.map +1 -0
  19. package/dist/api/cda/assets.js +82 -0
  20. package/dist/api/cda/assets.js.map +1 -0
  21. package/dist/api/cda/blocks.d.ts +4 -0
  22. package/dist/api/cda/blocks.d.ts.map +1 -0
  23. package/dist/api/cda/blocks.js +92 -0
  24. package/dist/api/cda/blocks.js.map +1 -0
  25. package/dist/api/cda/content.d.ts +4 -0
  26. package/dist/api/cda/content.d.ts.map +1 -0
  27. package/dist/api/cda/content.js +192 -0
  28. package/dist/api/cda/content.js.map +1 -0
  29. package/dist/api/cda/index.d.ts +4 -0
  30. package/dist/api/cda/index.d.ts.map +1 -0
  31. package/dist/api/cda/index.js +21 -0
  32. package/dist/api/cda/index.js.map +1 -0
  33. package/dist/api/cda/media.d.ts +4 -0
  34. package/dist/api/cda/media.d.ts.map +1 -0
  35. package/dist/api/cda/media.js +114 -0
  36. package/dist/api/cda/media.js.map +1 -0
  37. package/dist/api/cda/redirects.d.ts +4 -0
  38. package/dist/api/cda/redirects.d.ts.map +1 -0
  39. package/dist/api/cda/redirects.js +69 -0
  40. package/dist/api/cda/redirects.js.map +1 -0
  41. package/dist/api/cda/schemas.d.ts +4 -0
  42. package/dist/api/cda/schemas.d.ts.map +1 -0
  43. package/dist/api/cda/schemas.js +113 -0
  44. package/dist/api/cda/schemas.js.map +1 -0
  45. package/dist/api/cda/taxonomies.d.ts +4 -0
  46. package/dist/api/cda/taxonomies.d.ts.map +1 -0
  47. package/dist/api/cda/taxonomies.js +79 -0
  48. package/dist/api/cda/taxonomies.js.map +1 -0
  49. package/dist/api/cma/ai.d.ts +4 -0
  50. package/dist/api/cma/ai.d.ts.map +1 -0
  51. package/dist/api/cma/ai.js +458 -0
  52. package/dist/api/cma/ai.js.map +1 -0
  53. package/dist/api/cma/assets.d.ts +4 -0
  54. package/dist/api/cma/assets.d.ts.map +1 -0
  55. package/dist/api/cma/assets.js +166 -0
  56. package/dist/api/cma/assets.js.map +1 -0
  57. package/dist/api/cma/audit.d.ts +4 -0
  58. package/dist/api/cma/audit.d.ts.map +1 -0
  59. package/dist/api/cma/audit.js +74 -0
  60. package/dist/api/cma/audit.js.map +1 -0
  61. package/dist/api/cma/auth.d.ts +4 -0
  62. package/dist/api/cma/auth.d.ts.map +1 -0
  63. package/dist/api/cma/auth.js +123 -0
  64. package/dist/api/cma/auth.js.map +1 -0
  65. package/dist/api/cma/blocks.d.ts +4 -0
  66. package/dist/api/cma/blocks.d.ts.map +1 -0
  67. package/dist/api/cma/blocks.js +249 -0
  68. package/dist/api/cma/blocks.js.map +1 -0
  69. package/dist/api/cma/bulk.d.ts +4 -0
  70. package/dist/api/cma/bulk.d.ts.map +1 -0
  71. package/dist/api/cma/bulk.js +258 -0
  72. package/dist/api/cma/bulk.js.map +1 -0
  73. package/dist/api/cma/cache.d.ts +4 -0
  74. package/dist/api/cma/cache.d.ts.map +1 -0
  75. package/dist/api/cma/cache.js +99 -0
  76. package/dist/api/cma/cache.js.map +1 -0
  77. package/dist/api/cma/codegen.d.ts +4 -0
  78. package/dist/api/cma/codegen.d.ts.map +1 -0
  79. package/dist/api/cma/codegen.js +22 -0
  80. package/dist/api/cma/codegen.js.map +1 -0
  81. package/dist/api/cma/comments.d.ts +4 -0
  82. package/dist/api/cma/comments.d.ts.map +1 -0
  83. package/dist/api/cma/comments.js +164 -0
  84. package/dist/api/cma/comments.js.map +1 -0
  85. package/dist/api/cma/diff.d.ts +4 -0
  86. package/dist/api/cma/diff.d.ts.map +1 -0
  87. package/dist/api/cma/diff.js +88 -0
  88. package/dist/api/cma/diff.js.map +1 -0
  89. package/dist/api/cma/entries.d.ts +4 -0
  90. package/dist/api/cma/entries.d.ts.map +1 -0
  91. package/dist/api/cma/entries.js +736 -0
  92. package/dist/api/cma/entries.js.map +1 -0
  93. package/dist/api/cma/environments.d.ts +4 -0
  94. package/dist/api/cma/environments.d.ts.map +1 -0
  95. package/dist/api/cma/environments.js +160 -0
  96. package/dist/api/cma/environments.js.map +1 -0
  97. package/dist/api/cma/extensions.d.ts +4 -0
  98. package/dist/api/cma/extensions.d.ts.map +1 -0
  99. package/dist/api/cma/extensions.js +82 -0
  100. package/dist/api/cma/extensions.js.map +1 -0
  101. package/dist/api/cma/importexport.d.ts +4 -0
  102. package/dist/api/cma/importexport.d.ts.map +1 -0
  103. package/dist/api/cma/importexport.js +496 -0
  104. package/dist/api/cma/importexport.js.map +1 -0
  105. package/dist/api/cma/index.d.ts +4 -0
  106. package/dist/api/cma/index.d.ts.map +1 -0
  107. package/dist/api/cma/index.js +69 -0
  108. package/dist/api/cma/index.js.map +1 -0
  109. package/dist/api/cma/live.d.ts +4 -0
  110. package/dist/api/cma/live.d.ts.map +1 -0
  111. package/dist/api/cma/live.js +64 -0
  112. package/dist/api/cma/live.js.map +1 -0
  113. package/dist/api/cma/locales.d.ts +4 -0
  114. package/dist/api/cma/locales.d.ts.map +1 -0
  115. package/dist/api/cma/locales.js +117 -0
  116. package/dist/api/cma/locales.js.map +1 -0
  117. package/dist/api/cma/marketplace.d.ts +4 -0
  118. package/dist/api/cma/marketplace.d.ts.map +1 -0
  119. package/dist/api/cma/marketplace.js +550 -0
  120. package/dist/api/cma/marketplace.js.map +1 -0
  121. package/dist/api/cma/redirects.d.ts +4 -0
  122. package/dist/api/cma/redirects.d.ts.map +1 -0
  123. package/dist/api/cma/redirects.js +120 -0
  124. package/dist/api/cma/redirects.js.map +1 -0
  125. package/dist/api/cma/relationships.d.ts +4 -0
  126. package/dist/api/cma/relationships.d.ts.map +1 -0
  127. package/dist/api/cma/relationships.js +47 -0
  128. package/dist/api/cma/relationships.js.map +1 -0
  129. package/dist/api/cma/schemas.d.ts +4 -0
  130. package/dist/api/cma/schemas.d.ts.map +1 -0
  131. package/dist/api/cma/schemas.js +248 -0
  132. package/dist/api/cma/schemas.js.map +1 -0
  133. package/dist/api/cma/search.d.ts +4 -0
  134. package/dist/api/cma/search.d.ts.map +1 -0
  135. package/dist/api/cma/search.js +149 -0
  136. package/dist/api/cma/search.js.map +1 -0
  137. package/dist/api/cma/spaces.d.ts +4 -0
  138. package/dist/api/cma/spaces.d.ts.map +1 -0
  139. package/dist/api/cma/spaces.js +119 -0
  140. package/dist/api/cma/spaces.js.map +1 -0
  141. package/dist/api/cma/taxonomies.d.ts +4 -0
  142. package/dist/api/cma/taxonomies.d.ts.map +1 -0
  143. package/dist/api/cma/taxonomies.js +296 -0
  144. package/dist/api/cma/taxonomies.js.map +1 -0
  145. package/dist/api/cma/templates.d.ts +13 -0
  146. package/dist/api/cma/templates.d.ts.map +1 -0
  147. package/dist/api/cma/templates.js +312 -0
  148. package/dist/api/cma/templates.js.map +1 -0
  149. package/dist/api/cma/uploads.d.ts +4 -0
  150. package/dist/api/cma/uploads.d.ts.map +1 -0
  151. package/dist/api/cma/uploads.js +148 -0
  152. package/dist/api/cma/uploads.js.map +1 -0
  153. package/dist/api/cma/webhooks.d.ts +4 -0
  154. package/dist/api/cma/webhooks.d.ts.map +1 -0
  155. package/dist/api/cma/webhooks.js +175 -0
  156. package/dist/api/cma/webhooks.js.map +1 -0
  157. package/dist/api/cma/white-label.d.ts +4 -0
  158. package/dist/api/cma/white-label.d.ts.map +1 -0
  159. package/dist/api/cma/white-label.js +47 -0
  160. package/dist/api/cma/white-label.js.map +1 -0
  161. package/dist/api/graphql/index.d.ts +4 -0
  162. package/dist/api/graphql/index.d.ts.map +1 -0
  163. package/dist/api/graphql/index.js +57 -0
  164. package/dist/api/graphql/index.js.map +1 -0
  165. package/dist/api/graphql/introspection.d.ts +31 -0
  166. package/dist/api/graphql/introspection.d.ts.map +1 -0
  167. package/dist/api/graphql/introspection.js +90 -0
  168. package/dist/api/graphql/introspection.js.map +1 -0
  169. package/dist/api/graphql/parser.d.ts +14 -0
  170. package/dist/api/graphql/parser.d.ts.map +1 -0
  171. package/dist/api/graphql/parser.js +140 -0
  172. package/dist/api/graphql/parser.js.map +1 -0
  173. package/dist/api/graphql/resolver.d.ts +3 -0
  174. package/dist/api/graphql/resolver.d.ts.map +1 -0
  175. package/dist/api/graphql/resolver.js +138 -0
  176. package/dist/api/graphql/resolver.js.map +1 -0
  177. package/dist/api/preview/content.d.ts +4 -0
  178. package/dist/api/preview/content.d.ts.map +1 -0
  179. package/dist/api/preview/content.js +207 -0
  180. package/dist/api/preview/content.js.map +1 -0
  181. package/dist/api/preview/index.d.ts +4 -0
  182. package/dist/api/preview/index.d.ts.map +1 -0
  183. package/dist/api/preview/index.js +11 -0
  184. package/dist/api/preview/index.js.map +1 -0
  185. package/dist/api/preview/live.d.ts +4 -0
  186. package/dist/api/preview/live.d.ts.map +1 -0
  187. package/dist/api/preview/live.js +41 -0
  188. package/dist/api/preview/live.js.map +1 -0
  189. package/dist/audit/logger.d.ts +13 -0
  190. package/dist/audit/logger.d.ts.map +1 -0
  191. package/dist/audit/logger.js +21 -0
  192. package/dist/audit/logger.js.map +1 -0
  193. package/dist/audit/middleware.d.ts +7 -0
  194. package/dist/audit/middleware.d.ts.map +1 -0
  195. package/dist/audit/middleware.js +39 -0
  196. package/dist/audit/middleware.js.map +1 -0
  197. package/dist/auth/jwt.d.ts +9 -0
  198. package/dist/auth/jwt.d.ts.map +1 -0
  199. package/dist/auth/jwt.js +15 -0
  200. package/dist/auth/jwt.js.map +1 -0
  201. package/dist/auth/middleware.d.ts +24 -0
  202. package/dist/auth/middleware.d.ts.map +1 -0
  203. package/dist/auth/middleware.js +99 -0
  204. package/dist/auth/middleware.js.map +1 -0
  205. package/dist/auth/password.d.ts +3 -0
  206. package/dist/auth/password.d.ts.map +1 -0
  207. package/dist/auth/password.js +9 -0
  208. package/dist/auth/password.js.map +1 -0
  209. package/dist/auth/rate-limit.d.ts +19 -0
  210. package/dist/auth/rate-limit.d.ts.map +1 -0
  211. package/dist/auth/rate-limit.js +77 -0
  212. package/dist/auth/rate-limit.js.map +1 -0
  213. package/dist/auth/rbac.d.ts +10 -0
  214. package/dist/auth/rbac.d.ts.map +1 -0
  215. package/dist/auth/rbac.js +61 -0
  216. package/dist/auth/rbac.js.map +1 -0
  217. package/dist/blocks/core-blocks.d.ts +13 -0
  218. package/dist/blocks/core-blocks.d.ts.map +1 -0
  219. package/dist/blocks/core-blocks.js +113 -0
  220. package/dist/blocks/core-blocks.js.map +1 -0
  221. package/dist/blocks/renderer-sdk.d.ts +75 -0
  222. package/dist/blocks/renderer-sdk.d.ts.map +1 -0
  223. package/dist/blocks/renderer-sdk.js +112 -0
  224. package/dist/blocks/renderer-sdk.js.map +1 -0
  225. package/dist/blocks/seed-core-blocks.d.ts +6 -0
  226. package/dist/blocks/seed-core-blocks.d.ts.map +1 -0
  227. package/dist/blocks/seed-core-blocks.js +37 -0
  228. package/dist/blocks/seed-core-blocks.js.map +1 -0
  229. package/dist/blocks/validator.d.ts +10 -0
  230. package/dist/blocks/validator.d.ts.map +1 -0
  231. package/dist/blocks/validator.js +111 -0
  232. package/dist/blocks/validator.js.map +1 -0
  233. package/dist/cache/cdn-purge.d.ts +41 -0
  234. package/dist/cache/cdn-purge.d.ts.map +1 -0
  235. package/dist/cache/cdn-purge.js +180 -0
  236. package/dist/cache/cdn-purge.js.map +1 -0
  237. package/dist/cache/observability.d.ts +36 -0
  238. package/dist/cache/observability.d.ts.map +1 -0
  239. package/dist/cache/observability.js +110 -0
  240. package/dist/cache/observability.js.map +1 -0
  241. package/dist/cache/tags.d.ts +28 -0
  242. package/dist/cache/tags.d.ts.map +1 -0
  243. package/dist/cache/tags.js +94 -0
  244. package/dist/cache/tags.js.map +1 -0
  245. package/dist/cli/commands/codegen.d.ts +2 -0
  246. package/dist/cli/commands/codegen.d.ts.map +1 -0
  247. package/dist/cli/commands/codegen.js +73 -0
  248. package/dist/cli/commands/codegen.js.map +1 -0
  249. package/dist/cli/commands/dev.d.ts +2 -0
  250. package/dist/cli/commands/dev.d.ts.map +1 -0
  251. package/dist/cli/commands/dev.js +60 -0
  252. package/dist/cli/commands/dev.js.map +1 -0
  253. package/dist/cli/commands/help.d.ts +2 -0
  254. package/dist/cli/commands/help.d.ts.map +1 -0
  255. package/dist/cli/commands/help.js +32 -0
  256. package/dist/cli/commands/help.js.map +1 -0
  257. package/dist/cli/commands/init.d.ts +2 -0
  258. package/dist/cli/commands/init.d.ts.map +1 -0
  259. package/dist/cli/commands/init.js +90 -0
  260. package/dist/cli/commands/init.js.map +1 -0
  261. package/dist/cli/commands/migrate.d.ts +2 -0
  262. package/dist/cli/commands/migrate.d.ts.map +1 -0
  263. package/dist/cli/commands/migrate.js +27 -0
  264. package/dist/cli/commands/migrate.js.map +1 -0
  265. package/dist/cli/commands/seed.d.ts +2 -0
  266. package/dist/cli/commands/seed.d.ts.map +1 -0
  267. package/dist/cli/commands/seed.js +28 -0
  268. package/dist/cli/commands/seed.js.map +1 -0
  269. package/dist/cli/index.d.ts +16 -0
  270. package/dist/cli/index.d.ts.map +1 -0
  271. package/dist/cli/index.js +120 -0
  272. package/dist/cli/index.js.map +1 -0
  273. package/dist/config.d.ts +11 -0
  274. package/dist/config.d.ts.map +1 -0
  275. package/dist/config.js +11 -0
  276. package/dist/config.js.map +1 -0
  277. package/dist/content/advanced-query.d.ts +37 -0
  278. package/dist/content/advanced-query.d.ts.map +1 -0
  279. package/dist/content/advanced-query.js +162 -0
  280. package/dist/content/advanced-query.js.map +1 -0
  281. package/dist/content/cache.d.ts +27 -0
  282. package/dist/content/cache.d.ts.map +1 -0
  283. package/dist/content/cache.js +100 -0
  284. package/dist/content/cache.js.map +1 -0
  285. package/dist/content/diff.d.ts +13 -0
  286. package/dist/content/diff.d.ts.map +1 -0
  287. package/dist/content/diff.js +80 -0
  288. package/dist/content/diff.js.map +1 -0
  289. package/dist/content/localization.d.ts +13 -0
  290. package/dist/content/localization.d.ts.map +1 -0
  291. package/dist/content/localization.js +42 -0
  292. package/dist/content/localization.js.map +1 -0
  293. package/dist/content/materializer.d.ts +26 -0
  294. package/dist/content/materializer.d.ts.map +1 -0
  295. package/dist/content/materializer.js +175 -0
  296. package/dist/content/materializer.js.map +1 -0
  297. package/dist/content/relationships.d.ts +30 -0
  298. package/dist/content/relationships.d.ts.map +1 -0
  299. package/dist/content/relationships.js +123 -0
  300. package/dist/content/relationships.js.map +1 -0
  301. package/dist/db.d.ts +5 -0
  302. package/dist/db.d.ts.map +1 -0
  303. package/dist/db.js +5 -0
  304. package/dist/db.js.map +1 -0
  305. package/dist/events/emitter.d.ts +16 -0
  306. package/dist/events/emitter.d.ts.map +1 -0
  307. package/dist/events/emitter.js +15 -0
  308. package/dist/events/emitter.js.map +1 -0
  309. package/dist/events/sse.d.ts +16 -0
  310. package/dist/events/sse.d.ts.map +1 -0
  311. package/dist/events/sse.js +37 -0
  312. package/dist/events/sse.js.map +1 -0
  313. package/dist/events/wire.d.ts +2 -0
  314. package/dist/events/wire.d.ts.map +1 -0
  315. package/dist/events/wire.js +27 -0
  316. package/dist/events/wire.js.map +1 -0
  317. package/dist/extensions/billing.d.ts +60 -0
  318. package/dist/extensions/billing.d.ts.map +1 -0
  319. package/dist/extensions/billing.js +98 -0
  320. package/dist/extensions/billing.js.map +1 -0
  321. package/dist/extensions/manifest.d.ts +43 -0
  322. package/dist/extensions/manifest.d.ts.map +1 -0
  323. package/dist/extensions/manifest.js +66 -0
  324. package/dist/extensions/manifest.js.map +1 -0
  325. package/dist/extensions/marketplace.d.ts +50 -0
  326. package/dist/extensions/marketplace.d.ts.map +1 -0
  327. package/dist/extensions/marketplace.js +676 -0
  328. package/dist/extensions/marketplace.js.map +1 -0
  329. package/dist/extensions/router.d.ts +4 -0
  330. package/dist/extensions/router.d.ts.map +1 -0
  331. package/dist/extensions/router.js +50 -0
  332. package/dist/extensions/router.js.map +1 -0
  333. package/dist/extensions/runtime.d.ts +29 -0
  334. package/dist/extensions/runtime.d.ts.map +1 -0
  335. package/dist/extensions/runtime.js +201 -0
  336. package/dist/extensions/runtime.js.map +1 -0
  337. package/dist/extensions/sdk.d.ts +146 -0
  338. package/dist/extensions/sdk.d.ts.map +1 -0
  339. package/dist/extensions/sdk.js +114 -0
  340. package/dist/extensions/sdk.js.map +1 -0
  341. package/dist/integrations/sheets.d.ts +41 -0
  342. package/dist/integrations/sheets.d.ts.map +1 -0
  343. package/dist/integrations/sheets.js +230 -0
  344. package/dist/integrations/sheets.js.map +1 -0
  345. package/dist/media/metadata.d.ts +9 -0
  346. package/dist/media/metadata.d.ts.map +1 -0
  347. package/dist/media/metadata.js +84 -0
  348. package/dist/media/metadata.js.map +1 -0
  349. package/dist/media/presets.d.ts +17 -0
  350. package/dist/media/presets.d.ts.map +1 -0
  351. package/dist/media/presets.js +21 -0
  352. package/dist/media/presets.js.map +1 -0
  353. package/dist/media/storage.d.ts +16 -0
  354. package/dist/media/storage.d.ts.map +1 -0
  355. package/dist/media/storage.js +39 -0
  356. package/dist/media/storage.js.map +1 -0
  357. package/dist/media/transforms-engine.d.ts +46 -0
  358. package/dist/media/transforms-engine.d.ts.map +1 -0
  359. package/dist/media/transforms-engine.js +91 -0
  360. package/dist/media/transforms-engine.js.map +1 -0
  361. package/dist/media/transforms.d.ts +15 -0
  362. package/dist/media/transforms.d.ts.map +1 -0
  363. package/dist/media/transforms.js +22 -0
  364. package/dist/media/transforms.js.map +1 -0
  365. package/dist/media/usage.d.ts +21 -0
  366. package/dist/media/usage.d.ts.map +1 -0
  367. package/dist/media/usage.js +105 -0
  368. package/dist/media/usage.js.map +1 -0
  369. package/dist/redis.d.ts +2 -0
  370. package/dist/redis.d.ts.map +1 -0
  371. package/dist/redis.js +9 -0
  372. package/dist/redis.js.map +1 -0
  373. package/dist/schema/codegen.d.ts +6 -0
  374. package/dist/schema/codegen.d.ts.map +1 -0
  375. package/dist/schema/codegen.js +95 -0
  376. package/dist/schema/codegen.js.map +1 -0
  377. package/dist/schema/json-schema.d.ts +42 -0
  378. package/dist/schema/json-schema.d.ts.map +1 -0
  379. package/dist/schema/json-schema.js +68 -0
  380. package/dist/schema/json-schema.js.map +1 -0
  381. package/dist/schema/validator.d.ts +14 -0
  382. package/dist/schema/validator.d.ts.map +1 -0
  383. package/dist/schema/validator.js +103 -0
  384. package/dist/schema/validator.js.map +1 -0
  385. package/dist/sdk/client.d.ts +86 -0
  386. package/dist/sdk/client.d.ts.map +1 -0
  387. package/dist/sdk/client.js +117 -0
  388. package/dist/sdk/client.js.map +1 -0
  389. package/dist/server.d.ts +2 -0
  390. package/dist/server.d.ts.map +1 -0
  391. package/dist/server.js +59 -0
  392. package/dist/server.js.map +1 -0
  393. package/dist/spaces/premium-templates.d.ts +37 -0
  394. package/dist/spaces/premium-templates.d.ts.map +1 -0
  395. package/dist/spaces/premium-templates.js +1603 -0
  396. package/dist/spaces/premium-templates.js.map +1 -0
  397. package/dist/spaces/provisioner.d.ts +16 -0
  398. package/dist/spaces/provisioner.d.ts.map +1 -0
  399. package/dist/spaces/provisioner.js +143 -0
  400. package/dist/spaces/provisioner.js.map +1 -0
  401. package/dist/spaces/template-registry.d.ts +34 -0
  402. package/dist/spaces/template-registry.d.ts.map +1 -0
  403. package/dist/spaces/template-registry.js +55 -0
  404. package/dist/spaces/template-registry.js.map +1 -0
  405. package/dist/spaces/templates.d.ts +44 -0
  406. package/dist/spaces/templates.d.ts.map +1 -0
  407. package/dist/spaces/templates.js +201 -0
  408. package/dist/spaces/templates.js.map +1 -0
  409. package/dist/spaces/white-label.d.ts +20 -0
  410. package/dist/spaces/white-label.d.ts.map +1 -0
  411. package/dist/spaces/white-label.js +32 -0
  412. package/dist/spaces/white-label.js.map +1 -0
  413. package/dist/utils/query-shaping.d.ts +27 -0
  414. package/dist/utils/query-shaping.d.ts.map +1 -0
  415. package/dist/utils/query-shaping.js +69 -0
  416. package/dist/utils/query-shaping.js.map +1 -0
  417. package/dist/utils/space.d.ts +4 -0
  418. package/dist/utils/space.d.ts.map +1 -0
  419. package/dist/utils/space.js +17 -0
  420. package/dist/utils/space.js.map +1 -0
  421. package/dist/webhooks/dispatcher.d.ts +9 -0
  422. package/dist/webhooks/dispatcher.d.ts.map +1 -0
  423. package/dist/webhooks/dispatcher.js +102 -0
  424. package/dist/webhooks/dispatcher.js.map +1 -0
  425. package/package.json +84 -0
  426. package/prisma/migrations/20260403025542_init/migration.sql +315 -0
  427. package/prisma/migrations/20260403034855_add_blocks_and_patterns/migration.sql +40 -0
  428. package/prisma/migrations/20260403041936_add_published_documents/migration.sql +30 -0
  429. package/prisma/migrations/20260403042809_add_locales_and_taxonomies/migration.sql +58 -0
  430. package/prisma/migrations/20260403043033_add_scheduled_unpublish_at/migration.sql +2 -0
  431. package/prisma/migrations/20260403052801_add_environments_and_whitelabel/migration.sql +65 -0
  432. package/prisma/migrations/20260403055920_add_marketplace_and_extension_config/migration.sql +73 -0
  433. package/prisma/migrations/migration_lock.toml +3 -0
  434. package/prisma/schema.prisma +530 -0
  435. package/prisma/seed.ts +154 -0
@@ -0,0 +1,1603 @@
1
+ /**
2
+ * Premium / paid template starters for the HTMLess marketplace.
3
+ *
4
+ * Each premium template extends the base Template type with pricing,
5
+ * a features list, and — critically — sample entries with realistic
6
+ * block-based body content so a space is immediately useful.
7
+ */
8
+ // ─── Helper: shorthand field builder ────────────────────────────────
9
+ let _order = 0;
10
+ function f(key, name, type, opts = {}) {
11
+ const field = { key, name, type, sortOrder: _order++, ...opts };
12
+ return field;
13
+ }
14
+ function resetOrder() { _order = 0; }
15
+ // ─── Block helpers ──────────────────────────────────────────────────
16
+ function heading(level, text) {
17
+ return { type: 'heading', attrs: { level, text } };
18
+ }
19
+ function paragraph(text) {
20
+ return { type: 'paragraph', attrs: { text } };
21
+ }
22
+ function image(src, alt) {
23
+ return { type: 'image', attrs: { src, alt } };
24
+ }
25
+ function codeBlock(language, code) {
26
+ return { type: 'code', attrs: { language, code } };
27
+ }
28
+ function callout(variant, text) {
29
+ return { type: 'callout', attrs: { variant, text } };
30
+ }
31
+ function list(ordered, items) {
32
+ return { type: 'list', attrs: { ordered, items } };
33
+ }
34
+ // ═══════════════════════════════════════════════════════════════════
35
+ // 1. SaaS Boilerplate ($99)
36
+ // ═══════════════════════════════════════════════════════════════════
37
+ resetOrder();
38
+ const saasBoilerplateContentTypes = [
39
+ {
40
+ key: 'page',
41
+ name: 'Page',
42
+ description: 'Marketing and landing pages with hero sections, feature grids, and CTAs',
43
+ fields: [
44
+ f('title', 'Title', 'text', { required: true, localized: true }),
45
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
46
+ f('hero', 'Hero Section', 'json', { localized: true }),
47
+ f('featuresList', 'Features List', 'json', { localized: true }),
48
+ f('cta', 'Call to Action', 'json', { localized: true }),
49
+ f('body', 'Body', 'richtext', { localized: true }),
50
+ f('metaTitle', 'Meta Title', 'text', { localized: true }),
51
+ f('metaDescription', 'Meta Description', 'text', { localized: true }),
52
+ ],
53
+ },
54
+ (() => {
55
+ resetOrder();
56
+ return {
57
+ key: 'feature',
58
+ name: 'Feature',
59
+ description: 'Individual product features displayed on landing pages',
60
+ fields: [
61
+ f('title', 'Title', 'text', { required: true, localized: true }),
62
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
63
+ f('description', 'Description', 'richtext', { required: true, localized: true }),
64
+ f('icon', 'Icon', 'text'),
65
+ f('category', 'Category', 'text'),
66
+ f('order', 'Order', 'number'),
67
+ ],
68
+ };
69
+ })(),
70
+ (() => {
71
+ resetOrder();
72
+ return {
73
+ key: 'pricing-plan',
74
+ name: 'Pricing Plan',
75
+ description: 'Subscription tiers with feature breakdowns',
76
+ fields: [
77
+ f('name', 'Name', 'text', { required: true, localized: true }),
78
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
79
+ f('price', 'Price', 'number', { required: true }),
80
+ f('interval', 'Billing Interval', 'enum', { enumValues: ['monthly', 'yearly'] }),
81
+ f('features', 'Features', 'json', { localized: true }),
82
+ f('highlighted', 'Highlighted', 'boolean'),
83
+ f('order', 'Order', 'number'),
84
+ ],
85
+ };
86
+ })(),
87
+ (() => {
88
+ resetOrder();
89
+ return {
90
+ key: 'testimonial',
91
+ name: 'Testimonial',
92
+ description: 'Customer testimonials and social proof',
93
+ fields: [
94
+ f('author', 'Author', 'text', { required: true }),
95
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
96
+ f('role', 'Role', 'text'),
97
+ f('company', 'Company', 'text'),
98
+ f('quote', 'Quote', 'text', { required: true, localized: true }),
99
+ f('avatar', 'Avatar', 'media'),
100
+ f('order', 'Order', 'number'),
101
+ ],
102
+ };
103
+ })(),
104
+ (() => {
105
+ resetOrder();
106
+ return {
107
+ key: 'faq',
108
+ name: 'FAQ',
109
+ description: 'Frequently asked questions grouped by category',
110
+ fields: [
111
+ f('question', 'Question', 'text', { required: true, localized: true }),
112
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
113
+ f('answer', 'Answer', 'richtext', { required: true, localized: true }),
114
+ f('category', 'Category', 'text'),
115
+ f('order', 'Order', 'number'),
116
+ ],
117
+ };
118
+ })(),
119
+ (() => {
120
+ resetOrder();
121
+ return {
122
+ key: 'changelog',
123
+ name: 'Changelog',
124
+ description: 'Product release notes and version history',
125
+ fields: [
126
+ f('version', 'Version', 'text', { required: true }),
127
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
128
+ f('date', 'Date', 'date', { required: true }),
129
+ f('entries', 'Entries', 'json', { required: true }),
130
+ f('body', 'Body', 'richtext', { localized: true }),
131
+ ],
132
+ };
133
+ })(),
134
+ (() => {
135
+ resetOrder();
136
+ return {
137
+ key: 'blog-post',
138
+ name: 'Blog Post',
139
+ description: 'Company blog posts and thought leadership',
140
+ fields: [
141
+ f('title', 'Title', 'text', { required: true, localized: true }),
142
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
143
+ f('body', 'Body', 'richtext', { required: true, localized: true }),
144
+ f('author', 'Author', 'text'),
145
+ f('image', 'Featured Image', 'media'),
146
+ f('category', 'Category', 'text'),
147
+ f('publishedDate', 'Published Date', 'date'),
148
+ ],
149
+ };
150
+ })(),
151
+ ];
152
+ const saasBoilerplateTaxonomies = [
153
+ { key: 'page-section', name: 'Page Section', hierarchical: true },
154
+ { key: 'feature-category', name: 'Feature Category' },
155
+ { key: 'faq-category', name: 'FAQ Category' },
156
+ { key: 'blog-category', name: 'Blog Category' },
157
+ ];
158
+ const saasBoilerplateEntries = [
159
+ // ── Pages ──
160
+ {
161
+ contentTypeKey: 'page',
162
+ slug: 'home',
163
+ data: {
164
+ title: { en: 'Ship Faster with Acme Platform', es: 'Lanza mas rapido con Acme Platform' },
165
+ hero: {
166
+ en: { headline: 'Ship Faster with Acme Platform', subheadline: 'The all-in-one platform that helps product teams build, iterate, and deploy 10x faster.', ctaText: 'Start Free Trial', ctaLink: '/signup' },
167
+ es: { headline: 'Lanza mas rapido con Acme Platform', subheadline: 'La plataforma todo-en-uno que ayuda a equipos de producto a construir, iterar y desplegar 10x mas rapido.', ctaText: 'Prueba Gratis', ctaLink: '/signup' },
168
+ },
169
+ featuresList: {
170
+ en: ['Real-time collaboration', 'One-click deployments', 'Built-in analytics', 'Enterprise SSO'],
171
+ es: ['Colaboracion en tiempo real', 'Despliegues con un clic', 'Analitica integrada', 'SSO empresarial'],
172
+ },
173
+ cta: { en: { text: 'Get started for free', link: '/signup' }, es: { text: 'Comienza gratis', link: '/signup' } },
174
+ body: [
175
+ heading(1, 'Why teams choose Acme'),
176
+ paragraph('Over 2,000 companies rely on Acme to power their product development workflow. From startups to Fortune 500 enterprises, our platform scales with your ambitions.'),
177
+ ],
178
+ metaTitle: { en: 'Acme Platform — Ship Software Faster', es: 'Acme Platform — Lanza Software Mas Rapido' },
179
+ metaDescription: { en: 'The all-in-one platform for product teams. Build, iterate, and deploy 10x faster with real-time collaboration and one-click deployments.', es: 'La plataforma todo-en-uno para equipos de producto.' },
180
+ },
181
+ },
182
+ {
183
+ contentTypeKey: 'page',
184
+ slug: 'about',
185
+ data: {
186
+ title: { en: 'About Us', es: 'Sobre Nosotros' },
187
+ body: [
188
+ heading(1, 'Our Story'),
189
+ paragraph('Acme was founded in 2022 by a team of engineers frustrated with fragmented toolchains. We believed product teams deserved a single, cohesive platform that just works.'),
190
+ heading(2, 'Our Mission'),
191
+ paragraph('We are on a mission to eliminate the friction between idea and production. Every feature we build is guided by a simple question: does this help teams ship faster?'),
192
+ heading(2, 'The Team'),
193
+ paragraph('We are a distributed team of 45 across San Francisco, London, and Tokyo, backed by $32M in Series B funding from Sequoia Capital and Accel Partners.'),
194
+ ],
195
+ metaTitle: { en: 'About Acme Platform', es: 'Sobre Acme Platform' },
196
+ },
197
+ },
198
+ {
199
+ contentTypeKey: 'page',
200
+ slug: 'pricing',
201
+ data: {
202
+ title: { en: 'Simple, Transparent Pricing', es: 'Precios Simples y Transparentes' },
203
+ body: [
204
+ heading(1, 'Choose the plan that fits your team'),
205
+ paragraph('All plans include a 14-day free trial. No credit card required. Upgrade, downgrade, or cancel at any time.'),
206
+ ],
207
+ metaTitle: { en: 'Pricing — Acme Platform', es: 'Precios — Acme Platform' },
208
+ },
209
+ },
210
+ // ── Features ──
211
+ {
212
+ contentTypeKey: 'feature',
213
+ slug: 'real-time-collaboration',
214
+ data: {
215
+ title: { en: 'Real-Time Collaboration', es: 'Colaboracion en Tiempo Real' },
216
+ description: { en: 'See changes as they happen. Multiple team members can edit simultaneously with conflict-free resolution.', es: 'Ve los cambios mientras ocurren. Varios miembros pueden editar simultaneamente.' },
217
+ icon: 'users',
218
+ category: 'collaboration',
219
+ order: 1,
220
+ },
221
+ },
222
+ {
223
+ contentTypeKey: 'feature',
224
+ slug: 'one-click-deploy',
225
+ data: {
226
+ title: { en: 'One-Click Deployments', es: 'Despliegues con Un Clic' },
227
+ description: { en: 'Push to production in seconds. Automatic rollbacks, blue-green deployments, and real-time logs included.', es: 'Despliega a produccion en segundos. Rollbacks automaticos y logs en tiempo real incluidos.' },
228
+ icon: 'rocket',
229
+ category: 'deployment',
230
+ order: 2,
231
+ },
232
+ },
233
+ {
234
+ contentTypeKey: 'feature',
235
+ slug: 'built-in-analytics',
236
+ data: {
237
+ title: { en: 'Built-In Analytics', es: 'Analitica Integrada' },
238
+ description: { en: 'Track performance metrics, user behavior, and business KPIs without third-party scripts. Privacy-first by design.', es: 'Rastrea metricas de rendimiento y comportamiento de usuarios sin scripts de terceros.' },
239
+ icon: 'chart-bar',
240
+ category: 'analytics',
241
+ order: 3,
242
+ },
243
+ },
244
+ {
245
+ contentTypeKey: 'feature',
246
+ slug: 'enterprise-sso',
247
+ data: {
248
+ title: { en: 'Enterprise SSO', es: 'SSO Empresarial' },
249
+ description: { en: 'SAML 2.0 and OpenID Connect support with automated user provisioning via SCIM. SOC 2 Type II compliant.', es: 'Soporte para SAML 2.0 y OpenID Connect con aprovisionamiento automatico.' },
250
+ icon: 'shield-check',
251
+ category: 'security',
252
+ order: 4,
253
+ },
254
+ },
255
+ {
256
+ contentTypeKey: 'feature',
257
+ slug: 'api-first',
258
+ data: {
259
+ title: { en: 'API-First Architecture', es: 'Arquitectura API-First' },
260
+ description: { en: 'Every feature is accessible via our REST and GraphQL APIs. Build custom integrations and automate workflows with full programmatic control.', es: 'Cada funcionalidad es accesible via nuestras APIs REST y GraphQL.' },
261
+ icon: 'code',
262
+ category: 'developer',
263
+ order: 5,
264
+ },
265
+ },
266
+ {
267
+ contentTypeKey: 'feature',
268
+ slug: 'version-control',
269
+ data: {
270
+ title: { en: 'Built-In Version Control', es: 'Control de Versiones Integrado' },
271
+ description: { en: 'Every change is tracked with full audit history. Branch, diff, and merge content just like code.', es: 'Cada cambio es rastreado. Crea ramas, compara y fusiona contenido como codigo.' },
272
+ icon: 'git-branch',
273
+ category: 'developer',
274
+ order: 6,
275
+ },
276
+ },
277
+ // ── Pricing Plans ──
278
+ {
279
+ contentTypeKey: 'pricing-plan',
280
+ slug: 'starter',
281
+ data: {
282
+ name: { en: 'Starter', es: 'Inicial' },
283
+ price: 0,
284
+ interval: 'monthly',
285
+ features: {
286
+ en: ['Up to 3 team members', '1,000 entries', '5 GB storage', 'Community support', 'REST API access'],
287
+ es: ['Hasta 3 miembros', '1.000 entradas', '5 GB almacenamiento', 'Soporte comunidad', 'Acceso API REST'],
288
+ },
289
+ highlighted: false,
290
+ order: 1,
291
+ },
292
+ },
293
+ {
294
+ contentTypeKey: 'pricing-plan',
295
+ slug: 'pro',
296
+ data: {
297
+ name: { en: 'Pro', es: 'Pro' },
298
+ price: 49,
299
+ interval: 'monthly',
300
+ features: {
301
+ en: ['Up to 15 team members', '50,000 entries', '50 GB storage', 'Priority email support', 'REST + GraphQL APIs', 'Webhooks', 'Custom roles'],
302
+ es: ['Hasta 15 miembros', '50.000 entradas', '50 GB almacenamiento', 'Soporte prioritario', 'APIs REST + GraphQL', 'Webhooks', 'Roles personalizados'],
303
+ },
304
+ highlighted: true,
305
+ order: 2,
306
+ },
307
+ },
308
+ {
309
+ contentTypeKey: 'pricing-plan',
310
+ slug: 'enterprise',
311
+ data: {
312
+ name: { en: 'Enterprise', es: 'Empresarial' },
313
+ price: 199,
314
+ interval: 'monthly',
315
+ features: {
316
+ en: ['Unlimited team members', 'Unlimited entries', '500 GB storage', 'Dedicated account manager', 'SSO / SAML', 'SLA guarantee', 'Custom contract'],
317
+ es: ['Miembros ilimitados', 'Entradas ilimitadas', '500 GB almacenamiento', 'Gerente de cuenta dedicado', 'SSO / SAML', 'Garantia SLA', 'Contrato personalizado'],
318
+ },
319
+ highlighted: false,
320
+ order: 3,
321
+ },
322
+ },
323
+ // ── Testimonials ──
324
+ {
325
+ contentTypeKey: 'testimonial',
326
+ slug: 'sarah-chen',
327
+ data: {
328
+ author: 'Sarah Chen',
329
+ role: 'VP of Engineering',
330
+ company: 'Streamline Inc.',
331
+ quote: { en: 'Acme cut our deployment time from 45 minutes to under 2 minutes. The real-time collaboration alone was worth switching for.', es: 'Acme redujo nuestro tiempo de despliegue de 45 minutos a menos de 2. Solo la colaboracion en tiempo real valio el cambio.' },
332
+ order: 1,
333
+ },
334
+ },
335
+ {
336
+ contentTypeKey: 'testimonial',
337
+ slug: 'marcus-johnson',
338
+ data: {
339
+ author: 'Marcus Johnson',
340
+ role: 'CTO',
341
+ company: 'Finovate',
342
+ quote: { en: 'We evaluated 12 platforms before choosing Acme. Nothing else came close in terms of developer experience and API quality.', es: 'Evaluamos 12 plataformas antes de elegir Acme. Nada se acerco en experiencia de desarrollador y calidad de API.' },
343
+ order: 2,
344
+ },
345
+ },
346
+ {
347
+ contentTypeKey: 'testimonial',
348
+ slug: 'elena-rodriguez',
349
+ data: {
350
+ author: 'Elena Rodriguez',
351
+ role: 'Product Manager',
352
+ company: 'Nexora',
353
+ quote: { en: 'The content modeling flexibility is incredible. We migrated from Contentful in a weekend and never looked back.', es: 'La flexibilidad del modelado de contenido es increible. Migramos desde Contentful en un fin de semana.' },
354
+ order: 3,
355
+ },
356
+ },
357
+ {
358
+ contentTypeKey: 'testimonial',
359
+ slug: 'david-park',
360
+ data: {
361
+ author: 'David Park',
362
+ role: 'Head of Growth',
363
+ company: 'Launchpad.io',
364
+ quote: { en: 'Our marketing team can now ship landing pages without engineering support. That alone saves us 20+ hours per sprint.', es: 'Nuestro equipo de marketing ahora puede lanzar landing pages sin soporte de ingenieria.' },
365
+ order: 4,
366
+ },
367
+ },
368
+ // ── FAQs ──
369
+ {
370
+ contentTypeKey: 'faq',
371
+ slug: 'what-is-acme',
372
+ data: {
373
+ question: { en: 'What is Acme Platform?', es: 'Que es Acme Platform?' },
374
+ answer: { en: 'Acme is an all-in-one platform for product teams that combines content management, deployment, analytics, and collaboration into a single tool.', es: 'Acme es una plataforma todo-en-uno para equipos de producto.' },
375
+ category: 'general',
376
+ order: 1,
377
+ },
378
+ },
379
+ {
380
+ contentTypeKey: 'faq',
381
+ slug: 'free-trial',
382
+ data: {
383
+ question: { en: 'Is there a free trial?', es: 'Hay prueba gratuita?' },
384
+ answer: { en: 'Yes! Every plan includes a 14-day free trial with full access to all features. No credit card required to start.', es: 'Si. Cada plan incluye 14 dias de prueba gratis con acceso completo.' },
385
+ category: 'billing',
386
+ order: 2,
387
+ },
388
+ },
389
+ {
390
+ contentTypeKey: 'faq',
391
+ slug: 'data-migration',
392
+ data: {
393
+ question: { en: 'Can I migrate from another CMS?', es: 'Puedo migrar desde otro CMS?' },
394
+ answer: { en: 'Absolutely. We provide import tools for Contentful, Sanity, Strapi, and WordPress. Our team also offers white-glove migration for Enterprise plans.', es: 'Por supuesto. Ofrecemos herramientas de importacion para Contentful, Sanity, Strapi y WordPress.' },
395
+ category: 'general',
396
+ order: 3,
397
+ },
398
+ },
399
+ {
400
+ contentTypeKey: 'faq',
401
+ slug: 'api-rate-limits',
402
+ data: {
403
+ question: { en: 'What are the API rate limits?', es: 'Cuales son los limites de la API?' },
404
+ answer: { en: 'Starter plans get 100 requests/second, Pro gets 500/s, and Enterprise gets custom limits. Burst traffic up to 3x is allowed for short periods.', es: 'El plan Starter tiene 100 req/s, Pro tiene 500/s, y Enterprise tiene limites personalizados.' },
405
+ category: 'technical',
406
+ order: 4,
407
+ },
408
+ },
409
+ {
410
+ contentTypeKey: 'faq',
411
+ slug: 'uptime-sla',
412
+ data: {
413
+ question: { en: 'What is your uptime SLA?', es: 'Cual es su SLA de uptime?' },
414
+ answer: { en: 'We maintain 99.99% uptime for all paid plans. Enterprise customers receive a contractual SLA with financial penalties for downtime.', es: 'Mantenemos 99.99% uptime para planes de pago. Clientes Enterprise reciben SLA contractual.' },
415
+ category: 'technical',
416
+ order: 5,
417
+ },
418
+ },
419
+ {
420
+ contentTypeKey: 'faq',
421
+ slug: 'cancel-anytime',
422
+ data: {
423
+ question: { en: 'Can I cancel my subscription?', es: 'Puedo cancelar mi suscripcion?' },
424
+ answer: { en: 'Yes, you can cancel anytime from your account settings. Your data remains accessible for 30 days after cancellation.', es: 'Si, puede cancelar en cualquier momento. Sus datos quedan accesibles por 30 dias.' },
425
+ category: 'billing',
426
+ order: 6,
427
+ },
428
+ },
429
+ {
430
+ contentTypeKey: 'faq',
431
+ slug: 'team-collaboration',
432
+ data: {
433
+ question: { en: 'How does team collaboration work?', es: 'Como funciona la colaboracion en equipo?' },
434
+ answer: { en: 'Invite team members by email and assign roles (Admin, Editor, Author, Viewer). All changes are tracked with full audit history and real-time presence.', es: 'Invite miembros por email y asigne roles. Todos los cambios se rastrean con historial y presencia en tiempo real.' },
435
+ category: 'general',
436
+ order: 7,
437
+ },
438
+ },
439
+ {
440
+ contentTypeKey: 'faq',
441
+ slug: 'data-security',
442
+ data: {
443
+ question: { en: 'How is my data secured?', es: 'Como se aseguran mis datos?' },
444
+ answer: { en: 'All data is encrypted at rest (AES-256) and in transit (TLS 1.3). We are SOC 2 Type II certified and GDPR compliant. Enterprise plans include data residency options.', es: 'Datos encriptados en reposo (AES-256) y en transito (TLS 1.3). Certificados SOC 2 Type II y cumplimiento GDPR.' },
445
+ category: 'security',
446
+ order: 8,
447
+ },
448
+ },
449
+ // ── Changelog ──
450
+ {
451
+ contentTypeKey: 'changelog',
452
+ slug: 'v2-4-0',
453
+ data: {
454
+ version: '2.4.0',
455
+ date: '2026-03-15',
456
+ entries: [
457
+ { type: 'feature', text: 'GraphQL subscriptions for real-time content updates' },
458
+ { type: 'feature', text: 'Bulk publish and unpublish operations' },
459
+ { type: 'improvement', text: 'Content Delivery API response times reduced by 40%' },
460
+ { type: 'fix', text: 'Fixed slug uniqueness validation across environments' },
461
+ ],
462
+ body: [
463
+ heading(2, 'GraphQL Subscriptions'),
464
+ paragraph('You can now subscribe to content changes in real-time via GraphQL subscriptions. This enables live previews, collaborative editing indicators, and instant cache invalidation.'),
465
+ codeBlock('graphql', 'subscription {\n entryUpdated(contentType: "article") {\n id\n slug\n data\n }\n}'),
466
+ ],
467
+ },
468
+ },
469
+ {
470
+ contentTypeKey: 'changelog',
471
+ slug: 'v2-3-0',
472
+ data: {
473
+ version: '2.3.0',
474
+ date: '2026-02-28',
475
+ entries: [
476
+ { type: 'feature', text: 'AI-powered content suggestions and auto-tagging' },
477
+ { type: 'feature', text: 'Custom block definitions with JSON Schema validation' },
478
+ { type: 'improvement', text: 'Webhook delivery reliability improved to 99.97%' },
479
+ { type: 'fix', text: 'Fixed media upload progress bar stalling at 99%' },
480
+ { type: 'fix', text: 'Resolved timezone handling for scheduled publishing' },
481
+ ],
482
+ },
483
+ },
484
+ // ── Blog Posts ──
485
+ {
486
+ contentTypeKey: 'blog-post',
487
+ slug: 'introducing-acme-v2',
488
+ data: {
489
+ title: { en: 'Introducing Acme v2: Faster, Smarter, More Flexible', es: 'Presentamos Acme v2: Mas Rapido, Inteligente y Flexible' },
490
+ body: [
491
+ heading(1, 'Introducing Acme v2'),
492
+ paragraph('After 8 months of development and feedback from over 500 beta testers, we are thrilled to announce Acme Platform v2. This release represents the biggest leap forward since our initial launch.'),
493
+ heading(2, 'What is new'),
494
+ paragraph('Acme v2 introduces a completely redesigned content editor, real-time collaboration, and an AI assistant that helps you write, tag, and optimize content.'),
495
+ callout('info', 'Existing users will be automatically migrated to v2. No action required on your part.'),
496
+ heading(2, 'Performance improvements'),
497
+ paragraph('We rewrote our Content Delivery API from the ground up. Average response times dropped from 120ms to 18ms at the 95th percentile, with a global edge cache ensuring sub-50ms responses worldwide.'),
498
+ ],
499
+ author: 'Acme Team',
500
+ category: 'announcements',
501
+ publishedDate: '2026-03-01',
502
+ },
503
+ },
504
+ {
505
+ contentTypeKey: 'blog-post',
506
+ slug: 'content-modeling-best-practices',
507
+ data: {
508
+ title: { en: 'Content Modeling Best Practices for Headless CMS', es: 'Mejores Practicas de Modelado de Contenido' },
509
+ body: [
510
+ heading(1, 'Content Modeling Best Practices'),
511
+ paragraph('A well-designed content model is the foundation of a successful headless CMS implementation. In this guide, we share the patterns and anti-patterns we have seen across thousands of Acme spaces.'),
512
+ heading(2, '1. Start with the consumer'),
513
+ paragraph('Before creating content types, map out every surface where content will appear: website, mobile app, email, digital signage. Each consumer has different data needs.'),
514
+ heading(2, '2. Normalize aggressively'),
515
+ paragraph('If a piece of content appears in more than one place, make it a separate content type and use references. Duplication leads to inconsistency.'),
516
+ heading(2, '3. Use taxonomies for classification'),
517
+ paragraph('Categories, tags, and other classification systems should be modeled as taxonomies rather than free-text fields. This enables filtering, faceted search, and consistent labeling.'),
518
+ callout('tip', 'Use hierarchical taxonomies for categories (e.g. Electronics > Phones > Smartphones) and flat taxonomies for tags.'),
519
+ ],
520
+ author: 'Engineering Team',
521
+ category: 'tutorials',
522
+ publishedDate: '2026-02-15',
523
+ },
524
+ },
525
+ {
526
+ contentTypeKey: 'blog-post',
527
+ slug: 'soc2-certification',
528
+ data: {
529
+ title: { en: 'Acme Achieves SOC 2 Type II Certification', es: 'Acme Obtiene Certificacion SOC 2 Tipo II' },
530
+ body: [
531
+ heading(1, 'SOC 2 Type II Certification'),
532
+ paragraph('We are proud to announce that Acme Platform has achieved SOC 2 Type II certification, the gold standard for security and compliance in cloud services.'),
533
+ paragraph('This certification validates that our security controls have been operating effectively over an extended audit period. Enterprise customers can request our full audit report through their account manager.'),
534
+ ],
535
+ author: 'Security Team',
536
+ category: 'announcements',
537
+ publishedDate: '2026-01-20',
538
+ },
539
+ },
540
+ ];
541
+ export const saasBoilerplate = {
542
+ key: 'saas-boilerplate',
543
+ name: 'SaaS Boilerplate',
544
+ description: 'Complete SaaS product site with landing pages, feature showcases, pricing tiers, testimonials, FAQ, changelog, and a company blog. Bilingual English/Spanish.',
545
+ price: 99,
546
+ currency: 'USD',
547
+ features: [
548
+ '7 content types with rich field sets',
549
+ '30+ sample entries with realistic content',
550
+ 'Block-based body content for pages and posts',
551
+ 'English and Spanish locales with translated content',
552
+ '4 taxonomy categories for organizing content',
553
+ 'Pricing plans with feature breakdowns',
554
+ 'Customer testimonials and social proof',
555
+ 'Product changelog with release notes',
556
+ ],
557
+ previewUrl: 'https://templates.htmless.dev/saas-boilerplate',
558
+ contentTypes: saasBoilerplateContentTypes,
559
+ taxonomies: saasBoilerplateTaxonomies,
560
+ locales: [
561
+ { code: 'en', name: 'English', isDefault: true },
562
+ { code: 'es', name: 'Spanish' },
563
+ ],
564
+ sampleEntries: saasBoilerplateEntries,
565
+ readme: `# SaaS Boilerplate Template
566
+
567
+ A production-ready content structure for SaaS product websites. Includes 7 content types, 30+ sample entries, and bilingual content in English and Spanish.
568
+
569
+ ## Content Types
570
+
571
+ - **Page** — Marketing pages with hero sections, feature lists, and CTAs
572
+ - **Feature** — Individual product features with icons and categories
573
+ - **Pricing Plan** — Subscription tiers with feature breakdowns
574
+ - **Testimonial** — Customer quotes with author details
575
+ - **FAQ** — Frequently asked questions grouped by category
576
+ - **Changelog** — Version history with structured release notes
577
+ - **Blog Post** — Company blog with rich block content
578
+
579
+ ## Getting Started
580
+
581
+ 1. Apply this template to a new space
582
+ 2. Customize the sample content to match your product
583
+ 3. Connect your frontend via the Content Delivery API
584
+ 4. Publish and go live
585
+ `,
586
+ };
587
+ // ═══════════════════════════════════════════════════════════════════
588
+ // 2. Blog Engine ($49)
589
+ // ═══════════════════════════════════════════════════════════════════
590
+ resetOrder();
591
+ const blogEngineContentTypes = [
592
+ {
593
+ key: 'post',
594
+ name: 'Post',
595
+ description: 'Blog posts with block-based rich content',
596
+ fields: [
597
+ f('title', 'Title', 'text', { required: true, localized: true }),
598
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
599
+ f('body', 'Body', 'richtext', { required: true, localized: true }),
600
+ f('excerpt', 'Excerpt', 'text', { localized: true }),
601
+ f('featuredImage', 'Featured Image', 'media'),
602
+ f('author', 'Author', 'reference', { referenceTarget: 'author' }),
603
+ f('publishedDate', 'Published Date', 'date'),
604
+ f('readingTime', 'Reading Time (min)', 'number'),
605
+ f('tags', 'Tags', 'json'),
606
+ ],
607
+ },
608
+ (() => {
609
+ resetOrder();
610
+ return {
611
+ key: 'author',
612
+ name: 'Author',
613
+ description: 'Blog authors with bios and social links',
614
+ fields: [
615
+ f('name', 'Name', 'text', { required: true }),
616
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
617
+ f('bio', 'Bio', 'richtext'),
618
+ f('avatar', 'Avatar', 'media'),
619
+ f('socialLinks', 'Social Links', 'json'),
620
+ ],
621
+ };
622
+ })(),
623
+ (() => {
624
+ resetOrder();
625
+ return {
626
+ key: 'category',
627
+ name: 'Category',
628
+ description: 'Post categories for organizing content',
629
+ fields: [
630
+ f('name', 'Name', 'text', { required: true }),
631
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
632
+ f('description', 'Description', 'text'),
633
+ f('image', 'Cover Image', 'media'),
634
+ ],
635
+ };
636
+ })(),
637
+ (() => {
638
+ resetOrder();
639
+ return {
640
+ key: 'tag',
641
+ name: 'Tag',
642
+ description: 'Post tags for fine-grained content labeling',
643
+ fields: [
644
+ f('name', 'Name', 'text', { required: true }),
645
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
646
+ ],
647
+ };
648
+ })(),
649
+ (() => {
650
+ resetOrder();
651
+ return {
652
+ key: 'page',
653
+ name: 'Page',
654
+ description: 'Static pages (about, contact, etc.)',
655
+ fields: [
656
+ f('title', 'Title', 'text', { required: true }),
657
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
658
+ f('body', 'Body', 'richtext', { required: true }),
659
+ ],
660
+ };
661
+ })(),
662
+ ];
663
+ const blogEngineEntries = [
664
+ // ── Authors ──
665
+ {
666
+ contentTypeKey: 'author',
667
+ slug: 'jane-doe',
668
+ data: {
669
+ name: 'Jane Doe',
670
+ bio: 'Full-stack developer and technical writer with 10 years of experience building web applications. Passionate about developer tools, API design, and making complex topics accessible.',
671
+ socialLinks: { twitter: 'https://twitter.com/janedoe', github: 'https://github.com/janedoe', linkedin: 'https://linkedin.com/in/janedoe' },
672
+ },
673
+ },
674
+ {
675
+ contentTypeKey: 'author',
676
+ slug: 'alex-rivera',
677
+ data: {
678
+ name: 'Alex Rivera',
679
+ bio: 'Product designer turned developer advocate. Writes about design systems, accessibility, and the intersection of design and engineering.',
680
+ socialLinks: { twitter: 'https://twitter.com/alexrivera', dribbble: 'https://dribbble.com/alexrivera' },
681
+ },
682
+ },
683
+ // ── Categories ──
684
+ {
685
+ contentTypeKey: 'category',
686
+ slug: 'tutorials',
687
+ data: { name: 'Tutorials', description: 'Step-by-step guides and how-to articles for developers' },
688
+ },
689
+ {
690
+ contentTypeKey: 'category',
691
+ slug: 'engineering',
692
+ data: { name: 'Engineering', description: 'Deep dives into architecture, performance, and technical decisions' },
693
+ },
694
+ {
695
+ contentTypeKey: 'category',
696
+ slug: 'design',
697
+ data: { name: 'Design', description: 'UI/UX design patterns, accessibility, and design systems' },
698
+ },
699
+ {
700
+ contentTypeKey: 'category',
701
+ slug: 'news',
702
+ data: { name: 'News', description: 'Product updates, release announcements, and company news' },
703
+ },
704
+ // ── Tags ──
705
+ { contentTypeKey: 'tag', slug: 'javascript', data: { name: 'JavaScript' } },
706
+ { contentTypeKey: 'tag', slug: 'typescript', data: { name: 'TypeScript' } },
707
+ { contentTypeKey: 'tag', slug: 'react', data: { name: 'React' } },
708
+ { contentTypeKey: 'tag', slug: 'nextjs', data: { name: 'Next.js' } },
709
+ { contentTypeKey: 'tag', slug: 'api-design', data: { name: 'API Design' } },
710
+ { contentTypeKey: 'tag', slug: 'performance', data: { name: 'Performance' } },
711
+ { contentTypeKey: 'tag', slug: 'accessibility', data: { name: 'Accessibility' } },
712
+ { contentTypeKey: 'tag', slug: 'css', data: { name: 'CSS' } },
713
+ // ── Posts ──
714
+ {
715
+ contentTypeKey: 'post',
716
+ slug: 'building-type-safe-apis-with-trpc',
717
+ data: {
718
+ title: 'Building Type-Safe APIs with tRPC and Next.js',
719
+ body: [
720
+ heading(1, 'Building Type-Safe APIs with tRPC'),
721
+ paragraph('If you have ever wished your API calls had the same type safety as the rest of your TypeScript code, tRPC is the answer. In this tutorial, we will build a full-stack application with end-to-end type safety.'),
722
+ heading(2, 'What is tRPC?'),
723
+ paragraph('tRPC (TypeScript Remote Procedure Call) lets you build APIs where the input and output types are inferred automatically. No code generation, no schema definitions, no runtime overhead.'),
724
+ heading(2, 'Setting up the project'),
725
+ paragraph('Start by creating a new Next.js project with the T3 stack:'),
726
+ codeBlock('bash', 'npx create-t3-app@latest my-app\ncd my-app\nnpm install'),
727
+ heading(2, 'Defining a router'),
728
+ paragraph('Create your first tRPC router with a simple greeting procedure:'),
729
+ codeBlock('typescript', 'import { router, publicProcedure } from \'./trpc\';\nimport { z } from \'zod\';\n\nexport const appRouter = router({\n hello: publicProcedure\n .input(z.object({ name: z.string() }))\n .query(({ input }) => {\n return { greeting: `Hello ${input.name}!` };\n }),\n});'),
730
+ callout('tip', 'The input schema doubles as runtime validation. If a client sends invalid data, tRPC returns a 400 error automatically.'),
731
+ heading(2, 'Calling from the client'),
732
+ paragraph('On the client side, you get full autocompletion and type checking:'),
733
+ codeBlock('typescript', 'const { data } = trpc.hello.useQuery({ name: \'World\' });\n// data is typed as { greeting: string }'),
734
+ heading(2, 'Conclusion'),
735
+ paragraph('tRPC eliminates the gap between backend and frontend types. Combined with Zod for validation, you get a development experience that catches errors at compile time rather than runtime.'),
736
+ ],
737
+ excerpt: 'Learn how to build fully type-safe APIs using tRPC and Next.js, with end-to-end TypeScript inference and zero code generation.',
738
+ author: 'jane-doe',
739
+ publishedDate: '2026-03-20',
740
+ readingTime: 8,
741
+ tags: ['typescript', 'nextjs', 'api-design'],
742
+ },
743
+ },
744
+ {
745
+ contentTypeKey: 'post',
746
+ slug: 'css-container-queries-guide',
747
+ data: {
748
+ title: 'The Complete Guide to CSS Container Queries',
749
+ body: [
750
+ heading(1, 'CSS Container Queries: The Complete Guide'),
751
+ paragraph('Container queries are the most significant addition to CSS since Flexbox. They allow components to adapt their styling based on the size of their container rather than the viewport.'),
752
+ heading(2, 'Why container queries matter'),
753
+ paragraph('Media queries respond to viewport size, but modern applications are built with reusable components that live in containers of varying sizes. A card component might appear in a narrow sidebar and a wide main content area on the same page.'),
754
+ heading(2, 'Basic syntax'),
755
+ codeBlock('css', '.card-container {\n container-type: inline-size;\n container-name: card;\n}\n\n@container card (min-width: 400px) {\n .card {\n display: grid;\n grid-template-columns: 200px 1fr;\n }\n}'),
756
+ callout('info', 'Container queries have shipped in all major browsers since early 2023, so they are safe to use in production today.'),
757
+ heading(2, 'Container query units'),
758
+ paragraph('CSS also introduced container query length units: cqw, cqh, cqi, cqb, cqmin, and cqmax. These work like viewport units but relative to the container.'),
759
+ codeBlock('css', '.card-title {\n font-size: clamp(1rem, 3cqi, 2rem);\n}'),
760
+ heading(2, 'Real-world patterns'),
761
+ paragraph('Here are three patterns where container queries shine: responsive cards, adaptive navigation menus, and dashboard widgets that reconfigure based on available space.'),
762
+ ],
763
+ excerpt: 'Master CSS container queries with practical examples. Learn how to build truly responsive components that adapt to their container size.',
764
+ author: 'alex-rivera',
765
+ publishedDate: '2026-03-10',
766
+ readingTime: 6,
767
+ tags: ['css', 'performance'],
768
+ },
769
+ },
770
+ {
771
+ contentTypeKey: 'post',
772
+ slug: 'optimizing-react-performance',
773
+ data: {
774
+ title: 'Optimizing React Performance: Beyond React.memo',
775
+ body: [
776
+ heading(1, 'Optimizing React Performance'),
777
+ paragraph('React.memo is the go-to performance optimization, but it is often misused and rarely the best tool for the job. Let us explore the techniques that actually make a difference.'),
778
+ heading(2, 'Measure first'),
779
+ paragraph('Before optimizing, profile your application using React DevTools Profiler. Look for components that re-render frequently with the same props.'),
780
+ callout('warning', 'Premature optimization is the root of all evil. Always measure before and after to verify your changes actually improve performance.'),
781
+ heading(2, 'Technique 1: State colocation'),
782
+ paragraph('Move state as close to where it is used as possible. If only one child component needs a piece of state, do not store it in a parent that causes siblings to re-render.'),
783
+ heading(2, 'Technique 2: Composition patterns'),
784
+ paragraph('Use the children prop to prevent unnecessary re-renders:'),
785
+ codeBlock('tsx', '// Bad: ExpensiveTree re-renders when count changes\nfunction App() {\n const [count, setCount] = useState(0);\n return (\n <div>\n <button onClick={() => setCount(c => c + 1)}>{count}</button>\n <ExpensiveTree />\n </div>\n );\n}\n\n// Good: ExpensiveTree does NOT re-render\nfunction App() {\n return (\n <Counter>\n <ExpensiveTree />\n </Counter>\n );\n}'),
786
+ heading(2, 'Technique 3: useDeferredValue'),
787
+ paragraph('For expensive computations triggered by user input, useDeferredValue lets React prioritize the input update and defer the expensive re-render:'),
788
+ codeBlock('tsx', 'function SearchResults({ query }: { query: string }) {\n const deferredQuery = useDeferredValue(query);\n const results = useMemo(() => filterItems(deferredQuery), [deferredQuery]);\n return <List items={results} />;\n}'),
789
+ ],
790
+ excerpt: 'Go beyond React.memo with state colocation, composition patterns, and concurrent features to build genuinely fast React applications.',
791
+ author: 'jane-doe',
792
+ publishedDate: '2026-02-28',
793
+ readingTime: 10,
794
+ tags: ['react', 'javascript', 'performance'],
795
+ },
796
+ },
797
+ {
798
+ contentTypeKey: 'post',
799
+ slug: 'building-accessible-forms',
800
+ data: {
801
+ title: 'Building Accessible Forms That Everyone Can Use',
802
+ body: [
803
+ heading(1, 'Accessible Forms That Everyone Can Use'),
804
+ paragraph('Forms are the primary way users interact with web applications, yet they remain one of the most common sources of accessibility barriers. Here is how to get them right.'),
805
+ heading(2, 'Labels and instructions'),
806
+ paragraph('Every input needs a visible, associated label. Placeholder text is not a substitute for a label because it disappears when the user starts typing.'),
807
+ codeBlock('html', '<label for="email">Email address</label>\n<input type="email" id="email" name="email"\n aria-describedby="email-hint"\n required />\n<p id="email-hint">We will never share your email.</p>'),
808
+ heading(2, 'Error handling'),
809
+ paragraph('When validation fails, clearly describe what went wrong and how to fix it. Associate error messages with their inputs using aria-describedby.'),
810
+ callout('tip', 'Use aria-live="polite" on your error summary so screen readers announce errors automatically when they appear.'),
811
+ heading(2, 'Keyboard navigation'),
812
+ paragraph('Users must be able to complete the entire form using only the keyboard. Tab through every input, radio button, checkbox, and submit button to verify the order is logical.'),
813
+ image('https://images.unsplash.com/photo-1555421689-d68471e189f2', 'Developer testing keyboard navigation on a form'),
814
+ heading(2, 'Testing checklist'),
815
+ list(true, [
816
+ 'All inputs have visible labels',
817
+ 'Error messages are descriptive and associated with inputs',
818
+ 'Form is fully navigable by keyboard',
819
+ 'Screen reader announces all labels, hints, and errors',
820
+ 'Color is not the only indicator of state (error, success)',
821
+ ]),
822
+ ],
823
+ excerpt: 'A practical guide to building web forms that work for everyone, including keyboard and screen reader users.',
824
+ author: 'alex-rivera',
825
+ publishedDate: '2026-02-15',
826
+ readingTime: 7,
827
+ tags: ['accessibility', 'css', 'javascript'],
828
+ },
829
+ },
830
+ {
831
+ contentTypeKey: 'post',
832
+ slug: 'next-js-server-components-patterns',
833
+ data: {
834
+ title: 'Practical Patterns for Next.js Server Components',
835
+ body: [
836
+ heading(1, 'Practical Patterns for Server Components'),
837
+ paragraph('React Server Components are now the default in Next.js App Router. After a year of using them in production, here are the patterns that have proven most useful.'),
838
+ heading(2, 'Pattern 1: Data fetching at the top'),
839
+ paragraph('Fetch data in Server Components at the top of the component tree and pass it down as props. This eliminates client-side loading states for initial page loads.'),
840
+ codeBlock('tsx', '// app/posts/page.tsx (Server Component)\nexport default async function PostsPage() {\n const posts = await db.post.findMany({\n orderBy: { publishedDate: \'desc\' },\n take: 20,\n });\n return <PostList posts={posts} />;\n}'),
841
+ heading(2, 'Pattern 2: Client islands'),
842
+ paragraph('Use the "client island" pattern: wrap only the interactive parts in Client Components while keeping the surrounding layout as a Server Component.'),
843
+ heading(2, 'Pattern 3: Streaming with Suspense'),
844
+ paragraph('For slow data sources, wrap the component in Suspense to stream the rest of the page immediately while the slow part loads:'),
845
+ codeBlock('tsx', '<Suspense fallback={<AnalyticsSkeleton />}>\n <AnalyticsDashboard />\n</Suspense>'),
846
+ callout('info', 'Streaming works automatically with Next.js App Router. No additional configuration needed.'),
847
+ ],
848
+ excerpt: 'Battle-tested patterns for building production applications with React Server Components and Next.js App Router.',
849
+ author: 'jane-doe',
850
+ publishedDate: '2026-01-30',
851
+ readingTime: 9,
852
+ tags: ['react', 'nextjs', 'typescript'],
853
+ },
854
+ },
855
+ // ── Pages ──
856
+ {
857
+ contentTypeKey: 'page',
858
+ slug: 'about',
859
+ data: {
860
+ title: 'About This Blog',
861
+ body: [
862
+ heading(1, 'About'),
863
+ paragraph('This blog covers web development, design, and engineering. We publish in-depth tutorials, technical deep dives, and practical guides for modern web development.'),
864
+ heading(2, 'Who writes here'),
865
+ paragraph('Our authors are practicing engineers and designers who write about the tools and techniques they use every day. No fluff, no hype — just practical knowledge.'),
866
+ heading(2, 'Contributing'),
867
+ paragraph('We welcome guest posts. If you have a topic you are passionate about, reach out via the contact page.'),
868
+ ],
869
+ },
870
+ },
871
+ {
872
+ contentTypeKey: 'page',
873
+ slug: 'contact',
874
+ data: {
875
+ title: 'Contact Us',
876
+ body: [
877
+ heading(1, 'Get in Touch'),
878
+ paragraph('Have a question, suggestion, or guest post idea? We would love to hear from you.'),
879
+ paragraph('Email us at hello@blog.example.com or find us on Twitter @blogexample.'),
880
+ ],
881
+ },
882
+ },
883
+ ];
884
+ export const blogEngine = {
885
+ key: 'blog-engine',
886
+ name: 'Blog Engine',
887
+ description: 'A fully-featured blog with posts, authors, categories, tags, and static pages. Posts include realistic block content with code samples, callouts, images, and lists.',
888
+ price: 49,
889
+ currency: 'USD',
890
+ features: [
891
+ '5 content types (Post, Author, Category, Tag, Page)',
892
+ '5 posts with realistic block-based content',
893
+ 'Code blocks, callouts, images, and ordered lists',
894
+ '2 author profiles with social links',
895
+ '4 categories and 8 tags',
896
+ '2 static pages (about, contact)',
897
+ 'Category and tag taxonomies',
898
+ 'Reading time field for posts',
899
+ ],
900
+ previewUrl: 'https://templates.htmless.dev/blog-engine',
901
+ contentTypes: blogEngineContentTypes,
902
+ taxonomies: [
903
+ { key: 'category', name: 'Category', hierarchical: true },
904
+ { key: 'tag', name: 'Tag', hierarchical: false },
905
+ ],
906
+ locales: [
907
+ { code: 'en', name: 'English', isDefault: true },
908
+ ],
909
+ sampleEntries: blogEngineEntries,
910
+ readme: `# Blog Engine Template
911
+
912
+ A production-ready blog content structure with 5 content types and 20+ sample entries. Posts include realistic block content with headings, paragraphs, code samples, callouts, and images.
913
+
914
+ ## Content Types
915
+
916
+ - **Post** — Blog posts with block-based bodies, excerpts, author references, reading time, and tags
917
+ - **Author** — Writer profiles with bios and social media links
918
+ - **Category** — Hierarchical categories for organizing posts
919
+ - **Tag** — Flat tags for fine-grained content labeling
920
+ - **Page** — Static pages for about, contact, and similar content
921
+
922
+ ## Getting Started
923
+
924
+ 1. Apply this template to create your blog space
925
+ 2. Customize authors and categories
926
+ 3. Write your first post using the block editor
927
+ 4. Connect via CDA and render on your frontend
928
+ `,
929
+ };
930
+ // ═══════════════════════════════════════════════════════════════════
931
+ // 3. AI Dashboard ($149)
932
+ // ═══════════════════════════════════════════════════════════════════
933
+ resetOrder();
934
+ const aiDashboardContentTypes = [
935
+ {
936
+ key: 'dashboard',
937
+ name: 'Dashboard',
938
+ description: 'Configurable AI dashboard with widget layouts',
939
+ fields: [
940
+ f('title', 'Title', 'text', { required: true }),
941
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
942
+ f('description', 'Description', 'text'),
943
+ f('widgets', 'Widgets', 'json', { required: true }),
944
+ ],
945
+ },
946
+ (() => {
947
+ resetOrder();
948
+ return {
949
+ key: 'model',
950
+ name: 'Model',
951
+ description: 'AI model configurations with provider and endpoint details',
952
+ fields: [
953
+ f('name', 'Name', 'text', { required: true }),
954
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
955
+ f('provider', 'Provider', 'text', { required: true }),
956
+ f('endpoint', 'Endpoint', 'text', { required: true }),
957
+ f('apiKey', 'API Key', 'text'),
958
+ f('config', 'Configuration', 'json'),
959
+ ],
960
+ };
961
+ })(),
962
+ (() => {
963
+ resetOrder();
964
+ return {
965
+ key: 'prompt',
966
+ name: 'Prompt',
967
+ description: 'Reusable prompt templates with variable substitution',
968
+ fields: [
969
+ f('name', 'Name', 'text', { required: true }),
970
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
971
+ f('template', 'Template', 'richtext', { required: true }),
972
+ f('variables', 'Variables', 'json'),
973
+ f('model', 'Model', 'reference', { referenceTarget: 'model' }),
974
+ ],
975
+ };
976
+ })(),
977
+ (() => {
978
+ resetOrder();
979
+ return {
980
+ key: 'conversation',
981
+ name: 'Conversation',
982
+ description: 'Saved AI conversations with full message history',
983
+ fields: [
984
+ f('title', 'Title', 'text', { required: true }),
985
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
986
+ f('messages', 'Messages', 'json', { required: true }),
987
+ f('model', 'Model', 'reference', { referenceTarget: 'model' }),
988
+ ],
989
+ };
990
+ })(),
991
+ (() => {
992
+ resetOrder();
993
+ return {
994
+ key: 'knowledge-base',
995
+ name: 'Knowledge Base',
996
+ description: 'Document collections for RAG and context injection',
997
+ fields: [
998
+ f('title', 'Title', 'text', { required: true }),
999
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
1000
+ f('description', 'Description', 'text'),
1001
+ f('documents', 'Documents', 'json', { required: true }),
1002
+ ],
1003
+ };
1004
+ })(),
1005
+ ];
1006
+ const aiDashboardEntries = [
1007
+ // ── Dashboard ──
1008
+ {
1009
+ contentTypeKey: 'dashboard',
1010
+ slug: 'main-dashboard',
1011
+ data: {
1012
+ title: 'AI Operations Dashboard',
1013
+ description: 'Central hub for monitoring AI model usage, prompt performance, and conversation analytics.',
1014
+ widgets: [
1015
+ { id: 'w1', type: 'metric', title: 'Total API Calls (24h)', config: { source: 'api_logs', metric: 'count', timeRange: '24h' }, position: { x: 0, y: 0, w: 3, h: 1 } },
1016
+ { id: 'w2', type: 'metric', title: 'Avg Response Time', config: { source: 'api_logs', metric: 'avg_latency', timeRange: '24h' }, position: { x: 3, y: 0, w: 3, h: 1 } },
1017
+ { id: 'w3', type: 'metric', title: 'Token Usage', config: { source: 'api_logs', metric: 'total_tokens', timeRange: '24h' }, position: { x: 6, y: 0, w: 3, h: 1 } },
1018
+ { id: 'w4', type: 'metric', title: 'Error Rate', config: { source: 'api_logs', metric: 'error_rate', timeRange: '24h' }, position: { x: 9, y: 0, w: 3, h: 1 } },
1019
+ { id: 'w5', type: 'chart', title: 'Requests Over Time', config: { source: 'api_logs', chartType: 'line', groupBy: 'hour', metric: 'count', timeRange: '7d' }, position: { x: 0, y: 1, w: 6, h: 2 } },
1020
+ { id: 'w6', type: 'chart', title: 'Model Usage Distribution', config: { source: 'api_logs', chartType: 'pie', groupBy: 'model', metric: 'count', timeRange: '30d' }, position: { x: 6, y: 1, w: 6, h: 2 } },
1021
+ { id: 'w7', type: 'table', title: 'Recent Conversations', config: { source: 'conversations', columns: ['title', 'model', 'messageCount', 'updatedAt'], limit: 10 }, position: { x: 0, y: 3, w: 12, h: 2 } },
1022
+ ],
1023
+ },
1024
+ },
1025
+ // ── Models ──
1026
+ {
1027
+ contentTypeKey: 'model',
1028
+ slug: 'gpt-4o',
1029
+ data: {
1030
+ name: 'GPT-4o',
1031
+ provider: 'OpenAI',
1032
+ endpoint: 'https://api.openai.com/v1/chat/completions',
1033
+ apiKey: 'sk-placeholder-replace-with-your-key',
1034
+ config: {
1035
+ model: 'gpt-4o',
1036
+ maxTokens: 4096,
1037
+ temperature: 0.7,
1038
+ topP: 1,
1039
+ frequencyPenalty: 0,
1040
+ presencePenalty: 0,
1041
+ responseFormat: 'text',
1042
+ },
1043
+ },
1044
+ },
1045
+ {
1046
+ contentTypeKey: 'model',
1047
+ slug: 'claude-sonnet',
1048
+ data: {
1049
+ name: 'Claude Sonnet 4',
1050
+ provider: 'Anthropic',
1051
+ endpoint: 'https://api.anthropic.com/v1/messages',
1052
+ apiKey: 'sk-ant-placeholder-replace-with-your-key',
1053
+ config: {
1054
+ model: 'claude-sonnet-4-20250514',
1055
+ maxTokens: 8192,
1056
+ temperature: 0.7,
1057
+ topP: 0.9,
1058
+ systemPrompt: 'You are a helpful AI assistant.',
1059
+ },
1060
+ },
1061
+ },
1062
+ // ── Prompts ──
1063
+ {
1064
+ contentTypeKey: 'prompt',
1065
+ slug: 'summarize-article',
1066
+ data: {
1067
+ name: 'Summarize Article',
1068
+ template: 'You are an expert content summarizer. Summarize the following article in {{length}} sentences. Focus on key takeaways and actionable insights.\n\n---\n\n{{article_text}}\n\n---\n\nProvide the summary in bullet points.',
1069
+ variables: [
1070
+ { key: 'article_text', label: 'Article Text', type: 'textarea', required: true },
1071
+ { key: 'length', label: 'Number of Sentences', type: 'number', default: 5 },
1072
+ ],
1073
+ model: 'claude-sonnet',
1074
+ },
1075
+ },
1076
+ {
1077
+ contentTypeKey: 'prompt',
1078
+ slug: 'generate-blog-outline',
1079
+ data: {
1080
+ name: 'Generate Blog Outline',
1081
+ template: 'Create a detailed blog post outline for the topic: "{{topic}}"\n\nTarget audience: {{audience}}\nTone: {{tone}}\nTarget word count: {{word_count}}\n\nInclude:\n- A compelling title\n- Introduction hook\n- 4-6 main sections with subsections\n- Key points to cover in each section\n- Conclusion with call-to-action\n- SEO keywords to target',
1082
+ variables: [
1083
+ { key: 'topic', label: 'Topic', type: 'text', required: true },
1084
+ { key: 'audience', label: 'Target Audience', type: 'text', default: 'developers' },
1085
+ { key: 'tone', label: 'Tone', type: 'select', options: ['professional', 'casual', 'academic', 'conversational'], default: 'conversational' },
1086
+ { key: 'word_count', label: 'Word Count', type: 'number', default: 2000 },
1087
+ ],
1088
+ model: 'gpt-4o',
1089
+ },
1090
+ },
1091
+ {
1092
+ contentTypeKey: 'prompt',
1093
+ slug: 'code-review',
1094
+ data: {
1095
+ name: 'Code Review',
1096
+ template: 'Review the following {{language}} code. Evaluate it for:\n\n1. **Correctness** — Are there bugs or logical errors?\n2. **Performance** — Are there inefficiencies or potential bottlenecks?\n3. **Readability** — Is the code clear and well-structured?\n4. **Security** — Are there any security vulnerabilities?\n5. **Best Practices** — Does it follow {{language}} conventions?\n\n```{{language}}\n{{code}}\n```\n\nProvide specific, actionable feedback with code examples for suggested improvements.',
1097
+ variables: [
1098
+ { key: 'code', label: 'Code', type: 'textarea', required: true },
1099
+ { key: 'language', label: 'Language', type: 'text', default: 'TypeScript' },
1100
+ ],
1101
+ model: 'claude-sonnet',
1102
+ },
1103
+ },
1104
+ {
1105
+ contentTypeKey: 'prompt',
1106
+ slug: 'extract-structured-data',
1107
+ data: {
1108
+ name: 'Extract Structured Data',
1109
+ template: 'Extract structured data from the following text and return it as a JSON object matching this schema:\n\n```json\n{{schema}}\n```\n\nText to extract from:\n\n{{text}}\n\nReturn ONLY valid JSON. Do not include explanations.',
1110
+ variables: [
1111
+ { key: 'text', label: 'Source Text', type: 'textarea', required: true },
1112
+ { key: 'schema', label: 'Target JSON Schema', type: 'textarea', required: true },
1113
+ ],
1114
+ model: 'gpt-4o',
1115
+ },
1116
+ },
1117
+ // ── Conversation ──
1118
+ {
1119
+ contentTypeKey: 'conversation',
1120
+ slug: 'api-architecture-discussion',
1121
+ data: {
1122
+ title: 'API Architecture Discussion',
1123
+ messages: [
1124
+ { role: 'user', content: 'I am designing a REST API for a multi-tenant CMS. Each tenant (space) has its own content types, entries, and assets. What is the best URL structure?', timestamp: '2026-03-28T10:00:00Z' },
1125
+ { role: 'assistant', content: 'For a multi-tenant CMS API, I recommend a structure that makes the space context explicit while keeping URLs clean:\n\n**Option A: Header-based tenancy**\n```\nGET /v1/entries\nX-Space-Id: space_abc123\n```\n\n**Option B: URL-based tenancy**\n```\nGET /v1/spaces/abc123/entries\n```\n\nOption A is cleaner for SDKs (set the header once), while Option B is more explicit and easier to debug. Most mature CMS platforms (Contentful, Sanity) use a hybrid approach.\n\nFor your CMA (Content Management API), I would use header-based tenancy with explicit space routes for cross-space operations like listing spaces.', timestamp: '2026-03-28T10:00:15Z' },
1126
+ { role: 'user', content: 'Good points. How should I handle versioning of content entries? I need draft and published states with full version history.', timestamp: '2026-03-28T10:01:00Z' },
1127
+ { role: 'assistant', content: 'Here is a proven pattern for content versioning:\n\n1. **Entries** are the anchor — they hold the slug and content type reference\n2. **EntryVersions** store the actual data as immutable JSON snapshots\n3. **EntryState** tracks the current draft and published version IDs\n\nThis gives you:\n- Full version history (every save creates a new EntryVersion)\n- Independent draft/published states\n- Easy rollback (point draftVersionId to an older version)\n- Efficient diffing between any two versions\n\nThe CMA returns the draft version by default, while the CDA always returns the published version. This separation keeps the read path fast.', timestamp: '2026-03-28T10:01:30Z' },
1128
+ ],
1129
+ model: 'claude-sonnet',
1130
+ },
1131
+ },
1132
+ // ── Knowledge Base ──
1133
+ {
1134
+ contentTypeKey: 'knowledge-base',
1135
+ slug: 'product-docs',
1136
+ data: {
1137
+ title: 'Product Documentation',
1138
+ description: 'Core product documentation for RAG-powered support and content generation. Includes API reference, getting started guides, and architecture overviews.',
1139
+ documents: [
1140
+ { id: 'doc-1', title: 'Getting Started Guide', type: 'markdown', content: '# Getting Started\n\nWelcome to the platform. This guide walks you through creating your first space, defining content types, and publishing your first entry.\n\n## Step 1: Create a Space\n\nA space is an isolated content environment. Create one via the dashboard or API.\n\n## Step 2: Define Content Types\n\nContent types are the schema for your content. Define fields like title, body, images, and references.\n\n## Step 3: Create and Publish\n\nCreate entries, preview them, and publish when ready.', wordCount: 85, updatedAt: '2026-03-15' },
1141
+ { id: 'doc-2', title: 'API Reference Overview', type: 'markdown', content: '# API Reference\n\nThe platform exposes two APIs:\n\n- **CMA (Content Management API)** — Full CRUD operations for content, schemas, assets, and settings. Requires authentication.\n- **CDA (Content Delivery API)** — Read-only, optimized for content delivery. Supports caching and CDN integration.\n\nAll endpoints return JSON. Rate limits apply based on your plan tier.', wordCount: 55, updatedAt: '2026-03-20' },
1142
+ { id: 'doc-3', title: 'Architecture Overview', type: 'markdown', content: '# Architecture\n\nThe platform uses a multi-tenant architecture with logical isolation at the database level. Each space has its own content types, entries, assets, and configurations.\n\nKey components:\n- Express.js API server\n- PostgreSQL with Prisma ORM\n- Redis for caching and real-time events\n- S3-compatible storage for media assets\n- Traefik for reverse proxy and TLS termination', wordCount: 60, updatedAt: '2026-03-10' },
1143
+ ],
1144
+ },
1145
+ },
1146
+ ];
1147
+ export const aiDashboard = {
1148
+ key: 'ai-dashboard',
1149
+ name: 'AI Dashboard',
1150
+ description: 'A content structure for building AI-powered dashboards with model management, reusable prompt templates, conversation storage, and RAG knowledge bases.',
1151
+ price: 149,
1152
+ currency: 'USD',
1153
+ features: [
1154
+ '5 content types for AI operations',
1155
+ 'Dashboard with configurable widget layouts',
1156
+ 'Model configurations for GPT-4o and Claude',
1157
+ '4 reusable prompt templates with variables',
1158
+ 'Conversation storage with full message history',
1159
+ 'Knowledge base for RAG document management',
1160
+ 'JSON-based widget and config schemas',
1161
+ ],
1162
+ previewUrl: 'https://templates.htmless.dev/ai-dashboard',
1163
+ contentTypes: aiDashboardContentTypes,
1164
+ taxonomies: [],
1165
+ locales: [
1166
+ { code: 'en', name: 'English', isDefault: true },
1167
+ ],
1168
+ sampleEntries: aiDashboardEntries,
1169
+ readme: `# AI Dashboard Template
1170
+
1171
+ A content structure for building AI-powered dashboards and tools. Includes model management, reusable prompt templates, conversation storage, and knowledge bases for RAG.
1172
+
1173
+ ## Content Types
1174
+
1175
+ - **Dashboard** — Widget-based layouts with metric, chart, and table components
1176
+ - **Model** — AI model configurations (provider, endpoint, parameters)
1177
+ - **Prompt** — Reusable prompt templates with variable substitution
1178
+ - **Conversation** — Saved AI conversations with message history
1179
+ - **Knowledge Base** — Document collections for context injection and RAG
1180
+
1181
+ ## Getting Started
1182
+
1183
+ 1. Apply this template to create your AI dashboard space
1184
+ 2. Replace placeholder API keys with your actual keys
1185
+ 3. Customize prompts for your use case
1186
+ 4. Build your frontend consuming the CDA
1187
+ `,
1188
+ };
1189
+ // ═══════════════════════════════════════════════════════════════════
1190
+ // 4. E-commerce Content ($99)
1191
+ // ═══════════════════════════════════════════════════════════════════
1192
+ resetOrder();
1193
+ const ecommerceContentTypes = [
1194
+ {
1195
+ key: 'product',
1196
+ name: 'Product',
1197
+ description: 'Products with full e-commerce fields including pricing, inventory, and SEO',
1198
+ fields: [
1199
+ f('name', 'Name', 'text', { required: true, localized: true }),
1200
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
1201
+ f('description', 'Description', 'richtext', { required: true, localized: true }),
1202
+ f('price', 'Price', 'number', { required: true }),
1203
+ f('compareAtPrice', 'Compare At Price', 'number'),
1204
+ f('images', 'Images', 'json'),
1205
+ f('sku', 'SKU', 'text', { unique: true }),
1206
+ f('inStock', 'In Stock', 'boolean'),
1207
+ f('weight', 'Weight (g)', 'number'),
1208
+ f('category', 'Category', 'text'),
1209
+ f('brand', 'Brand', 'reference', { referenceTarget: 'brand' }),
1210
+ f('tags', 'Tags', 'json'),
1211
+ f('seoTitle', 'SEO Title', 'text', { localized: true }),
1212
+ f('seoDescription', 'SEO Description', 'text', { localized: true }),
1213
+ ],
1214
+ },
1215
+ (() => {
1216
+ resetOrder();
1217
+ return {
1218
+ key: 'collection',
1219
+ name: 'Collection',
1220
+ description: 'Curated product collections and categories',
1221
+ fields: [
1222
+ f('name', 'Name', 'text', { required: true, localized: true }),
1223
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
1224
+ f('description', 'Description', 'richtext', { localized: true }),
1225
+ f('image', 'Cover Image', 'media'),
1226
+ f('products', 'Products', 'json'),
1227
+ ],
1228
+ };
1229
+ })(),
1230
+ (() => {
1231
+ resetOrder();
1232
+ return {
1233
+ key: 'brand',
1234
+ name: 'Brand',
1235
+ description: 'Product brands with logos and descriptions',
1236
+ fields: [
1237
+ f('name', 'Name', 'text', { required: true }),
1238
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
1239
+ f('logo', 'Logo', 'media'),
1240
+ f('description', 'Description', 'richtext'),
1241
+ ],
1242
+ };
1243
+ })(),
1244
+ (() => {
1245
+ resetOrder();
1246
+ return {
1247
+ key: 'review',
1248
+ name: 'Review',
1249
+ description: 'Product reviews with ratings',
1250
+ fields: [
1251
+ f('product', 'Product', 'reference', { required: true, referenceTarget: 'product' }),
1252
+ f('slug', 'Slug', 'slug', { required: true, unique: true }),
1253
+ f('author', 'Author', 'text', { required: true }),
1254
+ f('rating', 'Rating', 'number', { required: true, validations: { min: 1, max: 5 } }),
1255
+ f('title', 'Title', 'text'),
1256
+ f('body', 'Body', 'richtext'),
1257
+ ],
1258
+ };
1259
+ })(),
1260
+ ];
1261
+ const ecommerceEntries = [
1262
+ // ── Brands ──
1263
+ {
1264
+ contentTypeKey: 'brand',
1265
+ slug: 'aurora-tech',
1266
+ data: {
1267
+ name: 'Aurora Tech',
1268
+ description: 'Premium consumer electronics and smart home devices. Founded in 2018 in San Francisco, Aurora Tech combines cutting-edge technology with minimalist Scandinavian design.',
1269
+ },
1270
+ },
1271
+ {
1272
+ contentTypeKey: 'brand',
1273
+ slug: 'verde-outdoor',
1274
+ data: {
1275
+ name: 'Verde Outdoor',
1276
+ description: 'Sustainable outdoor gear and apparel made from recycled and organic materials. B-Corp certified since 2020.',
1277
+ },
1278
+ },
1279
+ {
1280
+ contentTypeKey: 'brand',
1281
+ slug: 'craft-home',
1282
+ data: {
1283
+ name: 'Craft & Home',
1284
+ description: 'Artisanal home goods and decor sourced from independent makers around the world. Every piece tells a story.',
1285
+ },
1286
+ },
1287
+ // ── Products ──
1288
+ {
1289
+ contentTypeKey: 'product',
1290
+ slug: 'aurora-wireless-headphones',
1291
+ data: {
1292
+ name: { en: 'Aurora Wireless Headphones', es: 'Auriculares Inalambricos Aurora' },
1293
+ description: { en: 'Premium over-ear headphones with adaptive noise cancellation, 40-hour battery life, and lossless audio via Bluetooth 5.3. Crafted from recycled aluminum and protein leather.', es: 'Auriculares premium over-ear con cancelacion de ruido adaptativa, 40 horas de bateria y audio sin perdida via Bluetooth 5.3.' },
1294
+ price: 299.99,
1295
+ compareAtPrice: 349.99,
1296
+ images: [
1297
+ { url: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e', alt: 'Aurora Wireless Headphones - front view' },
1298
+ { url: 'https://images.unsplash.com/photo-1590658268037-6bf12f032f4e', alt: 'Aurora Wireless Headphones - side view' },
1299
+ ],
1300
+ sku: 'AUR-WH-001',
1301
+ inStock: true,
1302
+ weight: 265,
1303
+ category: 'electronics',
1304
+ brand: 'aurora-tech',
1305
+ tags: ['headphones', 'wireless', 'noise-cancelling', 'bluetooth'],
1306
+ seoTitle: { en: 'Aurora Wireless Headphones — Premium ANC Over-Ear', es: 'Auriculares Inalambricos Aurora — ANC Premium' },
1307
+ seoDescription: { en: 'Premium over-ear headphones with adaptive noise cancellation and 40-hour battery life. Free shipping.', es: 'Auriculares premium con cancelacion de ruido adaptativa y 40 horas de bateria. Envio gratis.' },
1308
+ },
1309
+ },
1310
+ {
1311
+ contentTypeKey: 'product',
1312
+ slug: 'aurora-smart-speaker',
1313
+ data: {
1314
+ name: { en: 'Aurora Smart Speaker', es: 'Altavoz Inteligente Aurora' },
1315
+ description: { en: 'Room-filling 360-degree sound with built-in voice assistant, multi-room support, and a walnut veneer finish. Plays lossless audio from all major streaming services.', es: 'Sonido 360 grados con asistente de voz integrado, soporte multi-habitacion y acabado en nogal.' },
1316
+ price: 179.99,
1317
+ images: [
1318
+ { url: 'https://images.unsplash.com/photo-1589492477829-5e65395b66cc', alt: 'Aurora Smart Speaker on shelf' },
1319
+ ],
1320
+ sku: 'AUR-SS-001',
1321
+ inStock: true,
1322
+ weight: 1200,
1323
+ category: 'electronics',
1324
+ brand: 'aurora-tech',
1325
+ tags: ['speaker', 'smart-home', 'voice-assistant'],
1326
+ seoTitle: { en: 'Aurora Smart Speaker — 360 Sound with Voice Assistant', es: 'Altavoz Inteligente Aurora' },
1327
+ },
1328
+ },
1329
+ {
1330
+ contentTypeKey: 'product',
1331
+ slug: 'verde-trail-jacket',
1332
+ data: {
1333
+ name: { en: 'Verde Trail Jacket', es: 'Chaqueta Trail Verde' },
1334
+ description: { en: 'Lightweight waterproof jacket made from 100% recycled nylon. 20K/20K waterproof-breathable rating with fully taped seams. Packs into its own chest pocket. Perfect for trail running and hiking in variable conditions.', es: 'Chaqueta ligera impermeable de nylon 100% reciclado. Clasificacion 20K/20K impermeable-transpirable. Se guarda en su propio bolsillo.' },
1335
+ price: 189.00,
1336
+ compareAtPrice: 220.00,
1337
+ images: [
1338
+ { url: 'https://images.unsplash.com/photo-1591047139829-d91aecb6caea', alt: 'Verde Trail Jacket worn outdoors' },
1339
+ ],
1340
+ sku: 'VRD-TJ-M-BLU',
1341
+ inStock: true,
1342
+ weight: 195,
1343
+ category: 'apparel',
1344
+ brand: 'verde-outdoor',
1345
+ tags: ['jacket', 'waterproof', 'hiking', 'trail-running', 'sustainable'],
1346
+ seoTitle: { en: 'Verde Trail Jacket — Recycled Waterproof Running Jacket', es: 'Chaqueta Trail Verde — Impermeable Reciclada' },
1347
+ },
1348
+ },
1349
+ {
1350
+ contentTypeKey: 'product',
1351
+ slug: 'verde-merino-base-layer',
1352
+ data: {
1353
+ name: { en: 'Verde Merino Base Layer', es: 'Capa Base Merino Verde' },
1354
+ description: { en: 'Ultrasoft 150gsm merino wool base layer with flatlock seams and odor resistance. Temperature-regulating for year-round comfort. Ethically sourced from New Zealand farms.', es: 'Capa base de lana merino ultrasuave de 150gsm con costuras planas y resistencia al olor.' },
1355
+ price: 89.00,
1356
+ images: [
1357
+ { url: 'https://images.unsplash.com/photo-1556906781-9a412961c28c', alt: 'Verde Merino Base Layer' },
1358
+ ],
1359
+ sku: 'VRD-MB-M-BLK',
1360
+ inStock: true,
1361
+ weight: 170,
1362
+ category: 'apparel',
1363
+ brand: 'verde-outdoor',
1364
+ tags: ['base-layer', 'merino', 'sustainable', 'hiking'],
1365
+ seoTitle: { en: 'Verde Merino Base Layer — Ethical Merino Wool', es: 'Capa Base Merino Verde' },
1366
+ },
1367
+ },
1368
+ {
1369
+ contentTypeKey: 'product',
1370
+ slug: 'handwoven-cotton-throw',
1371
+ data: {
1372
+ name: { en: 'Handwoven Cotton Throw', es: 'Manta de Algodon Tejida a Mano' },
1373
+ description: { en: 'Artisan-crafted throw blanket handwoven by cooperatives in Oaxaca, Mexico. Made from organic cotton with natural indigo dye. Each piece is unique with slight variations in pattern.', es: 'Manta artesanal tejida a mano por cooperativas en Oaxaca, Mexico. Algodon organico con tinte natural de indigo.' },
1374
+ price: 145.00,
1375
+ images: [
1376
+ { url: 'https://images.unsplash.com/photo-1555041469-a586c61ea9bc', alt: 'Handwoven cotton throw draped over sofa' },
1377
+ ],
1378
+ sku: 'CH-HCT-001',
1379
+ inStock: true,
1380
+ weight: 850,
1381
+ category: 'home',
1382
+ brand: 'craft-home',
1383
+ tags: ['throw', 'handwoven', 'organic', 'artisan'],
1384
+ seoTitle: { en: 'Handwoven Cotton Throw — Artisan Made in Oaxaca', es: 'Manta de Algodon Tejida a Mano' },
1385
+ },
1386
+ },
1387
+ {
1388
+ contentTypeKey: 'product',
1389
+ slug: 'ceramic-pour-over-set',
1390
+ data: {
1391
+ name: { en: 'Ceramic Pour-Over Coffee Set', es: 'Set de Cafe Pour-Over de Ceramica' },
1392
+ description: { en: 'Minimalist pour-over coffee set in matte white stoneware. Includes dripper, server, and two cups. Hand-thrown by a ceramicist in Portland, Oregon. Dishwasher safe.', es: 'Set minimalista pour-over en gres blanco mate. Incluye gotero, servidor y dos tazas. Hecho a mano en Portland.' },
1393
+ price: 78.00,
1394
+ images: [
1395
+ { url: 'https://images.unsplash.com/photo-1495474472287-4d71bcdd2085', alt: 'Ceramic pour-over coffee set on counter' },
1396
+ ],
1397
+ sku: 'CH-POS-WHT',
1398
+ inStock: true,
1399
+ weight: 620,
1400
+ category: 'home',
1401
+ brand: 'craft-home',
1402
+ tags: ['coffee', 'ceramic', 'handmade', 'kitchen'],
1403
+ seoTitle: { en: 'Ceramic Pour-Over Set — Handmade in Portland', es: 'Set Pour-Over de Ceramica' },
1404
+ },
1405
+ },
1406
+ {
1407
+ contentTypeKey: 'product',
1408
+ slug: 'aurora-fitness-tracker',
1409
+ data: {
1410
+ name: { en: 'Aurora Fitness Tracker', es: 'Rastreador Fitness Aurora' },
1411
+ description: { en: 'Ultra-thin fitness tracker with AMOLED display, GPS, heart rate monitoring, sleep tracking, and 14-day battery life. Swim-proof to 50 meters. Syncs with Apple Health and Google Fit.', es: 'Rastreador fitness ultrafino con pantalla AMOLED, GPS, monitor de ritmo cardiaco y 14 dias de bateria.' },
1412
+ price: 149.99,
1413
+ images: [
1414
+ { url: 'https://images.unsplash.com/photo-1575311373937-040b8e1fd5b6', alt: 'Aurora Fitness Tracker on wrist' },
1415
+ ],
1416
+ sku: 'AUR-FT-001',
1417
+ inStock: false,
1418
+ weight: 28,
1419
+ category: 'electronics',
1420
+ brand: 'aurora-tech',
1421
+ tags: ['fitness', 'wearable', 'gps', 'health'],
1422
+ seoTitle: { en: 'Aurora Fitness Tracker — 14-Day Battery, GPS, Swim-Proof', es: 'Rastreador Fitness Aurora' },
1423
+ },
1424
+ },
1425
+ {
1426
+ contentTypeKey: 'product',
1427
+ slug: 'verde-daypack-22l',
1428
+ data: {
1429
+ name: { en: 'Verde Daypack 22L', es: 'Mochila Verde 22L' },
1430
+ description: { en: 'Versatile 22-liter daypack made from recycled ocean plastic. Features a padded laptop sleeve (fits 15"), water bottle pockets, and a rain cover stowed in the base. PFC-free DWR coating.', es: 'Mochila versatil de 22 litros hecha de plastico oceanico reciclado. Compartimento acolchado para portatil de 15".' },
1431
+ price: 129.00,
1432
+ compareAtPrice: 149.00,
1433
+ images: [
1434
+ { url: 'https://images.unsplash.com/photo-1553062407-98eeb64c6a62', alt: 'Verde Daypack 22L in use' },
1435
+ ],
1436
+ sku: 'VRD-DP-22-GRN',
1437
+ inStock: true,
1438
+ weight: 680,
1439
+ category: 'accessories',
1440
+ brand: 'verde-outdoor',
1441
+ tags: ['backpack', 'sustainable', 'laptop', 'everyday-carry'],
1442
+ seoTitle: { en: 'Verde Daypack 22L — Recycled Ocean Plastic Backpack', es: 'Mochila Verde 22L' },
1443
+ },
1444
+ },
1445
+ // ── Collections ──
1446
+ {
1447
+ contentTypeKey: 'collection',
1448
+ slug: 'summer-essentials',
1449
+ data: {
1450
+ name: { en: 'Summer Essentials', es: 'Esenciales de Verano' },
1451
+ description: { en: 'Everything you need for the perfect summer — from outdoor gear to smart accessories. Curated for adventure seekers and urban explorers alike.', es: 'Todo lo que necesitas para el verano perfecto — desde equipo outdoor hasta accesorios inteligentes.' },
1452
+ products: ['verde-trail-jacket', 'verde-daypack-22l', 'aurora-wireless-headphones', 'aurora-fitness-tracker'],
1453
+ },
1454
+ },
1455
+ {
1456
+ contentTypeKey: 'collection',
1457
+ slug: 'home-and-living',
1458
+ data: {
1459
+ name: { en: 'Home & Living', es: 'Hogar y Vida' },
1460
+ description: { en: 'Thoughtfully crafted home goods that bring warmth and character to any space. Handmade by independent artisans.', es: 'Articulos para el hogar cuidadosamente elaborados que aportan calidez y caracter.' },
1461
+ products: ['handwoven-cotton-throw', 'ceramic-pour-over-set', 'aurora-smart-speaker'],
1462
+ },
1463
+ },
1464
+ {
1465
+ contentTypeKey: 'collection',
1466
+ slug: 'sustainable-picks',
1467
+ data: {
1468
+ name: { en: 'Sustainable Picks', es: 'Selecciones Sostenibles' },
1469
+ description: { en: 'Our most sustainable products — made from recycled materials, organic fibers, and ethically sourced ingredients. Good for you, good for the planet.', es: 'Nuestros productos mas sostenibles — hechos de materiales reciclados y fibras organicas.' },
1470
+ products: ['verde-trail-jacket', 'verde-merino-base-layer', 'verde-daypack-22l', 'handwoven-cotton-throw'],
1471
+ },
1472
+ },
1473
+ // ── Reviews ──
1474
+ {
1475
+ contentTypeKey: 'review',
1476
+ slug: 'review-headphones-sarah',
1477
+ data: {
1478
+ product: 'aurora-wireless-headphones',
1479
+ author: 'Sarah M.',
1480
+ rating: 5,
1481
+ title: 'Best headphones I have ever owned',
1482
+ body: 'The noise cancellation is incredible — completely silent on my daily commute. Battery life is exactly as advertised (I got 41 hours). The recycled materials feel premium, not cheap. Worth every penny.',
1483
+ },
1484
+ },
1485
+ {
1486
+ contentTypeKey: 'review',
1487
+ slug: 'review-headphones-james',
1488
+ data: {
1489
+ product: 'aurora-wireless-headphones',
1490
+ author: 'James K.',
1491
+ rating: 4,
1492
+ title: 'Great sound, slightly heavy',
1493
+ body: 'Sound quality is phenomenal, especially with lossless audio enabled. My only complaint is they feel a bit heavy after 3+ hours of continuous use. The carrying case is a nice touch.',
1494
+ },
1495
+ },
1496
+ {
1497
+ contentTypeKey: 'review',
1498
+ slug: 'review-trail-jacket-mike',
1499
+ data: {
1500
+ product: 'verde-trail-jacket',
1501
+ author: 'Mike R.',
1502
+ rating: 5,
1503
+ title: 'Survived a downpour on the PCT',
1504
+ body: 'Wore this through 6 hours of continuous rain on the Pacific Crest Trail. Stayed completely dry. It packs down to the size of a grapefruit. The fact that it is made from recycled materials is a bonus.',
1505
+ },
1506
+ },
1507
+ {
1508
+ contentTypeKey: 'review',
1509
+ slug: 'review-throw-lisa',
1510
+ data: {
1511
+ product: 'handwoven-cotton-throw',
1512
+ author: 'Lisa P.',
1513
+ rating: 5,
1514
+ title: 'Stunning craftsmanship',
1515
+ body: 'The colors are even more beautiful in person. You can see the slight variations in the weave that prove it is truly handmade. It has become the centerpiece of our living room.',
1516
+ },
1517
+ },
1518
+ {
1519
+ contentTypeKey: 'review',
1520
+ slug: 'review-coffee-set-tom',
1521
+ data: {
1522
+ product: 'ceramic-pour-over-set',
1523
+ author: 'Tom H.',
1524
+ rating: 4,
1525
+ title: 'Beautiful but fragile',
1526
+ body: 'The design is gorgeous and makes great coffee. The matte white finish is elegant. Docking one star because the dripper chip is thin and I worry about longevity. Handle with care and it will last.',
1527
+ },
1528
+ },
1529
+ {
1530
+ contentTypeKey: 'review',
1531
+ slug: 'review-daypack-anna',
1532
+ data: {
1533
+ product: 'verde-daypack-22l',
1534
+ author: 'Anna W.',
1535
+ rating: 5,
1536
+ title: 'My everyday carry for everything',
1537
+ body: 'I use this for commuting, day hikes, and weekend trips. The laptop sleeve is well-padded, the rain cover saved me during an unexpected shower, and knowing it is made from ocean plastic makes me feel good. The 22L size is perfect — big enough for a full day, small enough for the office.',
1538
+ },
1539
+ },
1540
+ ];
1541
+ export const ecommerceContent = {
1542
+ key: 'ecommerce-content',
1543
+ name: 'E-Commerce Content',
1544
+ description: 'Complete e-commerce content structure with products, collections, brands, and reviews. Includes 8 products across 3 brands with realistic descriptions, pricing, SKUs, and customer reviews. Bilingual English/Spanish.',
1545
+ price: 99,
1546
+ currency: 'USD',
1547
+ features: [
1548
+ '4 content types (Product, Collection, Brand, Review)',
1549
+ '8 products with full e-commerce fields',
1550
+ '3 brands with descriptions',
1551
+ '3 curated collections',
1552
+ '6 customer reviews with ratings',
1553
+ 'Compare-at pricing for sale items',
1554
+ 'SKU and inventory tracking fields',
1555
+ 'SEO title and description fields',
1556
+ 'English and Spanish locales',
1557
+ 'Product category, brand, and tag taxonomies',
1558
+ ],
1559
+ previewUrl: 'https://templates.htmless.dev/ecommerce-content',
1560
+ contentTypes: ecommerceContentTypes,
1561
+ taxonomies: [
1562
+ { key: 'product-category', name: 'Product Category', hierarchical: true },
1563
+ { key: 'brand', name: 'Brand', hierarchical: false },
1564
+ { key: 'tag', name: 'Tag', hierarchical: false },
1565
+ ],
1566
+ locales: [
1567
+ { code: 'en', name: 'English', isDefault: true },
1568
+ { code: 'es', name: 'Spanish' },
1569
+ ],
1570
+ sampleEntries: ecommerceEntries,
1571
+ readme: `# E-Commerce Content Template
1572
+
1573
+ A production-ready content structure for headless e-commerce. Includes 4 content types, 8 products across 3 brands, curated collections, and customer reviews. Bilingual English/Spanish.
1574
+
1575
+ ## Content Types
1576
+
1577
+ - **Product** — Full e-commerce fields: name, price, compareAtPrice, images, SKU, stock, weight, SEO
1578
+ - **Collection** — Curated product groupings with descriptions and cover images
1579
+ - **Brand** — Brand profiles with logos and descriptions
1580
+ - **Review** — Customer reviews with product references and star ratings
1581
+
1582
+ ## Getting Started
1583
+
1584
+ 1. Apply this template to create your e-commerce content space
1585
+ 2. Replace sample products with your actual inventory
1586
+ 3. Adjust collections and categories to match your store
1587
+ 4. Connect to your storefront via the Content Delivery API
1588
+ `,
1589
+ };
1590
+ // ─── Registry ───────────────────────────────────────────────────────
1591
+ export const premiumTemplates = [
1592
+ saasBoilerplate,
1593
+ blogEngine,
1594
+ aiDashboard,
1595
+ ecommerceContent,
1596
+ ];
1597
+ export function getPremiumTemplate(key) {
1598
+ return premiumTemplates.find((t) => t.key === key);
1599
+ }
1600
+ export function getPremiumTemplates() {
1601
+ return premiumTemplates;
1602
+ }
1603
+ //# sourceMappingURL=premium-templates.js.map