create-agntcms-app 0.2.1

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 (197) hide show
  1. package/README.md +39 -0
  2. package/dist/index.mjs +297 -0
  3. package/dist/template/.claude/settings.json +6 -0
  4. package/dist/template/.claude/skills/.gitkeep +0 -0
  5. package/dist/template/.claude-plugin/channel/server.mjs +254 -0
  6. package/dist/template/.claude-plugin/channel/server.ts +369 -0
  7. package/dist/template/.claude-plugin/plugin.json +17 -0
  8. package/dist/template/.mcp.json +8 -0
  9. package/dist/template/BRAND.md +49 -0
  10. package/dist/template/CLAUDE.md +157 -0
  11. package/dist/template/agntcms/config.ts +49 -0
  12. package/dist/template/agntcms/sections/ArticleBody/component.tsx +32 -0
  13. package/dist/template/agntcms/sections/ArticleBody/index.ts +10 -0
  14. package/dist/template/agntcms/sections/ArticleBody/schema.ts +5 -0
  15. package/dist/template/agntcms/sections/ArticleHero/component.tsx +87 -0
  16. package/dist/template/agntcms/sections/ArticleHero/index.ts +10 -0
  17. package/dist/template/agntcms/sections/ArticleHero/schema.ts +12 -0
  18. package/dist/template/agntcms/sections/Banner/component.tsx +83 -0
  19. package/dist/template/agntcms/sections/Banner/index.ts +10 -0
  20. package/dist/template/agntcms/sections/Banner/schema.ts +9 -0
  21. package/dist/template/agntcms/sections/BlogIndex/component.tsx +173 -0
  22. package/dist/template/agntcms/sections/BlogIndex/index.ts +10 -0
  23. package/dist/template/agntcms/sections/BlogIndex/schema.ts +33 -0
  24. package/dist/template/agntcms/sections/BlogIndexHeader/component.tsx +44 -0
  25. package/dist/template/agntcms/sections/BlogIndexHeader/index.ts +10 -0
  26. package/dist/template/agntcms/sections/BlogIndexHeader/schema.ts +8 -0
  27. package/dist/template/agntcms/sections/BlogPostBody/component.tsx +50 -0
  28. package/dist/template/agntcms/sections/BlogPostBody/index.ts +10 -0
  29. package/dist/template/agntcms/sections/BlogPostBody/schema.ts +10 -0
  30. package/dist/template/agntcms/sections/BlogPostHero/component.tsx +88 -0
  31. package/dist/template/agntcms/sections/BlogPostHero/index.ts +10 -0
  32. package/dist/template/agntcms/sections/BlogPostHero/schema.ts +35 -0
  33. package/dist/template/agntcms/sections/CaseStudies/component.tsx +92 -0
  34. package/dist/template/agntcms/sections/CaseStudies/index.ts +10 -0
  35. package/dist/template/agntcms/sections/CaseStudies/schema.ts +17 -0
  36. package/dist/template/agntcms/sections/ContactForm/component.tsx +119 -0
  37. package/dist/template/agntcms/sections/ContactForm/index.ts +10 -0
  38. package/dist/template/agntcms/sections/ContactForm/schema.ts +15 -0
  39. package/dist/template/agntcms/sections/DocsArticle/component.tsx +266 -0
  40. package/dist/template/agntcms/sections/DocsArticle/index.ts +10 -0
  41. package/dist/template/agntcms/sections/DocsArticle/schema.ts +33 -0
  42. package/dist/template/agntcms/sections/FAQ/component.tsx +57 -0
  43. package/dist/template/agntcms/sections/FAQ/index.ts +10 -0
  44. package/dist/template/agntcms/sections/FAQ/schema.ts +11 -0
  45. package/dist/template/agntcms/sections/FeatureGrid/component.tsx +117 -0
  46. package/dist/template/agntcms/sections/FeatureGrid/index.ts +10 -0
  47. package/dist/template/agntcms/sections/FeatureGrid/schema.ts +21 -0
  48. package/dist/template/agntcms/sections/FeaturedArticles/component.tsx +99 -0
  49. package/dist/template/agntcms/sections/FeaturedArticles/index.ts +10 -0
  50. package/dist/template/agntcms/sections/FeaturedArticles/schema.ts +17 -0
  51. package/dist/template/agntcms/sections/GettingStarted/component.tsx +116 -0
  52. package/dist/template/agntcms/sections/GettingStarted/index.ts +10 -0
  53. package/dist/template/agntcms/sections/GettingStarted/schema.ts +11 -0
  54. package/dist/template/agntcms/sections/Hero/component.tsx +148 -0
  55. package/dist/template/agntcms/sections/Hero/index.ts +10 -0
  56. package/dist/template/agntcms/sections/Hero/schema.ts +16 -0
  57. package/dist/template/agntcms/sections/HowItWorks/component.tsx +57 -0
  58. package/dist/template/agntcms/sections/HowItWorks/index.ts +10 -0
  59. package/dist/template/agntcms/sections/HowItWorks/schema.ts +11 -0
  60. package/dist/template/agntcms/sections/ImageText/component.tsx +110 -0
  61. package/dist/template/agntcms/sections/ImageText/index.ts +10 -0
  62. package/dist/template/agntcms/sections/ImageText/schema.ts +14 -0
  63. package/dist/template/agntcms/sections/LogoStrip/component.tsx +37 -0
  64. package/dist/template/agntcms/sections/LogoStrip/index.ts +10 -0
  65. package/dist/template/agntcms/sections/LogoStrip/schema.ts +6 -0
  66. package/dist/template/agntcms/sections/Newsletter/component.tsx +48 -0
  67. package/dist/template/agntcms/sections/Newsletter/index.ts +10 -0
  68. package/dist/template/agntcms/sections/Newsletter/schema.ts +8 -0
  69. package/dist/template/agntcms/sections/OpenSource/component.tsx +99 -0
  70. package/dist/template/agntcms/sections/OpenSource/index.ts +10 -0
  71. package/dist/template/agntcms/sections/OpenSource/schema.ts +13 -0
  72. package/dist/template/agntcms/sections/PainAnswer/component.tsx +81 -0
  73. package/dist/template/agntcms/sections/PainAnswer/index.ts +10 -0
  74. package/dist/template/agntcms/sections/PainAnswer/schema.ts +15 -0
  75. package/dist/template/agntcms/sections/PricingPlans/component.tsx +100 -0
  76. package/dist/template/agntcms/sections/PricingPlans/index.ts +10 -0
  77. package/dist/template/agntcms/sections/PricingPlans/schema.ts +13 -0
  78. package/dist/template/agntcms/sections/Problem/component.tsx +49 -0
  79. package/dist/template/agntcms/sections/Problem/index.ts +10 -0
  80. package/dist/template/agntcms/sections/Problem/schema.ts +12 -0
  81. package/dist/template/agntcms/sections/SiteFooter/component.tsx +88 -0
  82. package/dist/template/agntcms/sections/SiteFooter/index.ts +10 -0
  83. package/dist/template/agntcms/sections/SiteFooter/schema.ts +13 -0
  84. package/dist/template/agntcms/sections/SiteHeader/component.tsx +99 -0
  85. package/dist/template/agntcms/sections/SiteHeader/index.ts +10 -0
  86. package/dist/template/agntcms/sections/SiteHeader/schema.ts +14 -0
  87. package/dist/template/agntcms/sections/SiteMeta/component.tsx +26 -0
  88. package/dist/template/agntcms/sections/SiteMeta/index.ts +13 -0
  89. package/dist/template/agntcms/sections/SiteMeta/schema.ts +18 -0
  90. package/dist/template/agntcms/sections/TabbedFeatures/component.tsx +120 -0
  91. package/dist/template/agntcms/sections/TabbedFeatures/index.ts +10 -0
  92. package/dist/template/agntcms/sections/TabbedFeatures/schema.ts +13 -0
  93. package/dist/template/agntcms/sections/TeamGrid/component.tsx +77 -0
  94. package/dist/template/agntcms/sections/TeamGrid/index.ts +10 -0
  95. package/dist/template/agntcms/sections/TeamGrid/schema.ts +14 -0
  96. package/dist/template/agntcms/sections/Testimonials/component.tsx +76 -0
  97. package/dist/template/agntcms/sections/Testimonials/index.ts +10 -0
  98. package/dist/template/agntcms/sections/Testimonials/schema.ts +12 -0
  99. package/dist/template/agntcms/sections/WhatIsBuilt/component.tsx +86 -0
  100. package/dist/template/agntcms/sections/WhatIsBuilt/index.ts +10 -0
  101. package/dist/template/agntcms/sections/WhatIsBuilt/schema.ts +20 -0
  102. package/dist/template/agntcms/site-meta.ts +81 -0
  103. package/dist/template/app/[[...slug]]/page.tsx +123 -0
  104. package/dist/template/app/admin/AdminPageClient.tsx +77 -0
  105. package/dist/template/app/admin/AdminPageDynamic.tsx +24 -0
  106. package/dist/template/app/admin/page.tsx +14 -0
  107. package/dist/template/app/api/agntcms/_shared.ts +80 -0
  108. package/dist/template/app/api/agntcms/assets/route.ts +11 -0
  109. package/dist/template/app/api/agntcms/assets/upload/route.ts +11 -0
  110. package/dist/template/app/api/agntcms/draft/discard/route.ts +12 -0
  111. package/dist/template/app/api/agntcms/draft/list/route.ts +11 -0
  112. package/dist/template/app/api/agntcms/draft/publish/route.ts +11 -0
  113. package/dist/template/app/api/agntcms/draft/reorder/route.ts +10 -0
  114. package/dist/template/app/api/agntcms/draft/save/route.ts +11 -0
  115. package/dist/template/app/api/agntcms/events/route.ts +12 -0
  116. package/dist/template/app/api/agntcms/forms/delete/route.ts +17 -0
  117. package/dist/template/app/api/agntcms/forms/list/route.ts +24 -0
  118. package/dist/template/app/api/agntcms/forms/read/route.ts +23 -0
  119. package/dist/template/app/api/agntcms/forms/submit/route.ts +17 -0
  120. package/dist/template/app/api/agntcms/global/delete/route.ts +13 -0
  121. package/dist/template/app/api/agntcms/global/history/route.ts +10 -0
  122. package/dist/template/app/api/agntcms/global/list/route.ts +14 -0
  123. package/dist/template/app/api/agntcms/global/read/route.ts +11 -0
  124. package/dist/template/app/api/agntcms/global/rollback/route.ts +10 -0
  125. package/dist/template/app/api/agntcms/global/save/route.ts +14 -0
  126. package/dist/template/app/api/agntcms/mcp/route.ts +12 -0
  127. package/dist/template/app/api/agntcms/page/delete/route.ts +10 -0
  128. package/dist/template/app/api/agntcms/page/duplicate/route.ts +11 -0
  129. package/dist/template/app/api/agntcms/page/history/route.ts +10 -0
  130. package/dist/template/app/api/agntcms/page/list/route.ts +10 -0
  131. package/dist/template/app/api/agntcms/page/read/route.ts +11 -0
  132. package/dist/template/app/api/agntcms/page/rename/route.ts +10 -0
  133. package/dist/template/app/api/agntcms/page/rollback/route.ts +10 -0
  134. package/dist/template/app/api/agntcms/page/unpublish/route.ts +11 -0
  135. package/dist/template/app/api/agntcms/preview/enter/route.ts +13 -0
  136. package/dist/template/app/api/agntcms/preview/exit/route.ts +10 -0
  137. package/dist/template/app/api/agntcms/preview/issue/route.ts +12 -0
  138. package/dist/template/app/api/agntcms/template/list/route.ts +15 -0
  139. package/dist/template/app/apple-icon.svg +9 -0
  140. package/dist/template/app/icon.svg +9 -0
  141. package/dist/template/app/layout.tsx +107 -0
  142. package/dist/template/app/not-found.tsx +75 -0
  143. package/dist/template/app/robots.ts +33 -0
  144. package/dist/template/app/sitemap.ts +49 -0
  145. package/dist/template/content/globals/site-footer.json +53 -0
  146. package/dist/template/content/globals/site-header.json +18 -0
  147. package/dist/template/content/globals/site-meta.json +13 -0
  148. package/dist/template/content/pages/404.json +34 -0
  149. package/dist/template/content/pages/about.json +307 -0
  150. package/dist/template/content/pages/article-editor.json +61 -0
  151. package/dist/template/content/pages/article-schemas.json +61 -0
  152. package/dist/template/content/pages/blog.json +162 -0
  153. package/dist/template/content/pages/contact.json +29 -0
  154. package/dist/template/content/pages/home.json +243 -0
  155. package/dist/template/content/pages/pricing.json +219 -0
  156. package/dist/template/content/pages/services.json +177 -0
  157. package/dist/template/fonts/Satoshi-Medium.woff2 +0 -0
  158. package/dist/template/fonts/Satoshi-Regular.woff2 +0 -0
  159. package/dist/template/next.config.ts +6 -0
  160. package/dist/template/package.json +36 -0
  161. package/dist/template/postcss.config.mjs +5 -0
  162. package/dist/template/public/assets/.gitkeep +0 -0
  163. package/dist/template/public/assets/0418d7ed21f57e7b9e0546725c92b8419daeaa355675d9070fab0c2013cf1524.jpg +0 -0
  164. package/dist/template/public/assets/0d0475f21aa96435a8ed3cdb2fddcc6278492e76ae842f569432454f4d33631a.jpg +0 -0
  165. package/dist/template/public/assets/27457a1adee2372030d9876b0d52c44d46be98843999935eaef2526b9b961f12.jpg +0 -0
  166. package/dist/template/public/assets/3855d91192f0c6120b01427b78ef84e52baa9f4b5a17d4271e41c1bfd95a5b0c.jpg +0 -0
  167. package/dist/template/public/assets/3b3b90c5084635b746be673ede92a328f002f5621a42c9a5cb89c5e2435652cb.jpg +0 -0
  168. package/dist/template/public/assets/3e76165a78fd3e7b8ed1e93dee50803ae11110c756c8c1c89229a2dec2bc0abf.jpg +0 -0
  169. package/dist/template/public/assets/4a3e28f85dc850c347ea0fd931696aa936a6bd45f193e7f1c9328b5896fb272c.jpg +0 -0
  170. package/dist/template/public/assets/579f67d5fd4c9106c6cdf2ef29f50df934ad0fc2b7849bac1e1cfb1e3f92303b.jpg +0 -0
  171. package/dist/template/public/assets/5b95209269661bb60fb250f1da682e05b9efa64dd42f350608b299e6bf1f2f35.jpg +0 -0
  172. package/dist/template/public/assets/5e04b46f8317ef95a7ddf85aedfe5c098a755f05056325d0251eccf95ce51172.jpg +0 -0
  173. package/dist/template/public/assets/6167a9164be2cf1183bdfdd4946bf9b908570e79e92a2380c25f0bb702422bbd.jpg +0 -0
  174. package/dist/template/public/assets/75e723ec316de28247924e5dfb73a4b266e10de605e749f150883d280ed8ed16.jpg +0 -0
  175. package/dist/template/public/assets/816a11e6a7245feaf51bbebf09d1bda3f125b334bc24fc3b8f47b5380a7b4294.jpg +0 -0
  176. package/dist/template/public/assets/81eba6f5654b8746a9b0cba1a9521a67f2b4afaaefc7c88d66dfab1461270d8f.jpg +0 -0
  177. package/dist/template/public/assets/82a2ce9e49361098f77a28755779dc5a7c026831cbd135175749c1304e21dacc.jpg +0 -0
  178. package/dist/template/public/assets/8d7b02ba277ba56bdafdbd47b01f7df6d993c714b4dc2305eb65a1307c09647d.jpg +0 -0
  179. package/dist/template/public/assets/b303185b471678e4d62f678a1549ee26022f4745407d08cae44ecb1c25352293.jpg +0 -0
  180. package/dist/template/public/assets/b69b49169c11546100d6dd5280073bc0d84cbbcc6d33fa01ecf6a5866fa42237.jpg +0 -0
  181. package/dist/template/public/assets/c4d2f0d1a310e457ac722a399693652e3c86c55b294243d5ffc679394e12f9d1.jpg +0 -0
  182. package/dist/template/public/assets/cae09f4729f8a348b67267c2f2a550be0f3bfa420689afe1a5cf8b7e2b146238.png +0 -0
  183. package/dist/template/public/assets/cb3acf58b57417a4b26474ba04c096af7103c4320ed2f4f3683f79d7670a055c.jpg +0 -0
  184. package/dist/template/public/assets/d5a0701b2d156284e0ce851cd2534ec632db34f91fbcbee3b8a7784d45ce78d2.jpg +0 -0
  185. package/dist/template/public/assets/d6ef1c3f48b0e488521794fb60701da1fd2c3a1621d6ac5f17ccfd4909d3be60.jpg +0 -0
  186. package/dist/template/public/assets/de249ff9be2539cf0d1ce092de3c57001839b6c3e14fcee3fc31a7b7673ae007.jpg +0 -0
  187. package/dist/template/public/assets/eac45438956be187b010e24b3289757aa00f227c190d49ee99fea510552dd2ba.jpg +0 -0
  188. package/dist/template/public/assets/f8b9200065b5436c6a88361839edc2b89be88d3037c84a80d3ee95c32891510b.jpg +0 -0
  189. package/dist/template/public/assets/placeholder.png +0 -0
  190. package/dist/template/public/brand/mark.svg +6 -0
  191. package/dist/template/public/brand/wordmark-light.svg +6 -0
  192. package/dist/template/public/brand/wordmark.svg +6 -0
  193. package/dist/template/styles/globals.css +69 -0
  194. package/dist/template/styles/theme.css +492 -0
  195. package/dist/template/styles/typography.css +469 -0
  196. package/dist/template/tsconfig.json +30 -0
  197. package/package.json +30 -0
@@ -0,0 +1,77 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ 'use client'
3
+
4
+ // Client body for the admin page. Receives `definitions` injected by the
5
+ // server wrapper (page.tsx) so that the server-side config import never
6
+ // lands in the client bundle.
7
+ //
8
+ // PreviewProvider must wrap the toolbar so usePreviewMode() resolves to
9
+ // 'preview'. mode is hardcoded because this page always renders in the
10
+ // preview context.
11
+
12
+ import { useState } from 'react'
13
+ import { PreviewProvider, PreviewToolbar } from '@agntcms/next/client'
14
+ import type { PreviewToolbarProps } from '@agntcms/next/client'
15
+
16
+ interface AdminPageClientProps {
17
+ readonly definitions: PreviewToolbarProps['definitions']
18
+ }
19
+
20
+ function AdminContent(): React.ReactElement {
21
+ const [entering, setEntering] = useState(false)
22
+ const [error, setError] = useState<string | null>(null)
23
+
24
+ const handleEnterPreview = (): void => {
25
+ setEntering(true)
26
+ setError(null)
27
+
28
+ fetch('/api/agntcms/preview/enter', { method: 'POST' })
29
+ .then((res) => {
30
+ if (!res.ok) {
31
+ throw new Error(`Server responded with ${res.status}`)
32
+ }
33
+ // Redirect to homepage where PreviewToolbar will be visible
34
+ window.location.href = '/'
35
+ })
36
+ .catch((err: unknown) => {
37
+ const message = err instanceof Error ? err.message : 'Unknown error'
38
+ setError(`Failed to enter preview mode: ${message}`)
39
+ setEntering(false)
40
+ })
41
+ }
42
+
43
+ return (
44
+ <main className="flex flex-col items-center justify-center min-h-svh px-6 gap-4">
45
+ <h1 className="font-display text-display-sm text-text-primary font-medium m-0">
46
+ agntcms Admin
47
+ </h1>
48
+ <p className="text-md text-text-secondary m-0 text-center max-w-sm">
49
+ Enter preview mode to see unpublished content and use the editing toolbar.
50
+ </p>
51
+ <button
52
+ type="button"
53
+ onClick={handleEnterPreview}
54
+ disabled={entering}
55
+ className="px-6 py-2.5 bg-bg-brand-solid text-text-primary_on-brand rounded-lg text-md font-medium cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
56
+ >
57
+ {entering ? 'Entering preview\u2026' : 'Enter Preview Mode'}
58
+ </button>
59
+ {error !== null && (
60
+ <p className="text-sm text-text-error-primary m-0">{error}</p>
61
+ )}
62
+ </main>
63
+ )
64
+ }
65
+
66
+ export function AdminPageClient({ definitions }: AdminPageClientProps): React.ReactElement {
67
+ // Conditional spread avoids passing `undefined` to an optional prop under
68
+ // exactOptionalPropertyTypes — passing `undefined` explicitly is a type error
69
+ // even though the prop is optional.
70
+ const toolbarProps = definitions !== undefined ? { definitions } : {}
71
+ return (
72
+ <PreviewProvider mode="preview">
73
+ <AdminContent />
74
+ <PreviewToolbar {...toolbarProps} />
75
+ </PreviewProvider>
76
+ )
77
+ }
@@ -0,0 +1,24 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ 'use client'
3
+
4
+ // Thin client-component wrapper that disables SSR for AdminPageClient.
5
+ // `ssr: false` is only allowed inside client components (Next.js constraint),
6
+ // so this shim sits between the server page.tsx and the actual client body.
7
+ // Suppressing SSR is required because AdminPageClient renders PreviewToolbar,
8
+ // which accesses window at render time and would crash during prerendering.
9
+
10
+ import dynamic from 'next/dynamic'
11
+ import type { PreviewToolbarProps } from '@agntcms/next/client'
12
+
13
+ interface AdminPageClientProps {
14
+ readonly definitions: PreviewToolbarProps['definitions']
15
+ }
16
+
17
+ const AdminPageClientNoSSR = dynamic<AdminPageClientProps>(
18
+ () => import('./AdminPageClient').then((m) => m.AdminPageClient),
19
+ { ssr: false },
20
+ )
21
+
22
+ export function AdminPageDynamic(props: AdminPageClientProps): React.ReactElement {
23
+ return <AdminPageClientNoSSR {...props} />
24
+ }
@@ -0,0 +1,14 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+
3
+ // Server component: reads `config.sections` on the server so that the
4
+ // config module (which transitively imports fs/promises via adapters) never
5
+ // lands in the client bundle. Passes `definitions` down to AdminPageDynamic,
6
+ // which suppresses SSR for the interactive admin tree (required because
7
+ // PreviewToolbar accesses window at render time).
8
+
9
+ import config from '@/agntcms/config'
10
+ import { AdminPageDynamic } from './AdminPageDynamic'
11
+
12
+ export default function AdminPage(): React.ReactElement {
13
+ return <AdminPageDynamic definitions={config.sections} />
14
+ }
@@ -0,0 +1,80 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Module-level singletons shared across the frozen route handlers.
4
+ //
5
+ // Why module-level and not per-request:
6
+ //
7
+ // - The runtime is stateless: it holds no request-scoped data. Rebuilding
8
+ // it per request would pointlessly re-allocate the same closure on every
9
+ // hit.
10
+ //
11
+ // - The AgentBridge checks liveness of the external MCP channel server.
12
+ // Binding its lifetime to a module-level singleton is the correct choice.
13
+ //
14
+ // - The TaskStore is in-memory. Creating it per request would lose all
15
+ // pending tasks on the next request. Module-level is required.
16
+ //
17
+ // Next.js App Router running in Node.js (not Edge Runtime) preserves
18
+ // module state across requests within a single process. This file
19
+ // correctly exploits that guarantee. Do not import this file from any
20
+ // Edge-runtime segment.
21
+ //
22
+ // In development, Next.js HMR re-evaluates server modules on every file
23
+ // change. Without globalThis caching, the bridge resets to 'stopped' and
24
+ // the task store loses all pending tasks every time Claude Code writes a
25
+ // content file. The g.__agntcms_* slots below survive re-evaluation because
26
+ // globalThis outlives any individual module evaluation in the same process.
27
+ // contentAdapter and runtime are stateless closures — they don't need this.
28
+
29
+ import { createRuntime, buildFormRegistry, createRateLimit } from '@agntcms/next/server'
30
+ import { createAgentBridge, createTaskStore, createPreviewTokenStore } from '@agntcms/next/handlers'
31
+ import config from '@/agntcms/config'
32
+
33
+ export const contentAdapter = config.contentAdapter
34
+ export const assetAdapter = config.assetAdapter
35
+ export const submissionAdapter = config.submissionAdapter
36
+
37
+ // Build the form registry once from the registered definitions. The registry
38
+ // is stable across requests: `defineConfig` runs once at module-evaluation
39
+ // time and the definitions array never changes at runtime.
40
+ const formRegistry = buildFormRegistry(config.forms)
41
+
42
+ // Runtime wired with forms + submission adapter so `submitForm` works.
43
+ // The existing handlers that don't use forms (page, draft, global, etc.)
44
+ // share this same runtime — the forms wiring adds no overhead for those paths.
45
+ export const runtime = createRuntime({
46
+ contentAdapter,
47
+ forms: formRegistry,
48
+ submissionAdapter,
49
+ })
50
+
51
+ // In-memory rate limiter for the forms submit endpoint. One limiter per
52
+ // process — the globalThis pattern below ensures it survives HMR exactly
53
+ // the same way as the task store and bridge do.
54
+ const g2 = globalThis as unknown as {
55
+ __agntcms_rateLimit?: ReturnType<typeof createRateLimit>
56
+ }
57
+
58
+ export const rateLimit = g2.__agntcms_rateLimit ??= createRateLimit({
59
+ perWindow: config.submissionRateLimit.perMinute,
60
+ windowMs: 60_000,
61
+ })
62
+
63
+ // Persist stateful singletons across Next.js HMR re-evaluations in dev mode.
64
+ const g = globalThis as unknown as {
65
+ __agntcms_taskStore?: ReturnType<typeof createTaskStore>
66
+ __agntcms_bridge?: ReturnType<typeof createAgentBridge>
67
+ __agntcms_previewTokenStore?: ReturnType<typeof createPreviewTokenStore>
68
+ }
69
+
70
+ export const taskStore = g.__agntcms_taskStore ??= createTaskStore()
71
+
72
+ const channelCallbackUrl = process.env['agntcms_CALLBACK_URL']
73
+
74
+ export const bridge = g.__agntcms_bridge ??= createAgentBridge({
75
+ taskStore,
76
+ channelPort: Number(process.env['agntcms_CHANNEL_PORT'] ?? 4819),
77
+ ...(channelCallbackUrl !== undefined ? { callbackUrl: channelCallbackUrl } : {}),
78
+ })
79
+
80
+ export const previewTokenStore = g.__agntcms_previewTokenStore ??= createPreviewTokenStore()
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Lists all uploaded assets for the image picker modal.
4
+ // Delegates to createAssetsHandler; see packages/next/src/handlers/assets/.
5
+
6
+ import { createAssetsHandler } from '@agntcms/next/handlers'
7
+ import { assetAdapter } from '../_shared'
8
+
9
+ const { list: GET } = createAssetsHandler({ assetAdapter })
10
+
11
+ export { GET }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Uploads a new image asset (multipart/form-data: file + alt).
4
+ // Delegates to createAssetsHandler; see packages/next/src/handlers/assets/.
5
+
6
+ import { createAssetsHandler } from '@agntcms/next/handlers'
7
+ import { assetAdapter } from '../../_shared'
8
+
9
+ const { upload: POST } = createAssetsHandler({ assetAdapter })
10
+
11
+ export { POST }
@@ -0,0 +1,12 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Discards a draft. A published version must exist for the slug;
4
+ // discarding a draft with no published fallback is blocked (would lose
5
+ // all data). The request body must contain { slug }.
6
+
7
+ import { createDraftHandler } from '@agntcms/next/handlers'
8
+ import { contentAdapter, runtime } from '../../_shared'
9
+
10
+ const { discard: POST } = createDraftHandler({ contentAdapter, runtime })
11
+
12
+ export { POST }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Returns the list of all pending drafts with their slugs and last-updated
4
+ // timestamps. Used by the admin UI to show the drafts panel.
5
+
6
+ import { createDraftHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter, runtime } from '../../_shared'
8
+
9
+ const { list: GET } = createDraftHandler({ contentAdapter, runtime })
10
+
11
+ export { GET }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Promotes a draft to published. The request body must contain { slug }.
4
+ // On success the draft is deleted and the page content file is updated.
5
+
6
+ import { createDraftHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter, runtime } from '../../_shared'
8
+
9
+ const { publish: POST } = createDraftHandler({ contentAdapter, runtime })
10
+
11
+ export { POST }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Reorders sections within a draft page.
4
+
5
+ import { createDraftHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter, runtime } from '../../_shared'
7
+
8
+ const { reorder: POST } = createDraftHandler({ contentAdapter, runtime })
9
+
10
+ export { POST }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Saves a full-page draft. The request body must be a JSON-serialised
4
+ // Page object (slug + sections array, optional seo).
5
+
6
+ import { createDraftHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter, runtime } from '../../_shared'
8
+
9
+ const { save: POST } = createDraftHandler({ contentAdapter, runtime })
10
+
11
+ export { POST }
@@ -0,0 +1,12 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // SSE stream for task lifecycle events. Clients subscribe with
4
+ // GET /api/agntcms/events?taskId=<id> and receive progress, completed,
5
+ // and failed frames. The stream closes automatically on terminal events.
6
+
7
+ import { createEventsHandler } from '@agntcms/next/handlers'
8
+ import { taskStore } from '../_shared'
9
+
10
+ const { GET } = createEventsHandler({ taskStore })
11
+
12
+ export { GET }
@@ -0,0 +1,17 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Reserved route. Submission delete via UI is feature-gated off in v1.
4
+ // Always returns HTTP 501 with a clear message so the AdminModal can show
5
+ // a "not yet available" hint without crashing.
6
+ //
7
+ // The route surface is registered now so a future patch can enable the
8
+ // feature without touching this frozen file (which would be a breaking
9
+ // framework change). See ARCHITECTURE.md §6.5 and §12.
10
+
11
+ import { createFormsDeleteHandler } from '@agntcms/next/handlers'
12
+
13
+ const handle = createFormsDeleteHandler()
14
+
15
+ export async function POST(_req: Request): Promise<Response> {
16
+ return handle(_req)
17
+ }
@@ -0,0 +1,24 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Returns the list of registered form definitions (name + schema) and the
4
+ // configured adapter kind. Consumed by the AdminModal "Submissions" tab to
5
+ // render the form picker and decide whether local submissions are readable.
6
+ //
7
+ // See ARCHITECTURE.md §6.5.
8
+
9
+ import { createFormsListHandler } from '@agntcms/next/handlers'
10
+ import config from '@/agntcms/config'
11
+ import { submissionAdapter } from '../../_shared'
12
+
13
+ // `adapter: submissionAdapter.info` is wired so the AdminModal knows whether
14
+ // submissions are locally readable. Without it the handler would default to
15
+ // `{ kind: 'fs' }` and the modal would issue 501-returning fetches against a
16
+ // webhook adapter.
17
+ const handle = createFormsListHandler({
18
+ forms: config.forms,
19
+ adapter: submissionAdapter.info,
20
+ })
21
+
22
+ export async function GET(req: Request): Promise<Response> {
23
+ return handle(req)
24
+ }
@@ -0,0 +1,23 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Two modes:
4
+ // GET /api/agntcms/forms/read?form=X — list submissions for form X
5
+ // GET /api/agntcms/forms/read?form=X&id=Y — read one submission by ID
6
+ //
7
+ // Returns 501 when the configured SubmissionStorageAdapter is webhook-only
8
+ // (no local copies). The AdminModal "Submissions" tab uses this to surface
9
+ // a "no local copy" hint.
10
+ //
11
+ // See ARCHITECTURE.md §6.5.
12
+
13
+ import { createFormsReadHandler } from '@agntcms/next/handlers'
14
+ import { submissionAdapter } from '../../_shared'
15
+ import config from '@/agntcms/config'
16
+
17
+ const knownForms = new Set(config.forms.map((f) => f.name))
18
+
19
+ const handle = createFormsReadHandler({ submissionAdapter, knownForms })
20
+
21
+ export async function GET(req: Request): Promise<Response> {
22
+ return handle(req)
23
+ }
@@ -0,0 +1,17 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Accepts form submissions from <Form definition={...} /> client components.
4
+ // Validates the payload against the registered form schema, applies the
5
+ // honeypot suppression check, enforces the per-IP-per-form rate limit, and
6
+ // stores the submission via the configured SubmissionStorageAdapter.
7
+ //
8
+ // See ARCHITECTURE.md §6.5 for the full submission pipeline.
9
+
10
+ import { createSubmitFormHandler } from '@agntcms/next/handlers'
11
+ import { runtime, rateLimit } from '../../_shared'
12
+
13
+ const handle = createSubmitFormHandler({ runtime, rateLimit })
14
+
15
+ export async function POST(req: Request): Promise<Response> {
16
+ return handle(req)
17
+ }
@@ -0,0 +1,13 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Deletes a global content block by name.
4
+
5
+ import { createGlobalHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter } from '../../_shared'
7
+ import config from '@/agntcms/config'
8
+
9
+ const allowedTypes = new Set(config.sections.map((s) => s.name))
10
+
11
+ const { delete: DELETE } = createGlobalHandler({ contentAdapter, allowedTypes })
12
+
13
+ export { DELETE }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Lists version history snapshots for a global.
4
+
5
+ import { createGlobalHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter } from '../../_shared'
7
+
8
+ const { listHistory: GET } = createGlobalHandler({ contentAdapter })
9
+
10
+ export { GET }
@@ -0,0 +1,14 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Returns the list of all globals with their names, types, and timestamps.
4
+ // Includes registered section type names for the admin UI picker.
5
+
6
+ import { createGlobalHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter } from '../../_shared'
8
+ import config from '@/agntcms/config'
9
+
10
+ const allowedTypes = new Set(config.sections.map((s) => s.name))
11
+
12
+ const { list: GET } = createGlobalHandler({ contentAdapter, allowedTypes })
13
+
14
+ export { GET }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Returns a single global content block by name.
4
+ // Accepts: GET /api/agntcms/global/read?name=<name>
5
+
6
+ import { createGlobalHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter } from '../../_shared'
8
+
9
+ const { read: GET } = createGlobalHandler({ contentAdapter })
10
+
11
+ export { GET }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Rolls back a global to a previous version snapshot.
4
+
5
+ import { createGlobalHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter } from '../../_shared'
7
+
8
+ const { rollback: POST } = createGlobalHandler({ contentAdapter })
9
+
10
+ export { POST }
@@ -0,0 +1,14 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Creates or updates a global content block.
4
+
5
+ import { createGlobalHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter } from '../../_shared'
7
+ import config from '@/agntcms/config'
8
+
9
+ const allowedTypes = new Set(config.sections.map((s) => s.name))
10
+ const sectionDefaults = new Map(config.sections.map((s) => [s.name, s.defaults]))
11
+
12
+ const { save: POST } = createGlobalHandler({ contentAdapter, allowedTypes, sectionDefaults })
13
+
14
+ export { POST }
@@ -0,0 +1,12 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Action-discriminated endpoint for the AgentBridge lifecycle and task
4
+ // dispatch. Accepts { action: "start" | "stop" | "status" | "push_task" }.
5
+ // The bridge starts lazily: call { action: "start" } before pushing tasks.
6
+
7
+ import { createMcpHandler } from '@agntcms/next/handlers'
8
+ import { bridge, taskStore } from '../_shared'
9
+
10
+ const { POST } = createMcpHandler({ bridge, taskStore })
11
+
12
+ export { POST }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Deletes a published page and its draft (if any). History is preserved.
4
+
5
+ import { createPageHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter, runtime } from '../../_shared'
7
+
8
+ const { deletePage: POST } = createPageHandler({ contentAdapter, runtime })
9
+
10
+ export { POST }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Duplicates a page under a new slug, saving the clone as a draft.
4
+ // The request body must contain { slug, newSlug }.
5
+
6
+ import { createPageHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter, runtime } from '../../_shared'
8
+
9
+ const { duplicate: POST } = createPageHandler({ contentAdapter, runtime })
10
+
11
+ export { POST }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Lists version history snapshots for a page.
4
+
5
+ import { createPageHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter, runtime } from '../../_shared'
7
+
8
+ const { listHistory: GET } = createPageHandler({ contentAdapter, runtime })
9
+
10
+ export { GET }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Returns the list of all pages (published and drafts) with their status.
4
+
5
+ import { createPageHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter, runtime } from '../../_shared'
7
+
8
+ const { list: GET } = createPageHandler({ contentAdapter, runtime })
9
+
10
+ export { GET }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Returns a single page by slug. Draft is returned if one exists,
4
+ // otherwise the published version is returned.
5
+
6
+ import { createPageHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter, runtime } from '../../_shared'
8
+
9
+ const { read: GET } = createPageHandler({ contentAdapter, runtime })
10
+
11
+ export { GET }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Atomically renames a page slug.
4
+
5
+ import { createPageHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter, runtime } from '../../_shared'
7
+
8
+ const { rename: POST } = createPageHandler({ contentAdapter, runtime })
9
+
10
+ export { POST }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Rolls back a page to a previous version snapshot.
4
+
5
+ import { createPageHandler } from '@agntcms/next/handlers'
6
+ import { contentAdapter, runtime } from '../../_shared'
7
+
8
+ const { rollback: POST } = createPageHandler({ contentAdapter, runtime })
9
+
10
+ export { POST }
@@ -0,0 +1,11 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Unpublishes a page. If only a published version exists, its content is preserved as a draft.
4
+ // Draft (if any) is kept. History is preserved.
5
+
6
+ import { createPageHandler } from '@agntcms/next/handlers'
7
+ import { contentAdapter, runtime } from '../../_shared'
8
+
9
+ const { unpublish: POST } = createPageHandler({ contentAdapter, runtime })
10
+
11
+ export { POST }
@@ -0,0 +1,13 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Preview mode entry. POST sets the cookie directly; GET exchanges a
4
+ // one-time token for the cookie and redirects to the page.
5
+
6
+ import { createPreviewHandler } from '@agntcms/next/handlers'
7
+ import { previewTokenStore } from '../../_shared'
8
+
9
+ const handler = createPreviewHandler({ tokenStore: previewTokenStore })
10
+ const POST = handler.enter
11
+ const GET = handler.enterWithToken
12
+
13
+ export { POST, GET }
@@ -0,0 +1,10 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Clears the preview-mode cookie, returning the site to published-only
4
+ // content rendering.
5
+
6
+ import { createPreviewHandler } from '@agntcms/next/handlers'
7
+
8
+ const { exit: POST } = createPreviewHandler()
9
+
10
+ export { POST }
@@ -0,0 +1,12 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Issues a one-time preview token for a given slug. The agent calls this
4
+ // after creating or updating a page, then sends the resulting URL to the
5
+ // editor.
6
+
7
+ import { createPreviewHandler } from '@agntcms/next/handlers'
8
+ import { previewTokenStore } from '../../_shared'
9
+
10
+ const { issueToken: POST } = createPreviewHandler({ tokenStore: previewTokenStore })
11
+
12
+ export { POST }
@@ -0,0 +1,15 @@
1
+ // FROZEN — do not edit. Framework file managed by agntcms.
2
+ //
3
+ // Returns the list of configured page-creation templates with each section's
4
+ // default field values pre-resolved from the registered section definitions.
5
+
6
+ import { createTemplateHandler } from '@agntcms/next/handlers'
7
+ import config from '@/agntcms/config'
8
+
9
+ // Build a map from section type name to its pre-computed default data so
10
+ // the handler can resolve template sections without importing from config/.
11
+ const sectionDefaults = new Map(config.sections.map((s) => [s.name, s.defaults]))
12
+
13
+ const { list: GET } = createTemplateHandler({ sectionDefaults, templates: config.templates })
14
+
15
+ export { GET }
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180">
2
+ <rect width="180" height="180" fill="#141413"/>
3
+ <g stroke="#E8E6DC" stroke-width="15" stroke-linecap="square" fill="none">
4
+ <line x1="45" y1="135" x2="90" y2="34"/>
5
+ <line x1="90" y1="34" x2="135" y2="135"/>
6
+ <line x1="62" y1="101" x2="118" y2="101"/>
7
+ </g>
8
+ <rect x="45" y="152" width="90" height="11" fill="#00C9A7"/>
9
+ </svg>