octocms 0.4.9 → 0.4.12

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 (90) hide show
  1. package/dist/admin/AdminApp.d.ts +2 -2
  2. package/dist/admin/AdminApp.d.ts.map +1 -1
  3. package/dist/admin/AdminApp.js +1 -2
  4. package/dist/admin/AdminApp.js.map +1 -1
  5. package/dist/admin/actions/files.d.ts.map +1 -1
  6. package/dist/admin/actions/files.js +1 -0
  7. package/dist/admin/actions/files.js.map +1 -1
  8. package/dist/admin/actions/git.d.ts +17 -0
  9. package/dist/admin/actions/git.d.ts.map +1 -1
  10. package/dist/admin/actions/git.js +11 -0
  11. package/dist/admin/actions/git.js.map +1 -1
  12. package/dist/admin/github.d.ts +16 -0
  13. package/dist/admin/github.d.ts.map +1 -1
  14. package/dist/admin/github.js +27 -0
  15. package/dist/admin/github.js.map +1 -1
  16. package/dist/admin/query/hooks/useRecentCMSPullRequests.d.ts +7 -0
  17. package/dist/admin/query/hooks/useRecentCMSPullRequests.d.ts.map +1 -0
  18. package/dist/admin/query/hooks/useRecentCMSPullRequests.js +16 -0
  19. package/dist/admin/query/hooks/useRecentCMSPullRequests.js.map +1 -0
  20. package/dist/admin/query/keys.d.ts +1 -0
  21. package/dist/admin/query/keys.d.ts.map +1 -1
  22. package/dist/admin/query/keys.js +2 -1
  23. package/dist/admin/query/keys.js.map +1 -1
  24. package/dist/agent/index.cjs +29 -1
  25. package/dist/agent/index.cjs.map +1 -1
  26. package/dist/chunk-L27J3XWV.js +7 -0
  27. package/dist/chunk-L27J3XWV.js.map +1 -0
  28. package/dist/cli/index.js +3 -3
  29. package/dist/components/Dashboard/DashboardContent.d.ts.map +1 -1
  30. package/dist/components/Dashboard/DashboardContent.js +30 -9
  31. package/dist/components/Dashboard/DashboardContent.js.map +1 -1
  32. package/dist/components/Dashboard/RecentPullRequests.d.ts +7 -0
  33. package/dist/components/Dashboard/RecentPullRequests.d.ts.map +1 -0
  34. package/dist/components/Dashboard/RecentPullRequests.js +96 -0
  35. package/dist/components/Dashboard/RecentPullRequests.js.map +1 -0
  36. package/dist/components/Dashboard/skeletons/{DashboardPageChromeSkeleton.d.ts → ContentPageChromeSkeleton.d.ts} +3 -3
  37. package/dist/components/Dashboard/skeletons/ContentPageChromeSkeleton.d.ts.map +1 -0
  38. package/dist/components/Dashboard/skeletons/{DashboardPageChromeSkeleton.js → ContentPageChromeSkeleton.js} +3 -3
  39. package/dist/components/Dashboard/skeletons/ContentPageChromeSkeleton.js.map +1 -0
  40. package/dist/components/FormImageField.d.ts +9 -1
  41. package/dist/components/FormImageField.d.ts.map +1 -1
  42. package/dist/components/FormImageField.js +20 -12
  43. package/dist/components/FormImageField.js.map +1 -1
  44. package/dist/components/FormMarkdownField.d.ts.map +1 -1
  45. package/dist/components/FormMarkdownField.js +36 -0
  46. package/dist/components/FormMarkdownField.js.map +1 -1
  47. package/dist/components/Layout/TopHeader.d.ts.map +1 -1
  48. package/dist/components/Layout/TopHeader.js +2 -3
  49. package/dist/components/Layout/TopHeader.js.map +1 -1
  50. package/dist/components/MediaManager/MarkdownImageEditToolbar.d.ts +13 -0
  51. package/dist/components/MediaManager/MarkdownImageEditToolbar.d.ts.map +1 -0
  52. package/dist/components/MediaManager/MarkdownImageEditToolbar.js +83 -0
  53. package/dist/components/MediaManager/MarkdownImageEditToolbar.js.map +1 -0
  54. package/dist/components/MediaManager/MarkdownInsertImageDialog.d.ts +3 -0
  55. package/dist/components/MediaManager/MarkdownInsertImageDialog.d.ts.map +1 -0
  56. package/dist/components/MediaManager/MarkdownInsertImageDialog.js +120 -0
  57. package/dist/components/MediaManager/MarkdownInsertImageDialog.js.map +1 -0
  58. package/dist/components/skeletons/MainSlotSkeleton.js +3 -3
  59. package/dist/components/skeletons/MainSlotSkeleton.js.map +1 -1
  60. package/dist/{embeddingsGen-NZQ2RXXP.js → embeddingsGen-7MXSZQ43.js} +2 -2
  61. package/dist/{github-RGFCTMMT.js → github-7HIP6RW3.js} +28 -1
  62. package/dist/github-7HIP6RW3.js.map +1 -0
  63. package/dist/globals.css +149 -3
  64. package/dist/index.cjs +47 -19
  65. package/dist/index.cjs.map +1 -1
  66. package/dist/{init-W645ZB34.js → init-N6K464EZ.js} +2 -2
  67. package/dist/lib/stageMediaFiles.d.ts +16 -0
  68. package/dist/lib/stageMediaFiles.d.ts.map +1 -0
  69. package/dist/lib/stageMediaFiles.js +20 -0
  70. package/dist/lib/stageMediaFiles.js.map +1 -0
  71. package/dist/query.cjs +47 -19
  72. package/dist/query.cjs.map +1 -1
  73. package/dist/query.d.ts.map +1 -1
  74. package/dist/query.js +47 -19
  75. package/dist/query.js.map +1 -1
  76. package/docs/overview.md +1 -0
  77. package/docs/schema.md +31 -1
  78. package/globals.css +149 -3
  79. package/package.json +1 -1
  80. package/dist/admin/pages/DashboardPage.d.ts +0 -2
  81. package/dist/admin/pages/DashboardPage.d.ts.map +0 -1
  82. package/dist/admin/pages/DashboardPage.js +0 -18
  83. package/dist/admin/pages/DashboardPage.js.map +0 -1
  84. package/dist/chunk-GL7FGEA4.js +0 -7
  85. package/dist/chunk-GL7FGEA4.js.map +0 -1
  86. package/dist/components/Dashboard/skeletons/DashboardPageChromeSkeleton.d.ts.map +0 -1
  87. package/dist/components/Dashboard/skeletons/DashboardPageChromeSkeleton.js.map +0 -1
  88. package/dist/github-RGFCTMMT.js.map +0 -1
  89. /package/dist/{embeddingsGen-NZQ2RXXP.js.map → embeddingsGen-7MXSZQ43.js.map} +0 -0
  90. /package/dist/{init-W645ZB34.js.map → init-N6K464EZ.js.map} +0 -0
@@ -8,8 +8,8 @@ type AdminAppProps = {
8
8
  * file in the user app that re-exports this component as the default.
9
9
  *
10
10
  * Route segments map to admin pages:
11
- * /cms → DashboardPage (empty home)
12
- * /cms/content → ContentPage (all entries)
11
+ * /cms → ContentPage (admin home — content list)
12
+ * /cms/content → ContentPage (alias for /cms — kept for legacy links)
13
13
  * /cms/content/<type> → CollectionPage
14
14
  * /cms/content/<type>/<id> → EntryPage
15
15
  * /cms/chat → ChatPage (gated on `isAgentEnabled(agentConfig)`)
@@ -1 +1 @@
1
- {"version":3,"file":"AdminApp.d.ts","sourceRoot":"","sources":["../../admin/AdminApp.tsx"],"names":[],"mappings":"AAYA,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,aAAa,oDAyCvD"}
1
+ {"version":3,"file":"AdminApp.d.ts","sourceRoot":"","sources":["../../admin/AdminApp.tsx"],"names":[],"mappings":"AAWA,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,aAAa,oDAyCvD"}
@@ -6,7 +6,6 @@ import { CollectionPage } from "./pages/CollectionPage";
6
6
  import { ContentModelPage } from "./pages/ContentModelPage";
7
7
  import { ContentPage } from "./pages/ContentPage";
8
8
  import { ContentTypePage } from "./pages/ContentTypePage";
9
- import { DashboardPage } from "./pages/DashboardPage";
10
9
  import { EntryPage } from "./pages/EntryPage";
11
10
  import { MediaAssetPage } from "./pages/MediaAssetPage";
12
11
  import { MediaPage } from "./pages/MediaPage";
@@ -14,7 +13,7 @@ async function AdminApp({ params }) {
14
13
  const { path } = await params;
15
14
  const segments = path != null ? path : [];
16
15
  if (segments.length === 0) {
17
- return /* @__PURE__ */ jsx(DashboardPage, {});
16
+ return /* @__PURE__ */ jsx(ContentPage, {});
18
17
  }
19
18
  if (segments[0] === "chat") {
20
19
  return /* @__PURE__ */ jsx(ChatPage, {});
@@ -1 +1 @@
1
- {"version":3,"sources":["../../admin/AdminApp.tsx"],"sourcesContent":["import { DashboardContentSkeleton } from '../components/Dashboard/DashboardContent.skeleton';\n\nimport { ChatPage } from './pages/ChatPage';\nimport { CollectionPage } from './pages/CollectionPage';\nimport { ContentModelPage } from './pages/ContentModelPage';\nimport { ContentPage } from './pages/ContentPage';\nimport { ContentTypePage } from './pages/ContentTypePage';\nimport { DashboardPage } from './pages/DashboardPage';\nimport { EntryPage } from './pages/EntryPage';\nimport { MediaAssetPage } from './pages/MediaAssetPage';\nimport { MediaPage } from './pages/MediaPage';\n\ntype AdminAppProps = {\n params: Promise<{ path?: string[] }>;\n};\n\n/**\n * Catch-all admin router. Mounted via a single `src/app/cms/[[...path]]/page.tsx`\n * file in the user app that re-exports this component as the default.\n *\n * Route segments map to admin pages:\n * /cms → DashboardPage (empty home)\n * /cms/content → ContentPage (all entries)\n * /cms/content/<type> → CollectionPage\n * /cms/content/<type>/<id> → EntryPage\n * /cms/chat → ChatPage (gated on `isAgentEnabled(agentConfig)`)\n * /cms/media → MediaPage (library — grid + folders)\n * /cms/media/<id> → MediaAssetPage (full-page asset editor)\n * /cms/model → ContentModelPage\n * /cms/model/<type> → ContentTypePage\n *\n * **No `Suspense` in the dispatcher** — `await params` runs in this async RSC; Next.js\n * keeps the previous segment visible during navigation. Thin server shells (`*Page`)\n * hand off to client components that load via TanStack Query and render their own\n * block-level skeletons (`LeftPanelSkeleton`, `ContentTableSkeleton`, etc.).\n */\nexport async function AdminApp({ params }: AdminAppProps) {\n const { path } = await params;\n const segments = path ?? [];\n\n if (segments.length === 0) {\n return <DashboardPage />;\n }\n\n if (segments[0] === 'chat') {\n return <ChatPage />;\n }\n\n if (segments[0] === 'media') {\n if (segments.length === 1) {\n return <MediaPage />;\n }\n const id = segments[1];\n return <MediaAssetPage id={id} key={id} />;\n }\n\n if (segments[0] === 'model') {\n if (segments.length === 1) {\n return <ContentModelPage />;\n }\n const [, type] = segments;\n return <ContentTypePage type={type} key={type} />;\n }\n\n if (segments[0] === 'content') {\n if (segments.length === 1) {\n return <ContentPage />;\n }\n if (segments.length === 2) {\n const [, type] = segments;\n return <CollectionPage params={Promise.resolve({ type })} key={type} />;\n }\n const [, type, id] = segments;\n return <EntryPage params={Promise.resolve({ type, id })} key={`${type}/${id}`} />;\n }\n\n return <DashboardContentSkeleton />;\n}\n"],"mappings":";AAyCW;AAzCX,SAAS,gCAAgC;AAEzC,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AA0B1B,eAAsB,SAAS,EAAE,OAAO,GAAkB;AACxD,QAAM,EAAE,KAAK,IAAI,MAAM;AACvB,QAAM,WAAW,sBAAQ,CAAC;AAE1B,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,oBAAC,iBAAc;AAAA,EACxB;AAEA,MAAI,SAAS,CAAC,MAAM,QAAQ;AAC1B,WAAO,oBAAC,YAAS;AAAA,EACnB;AAEA,MAAI,SAAS,CAAC,MAAM,SAAS;AAC3B,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO,oBAAC,aAAU;AAAA,IACpB;AACA,UAAM,KAAK,SAAS,CAAC;AACrB,WAAO,oBAAC,kBAAe,MAAa,EAAI;AAAA,EAC1C;AAEA,MAAI,SAAS,CAAC,MAAM,SAAS;AAC3B,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO,oBAAC,oBAAiB;AAAA,IAC3B;AACA,UAAM,CAAC,EAAE,IAAI,IAAI;AACjB,WAAO,oBAAC,mBAAgB,QAAiB,IAAM;AAAA,EACjD;AAEA,MAAI,SAAS,CAAC,MAAM,WAAW;AAC7B,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO,oBAAC,eAAY;AAAA,IACtB;AACA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,CAAC,EAAEA,KAAI,IAAI;AACjB,aAAO,oBAAC,kBAAe,QAAQ,QAAQ,QAAQ,EAAE,MAAAA,MAAK,CAAC,KAAQA,KAAM;AAAA,IACvE;AACA,UAAM,CAAC,EAAE,MAAM,EAAE,IAAI;AACrB,WAAO,oBAAC,aAAU,QAAQ,QAAQ,QAAQ,EAAE,MAAM,GAAG,CAAC,KAAQ,GAAG,IAAI,IAAI,EAAE,EAAI;AAAA,EACjF;AAEA,SAAO,oBAAC,4BAAyB;AACnC;","names":["type"]}
1
+ {"version":3,"sources":["../../admin/AdminApp.tsx"],"sourcesContent":["import { DashboardContentSkeleton } from '../components/Dashboard/DashboardContent.skeleton';\n\nimport { ChatPage } from './pages/ChatPage';\nimport { CollectionPage } from './pages/CollectionPage';\nimport { ContentModelPage } from './pages/ContentModelPage';\nimport { ContentPage } from './pages/ContentPage';\nimport { ContentTypePage } from './pages/ContentTypePage';\nimport { EntryPage } from './pages/EntryPage';\nimport { MediaAssetPage } from './pages/MediaAssetPage';\nimport { MediaPage } from './pages/MediaPage';\n\ntype AdminAppProps = {\n params: Promise<{ path?: string[] }>;\n};\n\n/**\n * Catch-all admin router. Mounted via a single `src/app/cms/[[...path]]/page.tsx`\n * file in the user app that re-exports this component as the default.\n *\n * Route segments map to admin pages:\n * /cms → ContentPage (admin home — content list)\n * /cms/content → ContentPage (alias for /cms — kept for legacy links)\n * /cms/content/<type> → CollectionPage\n * /cms/content/<type>/<id> → EntryPage\n * /cms/chat → ChatPage (gated on `isAgentEnabled(agentConfig)`)\n * /cms/media → MediaPage (library — grid + folders)\n * /cms/media/<id> → MediaAssetPage (full-page asset editor)\n * /cms/model → ContentModelPage\n * /cms/model/<type> → ContentTypePage\n *\n * **No `Suspense` in the dispatcher** — `await params` runs in this async RSC; Next.js\n * keeps the previous segment visible during navigation. Thin server shells (`*Page`)\n * hand off to client components that load via TanStack Query and render their own\n * block-level skeletons (`LeftPanelSkeleton`, `ContentTableSkeleton`, etc.).\n */\nexport async function AdminApp({ params }: AdminAppProps) {\n const { path } = await params;\n const segments = path ?? [];\n\n if (segments.length === 0) {\n return <ContentPage />;\n }\n\n if (segments[0] === 'chat') {\n return <ChatPage />;\n }\n\n if (segments[0] === 'media') {\n if (segments.length === 1) {\n return <MediaPage />;\n }\n const id = segments[1];\n return <MediaAssetPage id={id} key={id} />;\n }\n\n if (segments[0] === 'model') {\n if (segments.length === 1) {\n return <ContentModelPage />;\n }\n const [, type] = segments;\n return <ContentTypePage type={type} key={type} />;\n }\n\n if (segments[0] === 'content') {\n if (segments.length === 1) {\n return <ContentPage />;\n }\n if (segments.length === 2) {\n const [, type] = segments;\n return <CollectionPage params={Promise.resolve({ type })} key={type} />;\n }\n const [, type, id] = segments;\n return <EntryPage params={Promise.resolve({ type, id })} key={`${type}/${id}`} />;\n }\n\n return <DashboardContentSkeleton />;\n}\n"],"mappings":";AAwCW;AAxCX,SAAS,gCAAgC;AAEzC,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AA0B1B,eAAsB,SAAS,EAAE,OAAO,GAAkB;AACxD,QAAM,EAAE,KAAK,IAAI,MAAM;AACvB,QAAM,WAAW,sBAAQ,CAAC;AAE1B,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,oBAAC,eAAY;AAAA,EACtB;AAEA,MAAI,SAAS,CAAC,MAAM,QAAQ;AAC1B,WAAO,oBAAC,YAAS;AAAA,EACnB;AAEA,MAAI,SAAS,CAAC,MAAM,SAAS;AAC3B,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO,oBAAC,aAAU;AAAA,IACpB;AACA,UAAM,KAAK,SAAS,CAAC;AACrB,WAAO,oBAAC,kBAAe,MAAa,EAAI;AAAA,EAC1C;AAEA,MAAI,SAAS,CAAC,MAAM,SAAS;AAC3B,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO,oBAAC,oBAAiB;AAAA,IAC3B;AACA,UAAM,CAAC,EAAE,IAAI,IAAI;AACjB,WAAO,oBAAC,mBAAgB,QAAiB,IAAM;AAAA,EACjD;AAEA,MAAI,SAAS,CAAC,MAAM,WAAW;AAC7B,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO,oBAAC,eAAY;AAAA,IACtB;AACA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,CAAC,EAAEA,KAAI,IAAI;AACjB,aAAO,oBAAC,kBAAe,QAAQ,QAAQ,QAAQ,EAAE,MAAAA,MAAK,CAAC,KAAQA,KAAM;AAAA,IACvE;AACA,UAAM,CAAC,EAAE,MAAM,EAAE,IAAI;AACrB,WAAO,oBAAC,aAAU,QAAQ,QAAQ,QAAQ,EAAE,MAAM,GAAG,CAAC,KAAQ,GAAG,IAAI,IAAI,EAAE,EAAI;AAAA,EACjF;AAEA,SAAO,oBAAC,4BAAyB;AACnC;","names":["type"]}
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../admin/actions/files.ts"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,CAAC;AA+B1B,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAgM9C;;GAEG;AACH,eAAO,MAAM,sCAAsC,QAAa,OAAO,CAAC,IAAI,CAQ3E,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAU,UAAU,MAAM,EAAE,iBAAiB,MAAM,EAAE,UAAU,MAAM,kBAyB7G,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,aAAY,MAAa,sBAgC9D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,QAAa,OAAO,CAAC,MAAM,EAAE,CAkB7D,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,SAAQ,MAAa,sBAqBxD,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,UAAU,MAAM,iBAkF7C,CAAC;AAuBF,eAAO,MAAM,QAAQ,GACnB,UAAU,GAAG,EACb,UAAU,MAAM,EAChB,UAAU;IAAE,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAAE,KAC3C,OAAO,CAAC,cAAc,CAoJxB,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,aAAa,CAmDjE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,YAAY,CA2DvE,CAAC"}
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../admin/actions/files.ts"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,CAAC;AA+B1B,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAgM9C;;GAEG;AACH,eAAO,MAAM,sCAAsC,QAAa,OAAO,CAAC,IAAI,CAQ3E,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAU,UAAU,MAAM,EAAE,iBAAiB,MAAM,EAAE,UAAU,MAAM,kBAyB7G,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,aAAY,MAAa,sBAgC9D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,QAAa,OAAO,CAAC,MAAM,EAAE,CAkB7D,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,SAAQ,MAAa,sBAqBxD,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,UAAU,MAAM,iBAkF7C,CAAC;AAuBF,eAAO,MAAM,QAAQ,GACnB,UAAU,GAAG,EACb,UAAU,MAAM,EAChB,UAAU;IAAE,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAAE,KAC3C,OAAO,CAAC,cAAc,CAoJxB,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,aAAa,CAoDjE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,YAAY,CA2DvE,CAAC"}
@@ -551,6 +551,7 @@ const newFile = async (type) => {
551
551
  process.cwd(),
552
552
  file
553
553
  );
554
+ await fsPromises.mkdir(path.dirname(filePath), { recursive: true });
554
555
  await fsPromises.writeFile(filePath, normalizedData, "utf8");
555
556
  await persistBranchHistoryEntryIfNeeded(activeBranchDev, file);
556
557
  await syncEmbeddingsForUpsertIfEnabled(file, values, {}, activeBranchDev, false);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../admin/actions/files.ts"],"sourcesContent":["'use server';\n\nimport './registerConfig';\n\nimport fsPromises from 'fs/promises';\nimport path from 'path';\n\nimport { glob } from 'glob';\nimport { cookies } from 'next/headers';\n\nimport { getConfig } from '../../lib/configStore';\nimport { getAgentConfig } from '../../agent/configStore';\nimport { syncEmbeddingsAfterRemove, syncEmbeddingsAfterUpsert } from '../../agent/embeddingsHook';\nimport { BRANCH_HISTORY_FILE_PATH, mergeHistoryContentWithAppendedEntry } from '../../lib/branchHistory';\nimport { companionMarkdownPathsForEntry, companionRichTextPathsForEntry } from '../../lib/companionMarkdown';\nimport { initialFieldsForNewEntry } from '../../lib/initialEntryFields';\nimport { persistedFieldsFromFormStrings } from '../../lib/persistedFormFields';\nimport { normalizeStoredSlug } from '../../lib/slugField';\nimport { validateEntryFields } from '../../lib/validateEntryFields';\nimport type { Config } from '../types';\n\nimport {\n deleteGitHubFile,\n getGitHubFile,\n isProductionMode,\n listGitHubFiles,\n listGitHubFilesRecursive,\n readGitHubFilePublic,\n saveGitHubFile,\n} from '../github';\nimport { applyMutation, getStoredContentFiles, getStoredFile, getStoredFileSha } from '../store/contentStore';\nimport { mediaContentFolder, mediaEntryPath } from '../../lib/mediaPath';\nimport { buildJsons } from './build';\nimport {\n actionErr,\n actionOk,\n getErrorMessage,\n type ActionResult,\n type NewFileResult,\n type SaveFileResult,\n} from './utils';\n\nexport type { SaveFileResult } from './utils';\n\nconst CMS_ACTIVE_BRANCH_COOKIE = 'cms-active-branch';\n\nfunction normalizeContentPath(p: string): string {\n return p.replace(/\\\\/g, '/');\n}\n\n/** Best-effort embedding store sync after content writes. No-op when the agent isn't configured. */\nasync function syncEmbeddingsForUpsertIfEnabled(\n entryPath: string,\n payload: { sys?: { type?: string }; fields?: Record<string, unknown> },\n companions: Record<string, string>,\n branch: string | undefined,\n isProduction: boolean,\n): Promise<void> {\n const agentConfig = getAgentConfig();\n if (!agentConfig) return;\n const config = getConfig();\n await syncEmbeddingsAfterUpsert({ agentConfig, config, entryPath, payload, companions, branch, isProduction });\n}\n\nasync function syncEmbeddingsForRemoveIfEnabled(\n entryPath: string,\n branch: string | undefined,\n isProduction: boolean,\n): Promise<void> {\n const agentConfig = getAgentConfig();\n if (!agentConfig) return;\n await syncEmbeddingsAfterRemove({ agentConfig, entryPath, branch, isProduction });\n}\n\n/** Records the entry path under the active branch in `cms/branch-history.json` (GitHub or local). Best-effort. */\nasync function persistBranchHistoryEntryIfNeeded(activeBranch: string | undefined, entryPath: string): Promise<void> {\n if (!activeBranch) {\n return;\n }\n\n const normalized = normalizeContentPath(entryPath);\n\n if (isProductionMode()) {\n try {\n const historyFile = await getGitHubFile(BRANCH_HISTORY_FILE_PATH, activeBranch);\n const next = mergeHistoryContentWithAppendedEntry(historyFile?.content ?? '', activeBranch, normalized);\n if (next == null) {\n return;\n }\n\n await saveGitHubFile(BRANCH_HISTORY_FILE_PATH, next, 'CMS: track entry in branch history', activeBranch);\n } catch {\n /* best-effort sidecar — primary save must still succeed */\n }\n\n return;\n }\n\n try {\n const abs = path.join(/*turbopackIgnore: true*/ process.cwd(), BRANCH_HISTORY_FILE_PATH);\n let raw = '';\n try {\n raw = await fsPromises.readFile(abs, { encoding: 'utf8' });\n } catch {\n raw = '';\n }\n\n const next = mergeHistoryContentWithAppendedEntry(raw, activeBranch, normalized);\n if (next == null) {\n return;\n }\n\n await fsPromises.mkdir(path.dirname(abs), { recursive: true });\n await fsPromises.writeFile(abs, next, 'utf8');\n } catch {\n /* best-effort sidecar */\n }\n}\n\nasync function assertSlugFieldsUnique(\n entryType: string,\n fileName: string,\n persistedFields: Record<string, unknown>,\n): Promise<{ ok: true } | { ok: false; fieldKey: string; message: string }> {\n const config = getConfig();\n const col = config.collections[entryType as keyof Config['collections']];\n if (!col) {\n return { ok: true };\n }\n\n const slugFieldEntries = Object.entries(col.fields).filter(([, def]) => def.format === 'slug');\n if (slugFieldEntries.length === 0) {\n return { ok: true };\n }\n\n const selfPath = normalizeContentPath(fileName);\n const siblings = await getContentFiles(entryType);\n if (!Array.isArray(siblings)) {\n return { ok: true };\n }\n\n for (const [slugKey] of slugFieldEntries) {\n const candidate = persistedFields[slugKey];\n if (typeof candidate !== 'string' || !candidate.trim()) {\n continue;\n }\n const normCandidate = normalizeStoredSlug(candidate);\n if (!normCandidate) {\n continue;\n }\n\n for (const siblingPath of siblings) {\n if (normalizeContentPath(siblingPath) === selfPath) {\n continue;\n }\n let data: unknown;\n try {\n data = await getFile(siblingPath);\n } catch {\n continue;\n }\n if (!data || typeof data !== 'object') {\n continue;\n }\n const fields = (data as { fields?: Record<string, unknown> }).fields;\n if (!fields) {\n continue;\n }\n const other = fields[slugKey];\n if (typeof other !== 'string' || !other.trim()) {\n continue;\n }\n if (normalizeStoredSlug(other) === normCandidate) {\n return {\n ok: false,\n fieldKey: slugKey,\n message: `Another ${col.label} already uses this slug. Choose a different value.`,\n };\n }\n }\n }\n\n return { ok: true };\n}\n\nconst MEDIA_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nasync function assertImageFieldsReferenceMediaWithTitle(\n entryType: string,\n strFields: Record<string, string>,\n): Promise<{ ok: true } | { ok: false; fieldKey: string; message: string }> {\n const config = getConfig();\n const col = config.collections[entryType as keyof Config['collections']];\n if (!col) {\n return { ok: true };\n }\n\n for (const [key, def] of Object.entries(col.fields)) {\n if (def.format !== 'image') {\n continue;\n }\n const raw = (strFields[key] ?? '').trim();\n if (!raw || raw.startsWith('/')) {\n continue;\n }\n if (!MEDIA_UUID_RE.test(raw)) {\n continue;\n }\n\n const mediaPath = mediaEntryPath(raw);\n let media: unknown;\n try {\n media = await getFile(mediaPath);\n } catch {\n return {\n ok: false,\n fieldKey: key,\n message: `Media not found for ${def.label}. Choose a valid image in the Media library.`,\n };\n }\n\n const title = (media as { fields?: { title?: unknown } })?.fields?.title;\n if (typeof title !== 'string' || !title.trim()) {\n return {\n ok: false,\n fieldKey: key,\n message: `Selected image is missing a required Title; fix it in the Media library.`,\n };\n }\n }\n\n return { ok: true };\n}\n\n/**\n * In production, reject writes that would target `config.git.baseBranch` (no feature branch cookie).\n */\nexport const assertFeatureBranchForWritesIfRequired = async (): Promise<void> => {\n if (!isProductionMode()) {\n return;\n }\n\n if (!(await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value) {\n throw new Error('Create or select a branch before editing.');\n }\n};\n\nexport const waitForPublicReadConsistency = async (fileName: string, expectedContent: string, readRef?: string) => {\n if (!isProductionMode()) {\n return;\n }\n\n const parsedAttempts = Number.parseInt(process.env.CMS_GITHUB_CONSISTENCY_ATTEMPTS || '8', 10);\n const parsedDelayMs = Number.parseInt(process.env.CMS_GITHUB_CONSISTENCY_DELAY_MS || '250', 10);\n const maxAttempts = Number.isFinite(parsedAttempts) && parsedAttempts > 0 ? parsedAttempts : 1;\n const delayMs = Number.isFinite(parsedDelayMs) && parsedDelayMs >= 0 ? parsedDelayMs : 250;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const visibleContent = await readGitHubFilePublic(fileName, readRef);\n\n if (visibleContent === expectedContent) {\n return;\n }\n } catch (_e) {\n // Ignore transient read failures and retry within the same save request.\n }\n\n if (attempt < maxAttempts && delayMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n};\n\nexport const getContentFiles = async (collection: string = '**') => {\n const config = getConfig();\n try {\n if (isProductionMode()) {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n // Try in-memory store first (instant)\n try {\n const stored = await getStoredContentFiles(collection, activeBranch);\n if (stored) return stored;\n } catch {\n // Store unavailable — fall through to direct GitHub API\n }\n\n try {\n if (collection === '**') {\n const listed = await listGitHubFilesRecursive(config.contentFolder, '.json', activeBranch);\n return Array.isArray(listed) ? listed : [];\n }\n\n const listed = await listGitHubFiles(`${config.contentFolder}/${collection}`, '.json', activeBranch);\n return Array.isArray(listed) ? listed : [];\n } catch (e) {\n // Fall back to local files if GitHub API access is not available.\n }\n }\n\n const files = await glob(`${config.contentFolder}/${collection}/*.json`);\n return files || [];\n } catch (e) {\n return [];\n }\n};\n\n/**\n * List media-entry JSON files (e.g. `cms/media/media-<uuid>.json`).\n *\n * Distinct from `getContentFiles`, which lists editorial content under\n * `config.contentFolder`, and from `getMediaFiles`, which lists physical image\n * binaries under `config.mediaFolder`. This is the JSON-entry layer.\n */\nexport const getMediaContentFiles = async (): Promise<string[]> => {\n const folder = mediaContentFolder();\n try {\n if (isProductionMode()) {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n try {\n return await listGitHubFiles(folder, '.json', activeBranch);\n } catch (_e) {\n // Fall back to local files if GitHub API access is not available.\n }\n }\n\n const files = await glob(`${folder}/*.json`);\n return files || [];\n } catch (_e) {\n return [];\n }\n};\n\nexport const getMediaFiles = async (folder: string = '**') => {\n const config = getConfig();\n try {\n if (isProductionMode()) {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n try {\n const dir = folder === '**' ? config.mediaFolder : `${config.mediaFolder}/${folder}`;\n const allFiles = await listGitHubFilesRecursive(dir, undefined, activeBranch);\n const extensions = config.mediaAllowedFormats;\n return allFiles.filter((f) => extensions.some((ext) => f.endsWith(`.${ext}`)));\n } catch (e) {\n // Fall back to local files if GitHub API access is not available.\n }\n }\n\n const files = await glob(`${config.mediaFolder}/${folder}/*.{${config.mediaAllowedFormats.join(',')}}`);\n return files || [];\n } catch (e) {\n return [];\n }\n};\n\nexport const getFile = async (fileName: string) => {\n const config = getConfig();\n try {\n let entry: any;\n\n if (isProductionMode()) {\n // Try in-memory store first (instant, includes pre-merged companions)\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const stored = await getStoredFile(fileName, activeBranch);\n\n if (stored) {\n entry = structuredClone(stored.content);\n // Merge pre-cached companion markdown into fields\n if (entry.fields) {\n for (const [fieldName, mdContent] of Object.entries(stored.companionMarkdown)) {\n entry.fields[fieldName] = mdContent;\n }\n }\n return entry;\n }\n } catch {\n // Store unavailable — fall through to direct GitHub API\n }\n\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const result = await getGitHubFile(fileName, activeBranch);\n\n if (result) {\n entry = JSON.parse(result.content);\n }\n } catch (e) {\n // Fall back to local file if GitHub API access is not available.\n }\n\n // Cold serverless instance: content store is empty. `getGitHubFile` may return null\n // (404 race) or throw before `readGitHubFilePublic`'s multi-client retry path runs.\n // Never fall through to `fs.readFile` on deploy — the repo is not on disk (ENOENT → 500).\n if (!entry) {\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const raw = await readGitHubFilePublic(fileName, activeBranch);\n if (raw) {\n entry = JSON.parse(raw);\n }\n } catch {\n /* best-effort */\n }\n }\n }\n\n if (!entry) {\n if (isProductionMode()) {\n return {};\n }\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), fileName);\n const data = await fsPromises.readFile(filePath, { encoding: 'utf8' });\n entry = JSON.parse(data);\n }\n\n if (!entry) {\n return {};\n }\n\n // Merge companion markdown and richtext files into fields\n const collectionType = entry?.sys?.type;\n if (typeof collectionType === 'string' && entry.fields) {\n const companionPaths = companionMarkdownPathsForEntry(fileName, collectionType, config.collections);\n for (const [fieldName, mdPath] of Object.entries(companionPaths)) {\n entry.fields[fieldName] = await readCompanionMarkdownContent(mdPath);\n }\n const richTextPaths = companionRichTextPathsForEntry(fileName, collectionType, config.collections);\n for (const [fieldName, mdxPath] of Object.entries(richTextPaths)) {\n entry.fields[fieldName] = await readCompanionMarkdownContent(mdxPath);\n }\n }\n\n return entry;\n } catch (e) {\n throw new Error('Failed to get file');\n }\n};\n\n/** Read a companion markdown file as a string. Returns `\"\"` if the file does not exist. */\nasync function readCompanionMarkdownContent(filePath: string): Promise<string> {\n if (isProductionMode()) {\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const result = await getGitHubFile(filePath, activeBranch);\n return result?.content ?? '';\n } catch {\n return '';\n }\n }\n\n try {\n return await fsPromises.readFile(path.join(/*turbopackIgnore: true*/ process.cwd(), filePath), {\n encoding: 'utf8',\n });\n } catch {\n return '';\n }\n}\n\nexport const saveFile = async (\n formData: any,\n fileName: string,\n options?: { skipStatusTransition?: boolean },\n): Promise<SaveFileResult> => {\n const config = getConfig();\n try {\n let payload = formData;\n const entryType = payload?.sys?.type;\n const rawFields = payload?.fields;\n if (typeof entryType === 'string' && rawFields && typeof rawFields === 'object' && !Array.isArray(rawFields)) {\n const strFields: Record<string, string> = {};\n for (const [k, v] of Object.entries(rawFields)) {\n if (v == null) {\n strFields[k] = '';\n } else if (typeof v === 'object') {\n strFields[k] = JSON.stringify(v);\n } else {\n strFields[k] = String(v);\n }\n }\n const validated = validateEntryFields(entryType, strFields);\n if (!validated.ok) {\n const first = Object.values(validated.fieldErrors)[0];\n return {\n success: false,\n error: first || 'Validation failed',\n fieldErrors: validated.fieldErrors,\n };\n }\n\n const mediaTitles = await assertImageFieldsReferenceMediaWithTitle(entryType, strFields);\n if (!mediaTitles.ok) {\n return {\n success: false,\n error: mediaTitles.message,\n fieldErrors: { [mediaTitles.fieldKey]: mediaTitles.message },\n };\n }\n\n payload = {\n ...payload,\n fields: persistedFieldsFromFormStrings(entryType, strFields),\n };\n\n const slugUnique = await assertSlugFieldsUnique(entryType, fileName, payload.fields);\n if (!slugUnique.ok) {\n return {\n success: false,\n error: slugUnique.message,\n fieldErrors: { [slugUnique.fieldKey]: slugUnique.message },\n };\n }\n }\n\n // New entries start as draft (hidden from `query()`). First successful save promotes to `changed`\n // so they become eligible for public pages once the workspace branch is published from the header.\n if (!options?.skipStatusTransition && payload?.sys?.status === 'draft') {\n payload = { ...payload, sys: { ...payload.sys, status: 'changed' } };\n }\n\n // Auto-transition published/merged → changed on regular save (not on explicit publish)\n if (!options?.skipStatusTransition && (payload?.sys?.status === 'published' || payload?.sys?.status === 'merged')) {\n payload = { ...payload, sys: { ...payload.sys, status: 'changed' } };\n }\n\n // Extract markdown and richtext fields into companion files, remove from JSON payload\n const markdownContents: Record<string, string> = {};\n if (typeof entryType === 'string' && payload.fields) {\n const companionPaths = companionMarkdownPathsForEntry(fileName, entryType, config.collections);\n for (const [fieldName] of Object.entries(companionPaths)) {\n markdownContents[fieldName] = payload.fields[fieldName] ?? '';\n delete payload.fields[fieldName];\n }\n const richTextPaths = companionRichTextPathsForEntry(fileName, entryType, config.collections);\n for (const [fieldName] of Object.entries(richTextPaths)) {\n markdownContents[fieldName] = payload.fields[fieldName] ?? '';\n delete payload.fields[fieldName];\n }\n }\n\n const data = JSON.stringify(payload, null, 2);\n const normalizedData = `${data}\\n`;\n\n if (isProductionMode()) {\n await assertFeatureBranchForWritesIfRequired();\n const entryTypeLabel = payload?.sys?.type || 'content';\n const entryId = payload?.sys?.id || '';\n const message = `Update ${entryTypeLabel} ${entryId}`;\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n // Use cached SHA from the store to skip the pre-read API call\n const cachedSha = (await getStoredFileSha(fileName, activeBranch)) || undefined;\n await saveGitHubFile(fileName, normalizedData, message, activeBranch, cachedSha);\n // Write companion markdown and richtext files\n const mdPaths =\n typeof entryType === 'string' ? companionMarkdownPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, mdPath] of Object.entries(mdPaths)) {\n const mdContent = markdownContents[fieldName] ?? '';\n await saveGitHubFile(mdPath, mdContent, `Update ${fieldName} for ${entryType} ${entryId}`, activeBranch);\n }\n const rtPaths =\n typeof entryType === 'string' ? companionRichTextPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, rtPath] of Object.entries(rtPaths)) {\n const rtContent = markdownContents[fieldName] ?? '';\n await saveGitHubFile(rtPath, rtContent, `Update ${fieldName} for ${entryType} ${entryId}`, activeBranch);\n }\n await waitForPublicReadConsistency(fileName, normalizedData);\n\n // Write-through: update in-memory store so subsequent reads are instant\n if (activeBranch) {\n applyMutation(activeBranch, {\n type: 'upsert',\n path: fileName,\n content: payload,\n sha: '', // SHA unknown after single-file commit; next tree fetch will correct it\n companions: markdownContents,\n });\n }\n\n await persistBranchHistoryEntryIfNeeded(activeBranch, fileName);\n await syncEmbeddingsForUpsertIfEnabled(fileName, payload, markdownContents, activeBranch, true);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n }\n\n const cookieStore = await cookies();\n const activeBranchDev = cookieStore.get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), fileName);\n await fsPromises.writeFile(filePath, normalizedData, 'utf8');\n // Write companion markdown and richtext files\n const mdPaths =\n typeof entryType === 'string' ? companionMarkdownPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, mdPath] of Object.entries(mdPaths)) {\n const mdContent = markdownContents[fieldName] ?? '';\n await fsPromises.writeFile(path.join(/*turbopackIgnore: true*/ process.cwd(), mdPath), mdContent, 'utf8');\n }\n const rtPathsDev =\n typeof entryType === 'string' ? companionRichTextPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, rtPath] of Object.entries(rtPathsDev)) {\n const rtContent = markdownContents[fieldName] ?? '';\n await fsPromises.writeFile(path.join(/*turbopackIgnore: true*/ process.cwd(), rtPath), rtContent, 'utf8');\n }\n await persistBranchHistoryEntryIfNeeded(activeBranchDev, fileName);\n await syncEmbeddingsForUpsertIfEnabled(fileName, payload, markdownContents, activeBranchDev, false);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n } catch (e) {\n return actionErr(new Error(`Failed to save file: ${getErrorMessage(e)}`));\n }\n};\n\nexport const newFile = async (type: string): Promise<NewFileResult> => {\n const config = getConfig();\n try {\n const id = crypto.randomUUID();\n const values = {\n sys: {\n id,\n type,\n status: 'draft' as const,\n },\n fields: initialFieldsForNewEntry(type),\n };\n const data = JSON.stringify(values, null, 2);\n const file = `${config.contentFolder}/${type}/${type}-${id}.json`;\n const normalizedData = `${data}\\n`;\n\n if (isProductionMode()) {\n await assertFeatureBranchForWritesIfRequired();\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n await saveGitHubFile(file, normalizedData, `Create new ${type} ${id}`, activeBranch);\n await waitForPublicReadConsistency(file, normalizedData);\n\n // Write-through: add new entry to in-memory store\n if (activeBranch) {\n applyMutation(activeBranch, {\n type: 'upsert',\n path: file,\n content: values,\n sha: '',\n });\n }\n\n await persistBranchHistoryEntryIfNeeded(activeBranch, file);\n await syncEmbeddingsForUpsertIfEnabled(file, values, {}, activeBranch, true);\n const built = await buildJsons(file);\n\n return built.success ? { success: true, path: file } : { success: false, error: built.error };\n }\n\n const cookieStore = await cookies();\n const activeBranchDev = cookieStore.get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), file);\n await fsPromises.writeFile(filePath, normalizedData, 'utf8');\n await persistBranchHistoryEntryIfNeeded(activeBranchDev, file);\n await syncEmbeddingsForUpsertIfEnabled(file, values, {}, activeBranchDev, false);\n const built = await buildJsons(file);\n\n return built.success ? { success: true, path: file } : { success: false, error: built.error };\n } catch (e) {\n return { success: false, error: getErrorMessage(e) } satisfies NewFileResult;\n }\n};\n\nexport const removeFile = async (fileName: string): Promise<ActionResult> => {\n const config = getConfig();\n try {\n let collectionType: string | undefined;\n try {\n const existing = await getFile(fileName);\n collectionType = existing?.sys?.type;\n } catch {\n /* best-effort */\n }\n\n // Determine companion markdown and richtext files to delete\n const companionPaths =\n typeof collectionType === 'string'\n ? [\n ...Object.values(companionMarkdownPathsForEntry(fileName, collectionType, config.collections)),\n ...Object.values(companionRichTextPathsForEntry(fileName, collectionType, config.collections)),\n ]\n : [];\n\n if (isProductionMode()) {\n await assertFeatureBranchForWritesIfRequired();\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n await deleteGitHubFile(fileName, `Remove ${fileName}`, activeBranch);\n for (const mdPath of companionPaths) {\n try {\n await deleteGitHubFile(mdPath, `Remove companion ${mdPath}`, activeBranch);\n } catch {\n /* best-effort — companion may not exist */\n }\n }\n\n // Write-through: remove entry from in-memory store\n if (activeBranch) {\n applyMutation(activeBranch, { type: 'delete', path: fileName });\n }\n\n await syncEmbeddingsForRemoveIfEnabled(fileName, activeBranch, true);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n }\n\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), fileName);\n await fsPromises.unlink(filePath);\n for (const mdPath of companionPaths) {\n try {\n await fsPromises.unlink(path.join(/*turbopackIgnore: true*/ process.cwd(), mdPath));\n } catch {\n /* best-effort — companion may not exist */\n }\n }\n await syncEmbeddingsForRemoveIfEnabled(fileName, undefined, false);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n } catch (e) {\n return actionErr(e);\n }\n};\n"],"mappings":"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","names":["listed","mdPaths","built"]}
1
+ {"version":3,"sources":["../../../admin/actions/files.ts"],"sourcesContent":["'use server';\n\nimport './registerConfig';\n\nimport fsPromises from 'fs/promises';\nimport path from 'path';\n\nimport { glob } from 'glob';\nimport { cookies } from 'next/headers';\n\nimport { getConfig } from '../../lib/configStore';\nimport { getAgentConfig } from '../../agent/configStore';\nimport { syncEmbeddingsAfterRemove, syncEmbeddingsAfterUpsert } from '../../agent/embeddingsHook';\nimport { BRANCH_HISTORY_FILE_PATH, mergeHistoryContentWithAppendedEntry } from '../../lib/branchHistory';\nimport { companionMarkdownPathsForEntry, companionRichTextPathsForEntry } from '../../lib/companionMarkdown';\nimport { initialFieldsForNewEntry } from '../../lib/initialEntryFields';\nimport { persistedFieldsFromFormStrings } from '../../lib/persistedFormFields';\nimport { normalizeStoredSlug } from '../../lib/slugField';\nimport { validateEntryFields } from '../../lib/validateEntryFields';\nimport type { Config } from '../types';\n\nimport {\n deleteGitHubFile,\n getGitHubFile,\n isProductionMode,\n listGitHubFiles,\n listGitHubFilesRecursive,\n readGitHubFilePublic,\n saveGitHubFile,\n} from '../github';\nimport { applyMutation, getStoredContentFiles, getStoredFile, getStoredFileSha } from '../store/contentStore';\nimport { mediaContentFolder, mediaEntryPath } from '../../lib/mediaPath';\nimport { buildJsons } from './build';\nimport {\n actionErr,\n actionOk,\n getErrorMessage,\n type ActionResult,\n type NewFileResult,\n type SaveFileResult,\n} from './utils';\n\nexport type { SaveFileResult } from './utils';\n\nconst CMS_ACTIVE_BRANCH_COOKIE = 'cms-active-branch';\n\nfunction normalizeContentPath(p: string): string {\n return p.replace(/\\\\/g, '/');\n}\n\n/** Best-effort embedding store sync after content writes. No-op when the agent isn't configured. */\nasync function syncEmbeddingsForUpsertIfEnabled(\n entryPath: string,\n payload: { sys?: { type?: string }; fields?: Record<string, unknown> },\n companions: Record<string, string>,\n branch: string | undefined,\n isProduction: boolean,\n): Promise<void> {\n const agentConfig = getAgentConfig();\n if (!agentConfig) return;\n const config = getConfig();\n await syncEmbeddingsAfterUpsert({ agentConfig, config, entryPath, payload, companions, branch, isProduction });\n}\n\nasync function syncEmbeddingsForRemoveIfEnabled(\n entryPath: string,\n branch: string | undefined,\n isProduction: boolean,\n): Promise<void> {\n const agentConfig = getAgentConfig();\n if (!agentConfig) return;\n await syncEmbeddingsAfterRemove({ agentConfig, entryPath, branch, isProduction });\n}\n\n/** Records the entry path under the active branch in `cms/branch-history.json` (GitHub or local). Best-effort. */\nasync function persistBranchHistoryEntryIfNeeded(activeBranch: string | undefined, entryPath: string): Promise<void> {\n if (!activeBranch) {\n return;\n }\n\n const normalized = normalizeContentPath(entryPath);\n\n if (isProductionMode()) {\n try {\n const historyFile = await getGitHubFile(BRANCH_HISTORY_FILE_PATH, activeBranch);\n const next = mergeHistoryContentWithAppendedEntry(historyFile?.content ?? '', activeBranch, normalized);\n if (next == null) {\n return;\n }\n\n await saveGitHubFile(BRANCH_HISTORY_FILE_PATH, next, 'CMS: track entry in branch history', activeBranch);\n } catch {\n /* best-effort sidecar — primary save must still succeed */\n }\n\n return;\n }\n\n try {\n const abs = path.join(/*turbopackIgnore: true*/ process.cwd(), BRANCH_HISTORY_FILE_PATH);\n let raw = '';\n try {\n raw = await fsPromises.readFile(abs, { encoding: 'utf8' });\n } catch {\n raw = '';\n }\n\n const next = mergeHistoryContentWithAppendedEntry(raw, activeBranch, normalized);\n if (next == null) {\n return;\n }\n\n await fsPromises.mkdir(path.dirname(abs), { recursive: true });\n await fsPromises.writeFile(abs, next, 'utf8');\n } catch {\n /* best-effort sidecar */\n }\n}\n\nasync function assertSlugFieldsUnique(\n entryType: string,\n fileName: string,\n persistedFields: Record<string, unknown>,\n): Promise<{ ok: true } | { ok: false; fieldKey: string; message: string }> {\n const config = getConfig();\n const col = config.collections[entryType as keyof Config['collections']];\n if (!col) {\n return { ok: true };\n }\n\n const slugFieldEntries = Object.entries(col.fields).filter(([, def]) => def.format === 'slug');\n if (slugFieldEntries.length === 0) {\n return { ok: true };\n }\n\n const selfPath = normalizeContentPath(fileName);\n const siblings = await getContentFiles(entryType);\n if (!Array.isArray(siblings)) {\n return { ok: true };\n }\n\n for (const [slugKey] of slugFieldEntries) {\n const candidate = persistedFields[slugKey];\n if (typeof candidate !== 'string' || !candidate.trim()) {\n continue;\n }\n const normCandidate = normalizeStoredSlug(candidate);\n if (!normCandidate) {\n continue;\n }\n\n for (const siblingPath of siblings) {\n if (normalizeContentPath(siblingPath) === selfPath) {\n continue;\n }\n let data: unknown;\n try {\n data = await getFile(siblingPath);\n } catch {\n continue;\n }\n if (!data || typeof data !== 'object') {\n continue;\n }\n const fields = (data as { fields?: Record<string, unknown> }).fields;\n if (!fields) {\n continue;\n }\n const other = fields[slugKey];\n if (typeof other !== 'string' || !other.trim()) {\n continue;\n }\n if (normalizeStoredSlug(other) === normCandidate) {\n return {\n ok: false,\n fieldKey: slugKey,\n message: `Another ${col.label} already uses this slug. Choose a different value.`,\n };\n }\n }\n }\n\n return { ok: true };\n}\n\nconst MEDIA_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nasync function assertImageFieldsReferenceMediaWithTitle(\n entryType: string,\n strFields: Record<string, string>,\n): Promise<{ ok: true } | { ok: false; fieldKey: string; message: string }> {\n const config = getConfig();\n const col = config.collections[entryType as keyof Config['collections']];\n if (!col) {\n return { ok: true };\n }\n\n for (const [key, def] of Object.entries(col.fields)) {\n if (def.format !== 'image') {\n continue;\n }\n const raw = (strFields[key] ?? '').trim();\n if (!raw || raw.startsWith('/')) {\n continue;\n }\n if (!MEDIA_UUID_RE.test(raw)) {\n continue;\n }\n\n const mediaPath = mediaEntryPath(raw);\n let media: unknown;\n try {\n media = await getFile(mediaPath);\n } catch {\n return {\n ok: false,\n fieldKey: key,\n message: `Media not found for ${def.label}. Choose a valid image in the Media library.`,\n };\n }\n\n const title = (media as { fields?: { title?: unknown } })?.fields?.title;\n if (typeof title !== 'string' || !title.trim()) {\n return {\n ok: false,\n fieldKey: key,\n message: `Selected image is missing a required Title; fix it in the Media library.`,\n };\n }\n }\n\n return { ok: true };\n}\n\n/**\n * In production, reject writes that would target `config.git.baseBranch` (no feature branch cookie).\n */\nexport const assertFeatureBranchForWritesIfRequired = async (): Promise<void> => {\n if (!isProductionMode()) {\n return;\n }\n\n if (!(await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value) {\n throw new Error('Create or select a branch before editing.');\n }\n};\n\nexport const waitForPublicReadConsistency = async (fileName: string, expectedContent: string, readRef?: string) => {\n if (!isProductionMode()) {\n return;\n }\n\n const parsedAttempts = Number.parseInt(process.env.CMS_GITHUB_CONSISTENCY_ATTEMPTS || '8', 10);\n const parsedDelayMs = Number.parseInt(process.env.CMS_GITHUB_CONSISTENCY_DELAY_MS || '250', 10);\n const maxAttempts = Number.isFinite(parsedAttempts) && parsedAttempts > 0 ? parsedAttempts : 1;\n const delayMs = Number.isFinite(parsedDelayMs) && parsedDelayMs >= 0 ? parsedDelayMs : 250;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const visibleContent = await readGitHubFilePublic(fileName, readRef);\n\n if (visibleContent === expectedContent) {\n return;\n }\n } catch (_e) {\n // Ignore transient read failures and retry within the same save request.\n }\n\n if (attempt < maxAttempts && delayMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n};\n\nexport const getContentFiles = async (collection: string = '**') => {\n const config = getConfig();\n try {\n if (isProductionMode()) {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n // Try in-memory store first (instant)\n try {\n const stored = await getStoredContentFiles(collection, activeBranch);\n if (stored) return stored;\n } catch {\n // Store unavailable — fall through to direct GitHub API\n }\n\n try {\n if (collection === '**') {\n const listed = await listGitHubFilesRecursive(config.contentFolder, '.json', activeBranch);\n return Array.isArray(listed) ? listed : [];\n }\n\n const listed = await listGitHubFiles(`${config.contentFolder}/${collection}`, '.json', activeBranch);\n return Array.isArray(listed) ? listed : [];\n } catch (e) {\n // Fall back to local files if GitHub API access is not available.\n }\n }\n\n const files = await glob(`${config.contentFolder}/${collection}/*.json`);\n return files || [];\n } catch (e) {\n return [];\n }\n};\n\n/**\n * List media-entry JSON files (e.g. `cms/media/media-<uuid>.json`).\n *\n * Distinct from `getContentFiles`, which lists editorial content under\n * `config.contentFolder`, and from `getMediaFiles`, which lists physical image\n * binaries under `config.mediaFolder`. This is the JSON-entry layer.\n */\nexport const getMediaContentFiles = async (): Promise<string[]> => {\n const folder = mediaContentFolder();\n try {\n if (isProductionMode()) {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n try {\n return await listGitHubFiles(folder, '.json', activeBranch);\n } catch (_e) {\n // Fall back to local files if GitHub API access is not available.\n }\n }\n\n const files = await glob(`${folder}/*.json`);\n return files || [];\n } catch (_e) {\n return [];\n }\n};\n\nexport const getMediaFiles = async (folder: string = '**') => {\n const config = getConfig();\n try {\n if (isProductionMode()) {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n try {\n const dir = folder === '**' ? config.mediaFolder : `${config.mediaFolder}/${folder}`;\n const allFiles = await listGitHubFilesRecursive(dir, undefined, activeBranch);\n const extensions = config.mediaAllowedFormats;\n return allFiles.filter((f) => extensions.some((ext) => f.endsWith(`.${ext}`)));\n } catch (e) {\n // Fall back to local files if GitHub API access is not available.\n }\n }\n\n const files = await glob(`${config.mediaFolder}/${folder}/*.{${config.mediaAllowedFormats.join(',')}}`);\n return files || [];\n } catch (e) {\n return [];\n }\n};\n\nexport const getFile = async (fileName: string) => {\n const config = getConfig();\n try {\n let entry: any;\n\n if (isProductionMode()) {\n // Try in-memory store first (instant, includes pre-merged companions)\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const stored = await getStoredFile(fileName, activeBranch);\n\n if (stored) {\n entry = structuredClone(stored.content);\n // Merge pre-cached companion markdown into fields\n if (entry.fields) {\n for (const [fieldName, mdContent] of Object.entries(stored.companionMarkdown)) {\n entry.fields[fieldName] = mdContent;\n }\n }\n return entry;\n }\n } catch {\n // Store unavailable — fall through to direct GitHub API\n }\n\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const result = await getGitHubFile(fileName, activeBranch);\n\n if (result) {\n entry = JSON.parse(result.content);\n }\n } catch (e) {\n // Fall back to local file if GitHub API access is not available.\n }\n\n // Cold serverless instance: content store is empty. `getGitHubFile` may return null\n // (404 race) or throw before `readGitHubFilePublic`'s multi-client retry path runs.\n // Never fall through to `fs.readFile` on deploy — the repo is not on disk (ENOENT → 500).\n if (!entry) {\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const raw = await readGitHubFilePublic(fileName, activeBranch);\n if (raw) {\n entry = JSON.parse(raw);\n }\n } catch {\n /* best-effort */\n }\n }\n }\n\n if (!entry) {\n if (isProductionMode()) {\n return {};\n }\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), fileName);\n const data = await fsPromises.readFile(filePath, { encoding: 'utf8' });\n entry = JSON.parse(data);\n }\n\n if (!entry) {\n return {};\n }\n\n // Merge companion markdown and richtext files into fields\n const collectionType = entry?.sys?.type;\n if (typeof collectionType === 'string' && entry.fields) {\n const companionPaths = companionMarkdownPathsForEntry(fileName, collectionType, config.collections);\n for (const [fieldName, mdPath] of Object.entries(companionPaths)) {\n entry.fields[fieldName] = await readCompanionMarkdownContent(mdPath);\n }\n const richTextPaths = companionRichTextPathsForEntry(fileName, collectionType, config.collections);\n for (const [fieldName, mdxPath] of Object.entries(richTextPaths)) {\n entry.fields[fieldName] = await readCompanionMarkdownContent(mdxPath);\n }\n }\n\n return entry;\n } catch (e) {\n throw new Error('Failed to get file');\n }\n};\n\n/** Read a companion markdown file as a string. Returns `\"\"` if the file does not exist. */\nasync function readCompanionMarkdownContent(filePath: string): Promise<string> {\n if (isProductionMode()) {\n try {\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const result = await getGitHubFile(filePath, activeBranch);\n return result?.content ?? '';\n } catch {\n return '';\n }\n }\n\n try {\n return await fsPromises.readFile(path.join(/*turbopackIgnore: true*/ process.cwd(), filePath), {\n encoding: 'utf8',\n });\n } catch {\n return '';\n }\n}\n\nexport const saveFile = async (\n formData: any,\n fileName: string,\n options?: { skipStatusTransition?: boolean },\n): Promise<SaveFileResult> => {\n const config = getConfig();\n try {\n let payload = formData;\n const entryType = payload?.sys?.type;\n const rawFields = payload?.fields;\n if (typeof entryType === 'string' && rawFields && typeof rawFields === 'object' && !Array.isArray(rawFields)) {\n const strFields: Record<string, string> = {};\n for (const [k, v] of Object.entries(rawFields)) {\n if (v == null) {\n strFields[k] = '';\n } else if (typeof v === 'object') {\n strFields[k] = JSON.stringify(v);\n } else {\n strFields[k] = String(v);\n }\n }\n const validated = validateEntryFields(entryType, strFields);\n if (!validated.ok) {\n const first = Object.values(validated.fieldErrors)[0];\n return {\n success: false,\n error: first || 'Validation failed',\n fieldErrors: validated.fieldErrors,\n };\n }\n\n const mediaTitles = await assertImageFieldsReferenceMediaWithTitle(entryType, strFields);\n if (!mediaTitles.ok) {\n return {\n success: false,\n error: mediaTitles.message,\n fieldErrors: { [mediaTitles.fieldKey]: mediaTitles.message },\n };\n }\n\n payload = {\n ...payload,\n fields: persistedFieldsFromFormStrings(entryType, strFields),\n };\n\n const slugUnique = await assertSlugFieldsUnique(entryType, fileName, payload.fields);\n if (!slugUnique.ok) {\n return {\n success: false,\n error: slugUnique.message,\n fieldErrors: { [slugUnique.fieldKey]: slugUnique.message },\n };\n }\n }\n\n // New entries start as draft (hidden from `query()`). First successful save promotes to `changed`\n // so they become eligible for public pages once the workspace branch is published from the header.\n if (!options?.skipStatusTransition && payload?.sys?.status === 'draft') {\n payload = { ...payload, sys: { ...payload.sys, status: 'changed' } };\n }\n\n // Auto-transition published/merged → changed on regular save (not on explicit publish)\n if (!options?.skipStatusTransition && (payload?.sys?.status === 'published' || payload?.sys?.status === 'merged')) {\n payload = { ...payload, sys: { ...payload.sys, status: 'changed' } };\n }\n\n // Extract markdown and richtext fields into companion files, remove from JSON payload\n const markdownContents: Record<string, string> = {};\n if (typeof entryType === 'string' && payload.fields) {\n const companionPaths = companionMarkdownPathsForEntry(fileName, entryType, config.collections);\n for (const [fieldName] of Object.entries(companionPaths)) {\n markdownContents[fieldName] = payload.fields[fieldName] ?? '';\n delete payload.fields[fieldName];\n }\n const richTextPaths = companionRichTextPathsForEntry(fileName, entryType, config.collections);\n for (const [fieldName] of Object.entries(richTextPaths)) {\n markdownContents[fieldName] = payload.fields[fieldName] ?? '';\n delete payload.fields[fieldName];\n }\n }\n\n const data = JSON.stringify(payload, null, 2);\n const normalizedData = `${data}\\n`;\n\n if (isProductionMode()) {\n await assertFeatureBranchForWritesIfRequired();\n const entryTypeLabel = payload?.sys?.type || 'content';\n const entryId = payload?.sys?.id || '';\n const message = `Update ${entryTypeLabel} ${entryId}`;\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n\n // Use cached SHA from the store to skip the pre-read API call\n const cachedSha = (await getStoredFileSha(fileName, activeBranch)) || undefined;\n await saveGitHubFile(fileName, normalizedData, message, activeBranch, cachedSha);\n // Write companion markdown and richtext files\n const mdPaths =\n typeof entryType === 'string' ? companionMarkdownPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, mdPath] of Object.entries(mdPaths)) {\n const mdContent = markdownContents[fieldName] ?? '';\n await saveGitHubFile(mdPath, mdContent, `Update ${fieldName} for ${entryType} ${entryId}`, activeBranch);\n }\n const rtPaths =\n typeof entryType === 'string' ? companionRichTextPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, rtPath] of Object.entries(rtPaths)) {\n const rtContent = markdownContents[fieldName] ?? '';\n await saveGitHubFile(rtPath, rtContent, `Update ${fieldName} for ${entryType} ${entryId}`, activeBranch);\n }\n await waitForPublicReadConsistency(fileName, normalizedData);\n\n // Write-through: update in-memory store so subsequent reads are instant\n if (activeBranch) {\n applyMutation(activeBranch, {\n type: 'upsert',\n path: fileName,\n content: payload,\n sha: '', // SHA unknown after single-file commit; next tree fetch will correct it\n companions: markdownContents,\n });\n }\n\n await persistBranchHistoryEntryIfNeeded(activeBranch, fileName);\n await syncEmbeddingsForUpsertIfEnabled(fileName, payload, markdownContents, activeBranch, true);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n }\n\n const cookieStore = await cookies();\n const activeBranchDev = cookieStore.get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), fileName);\n await fsPromises.writeFile(filePath, normalizedData, 'utf8');\n // Write companion markdown and richtext files\n const mdPaths =\n typeof entryType === 'string' ? companionMarkdownPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, mdPath] of Object.entries(mdPaths)) {\n const mdContent = markdownContents[fieldName] ?? '';\n await fsPromises.writeFile(path.join(/*turbopackIgnore: true*/ process.cwd(), mdPath), mdContent, 'utf8');\n }\n const rtPathsDev =\n typeof entryType === 'string' ? companionRichTextPathsForEntry(fileName, entryType, config.collections) : {};\n for (const [fieldName, rtPath] of Object.entries(rtPathsDev)) {\n const rtContent = markdownContents[fieldName] ?? '';\n await fsPromises.writeFile(path.join(/*turbopackIgnore: true*/ process.cwd(), rtPath), rtContent, 'utf8');\n }\n await persistBranchHistoryEntryIfNeeded(activeBranchDev, fileName);\n await syncEmbeddingsForUpsertIfEnabled(fileName, payload, markdownContents, activeBranchDev, false);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n } catch (e) {\n return actionErr(new Error(`Failed to save file: ${getErrorMessage(e)}`));\n }\n};\n\nexport const newFile = async (type: string): Promise<NewFileResult> => {\n const config = getConfig();\n try {\n const id = crypto.randomUUID();\n const values = {\n sys: {\n id,\n type,\n status: 'draft' as const,\n },\n fields: initialFieldsForNewEntry(type),\n };\n const data = JSON.stringify(values, null, 2);\n const file = `${config.contentFolder}/${type}/${type}-${id}.json`;\n const normalizedData = `${data}\\n`;\n\n if (isProductionMode()) {\n await assertFeatureBranchForWritesIfRequired();\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n await saveGitHubFile(file, normalizedData, `Create new ${type} ${id}`, activeBranch);\n await waitForPublicReadConsistency(file, normalizedData);\n\n // Write-through: add new entry to in-memory store\n if (activeBranch) {\n applyMutation(activeBranch, {\n type: 'upsert',\n path: file,\n content: values,\n sha: '',\n });\n }\n\n await persistBranchHistoryEntryIfNeeded(activeBranch, file);\n await syncEmbeddingsForUpsertIfEnabled(file, values, {}, activeBranch, true);\n const built = await buildJsons(file);\n\n return built.success ? { success: true, path: file } : { success: false, error: built.error };\n }\n\n const cookieStore = await cookies();\n const activeBranchDev = cookieStore.get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), file);\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n await fsPromises.writeFile(filePath, normalizedData, 'utf8');\n await persistBranchHistoryEntryIfNeeded(activeBranchDev, file);\n await syncEmbeddingsForUpsertIfEnabled(file, values, {}, activeBranchDev, false);\n const built = await buildJsons(file);\n\n return built.success ? { success: true, path: file } : { success: false, error: built.error };\n } catch (e) {\n return { success: false, error: getErrorMessage(e) } satisfies NewFileResult;\n }\n};\n\nexport const removeFile = async (fileName: string): Promise<ActionResult> => {\n const config = getConfig();\n try {\n let collectionType: string | undefined;\n try {\n const existing = await getFile(fileName);\n collectionType = existing?.sys?.type;\n } catch {\n /* best-effort */\n }\n\n // Determine companion markdown and richtext files to delete\n const companionPaths =\n typeof collectionType === 'string'\n ? [\n ...Object.values(companionMarkdownPathsForEntry(fileName, collectionType, config.collections)),\n ...Object.values(companionRichTextPathsForEntry(fileName, collectionType, config.collections)),\n ]\n : [];\n\n if (isProductionMode()) {\n await assertFeatureBranchForWritesIfRequired();\n const activeBranch = (await cookies()).get(CMS_ACTIVE_BRANCH_COOKIE)?.value;\n await deleteGitHubFile(fileName, `Remove ${fileName}`, activeBranch);\n for (const mdPath of companionPaths) {\n try {\n await deleteGitHubFile(mdPath, `Remove companion ${mdPath}`, activeBranch);\n } catch {\n /* best-effort — companion may not exist */\n }\n }\n\n // Write-through: remove entry from in-memory store\n if (activeBranch) {\n applyMutation(activeBranch, { type: 'delete', path: fileName });\n }\n\n await syncEmbeddingsForRemoveIfEnabled(fileName, activeBranch, true);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n }\n\n const filePath = path.join(/*turbopackIgnore: true*/ process.cwd(), fileName);\n await fsPromises.unlink(filePath);\n for (const mdPath of companionPaths) {\n try {\n await fsPromises.unlink(path.join(/*turbopackIgnore: true*/ process.cwd(), mdPath));\n } catch {\n /* best-effort — companion may not exist */\n }\n }\n await syncEmbeddingsForRemoveIfEnabled(fileName, undefined, false);\n const built = await buildJsons(fileName);\n\n return built.success ? actionOk() : built;\n } catch (e) {\n return actionErr(e);\n }\n};\n"],"mappings":"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","names":["listed","mdPaths","built"]}
@@ -1,4 +1,5 @@
1
1
  import './registerConfig';
2
+ import { type RecentCMSPullRequestState } from '../github';
2
3
  import type { EntryCommitHistory } from '../../types';
3
4
  import { type ActionResult, type CreateBranchInput, type CreateBranchResult, type CreatePRResult } from './utils';
4
5
  export declare const pushToGit: () => Promise<ActionResult>;
@@ -56,4 +57,20 @@ export declare const publishBranch: (branchName: string) => Promise<ActionResult
56
57
  * shape so the UI never throws.
57
58
  */
58
59
  export declare const getEntryCommits: (filePath: string) => Promise<EntryCommitHistory>;
60
+ export type RecentCMSPullRequest = {
61
+ branch: string;
62
+ prUrl: string;
63
+ prNumber: number;
64
+ title: string;
65
+ state: RecentCMSPullRequestState;
66
+ updatedAt: string;
67
+ authorLogin: string | null;
68
+ authorAvatarUrl: string | null;
69
+ };
70
+ /**
71
+ * Most-recently-updated PRs tagged with the `cms-update` label, across all
72
+ * states (open / merged / closed). Powers the dashboard "Recent pull requests"
73
+ * card. Returns `[]` in dev or on error.
74
+ */
75
+ export declare const getRecentCMSPullRequests: (limit?: number) => Promise<RecentCMSPullRequest[]>;
59
76
  //# sourceMappingURL=git.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../admin/actions/git.ts"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,CAAC;AAsB1B,OAAO,KAAK,EAAe,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAQnE,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAQjB,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,YAAY,CA2BtD,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAa,OAAO,CAAC,cAAc,CAYvD,CAAC;AAEF,eAAO,MAAM,eAAe,wBAE3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,MAAM,CAoBhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,QAAa,OAAO,CAAC,OAAO,CAGvD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAU,OAAO,iBAAiB,KAAG,OAAO,CAAC,kBAAkB,CAoEvF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,IAAI,CAUtE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,IAAI,CAGhD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAa,OAAO,CAAC,SAAS,EAAE,CAsC3D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,YAAY,CAyB5E,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,kBAAkB,CAkDlF,CAAC"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../admin/actions/git.ts"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,CAAC;AAQ1B,OAAO,EAcL,KAAK,yBAAyB,EAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAe,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAQnE,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAQjB,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,YAAY,CA2BtD,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAa,OAAO,CAAC,cAAc,CAYvD,CAAC;AAEF,eAAO,MAAM,eAAe,wBAE3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,MAAM,CAoBhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,QAAa,OAAO,CAAC,OAAO,CAGvD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAU,OAAO,iBAAiB,KAAG,OAAO,CAAC,kBAAkB,CAoEvF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,IAAI,CAUtE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,IAAI,CAGhD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAa,OAAO,CAAC,SAAS,EAAE,CAsC3D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,YAAY,CAyB5E,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,kBAAkB,CAkDlF,CAAC;AAMF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,yBAAyB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAU,cAAS,KAAG,OAAO,CAAC,oBAAoB,EAAE,CASxF,CAAC"}
@@ -17,6 +17,7 @@ import {
17
17
  getPublishedPointerRef,
18
18
  isProductionMode,
19
19
  listGitHubCMSPullRequests,
20
+ listGitHubRecentCMSPullRequests,
20
21
  markPRReadyForReview,
21
22
  resolveContentBranch,
22
23
  saveGitHubFile
@@ -269,6 +270,15 @@ const getEntryCommits = async (filePath) => {
269
270
  return empty;
270
271
  }
271
272
  };
273
+ const getRecentCMSPullRequests = async (limit = 5) => {
274
+ if (!isProductionMode()) return [];
275
+ try {
276
+ return await listGitHubRecentCMSPullRequests(limit);
277
+ } catch (e) {
278
+ logCmsServerError({ operation: "getRecentCMSPullRequests", message: getErrorMessage(e) });
279
+ return [];
280
+ }
281
+ };
272
282
  export {
273
283
  clearBranch,
274
284
  createBranch,
@@ -276,6 +286,7 @@ export {
276
286
  getBranch,
277
287
  getEntryCommits,
278
288
  getIsProduction,
289
+ getRecentCMSPullRequests,
279
290
  hasActiveBranch,
280
291
  listCMSBranches,
281
292
  publishBranch,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../admin/actions/git.ts"],"sourcesContent":["'use server';\n\nimport './registerConfig';\n\nimport { execFile } from 'node:child_process';\n\nimport { cookies } from 'next/headers';\n\nimport { getConfig } from '../../lib/configStore';\n\nimport {\n assertGitHubConfig,\n createGitHubBranch,\n createGitHubCMSPullRequest,\n createGitHubPullRequest,\n getGitHubFile,\n getPublicOctokits,\n getPublishedPointerRef,\n isProductionMode,\n listGitHubCMSPullRequests,\n markPRReadyForReview,\n resolveContentBranch,\n saveGitHubFile,\n} from '../github';\nimport type { EntryCommit, EntryCommitHistory } from '../../types';\nimport {\n BRANCH_HISTORY_FILE_PATH,\n parseBranchHistoryFile,\n serializeBranchHistoryFile,\n upsertBranchWorkspace,\n} from '../../lib/branchHistory';\nimport { logCmsServerError } from '../../lib/cmsServerLog';\nimport {\n actionErr,\n actionOk,\n getErrorMessage,\n type ActionResult,\n type CreateBranchInput,\n type CreateBranchResult,\n type CreatePRResult,\n} from './utils';\nimport { getPointerFilePath, serializePointerPayload } from '../../lib/contentBranch';\nimport { warmBranch } from '../store/contentStore';\nimport { buildJsons } from './build';\nimport { waitForPublicReadConsistency } from './files';\n\nconst CMS_BRANCH_COOKIE = 'cms-active-branch';\n\nexport const pushToGit = async (): Promise<ActionResult> => {\n if (isProductionMode()) {\n // In production, commits are made via GitHub API on each save — no push needed\n return actionOk();\n }\n\n try {\n const cookieStore = await cookies();\n const activeBranch = cookieStore.get(CMS_BRANCH_COOKIE)?.value;\n const pushCmd = activeBranch\n ? `git commit -am CommitFromCMS && git push origin HEAD:${activeBranch}`\n : 'git commit -am CommitFromCMS && git push';\n\n await new Promise<void>((resolve, reject) => {\n execFile('sh', ['-c', pushCmd], (error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n\n return actionOk();\n } catch (e) {\n return actionErr(new Error(`Failed git push: ${getErrorMessage(e)}`));\n }\n};\n\nexport const createPR = async (): Promise<CreatePRResult> => {\n const config = getConfig();\n const baseBranch = config.git.baseBranch;\n const title = `CMS content update (${new Date().toISOString().split('T')[0]})`;\n const body = `Content changes from the CMS editor.\\n\\nSource branch: \\`${baseBranch}\\``;\n\n try {\n const { url, number } = await createGitHubPullRequest(title, body, baseBranch);\n return { success: true, url, number };\n } catch (e) {\n return actionErr(e);\n }\n};\n\nexport const getIsProduction = async () => {\n return isProductionMode();\n};\n\n/**\n * Get the currently active CMS branch.\n * In dev: falls back to the local git branch name.\n * In prod: falls back to `config.git.baseBranch`.\n */\nexport const getBranch = async (): Promise<string> => {\n const cookieStore = await cookies();\n const activeBranch = cookieStore.get(CMS_BRANCH_COOKIE)?.value;\n\n if (activeBranch) return activeBranch;\n\n if (!isProductionMode()) {\n try {\n return await new Promise<string>((resolve, reject) => {\n execFile('git', ['branch', '--show-current'], (error, stdout) => {\n if (error) reject(error);\n else resolve(stdout.trim());\n });\n });\n } catch (_e) {\n // fall through to config.git.baseBranch\n }\n }\n\n return getConfig().git.baseBranch;\n};\n\n/**\n * Returns true if a CMS feature branch is currently active (cookie is set).\n */\nexport const hasActiveBranch = async (): Promise<boolean> => {\n const cookieStore = await cookies();\n return !!cookieStore.get(CMS_BRANCH_COOKIE)?.value;\n};\n\n/**\n * Create a GitHub branch from `config.git.baseBranch`, commit `cms/branch-history.json` so the\n * branch has at least one commit, open a draft PR with the `cms-update` label (best effort),\n * and set the active CMS branch cookie.\n */\nexport const createBranch = async (input: CreateBranchInput): Promise<CreateBranchResult> => {\n const config = getConfig();\n const branchName = input.branchName.trim();\n const workspaceTitle = input.title.trim();\n const description = input.description?.trim();\n\n if (!branchName) {\n return { success: false, error: 'Branch name is required.' };\n }\n\n if (!workspaceTitle) {\n return { success: false, error: 'Workspace title is required.' };\n }\n\n const baseBranch = config.git.baseBranch;\n\n try {\n await createGitHubBranch(branchName);\n\n const historyRaw = await getGitHubFile(BRANCH_HISTORY_FILE_PATH, baseBranch);\n const historyDoc = parseBranchHistoryFile(historyRaw?.content ?? '');\n const merged = upsertBranchWorkspace(historyDoc, branchName, {\n title: workspaceTitle,\n ...(description ? { description } : {}),\n createdAt: new Date().toISOString(),\n });\n const historyContent = serializeBranchHistoryFile(merged);\n\n await saveGitHubFile(BRANCH_HISTORY_FILE_PATH, historyContent, 'CMS: add branch workspace metadata', branchName);\n } catch (e) {\n const msg = getErrorMessage(e);\n logCmsServerError({\n operation: 'createBranch.metadata',\n branch: branchName,\n message: msg,\n });\n return { success: false, error: msg };\n }\n\n const prBodyLines = [\n `Content changes from the CMS editor.`,\n '',\n `Branch: \\`${branchName}\\``,\n ...(description ? ['', description] : []),\n ];\n const prBody = prBodyLines.join('\\n');\n\n let prUrl = '';\n let prWarning: string | undefined;\n\n try {\n const pr = await createGitHubCMSPullRequest(branchName, workspaceTitle, prBody, baseBranch);\n prUrl = pr.url;\n } catch (e) {\n prWarning = getErrorMessage(e);\n }\n\n const cookieStore = await cookies();\n cookieStore.set(CMS_BRANCH_COOKIE, branchName, { path: '/' });\n\n // Pre-populate the content store for the new branch\n if (isProductionMode()) {\n warmBranch(branchName).catch(() => {\n /* best-effort */\n });\n }\n\n return prWarning ? { success: true, prUrl: '', prWarning } : { success: true, prUrl };\n};\n\n/**\n * Switch the active CMS branch to an existing branch (by PR).\n */\nexport const setActiveBranch = async (branchName: string): Promise<void> => {\n const cookieStore = await cookies();\n cookieStore.set(CMS_BRANCH_COOKIE, branchName, { path: '/' });\n\n // Pre-populate the content store so the first read after switching is instant\n if (isProductionMode()) {\n warmBranch(branchName).catch(() => {\n /* best-effort — first read will trigger a blocking fetch if this fails */\n });\n }\n};\n\n/**\n * Clear the active CMS branch, reverting listing/reads to `config.git.baseBranch`.\n */\nexport const clearBranch = async (): Promise<void> => {\n const cookieStore = await cookies();\n cookieStore.delete(CMS_BRANCH_COOKIE);\n};\n\nexport type CMSBranch = {\n branch: string;\n prUrl: string;\n prNumber: number;\n title: string;\n isPublished: boolean;\n};\n\n/**\n * List CMS branches for the header: base branch plus **open** PRs labelled `cms-update`\n * (see `listGitHubCMSPullRequests`). Remote `cms/*` refs without an open labelled PR are omitted.\n */\nexport const listCMSBranches = async (): Promise<CMSBranch[]> => {\n try {\n const config = getConfig();\n const baseBranch = config.git.baseBranch;\n const pointerBranch = config.git.publishedPointerBranch?.trim();\n\n const [publishedBranch, prList] = await Promise.all([resolveContentBranch(), listGitHubCMSPullRequests()]);\n\n const base: CMSBranch = {\n branch: baseBranch,\n prUrl: '',\n prNumber: 0,\n title: baseBranch,\n isPublished: publishedBranch === baseBranch,\n };\n\n const features: CMSBranch[] = [];\n\n for (const pr of prList) {\n const branch = pr.branch.trim();\n if (!branch || branch === baseBranch) continue;\n if (pointerBranch && branch === pointerBranch) continue;\n if (!branch.startsWith('cms/')) continue;\n features.push({\n branch,\n prUrl: pr.prUrl,\n prNumber: pr.prNumber,\n title: pr.title.trim() || branch,\n isPublished: branch === publishedBranch,\n });\n }\n\n features.sort((a, b) => b.prNumber - a.prNumber);\n\n return [base, ...features];\n } catch (_e) {\n return [];\n }\n};\n\n/**\n * Publish a branch by writing `{ \"branch\": \"<name>\", \"buildId\": \"<id>\" }` into the per-build\n * pointer file (see {@link getPointerFilePath}) on the pointer branch when\n * `config.git.publishedPointerBranch` is set, otherwise on the base branch, invalidating all\n * public caches, and marking the associated PR as ready for review.\n *\n * Public pages will serve content from the published branch on the next request.\n */\nexport const publishBranch = async (branchName: string): Promise<ActionResult> => {\n try {\n const config = getConfig();\n const baseBranch = config.git.baseBranch;\n const pointerRef = getPublishedPointerRef();\n const targetBranch = pointerRef ?? baseBranch;\n const pointerPath = getPointerFilePath();\n const content = serializePointerPayload(branchName);\n\n await saveGitHubFile(pointerPath, content, `Publish branch ${branchName} (${pointerPath})`, targetBranch);\n await waitForPublicReadConsistency(pointerPath, content, targetBranch);\n await buildJsons('');\n\n if (branchName !== baseBranch) {\n try {\n await markPRReadyForReview(branchName);\n } catch (_e) {\n // PR marking is best-effort — don't fail publish if it errors\n }\n }\n\n return actionOk();\n } catch (e) {\n return actionErr(new Error(`Failed to publish branch: ${getErrorMessage(e)}`));\n }\n};\n\n/**\n * Fetch the last 5 commits that touched the given entry file for display in the\n * editor History panel. Production-only (dev mode writes to the local FS so there\n * is no GitHub history to show). Best-effort: any failure resolves to an empty\n * shape so the UI never throws.\n */\nexport const getEntryCommits = async (filePath: string): Promise<EntryCommitHistory> => {\n const empty: EntryCommitHistory = { commits: [], seeAllUrl: '' };\n\n if (!isProductionMode()) {\n return empty;\n }\n if (!filePath) {\n return empty;\n }\n\n try {\n const { owner, repo } = assertGitHubConfig();\n const [octokit] = getPublicOctokits();\n const baseBranch = getConfig().git.baseBranch;\n\n const { data } = await octokit.rest.repos.listCommits({\n owner,\n repo,\n path: filePath,\n per_page: 5,\n });\n\n const commits: EntryCommit[] = data.slice(0, 5).map((c) => {\n const gitAuthor = c.commit.author;\n const committer = c.commit.committer;\n const ghAuthor = c.author;\n\n const message = (c.commit.message || '').split('\\n', 1)[0];\n const login = ghAuthor?.login ?? null;\n const name = gitAuthor?.name || ghAuthor?.login || 'unknown';\n const avatarUrl = ghAuthor?.avatar_url ?? null;\n const committedAt = gitAuthor?.date || committer?.date || '';\n\n return {\n sha: c.sha,\n shortSha: c.sha.slice(0, 7),\n message,\n author: { login, name, avatarUrl },\n committedAt,\n url: c.html_url,\n };\n });\n\n const seeAllUrl = `https://github.com/${owner}/${repo}/commits/${encodeURIComponent(baseBranch)}/${encodeURI(filePath)}`;\n\n return { commits, seeAllUrl };\n } catch (e) {\n logCmsServerError({ operation: 'getEntryCommits', message: getErrorMessage(e) });\n return empty;\n }\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../admin/actions/git.ts"],"sourcesContent":["'use server';\n\nimport './registerConfig';\n\nimport { execFile } from 'node:child_process';\n\nimport { cookies } from 'next/headers';\n\nimport { getConfig } from '../../lib/configStore';\n\nimport {\n assertGitHubConfig,\n createGitHubBranch,\n createGitHubCMSPullRequest,\n createGitHubPullRequest,\n getGitHubFile,\n getPublicOctokits,\n getPublishedPointerRef,\n isProductionMode,\n listGitHubCMSPullRequests,\n listGitHubRecentCMSPullRequests,\n markPRReadyForReview,\n resolveContentBranch,\n saveGitHubFile,\n type RecentCMSPullRequestState,\n} from '../github';\nimport type { EntryCommit, EntryCommitHistory } from '../../types';\nimport {\n BRANCH_HISTORY_FILE_PATH,\n parseBranchHistoryFile,\n serializeBranchHistoryFile,\n upsertBranchWorkspace,\n} from '../../lib/branchHistory';\nimport { logCmsServerError } from '../../lib/cmsServerLog';\nimport {\n actionErr,\n actionOk,\n getErrorMessage,\n type ActionResult,\n type CreateBranchInput,\n type CreateBranchResult,\n type CreatePRResult,\n} from './utils';\nimport { getPointerFilePath, serializePointerPayload } from '../../lib/contentBranch';\nimport { warmBranch } from '../store/contentStore';\nimport { buildJsons } from './build';\nimport { waitForPublicReadConsistency } from './files';\n\nconst CMS_BRANCH_COOKIE = 'cms-active-branch';\n\nexport const pushToGit = async (): Promise<ActionResult> => {\n if (isProductionMode()) {\n // In production, commits are made via GitHub API on each save — no push needed\n return actionOk();\n }\n\n try {\n const cookieStore = await cookies();\n const activeBranch = cookieStore.get(CMS_BRANCH_COOKIE)?.value;\n const pushCmd = activeBranch\n ? `git commit -am CommitFromCMS && git push origin HEAD:${activeBranch}`\n : 'git commit -am CommitFromCMS && git push';\n\n await new Promise<void>((resolve, reject) => {\n execFile('sh', ['-c', pushCmd], (error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n\n return actionOk();\n } catch (e) {\n return actionErr(new Error(`Failed git push: ${getErrorMessage(e)}`));\n }\n};\n\nexport const createPR = async (): Promise<CreatePRResult> => {\n const config = getConfig();\n const baseBranch = config.git.baseBranch;\n const title = `CMS content update (${new Date().toISOString().split('T')[0]})`;\n const body = `Content changes from the CMS editor.\\n\\nSource branch: \\`${baseBranch}\\``;\n\n try {\n const { url, number } = await createGitHubPullRequest(title, body, baseBranch);\n return { success: true, url, number };\n } catch (e) {\n return actionErr(e);\n }\n};\n\nexport const getIsProduction = async () => {\n return isProductionMode();\n};\n\n/**\n * Get the currently active CMS branch.\n * In dev: falls back to the local git branch name.\n * In prod: falls back to `config.git.baseBranch`.\n */\nexport const getBranch = async (): Promise<string> => {\n const cookieStore = await cookies();\n const activeBranch = cookieStore.get(CMS_BRANCH_COOKIE)?.value;\n\n if (activeBranch) return activeBranch;\n\n if (!isProductionMode()) {\n try {\n return await new Promise<string>((resolve, reject) => {\n execFile('git', ['branch', '--show-current'], (error, stdout) => {\n if (error) reject(error);\n else resolve(stdout.trim());\n });\n });\n } catch (_e) {\n // fall through to config.git.baseBranch\n }\n }\n\n return getConfig().git.baseBranch;\n};\n\n/**\n * Returns true if a CMS feature branch is currently active (cookie is set).\n */\nexport const hasActiveBranch = async (): Promise<boolean> => {\n const cookieStore = await cookies();\n return !!cookieStore.get(CMS_BRANCH_COOKIE)?.value;\n};\n\n/**\n * Create a GitHub branch from `config.git.baseBranch`, commit `cms/branch-history.json` so the\n * branch has at least one commit, open a draft PR with the `cms-update` label (best effort),\n * and set the active CMS branch cookie.\n */\nexport const createBranch = async (input: CreateBranchInput): Promise<CreateBranchResult> => {\n const config = getConfig();\n const branchName = input.branchName.trim();\n const workspaceTitle = input.title.trim();\n const description = input.description?.trim();\n\n if (!branchName) {\n return { success: false, error: 'Branch name is required.' };\n }\n\n if (!workspaceTitle) {\n return { success: false, error: 'Workspace title is required.' };\n }\n\n const baseBranch = config.git.baseBranch;\n\n try {\n await createGitHubBranch(branchName);\n\n const historyRaw = await getGitHubFile(BRANCH_HISTORY_FILE_PATH, baseBranch);\n const historyDoc = parseBranchHistoryFile(historyRaw?.content ?? '');\n const merged = upsertBranchWorkspace(historyDoc, branchName, {\n title: workspaceTitle,\n ...(description ? { description } : {}),\n createdAt: new Date().toISOString(),\n });\n const historyContent = serializeBranchHistoryFile(merged);\n\n await saveGitHubFile(BRANCH_HISTORY_FILE_PATH, historyContent, 'CMS: add branch workspace metadata', branchName);\n } catch (e) {\n const msg = getErrorMessage(e);\n logCmsServerError({\n operation: 'createBranch.metadata',\n branch: branchName,\n message: msg,\n });\n return { success: false, error: msg };\n }\n\n const prBodyLines = [\n `Content changes from the CMS editor.`,\n '',\n `Branch: \\`${branchName}\\``,\n ...(description ? ['', description] : []),\n ];\n const prBody = prBodyLines.join('\\n');\n\n let prUrl = '';\n let prWarning: string | undefined;\n\n try {\n const pr = await createGitHubCMSPullRequest(branchName, workspaceTitle, prBody, baseBranch);\n prUrl = pr.url;\n } catch (e) {\n prWarning = getErrorMessage(e);\n }\n\n const cookieStore = await cookies();\n cookieStore.set(CMS_BRANCH_COOKIE, branchName, { path: '/' });\n\n // Pre-populate the content store for the new branch\n if (isProductionMode()) {\n warmBranch(branchName).catch(() => {\n /* best-effort */\n });\n }\n\n return prWarning ? { success: true, prUrl: '', prWarning } : { success: true, prUrl };\n};\n\n/**\n * Switch the active CMS branch to an existing branch (by PR).\n */\nexport const setActiveBranch = async (branchName: string): Promise<void> => {\n const cookieStore = await cookies();\n cookieStore.set(CMS_BRANCH_COOKIE, branchName, { path: '/' });\n\n // Pre-populate the content store so the first read after switching is instant\n if (isProductionMode()) {\n warmBranch(branchName).catch(() => {\n /* best-effort — first read will trigger a blocking fetch if this fails */\n });\n }\n};\n\n/**\n * Clear the active CMS branch, reverting listing/reads to `config.git.baseBranch`.\n */\nexport const clearBranch = async (): Promise<void> => {\n const cookieStore = await cookies();\n cookieStore.delete(CMS_BRANCH_COOKIE);\n};\n\nexport type CMSBranch = {\n branch: string;\n prUrl: string;\n prNumber: number;\n title: string;\n isPublished: boolean;\n};\n\n/**\n * List CMS branches for the header: base branch plus **open** PRs labelled `cms-update`\n * (see `listGitHubCMSPullRequests`). Remote `cms/*` refs without an open labelled PR are omitted.\n */\nexport const listCMSBranches = async (): Promise<CMSBranch[]> => {\n try {\n const config = getConfig();\n const baseBranch = config.git.baseBranch;\n const pointerBranch = config.git.publishedPointerBranch?.trim();\n\n const [publishedBranch, prList] = await Promise.all([resolveContentBranch(), listGitHubCMSPullRequests()]);\n\n const base: CMSBranch = {\n branch: baseBranch,\n prUrl: '',\n prNumber: 0,\n title: baseBranch,\n isPublished: publishedBranch === baseBranch,\n };\n\n const features: CMSBranch[] = [];\n\n for (const pr of prList) {\n const branch = pr.branch.trim();\n if (!branch || branch === baseBranch) continue;\n if (pointerBranch && branch === pointerBranch) continue;\n if (!branch.startsWith('cms/')) continue;\n features.push({\n branch,\n prUrl: pr.prUrl,\n prNumber: pr.prNumber,\n title: pr.title.trim() || branch,\n isPublished: branch === publishedBranch,\n });\n }\n\n features.sort((a, b) => b.prNumber - a.prNumber);\n\n return [base, ...features];\n } catch (_e) {\n return [];\n }\n};\n\n/**\n * Publish a branch by writing `{ \"branch\": \"<name>\", \"buildId\": \"<id>\" }` into the per-build\n * pointer file (see {@link getPointerFilePath}) on the pointer branch when\n * `config.git.publishedPointerBranch` is set, otherwise on the base branch, invalidating all\n * public caches, and marking the associated PR as ready for review.\n *\n * Public pages will serve content from the published branch on the next request.\n */\nexport const publishBranch = async (branchName: string): Promise<ActionResult> => {\n try {\n const config = getConfig();\n const baseBranch = config.git.baseBranch;\n const pointerRef = getPublishedPointerRef();\n const targetBranch = pointerRef ?? baseBranch;\n const pointerPath = getPointerFilePath();\n const content = serializePointerPayload(branchName);\n\n await saveGitHubFile(pointerPath, content, `Publish branch ${branchName} (${pointerPath})`, targetBranch);\n await waitForPublicReadConsistency(pointerPath, content, targetBranch);\n await buildJsons('');\n\n if (branchName !== baseBranch) {\n try {\n await markPRReadyForReview(branchName);\n } catch (_e) {\n // PR marking is best-effort — don't fail publish if it errors\n }\n }\n\n return actionOk();\n } catch (e) {\n return actionErr(new Error(`Failed to publish branch: ${getErrorMessage(e)}`));\n }\n};\n\n/**\n * Fetch the last 5 commits that touched the given entry file for display in the\n * editor History panel. Production-only (dev mode writes to the local FS so there\n * is no GitHub history to show). Best-effort: any failure resolves to an empty\n * shape so the UI never throws.\n */\nexport const getEntryCommits = async (filePath: string): Promise<EntryCommitHistory> => {\n const empty: EntryCommitHistory = { commits: [], seeAllUrl: '' };\n\n if (!isProductionMode()) {\n return empty;\n }\n if (!filePath) {\n return empty;\n }\n\n try {\n const { owner, repo } = assertGitHubConfig();\n const [octokit] = getPublicOctokits();\n const baseBranch = getConfig().git.baseBranch;\n\n const { data } = await octokit.rest.repos.listCommits({\n owner,\n repo,\n path: filePath,\n per_page: 5,\n });\n\n const commits: EntryCommit[] = data.slice(0, 5).map((c) => {\n const gitAuthor = c.commit.author;\n const committer = c.commit.committer;\n const ghAuthor = c.author;\n\n const message = (c.commit.message || '').split('\\n', 1)[0];\n const login = ghAuthor?.login ?? null;\n const name = gitAuthor?.name || ghAuthor?.login || 'unknown';\n const avatarUrl = ghAuthor?.avatar_url ?? null;\n const committedAt = gitAuthor?.date || committer?.date || '';\n\n return {\n sha: c.sha,\n shortSha: c.sha.slice(0, 7),\n message,\n author: { login, name, avatarUrl },\n committedAt,\n url: c.html_url,\n };\n });\n\n const seeAllUrl = `https://github.com/${owner}/${repo}/commits/${encodeURIComponent(baseBranch)}/${encodeURI(filePath)}`;\n\n return { commits, seeAllUrl };\n } catch (e) {\n logCmsServerError({ operation: 'getEntryCommits', message: getErrorMessage(e) });\n return empty;\n }\n};\n\n// ---------------------------------------------------------------------------\n// Dashboard reads (production-only, best-effort)\n// ---------------------------------------------------------------------------\n\nexport type RecentCMSPullRequest = {\n branch: string;\n prUrl: string;\n prNumber: number;\n title: string;\n state: RecentCMSPullRequestState;\n updatedAt: string;\n authorLogin: string | null;\n authorAvatarUrl: string | null;\n};\n\n/**\n * Most-recently-updated PRs tagged with the `cms-update` label, across all\n * states (open / merged / closed). Powers the dashboard \"Recent pull requests\"\n * card. Returns `[]` in dev or on error.\n */\nexport const getRecentCMSPullRequests = async (limit = 5): Promise<RecentCMSPullRequest[]> => {\n if (!isProductionMode()) return [];\n\n try {\n return await listGitHubRecentCMSPullRequests(limit);\n } catch (e) {\n logCmsServerError({ operation: 'getRecentCMSPullRequests', message: getErrorMessage(e) });\n return [];\n }\n};\n"],"mappings":"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","names":[]}
@@ -84,6 +84,22 @@ export declare const listGitHubCMSPullRequests: () => Promise<{
84
84
  prNumber: number;
85
85
  title: string;
86
86
  }[]>;
87
+ export type RecentCMSPullRequestState = 'open' | 'merged' | 'closed';
88
+ /**
89
+ * List the most-recently-updated PRs tagged with the `cms-update` label,
90
+ * across all states (open / merged / closed). Used by the dashboard
91
+ * "Recent pull requests" card.
92
+ */
93
+ export declare const listGitHubRecentCMSPullRequests: (limit?: number) => Promise<{
94
+ branch: string;
95
+ prUrl: string;
96
+ prNumber: number;
97
+ title: string;
98
+ state: RecentCMSPullRequestState;
99
+ updatedAt: string;
100
+ authorLogin: string | null;
101
+ authorAvatarUrl: string | null;
102
+ }[]>;
87
103
  /**
88
104
  * Create a pull request from the configured branch to the target branch.
89
105
  */
@@ -1 +1 @@
1
- {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../admin/github.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../admin/github.ts"],"names":[],"mappings":"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"}
@@ -381,6 +381,32 @@ const listGitHubCMSPullRequests = async () => {
381
381
  title: pr.title
382
382
  }));
383
383
  };
384
+ const listGitHubRecentCMSPullRequests = async (limit = 5) => {
385
+ const octokit = await getWriteOctokit();
386
+ const { owner, repo } = assertGitHubConfig();
387
+ const { data: prs } = await octokit.rest.pulls.list({
388
+ owner,
389
+ repo,
390
+ state: "all",
391
+ sort: "updated",
392
+ direction: "desc",
393
+ per_page: 50
394
+ });
395
+ return prs.filter((pr) => pr.labels.some((l) => l.name === "cms-update")).slice(0, Math.max(1, limit)).map((pr) => {
396
+ var _a, _b, _c, _d;
397
+ const state = pr.merged_at ? "merged" : pr.state === "open" ? "open" : "closed";
398
+ return {
399
+ branch: pr.head.ref,
400
+ prUrl: pr.html_url,
401
+ prNumber: pr.number,
402
+ title: pr.title,
403
+ state,
404
+ updatedAt: pr.updated_at,
405
+ authorLogin: (_b = (_a = pr.user) == null ? void 0 : _a.login) != null ? _b : null,
406
+ authorAvatarUrl: (_d = (_c = pr.user) == null ? void 0 : _c.avatar_url) != null ? _d : null
407
+ };
408
+ });
409
+ };
384
410
  const createGitHubPullRequest = async (title, body, targetBranch = "main") => {
385
411
  const octokit = await getWriteOctokit();
386
412
  const { owner, repo, branch } = assertGitHubConfig();
@@ -443,6 +469,7 @@ export {
443
469
  listGitHubCMSPullRequests,
444
470
  listGitHubFiles,
445
471
  listGitHubFilesRecursive,
472
+ listGitHubRecentCMSPullRequests,
446
473
  markPRReadyForReview,
447
474
  mergePullRequest,
448
475
  readGitHubBinaryFilePublic,