@kyro-cms/admin 0.3.2 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/dist/EditorClient-XEUOVAAC.js +466 -0
  2. package/dist/EditorClient-XEUOVAAC.js.map +1 -0
  3. package/dist/EditorClient-YLCGVDXY.cjs +468 -0
  4. package/dist/EditorClient-YLCGVDXY.cjs.map +1 -0
  5. package/dist/chunk-7KPIUCGT.js +384 -0
  6. package/dist/chunk-7KPIUCGT.js.map +1 -0
  7. package/dist/chunk-GOACG6R7.cjs +473 -0
  8. package/dist/chunk-GOACG6R7.cjs.map +1 -0
  9. package/dist/index.cjs +14861 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.css +1661 -0
  12. package/dist/index.css.map +1 -0
  13. package/dist/index.d.ts +563 -0
  14. package/dist/index.js +14784 -0
  15. package/dist/index.js.map +1 -0
  16. package/package.json +19 -19
  17. package/src/components/ActionBar.tsx +7 -43
  18. package/src/components/Admin.tsx +138 -277
  19. package/src/components/ApiKeysManager.tsx +428 -419
  20. package/src/components/AuditLogsPage.tsx +35 -39
  21. package/src/components/AuthBridge.tsx +51 -0
  22. package/src/components/AutoForm.tsx +495 -1230
  23. package/src/components/BrandingHub.tsx +18 -19
  24. package/src/components/BulkActionsBar.tsx +1 -1
  25. package/src/components/CreateView.tsx +22 -36
  26. package/src/components/Dashboard.tsx +60 -84
  27. package/src/components/DetailView.tsx +113 -91
  28. package/src/components/DeveloperCenter.tsx +200 -198
  29. package/src/components/FieldRenderer.tsx +206 -0
  30. package/src/components/GraphQLPlayground.tsx +340 -480
  31. package/src/components/ListView.tsx +828 -254
  32. package/src/components/LoginPage.tsx +3 -4
  33. package/src/components/MarketplaceManager.tsx +254 -0
  34. package/src/components/MediaGallery.tsx +856 -1192
  35. package/src/components/PluginsManager.tsx +277 -0
  36. package/src/components/RestPlayground.tsx +398 -560
  37. package/src/components/SessionsManager.tsx +211 -0
  38. package/src/components/Sidebar.astro +179 -151
  39. package/src/components/ThemeProvider.tsx +7 -161
  40. package/src/components/UserManagement.tsx +162 -146
  41. package/src/components/UserMenu.tsx +110 -0
  42. package/src/components/WebhookManager.tsx +305 -367
  43. package/src/components/blocks/AccordionBlock.tsx +4 -4
  44. package/src/components/blocks/ArrayBlock.tsx +3 -3
  45. package/src/components/blocks/BlockEditModal.tsx +8 -8
  46. package/src/components/blocks/BlockWrapper.tsx +61 -0
  47. package/src/components/blocks/ButtonBlock.tsx +4 -4
  48. package/src/components/blocks/ChildBlocksTree.tsx +23 -25
  49. package/src/components/blocks/CodeBlock.tsx +15 -15
  50. package/src/components/blocks/ColumnsBlock.tsx +6 -44
  51. package/src/components/blocks/DividerBlock.tsx +3 -3
  52. package/src/components/blocks/FileBlock.tsx +4 -4
  53. package/src/components/blocks/HeadingBlock.tsx +6 -38
  54. package/src/components/blocks/HeroBlock.tsx +4 -4
  55. package/src/components/blocks/ImageBlock.tsx +4 -4
  56. package/src/components/blocks/LinkBlock.tsx +4 -4
  57. package/src/components/blocks/ListBlock.tsx +3 -3
  58. package/src/components/blocks/ParagraphBlock.tsx +12 -42
  59. package/src/components/blocks/RelationshipBlock.tsx +4 -4
  60. package/src/components/blocks/RichTextBlock.tsx +4 -4
  61. package/src/components/blocks/VStackBlock.tsx +5 -37
  62. package/src/components/blocks/VideoBlock.tsx +4 -4
  63. package/src/components/blocks/types.ts +11 -0
  64. package/src/components/fields/AccordionField.tsx +1 -1
  65. package/src/components/fields/ArrayField.tsx +2 -2
  66. package/src/components/fields/ArrayLayout.tsx +93 -0
  67. package/src/components/fields/BlocksField.tsx +122 -111
  68. package/src/components/fields/ButtonField.tsx +1 -1
  69. package/src/components/fields/CheckboxField.tsx +14 -15
  70. package/src/components/fields/ChildrenField.tsx +2 -2
  71. package/src/components/fields/CodeField.tsx +3 -3
  72. package/src/components/fields/ColumnsField.tsx +2 -2
  73. package/src/components/fields/DateField.tsx +13 -26
  74. package/src/components/fields/EditorClient.tsx +26 -28
  75. package/src/components/fields/FieldLayout.tsx +52 -0
  76. package/src/components/fields/GroupLayout.tsx +35 -0
  77. package/src/components/fields/JSONField.tsx +7 -7
  78. package/src/components/fields/LinkField.tsx +1 -1
  79. package/src/components/fields/MarkdownField.tsx +1 -1
  80. package/src/components/fields/NumberField.tsx +13 -26
  81. package/src/components/fields/PortableTextField.tsx +4 -4
  82. package/src/components/fields/PortableTextRenderer.tsx +1 -1
  83. package/src/components/fields/RelationshipBlockField.tsx +31 -23
  84. package/src/components/fields/RelationshipField.tsx +14 -14
  85. package/src/components/fields/SelectField.tsx +17 -26
  86. package/src/components/fields/TabsLayout.tsx +69 -0
  87. package/src/components/fields/TextField.tsx +85 -38
  88. package/src/components/fields/UploadField.tsx +71 -41
  89. package/src/components/fields/VideoField.tsx +1 -1
  90. package/src/components/fields/extensions/blockComponents.tsx +2 -2
  91. package/src/components/fields/extensions/blocksStore.ts +207 -193
  92. package/src/components/fields/types.ts +22 -0
  93. package/src/components/layout/Layout.tsx +1 -1
  94. package/src/components/ui/ActionMenu.tsx +63 -0
  95. package/src/components/ui/Badge.tsx +59 -5
  96. package/src/components/ui/BlockDrawer.tsx +4 -5
  97. package/src/components/ui/CommandPalette.tsx +58 -36
  98. package/src/components/ui/CommandPaletteWrapper.tsx +18 -17
  99. package/src/components/ui/Dropdown.tsx +18 -16
  100. package/src/components/ui/EmptyState.tsx +25 -0
  101. package/src/components/ui/GlobalModal.tsx +49 -0
  102. package/src/components/ui/IconButton.tsx +44 -0
  103. package/src/components/ui/Modal.tsx +19 -20
  104. package/src/components/ui/PageHeader.tsx +158 -0
  105. package/src/components/ui/Pagination.tsx +61 -0
  106. package/src/components/ui/PromptModal.tsx +1 -1
  107. package/src/components/ui/SearchInput.tsx +57 -0
  108. package/src/components/ui/SeoPreview.tsx +31 -0
  109. package/src/components/ui/SessionModal.tsx +0 -0
  110. package/src/components/ui/SlidePanel.tsx +2 -0
  111. package/src/components/ui/Toast.tsx +65 -122
  112. package/src/components/ui/Toaster.tsx +18 -0
  113. package/src/components/ui/icons.tsx +112 -0
  114. package/src/components/users/UserDetail.tsx +290 -0
  115. package/src/components/users/UserForm.tsx +242 -0
  116. package/src/components/users/UsersList.tsx +338 -0
  117. package/src/env.d.ts +13 -13
  118. package/src/fields/index.ts +2 -1
  119. package/src/global.d.ts +7 -0
  120. package/src/hooks/data.ts +2 -9
  121. package/src/hooks/useAsyncData.ts +36 -0
  122. package/src/hooks/useAutoFormState.ts +527 -0
  123. package/src/hooks/useSelection.ts +49 -0
  124. package/src/hooks/useSession.ts +0 -0
  125. package/src/index.ts +11 -1
  126. package/src/integration.ts +86 -11
  127. package/src/kyro-cms.d.ts +209 -0
  128. package/src/layouts/AdminLayout.astro +128 -11
  129. package/src/layouts/AuthLayout.astro +21 -5
  130. package/src/lib/api.ts +175 -55
  131. package/src/lib/autoform-store.ts +435 -0
  132. package/src/lib/config.ts +82 -34
  133. package/src/lib/createRegistry.ts +29 -0
  134. package/src/lib/default-kyro-config.ts +4 -0
  135. package/src/lib/globals.ts +50 -0
  136. package/src/lib/media-utils.ts +18 -0
  137. package/src/lib/object-utils.ts +77 -0
  138. package/src/lib/paths.ts +61 -0
  139. package/src/lib/stores/index.ts +370 -0
  140. package/src/lib/types.ts +43 -0
  141. package/src/lib/useResourceManager.ts +105 -0
  142. package/src/pages/403.astro +67 -0
  143. package/src/pages/[collection]/[id].astro +14 -180
  144. package/src/pages/[collection]/index.astro +11 -6
  145. package/src/pages/api-explorer.astro +173 -0
  146. package/src/pages/audit/index.astro +2 -0
  147. package/src/pages/auth/login.astro +122 -0
  148. package/src/pages/auth/register.astro +167 -0
  149. package/src/pages/graphql-explorer.astro +59 -0
  150. package/src/pages/{admin/graphql.astro → graphql.astro} +51 -17
  151. package/src/pages/index.astro +577 -0
  152. package/src/pages/index_ALT.astro +3 -0
  153. package/src/pages/keys.astro +11 -0
  154. package/src/pages/marketplace.astro +11 -0
  155. package/src/pages/media.astro +3 -0
  156. package/src/pages/plugins.astro +8 -0
  157. package/src/pages/preview/[collection]/[id].astro +188 -123
  158. package/src/pages/rest-playground.astro +62 -0
  159. package/src/pages/roles/index.astro +183 -76
  160. package/src/pages/sessions.astro +8 -0
  161. package/src/pages/settings/[slug].astro +92 -114
  162. package/src/pages/settings/index.astro +5 -3
  163. package/src/pages/users/[id].astro +25 -154
  164. package/src/pages/users/index.astro +19 -130
  165. package/src/pages/users/new.astro +9 -86
  166. package/src/pages/webhooks.astro +11 -0
  167. package/src/routes.ts +80 -0
  168. package/src/styles/main.css +119 -79
  169. package/src/theme/tokens.ts +1 -0
  170. package/src/vite-env.d.ts +14 -0
  171. package/src/collections/auth/index.ts +0 -155
  172. package/src/collections/portfolio/index.ts +0 -343
  173. package/src/components/ApiExplorer.tsx +0 -325
  174. package/src/components/EnhancedListView.tsx +0 -889
  175. package/src/components/GraphQLExplorer.tsx +0 -675
  176. package/src/components/Icons.tsx +0 -23
  177. package/src/components/StatusBadge.tsx +0 -76
  178. package/src/lib/MediaService.ts +0 -541
  179. package/src/lib/auth/sqlite-adapter.ts +0 -319
  180. package/src/lib/dataStore.ts +0 -226
  181. package/src/lib/db/adapter.ts +0 -54
  182. package/src/lib/db/drizzle-mysql-adapter.ts +0 -194
  183. package/src/lib/db/drizzle-mysql-auth-adapter.ts +0 -327
  184. package/src/lib/db/drizzle-postgres-adapter.ts +0 -202
  185. package/src/lib/db/drizzle-postgres-auth-adapter.ts +0 -304
  186. package/src/lib/db/drizzle-sqlite-adapter.ts +0 -227
  187. package/src/lib/db/drizzle-sqlite-auth-adapter.ts +0 -548
  188. package/src/lib/db/index.ts +0 -449
  189. package/src/lib/db/mongodb-adapter.ts +0 -207
  190. package/src/lib/db/mongodb-auth-adapter.ts +0 -305
  191. package/src/lib/db/schema/mysql-auth.ts +0 -113
  192. package/src/lib/db/schema/mysql-content.ts +0 -20
  193. package/src/lib/db/schema/postgres-auth.ts +0 -116
  194. package/src/lib/db/schema/postgres-content.ts +0 -35
  195. package/src/lib/db/schema/postgres-media.ts +0 -52
  196. package/src/lib/db/schema/postgres-settings.ts +0 -11
  197. package/src/lib/db/schema/sqlite-auth.ts +0 -112
  198. package/src/lib/db/schema/sqlite-content.ts +0 -20
  199. package/src/lib/db/version-adapter.ts +0 -248
  200. package/src/lib/graphql/index.ts +0 -1
  201. package/src/lib/graphql/schema.ts +0 -443
  202. package/src/lib/rate-limit.ts +0 -267
  203. package/src/lib/storage.ts +0 -374
  204. package/src/lib/store.ts +0 -85
  205. package/src/middleware.ts +0 -177
  206. package/src/pages/admin/api-explorer.astro +0 -98
  207. package/src/pages/admin/graphql-explorer.astro +0 -40
  208. package/src/pages/admin/index.astro +0 -286
  209. package/src/pages/admin/keys.astro +0 -8
  210. package/src/pages/admin/rest-playground.astro +0 -44
  211. package/src/pages/admin/webhooks.astro +0 -8
  212. package/src/pages/api/[collection]/[id]/publish.ts +0 -52
  213. package/src/pages/api/[collection]/[id]/unpublish.ts +0 -42
  214. package/src/pages/api/[collection]/[id]/versions.ts +0 -66
  215. package/src/pages/api/[collection]/[id].ts +0 -213
  216. package/src/pages/api/[collection]/index.ts +0 -209
  217. package/src/pages/api/auth/[id].ts +0 -121
  218. package/src/pages/api/auth/audit-logs.ts +0 -57
  219. package/src/pages/api/auth/login.ts +0 -211
  220. package/src/pages/api/auth/logout.ts +0 -66
  221. package/src/pages/api/auth/me.ts +0 -36
  222. package/src/pages/api/auth/refresh.ts +0 -119
  223. package/src/pages/api/auth/register.ts +0 -188
  224. package/src/pages/api/auth/users.ts +0 -97
  225. package/src/pages/api/collections.ts +0 -59
  226. package/src/pages/api/globals/[slug].ts +0 -42
  227. package/src/pages/api/graphql.ts +0 -90
  228. package/src/pages/api/health.ts +0 -426
  229. package/src/pages/api/keys/[id].ts +0 -26
  230. package/src/pages/api/keys/index.ts +0 -75
  231. package/src/pages/api/media/[id].ts +0 -309
  232. package/src/pages/api/media/folders.ts +0 -609
  233. package/src/pages/api/media/index.ts +0 -146
  234. package/src/pages/api/media/resize.ts +0 -267
  235. package/src/pages/api/search.ts +0 -82
  236. package/src/pages/api/slug-availability.ts +0 -70
  237. package/src/pages/api/storage-config.ts +0 -20
  238. package/src/pages/api/storage-status.ts +0 -206
  239. package/src/pages/api/upload.ts +0 -334
  240. package/src/pages/api/webhooks/index.ts +0 -71
  241. package/src/pages/login.astro +0 -82
  242. package/src/pages/register.astro +0 -102
@@ -1,98 +0,0 @@
1
- ---
2
- import AdminLayout from '../../layouts/AdminLayout.astro';
3
- import { ApiExplorer } from '../../components/ApiExplorer';
4
-
5
- const collectionsResponse = await fetch(`${Astro.url.origin}/api/collections`);
6
- const collectionsData = await collectionsResponse.json();
7
- const collections = collectionsData.collections || [];
8
- ---
9
-
10
- <AdminLayout title="API Explorer">
11
- <div class="flex-1 overflow-hidden p-8 pr-12">
12
- <!-- Header -->
13
- <div class="mb-6">
14
- <div class="flex items-center justify-between mb-4">
15
- <div>
16
- <h1 class="text-3xl font-black tracking-tighter text-[var(--kyro-text-primary)]">
17
- API Explorer
18
- </h1>
19
- <p class="text-[var(--kyro-text-secondary)] font-bold mt-2 text-sm uppercase tracking-wider">
20
- Test and explore REST API endpoints interactively
21
- </p>
22
- </div>
23
- <div class="flex items-center gap-3">
24
- <a
25
- href="/admin/rest-playground"
26
- class="flex items-center gap-2 px-4 py-2 bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-primary)] rounded-lg font-bold text-sm hover:bg-[var(--kyro-surface)] transition-all border border-[var(--kyro-border)]"
27
- >
28
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
29
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
30
- </svg>
31
- Playground
32
- </a>
33
- <a
34
- href="/api/collections"
35
- target="_blank"
36
- class="flex items-center gap-2 px-4 py-2 bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-primary)] rounded-lg font-bold text-sm hover:bg-[var(--kyro-surface)] transition-all border border-[var(--kyro-border)]"
37
- >
38
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
39
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
40
- </svg>
41
- Collections JSON
42
- </a>
43
- </div>
44
- </div>
45
-
46
- <!-- HTTP Methods Legend -->
47
- <div class="flex items-center gap-4 text-xs">
48
- <span class="text-[var(--kyro-text-muted)]">Methods:</span>
49
- <span class="px-2 py-1 bg-green-500/10 text-green-600 rounded font-bold">GET</span>
50
- <span class="px-2 py-1 bg-blue-500/10 text-blue-600 rounded font-bold">POST</span>
51
- <span class="px-2 py-1 bg-yellow-500/10 text-yellow-600 rounded font-bold">PATCH</span>
52
- <span class="px-2 py-1 bg-red-500/10 text-red-600 rounded font-bold">DELETE</span>
53
- </div>
54
- </div>
55
-
56
- <!-- Explorer Component -->
57
- <div class="surface-tile overflow-hidden p-6">
58
- <ApiExplorer client:load collections={collections} />
59
- </div>
60
-
61
- <!-- Quick Reference -->
62
- <div class="mt-6 surface-tile p-6">
63
- <h2 class="text-xl font-black text-[var(--kyro-text-primary)] mb-4">Quick Reference</h2>
64
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 text-sm">
65
- <div class="bg-[var(--kyro-surface-accent)] rounded-lg p-4">
66
- <h3 class="font-bold text-[var(--kyro-text-primary)] mb-2">List All</h3>
67
- <code class="text-xs text-[var(--kyro-text-secondary)] block">GET /api/:collection</code>
68
- <p class="text-xs text-[var(--kyro-text-muted)] mt-2">Returns all documents with pagination</p>
69
- </div>
70
- <div class="bg-[var(--kyro-surface-accent)] rounded-lg p-4">
71
- <h3 class="font-bold text-[var(--kyro-text-primary)] mb-2">Get One</h3>
72
- <code class="text-xs text-[var(--kyro-text-secondary)] block">GET /api/:collection/:id</code>
73
- <p class="text-xs text-[var(--kyro-text-muted)] mt-2">Returns a single document by ID</p>
74
- </div>
75
- <div class="bg-[var(--kyro-surface-accent)] rounded-lg p-4">
76
- <h3 class="font-bold text-[var(--kyro-text-primary)] mb-2">Create</h3>
77
- <code class="text-xs text-[var(--kyro-text-secondary)] block">POST /api/:collection</code>
78
- <p class="text-xs text-[var(--kyro-text-muted)] mt-2">Creates a new document</p>
79
- </div>
80
- <div class="bg-[var(--kyro-surface-accent)] rounded-lg p-4">
81
- <h3 class="font-bold text-[var(--kyro-text-primary)] mb-2">Update</h3>
82
- <code class="text-xs text-[var(--kyro-text-secondary)] block">PATCH /api/:collection/:id</code>
83
- <p class="text-xs text-[var(--kyro-text-muted)] mt-2">Updates an existing document</p>
84
- </div>
85
- <div class="bg-[var(--kyro-surface-accent)] rounded-lg p-4">
86
- <h3 class="font-bold text-[var(--kyro-text-primary)] mb-2">Delete</h3>
87
- <code class="text-xs text-[var(--kyro-text-secondary)] block">DELETE /api/:collection/:id</code>
88
- <p class="text-xs text-[var(--kyro-text-muted)] mt-2">Deletes a document</p>
89
- </div>
90
- <div class="bg-[var(--kyro-surface-accent)] rounded-lg p-4">
91
- <h3 class="font-bold text-[var(--kyro-text-primary)] mb-2">Pagination</h3>
92
- <code class="text-xs text-[var(--kyro-text-secondary)] block">?page=1&amp;limit=10</code>
93
- <p class="text-xs text-[var(--kyro-text-muted)] mt-2">Add query params for pagination</p>
94
- </div>
95
- </div>
96
- </div>
97
- </div>
98
- </AdminLayout>
@@ -1,40 +0,0 @@
1
- ---
2
- import AdminLayout from '../../layouts/AdminLayout.astro';
3
- import { GraphQLExplorer } from '../../components/GraphQLExplorer';
4
- ---
5
-
6
- <AdminLayout title="GraphQL Explorer">
7
- <div class="flex-1 overflow-hidden p-8 pr-12">
8
- <!-- Header -->
9
- <div class="mb-6">
10
- <div class="flex items-center justify-between mb-4">
11
- <div>
12
- <h1 class="text-3xl font-black tracking-tighter text-[var(--kyro-text-primary)]">
13
- GraphQL Explorer
14
- </h1>
15
- <p class="text-[var(--kyro-text-secondary)] font-bold mt-2 text-sm uppercase tracking-wider">
16
- Schema documentation and type explorer
17
- </p>
18
- </div>
19
- <div class="flex items-center gap-4">
20
- <a
21
- href="/admin/graphql"
22
- class="flex items-center gap-2 px-4 py-2 bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-primary)] rounded-lg font-bold text-sm hover:bg-[var(--kyro-surface)] transition-all border border-[var(--kyro-border)]"
23
- >
24
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
25
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
26
- </svg>
27
- Playground
28
- </a>
29
- </div>
30
- </div>
31
- </div>
32
-
33
- <!-- Explorer Container -->
34
- <div class="h-[calc(100vh-200px)] overflow-hidden">
35
- <div class="surface-tile h-full overflow-hidden p-6">
36
- <GraphQLExplorer client:load endpoint="/api/graphql" />
37
- </div>
38
- </div>
39
- </div>
40
- </AdminLayout>
@@ -1,286 +0,0 @@
1
- ---
2
- import AdminLayout from '../../layouts/AdminLayout.astro';
3
- import { collections } from "../../lib/config";
4
-
5
- const authCollections = ['users', 'roles', 'audit_logs'];
6
- const authItems = authCollections.map(slug => ({
7
- slug,
8
- label: collections[slug]?.label || slug,
9
- icon: slug === 'users' ? 'users' : slug === 'roles' ? 'shield' : 'file-text'
10
- }));
11
- ---
12
-
13
- <AdminLayout title="Dashboard">
14
- <div class="flex-1 overflow-y-auto p-8 pr-12 space-y-8">
15
- <!-- Header -->
16
- <div class="surface-tile p-6 flex items-center justify-between gap-8">
17
- <div class="relative flex-1 max-w-2xl">
18
- <div class="absolute inset-y-0 left-6 flex items-center pointer-events-none text-[var(--kyro-text-muted)]">
19
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
20
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
21
- </svg>
22
- </div>
23
- <input type="text" id="header-search-input" placeholder="Search anything..." class="w-full bg-[var(--kyro-surface-accent)] border border-transparent rounded-2xl py-4 pl-16 pr-8 text-lg font-medium focus:outline-none focus:bg-[var(--kyro-surface)] focus:border-[var(--kyro-border)] transition-all shadow-inner text-[var(--kyro-text-primary)] placeholder-[var(--kyro-text-muted)]" autocomplete="off" />
24
- <div id="header-search-results" class="hidden absolute top-full left-0 right-0 mt-2 bg-[var(--kyro-surface)] border border-[var(--kyro-border)] rounded-xl shadow-xl max-h-80 overflow-y-auto z-50"></div>
25
- </div>
26
- <div class="flex p-1.5 bg-[var(--kyro-surface-accent)] rounded-2xl">
27
- <button id="cmd-k-btn" class="flex items-center gap-3 px-8 py-3 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-xl font-bold shadow-lg transition-all active:scale-95 cursor-pointer">
28
- <span>⌘ K</span>
29
- </button>
30
- </div>
31
- </div>
32
-
33
- <!-- Quick Links Section -->
34
- <div class="surface-tile overflow-hidden">
35
- <div class="flex items-center justify-between p-6 border-b border-[var(--kyro-border)]">
36
- <div class="flex-1">
37
- <h2 class="text-xl font-black tracking-tight text-[var(--kyro-text-primary)] flex items-center gap-2">
38
- Quick Links
39
- </h2>
40
- <p class="text-xs text-[var(--kyro-text-secondary)] font-medium mt-1">
41
- Create new collection documents
42
- </p>
43
- </div>
44
- </div>
45
-
46
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4 p-4">
47
- {Object.entries(collections).filter(([slug]) => !['users', 'roles', 'audit_logs', 'media'].includes(slug)).slice(0, 6).map(([slug, config]: [string, any]) => (
48
- <a href={`/${slug}/new`} class="group p-4 bg-[var(--kyro-surface-accent)] rounded-xl hover:bg-[var(--kyro-surface)] transition-all border border-transparent hover:border-[var(--kyro-border)] shadow-sm hover:shadow-md">
49
- <div class="flex items-center gap-3">
50
- <div class="w-8 h-8 rounded-lg flex items-center justify-center bg-[var(--kyro-bg-secondary)] text-[var(--kyro-text-secondary)] group-hover:bg-[var(--kyro-surface-accent)] group-hover:text-[var(--kyro-primary)] transition-all">
51
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
52
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5v14M5 12h14"></path>
53
- </svg>
54
- </div>
55
- <span class="text-sm font-bold text-[var(--kyro-text-primary)]">New {config.label || slug}</span>
56
- </div>
57
- </a>
58
- ))}
59
- </div>
60
- </div>
61
-
62
- <!-- Security Quick Actions -->
63
- <div class="surface-tile overflow-hidden">
64
- <div class="p-6 border-b border-[var(--kyro-border)]">
65
- <h2 class="text-xl font-black tracking-tight text-[var(--kyro-text-primary)]">
66
- Security & Monitoring
67
- </h2>
68
- <p class="text-xs text-[var(--kyro-text-secondary)] font-medium mt-1">
69
- Rate limiting, audit logs, and account lockout settings
70
- </p>
71
- </div>
72
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 p-6">
73
- <a href="/audit" class="p-5 bg-[var(--kyro-surface-accent)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)] group">
74
- <div class="w-10 h-10 rounded-lg bg-orange-500/10 text-orange-500 flex items-center justify-center mb-3">
75
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
76
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
77
- </svg>
78
- </div>
79
- <h4 class="font-bold text-[var(--kyro-text-primary)] mb-1">Audit Logs</h4>
80
- <p class="text-xs text-[var(--kyro-text-secondary)]">View last 30 days</p>
81
- </a>
82
-
83
- <a href="/users?locked=true" class="p-5 bg-[var(--kyro-surface-accent)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)] group">
84
- <div class="w-10 h-10 rounded-lg bg-red-500/10 text-red-500 flex items-center justify-center mb-3">
85
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
86
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
87
- </svg>
88
- </div>
89
- <h4 class="font-bold text-[var(--kyro-text-primary)] mb-1">Locked Accounts</h4>
90
- <p class="text-xs text-[var(--kyro-text-secondary)]">Manage lockouts</p>
91
- </a>
92
-
93
- <a href="/roles" class="p-5 bg-[var(--kyro-surface-accent)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)] group">
94
- <div class="w-10 h-10 rounded-lg bg-indigo-500/10 text-indigo-500 flex items-center justify-center mb-3">
95
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
96
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
97
- </svg>
98
- </div>
99
- <h4 class="font-bold text-[var(--kyro-text-primary)] mb-1">Permissions</h4>
100
- <p class="text-xs text-[var(--kyro-text-secondary)]">RBAC settings</p>
101
- </a>
102
-
103
- <a href="/api/health" target="_blank" class="p-5 bg-[var(--kyro-surface-accent)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)] group">
104
- <div class="w-10 h-10 rounded-lg bg-green-500/10 text-green-500 flex items-center justify-center mb-3">
105
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
106
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
107
- </svg>
108
- </div>
109
- <h4 class="font-bold text-[var(--kyro-text-primary)] mb-1">API Health</h4>
110
- <p class="text-xs text-[var(--kyro-text-secondary)]">System status</p>
111
- </a>
112
- </div>
113
- </div>
114
-
115
- <!-- Developer Tools Section -->
116
- <div class="surface-tile overflow-hidden">
117
- <div class="p-6 border-b border-[var(--kyro-border)]">
118
- <h2 class="text-xl font-black tracking-tight text-[var(--kyro-text-primary)]">
119
- Developer Tools
120
- </h2>
121
- <p class="text-xs text-[var(--kyro-text-secondary)] font-medium mt-1">
122
- REST API & GraphQL testing tools
123
- </p>
124
- </div>
125
-
126
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-8 p-8">
127
- <!-- REST API -->
128
- <div class="bg-[var(--kyro-surface-accent)] rounded-2xl p-6">
129
- <div class="flex items-center gap-3 mb-6">
130
- <div class="w-10 h-10 rounded-xl bg-pink-500/10 flex items-center justify-center text-pink-500">
131
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
132
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
133
- </svg>
134
- </div>
135
- <div>
136
- <h3 class="text-xl font-black text-[var(--kyro-text-primary)]">REST API</h3>
137
- <p class="text-xs text-[var(--kyro-text-secondary)]">HTTP endpoints</p>
138
- </div>
139
- </div>
140
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
141
- <a href="/admin/api-explorer" class="group p-4 bg-[var(--kyro-surface)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)]">
142
- <div class="flex items-center gap-3 mb-2">
143
- <div class="w-8 h-8 rounded-lg bg-green-500/10 flex items-center justify-center text-green-500 group-hover:scale-110 transition-transform">
144
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
145
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
146
- </svg>
147
- </div>
148
- <h4 class="font-bold text-[var(--kyro-text-primary)]">Explorer</h4>
149
- </div>
150
- <p class="text-xs text-[var(--kyro-text-secondary)]">Test endpoints interactively</p>
151
- </a>
152
- <a href="/admin/rest-playground" class="group p-4 bg-[var(--kyro-surface)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)]">
153
- <div class="flex items-center gap-3 mb-2">
154
- <div class="w-8 h-8 rounded-lg bg-blue-500/10 flex items-center justify-center text-blue-500 group-hover:scale-110 transition-transform">
155
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
156
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
157
- </svg>
158
- </div>
159
- <h4 class="font-bold text-[var(--kyro-text-primary)]">Playground</h4>
160
- </div>
161
- <p class="text-xs text-[var(--kyro-text-secondary)]">Saved requests & history</p>
162
- </a>
163
- </div>
164
- <div class="mt-4 pt-4 border-t border-[var(--kyro-border)]">
165
- <a href="/api/collections" target="_blank" class="flex items-center gap-2 text-xs text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-secondary)] transition-colors">
166
- <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
167
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
168
- </svg>
169
- View Collections JSON
170
- </a>
171
- </div>
172
- </div>
173
-
174
- <!-- GraphQL -->
175
- <div class="bg-[var(--kyro-surface-accent)] rounded-2xl p-6">
176
- <div class="flex items-center gap-3 mb-6">
177
- <div class="w-10 h-10 rounded-xl bg-pink-500/10 flex items-center justify-center text-pink-500">
178
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
179
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
180
- </svg>
181
- </div>
182
- <div>
183
- <h3 class="text-xl font-black text-[var(--kyro-text-primary)]">GraphQL</h3>
184
- <p class="text-xs text-[var(--kyro-text-secondary)]">Query language API</p>
185
- </div>
186
- </div>
187
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
188
- <a href="/admin/graphql" class="group p-4 bg-[var(--kyro-surface)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)]">
189
- <div class="flex items-center gap-3 mb-2">
190
- <div class="w-8 h-8 rounded-lg bg-purple-500/10 flex items-center justify-center text-purple-500 group-hover:scale-110 transition-transform">
191
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
192
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
193
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
194
- </svg>
195
- </div>
196
- <h4 class="font-bold text-[var(--kyro-text-primary)]">Playground</h4>
197
- </div>
198
- <p class="text-xs text-[var(--kyro-text-secondary)]">Write & test queries</p>
199
- </a>
200
- <a href="/admin/graphql-explorer" class="group p-4 bg-[var(--kyro-surface)] rounded-xl hover:bg-[var(--kyro-surface-accent)] transition-all border border-transparent hover:border-[var(--kyro-border)]">
201
- <div class="flex items-center gap-3 mb-2">
202
- <div class="w-8 h-8 rounded-lg bg-orange-500/10 flex items-center justify-center text-orange-500 group-hover:scale-110 transition-transform">
203
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
204
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path>
205
- </svg>
206
- </div>
207
- <h4 class="font-bold text-[var(--kyro-text-primary)]">Explorer</h4>
208
- </div>
209
- <p class="text-xs text-[var(--kyro-text-secondary)]">Schema documentation</p>
210
- </a>
211
- </div>
212
- <div class="mt-4 pt-4 border-t border-[var(--kyro-border)]">
213
- <a href="/api/graphql" target="_blank" class="flex items-center gap-2 text-xs text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-secondary)] transition-colors">
214
- <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
215
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
216
- </svg>
217
- View GraphQL Endpoint
218
- </a>
219
- </div>
220
- </div>
221
- </div>
222
- </div>
223
-
224
- <script is:inline>
225
- (function() {
226
- var searchInput = document.getElementById('header-search-input');
227
- var searchResults = document.getElementById('header-search-results');
228
- if (!searchInput || !searchResults) return;
229
-
230
- var debounceTimer = null;
231
-
232
- function renderResults(results) {
233
- var html = '';
234
- if (!results || results.length === 0) {
235
- html = '<div class="p-4 text-center text-[var(--kyro-text-secondary)] opacity-60">No documents found</div>';
236
- } else {
237
- for (var i = 0; i < Math.min(results.length, 6); i++) {
238
- var r = results[i];
239
- html += '<a href="/' + r.collection + '/' + r.id + '" class="flex items-center justify-between px-4 py-3 hover:bg-[var(--kyro-surface-accent)] transition-colors">';
240
- html += '<div class="flex flex-col"><span class="font-bold text-sm text-[var(--kyro-text-primary)]">' + (r.title || 'Untitled') + '</span>';
241
- html += '<span class="text-[10px] font-black uppercase tracking-widest opacity-40">' + r.label + '</span></div>';
242
- html += '<span class="text-xs text-[var(--kyro-text-muted)]">View</span></a>';
243
- }
244
- }
245
- searchResults.innerHTML = html;
246
- searchResults.classList.remove('hidden');
247
- }
248
-
249
- function hideResults() {
250
- searchResults.classList.add('hidden');
251
- }
252
-
253
- searchInput.addEventListener('input', function(e) {
254
- var query = e.target.value.trim();
255
- if (query.length < 2) {
256
- searchResults.classList.add('hidden');
257
- return;
258
- }
259
- if (debounceTimer) clearTimeout(debounceTimer);
260
- debounceTimer = setTimeout(function() {
261
- var xhr = new XMLHttpRequest();
262
- xhr.open('GET', '/api/search?q=' + encodeURIComponent(query) + '&limit=10', true);
263
- xhr.onload = function() {
264
- if (xhr.status === 200) {
265
- try {
266
- var data = JSON.parse(xhr.responseText);
267
- if (data.results) renderResults(data.results);
268
- } catch(err) { console.error(err); }
269
- }
270
- };
271
- xhr.send();
272
- }, 300);
273
- });
274
-
275
- searchInput.addEventListener('blur', function() {
276
- setTimeout(hideResults, 200);
277
- });
278
-
279
- document.addEventListener('click', function(e) {
280
- if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) {
281
- hideResults();
282
- }
283
- });
284
- })();
285
- </script>
286
- </AdminLayout>
@@ -1,8 +0,0 @@
1
- ---
2
- import AdminLayout from "../../layouts/AdminLayout.astro";
3
- import { ApiKeysManager } from "../../components/ApiKeysManager";
4
- ---
5
-
6
- <AdminLayout title="API Keys">
7
- <ApiKeysManager client:only="react" />
8
- </AdminLayout>
@@ -1,44 +0,0 @@
1
- ---
2
- import AdminLayout from '../../layouts/AdminLayout.astro';
3
- import { RestPlayground } from '../../components/RestPlayground';
4
-
5
- const collectionsResponse = await fetch(`${Astro.url.origin}/api/collections`);
6
- const collectionsData = await collectionsResponse.json();
7
- const collections = collectionsData.collections || [];
8
- ---
9
-
10
- <AdminLayout title="REST Playground">
11
- <div class="flex-1 overflow-hidden p-8 pr-12">
12
- <!-- Header -->
13
- <div class="mb-6">
14
- <div class="flex items-center justify-between mb-4">
15
- <div>
16
- <h1 class="text-3xl font-black tracking-tighter text-[var(--kyro-text-primary)]">
17
- REST Playground
18
- </h1>
19
- <p class="text-[var(--kyro-text-secondary)] font-bold mt-2 text-sm uppercase tracking-wider">
20
- Saved collections, history, and environment variables
21
- </p>
22
- </div>
23
- <div class="flex items-center gap-4">
24
- <a
25
- href="/admin/api-explorer"
26
- class="flex items-center gap-2 px-4 py-2 bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-primary)] rounded-lg font-bold text-sm hover:bg-[var(--kyro-surface)] transition-all border border-[var(--kyro-border)]"
27
- >
28
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
29
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
30
- </svg>
31
- Explorer
32
- </a>
33
- </div>
34
- </div>
35
- </div>
36
-
37
- <!-- Playground Container -->
38
- <div class="h-[calc(100vh-200px)] overflow-hidden">
39
- <div class="surface-tile h-full overflow-hidden">
40
- <RestPlayground client:load collections={collections} />
41
- </div>
42
- </div>
43
- </div>
44
- </AdminLayout>
@@ -1,8 +0,0 @@
1
- ---
2
- import AdminLayout from "../../layouts/AdminLayout.astro";
3
- import { WebhookManager } from "../../components/WebhookManager";
4
- ---
5
-
6
- <AdminLayout title="Webhooks">
7
- <WebhookManager client:only="react" />
8
- </AdminLayout>
@@ -1,52 +0,0 @@
1
- import type { APIRoute } from "astro";
2
- import { dataStore } from "../../../../lib/dataStore";
3
- import { collections } from "../../../../lib/config";
4
-
5
- dataStore.initialize(collections);
6
-
7
- export const POST: APIRoute = async ({ params, request }) => {
8
- const collection = params.collection as string;
9
- const id = params.id as string;
10
-
11
- if (!collection || !collections[collection]) {
12
- return new Response(JSON.stringify({ error: "Invalid collection" }), {
13
- status: 404,
14
- headers: { "Content-Type": "application/json" },
15
- });
16
- }
17
-
18
- try {
19
- const doc = await dataStore.findById(collection, id);
20
- if (!doc) {
21
- return new Response(JSON.stringify({ error: "Document not found" }), {
22
- status: 404,
23
- headers: { "Content-Type": "application/json" },
24
- });
25
- }
26
-
27
- const now = new Date().toISOString();
28
- const updated = await dataStore.update(
29
- collection,
30
- id,
31
- {
32
- status: "published",
33
- publishedAt: now,
34
- },
35
- {
36
- versionStatus: "published",
37
- changeDescription: "Published changes",
38
- },
39
- );
40
-
41
- return new Response(JSON.stringify({ success: true, data: updated }), {
42
- status: 200,
43
- headers: { "Content-Type": "application/json" },
44
- });
45
- } catch (error) {
46
- console.error("Publish error:", error);
47
- return new Response(JSON.stringify({ error: "Failed to publish" }), {
48
- status: 500,
49
- headers: { "Content-Type": "application/json" },
50
- });
51
- }
52
- };
@@ -1,42 +0,0 @@
1
- import type { APIRoute } from "astro";
2
- import { dataStore } from "../../../../lib/dataStore";
3
- import { collections } from "../../../../lib/config";
4
-
5
- dataStore.initialize(collections);
6
-
7
- export const POST: APIRoute = async ({ params, request }) => {
8
- const collection = params.collection as string;
9
- const id = params.id as string;
10
-
11
- if (!collection || !collections[collection]) {
12
- return new Response(JSON.stringify({ error: "Invalid collection" }), {
13
- status: 404,
14
- headers: { "Content-Type": "application/json" },
15
- });
16
- }
17
-
18
- try {
19
- const doc = await dataStore.findById(collection, id);
20
- if (!doc) {
21
- return new Response(JSON.stringify({ error: "Document not found" }), {
22
- status: 404,
23
- headers: { "Content-Type": "application/json" },
24
- });
25
- }
26
-
27
- const updated = await dataStore.update(collection, id, {
28
- status: "draft",
29
- });
30
-
31
- return new Response(JSON.stringify({ success: true, data: updated }), {
32
- status: 200,
33
- headers: { "Content-Type": "application/json" },
34
- });
35
- } catch (error) {
36
- console.error("Unpublish error:", error);
37
- return new Response(JSON.stringify({ error: "Failed to unpublish" }), {
38
- status: 500,
39
- headers: { "Content-Type": "application/json" },
40
- });
41
- }
42
- };
@@ -1,66 +0,0 @@
1
- import type { APIRoute } from "astro";
2
- import { dataStore } from "../../../../lib/dataStore";
3
-
4
- export const GET: APIRoute = async ({ params, url }) => {
5
- const { collection, id } = params;
6
- if (!collection || !id) return new Response(null, { status: 400 });
7
-
8
- try {
9
- const compareA = url.searchParams.get("compareA");
10
- const compareB = url.searchParams.get("compareB");
11
-
12
- if (compareA && compareB) {
13
- const diffs = await dataStore.compareVersions(
14
- collection,
15
- id,
16
- isNaN(Number(compareA)) ? compareA : Number(compareA),
17
- isNaN(Number(compareB)) ? compareB : Number(compareB),
18
- );
19
- return new Response(JSON.stringify({ diffs }), {
20
- status: 200,
21
- headers: { "Content-Type": "application/json" },
22
- });
23
- }
24
-
25
- const versions = await dataStore.findVersions(collection, id);
26
- return new Response(JSON.stringify({ docs: versions }), {
27
- status: 200,
28
- headers: { "Content-Type": "application/json" },
29
- });
30
- } catch (error) {
31
- return new Response(JSON.stringify({ error: "Failed to fetch versions" }), {
32
- status: 500,
33
- });
34
- }
35
- };
36
-
37
- export const POST: APIRoute = async ({ params, request }) => {
38
- const { collection, id } = params;
39
- if (!collection || !id) return new Response(null, { status: 400 });
40
-
41
- try {
42
- const { versionId, action } = await request.json();
43
-
44
- if (action === "restore" && versionId) {
45
- const restored = await dataStore.restoreVersion(
46
- collection,
47
- id,
48
- versionId,
49
- );
50
- if (!restored)
51
- return new Response(JSON.stringify({ error: "Restore failed" }), {
52
- status: 400,
53
- });
54
- return new Response(JSON.stringify({ data: restored }), { status: 200 });
55
- }
56
-
57
- return new Response(JSON.stringify({ error: "Invalid action" }), {
58
- status: 400,
59
- });
60
- } catch (error) {
61
- return new Response(
62
- JSON.stringify({ error: "Failed to perform version action" }),
63
- { status: 500 },
64
- );
65
- }
66
- };