@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
@@ -0,0 +1,338 @@
1
+ import React, { useState } from "react";
2
+ import { useUIStore } from "../../lib/stores";
3
+
4
+ interface User {
5
+ id: string;
6
+ name?: string;
7
+ email: string;
8
+ role: string;
9
+ tenantId?: string;
10
+ locked?: boolean;
11
+ emailVerified?: boolean;
12
+ lastLogin?: string;
13
+ createdAt?: string;
14
+ failedLoginAttempts?: number;
15
+ }
16
+
17
+ interface UsersListProps {
18
+ initialUsers: User[];
19
+ initialTotal: number;
20
+ apiPath: string;
21
+ adminPath: string;
22
+ }
23
+
24
+ const roleColors: Record<string, string> = {
25
+ super_admin: "bg-red-50 text-red-600",
26
+ admin: "bg-purple-50 text-purple-600",
27
+ editor: "bg-blue-50 text-blue-600",
28
+ author: "bg-green-50 text-green-600",
29
+ customer: "bg-gray-50 text-gray-600",
30
+ guest: "bg-yellow-50 text-yellow-600",
31
+ };
32
+
33
+ export function UsersList({
34
+ initialUsers,
35
+ initialTotal,
36
+ apiPath,
37
+ adminPath,
38
+ }: UsersListProps) {
39
+ const [users, setUsers] = useState<User[]>(initialUsers);
40
+ const [totalUsers, setTotalUsers] = useState(initialTotal);
41
+ const { confirm, alert } = useUIStore();
42
+ const [deleting, setDeleting] = useState(false);
43
+ const [errorMsg, setErrorMsg] = useState<string | null>(null);
44
+
45
+ const handleDeleteClick = (user: User) => {
46
+ confirm({
47
+ title: "Delete User",
48
+ message: `Are you sure you want to delete ${user.email}? This action cannot be undone.`,
49
+ variant: "danger",
50
+ onConfirm: async () => {
51
+ setDeleting(true);
52
+ setErrorMsg(null);
53
+ try {
54
+ const res = await fetch(`${apiPath}/users/${user.id}`, {
55
+ method: "DELETE",
56
+ credentials: "include",
57
+ });
58
+ const data = await res.json();
59
+ if (res.ok) {
60
+ setUsers((prev) => prev.filter((u) => u.id !== user.id));
61
+ setTotalUsers((prev) => prev - 1);
62
+ } else {
63
+ setErrorMsg(data.error || "Failed to delete user");
64
+ }
65
+ } catch (e) {
66
+ setErrorMsg("Failed to delete user");
67
+ } finally {
68
+ setDeleting(false);
69
+ }
70
+ }
71
+ });
72
+ };
73
+
74
+ const formatDate = (dateStr?: string) => {
75
+ if (!dateStr) return "—";
76
+ return new Date(dateStr).toLocaleDateString("en-US", {
77
+ month: "short",
78
+ day: "numeric",
79
+ year: "numeric",
80
+ });
81
+ };
82
+
83
+ return (
84
+ <div className="flex-1 overflow-y-auto pr-12 space-y-8">
85
+ <div className="surface-tile p-6 flex items-center justify-between">
86
+ <div>
87
+ <h1 className="text-xl font-bold tracking-tighter text-[var(--kyro-text-primary)]">
88
+ Users
89
+ </h1>
90
+ <p className="text-sm text-[var(--kyro-text-secondary)] mt-1 font-medium">
91
+ Manage user accounts and permissions
92
+ <span className="ml-2 text-[var(--kyro-text-primary)] font-bold">
93
+ · {totalUsers} users
94
+ </span>
95
+ </p>
96
+ </div>
97
+ <a
98
+ href={`${adminPath}/users/new`}
99
+ className="flex items-center text-sm gap-2 px-6 py-2.5 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-xl transition-all hover:opacity-90 active:scale-95 shadow-lg"
100
+ >
101
+ <svg
102
+ className="w-4 h-4"
103
+ fill="none"
104
+ stroke="currentColor"
105
+ viewBox="0 0 24 24"
106
+ >
107
+ <path
108
+ strokeLinecap="round"
109
+ strokeLinejoin="round"
110
+ strokeWidth="2.5"
111
+ d="M12 5v14M5 12h14"
112
+ ></path>
113
+ </svg>
114
+ Add User
115
+ </a>
116
+ </div>
117
+
118
+ <div className="surface-tile overflow-hidden">
119
+ {users.length === 0 ? (
120
+ <div className="px-8 py-16 text-center">
121
+ <div className="flex flex-col items-center gap-4">
122
+ <div className="w-16 h-16 rounded-2xl bg-[var(--kyro-surface-accent)] flex items-center justify-center">
123
+ <svg
124
+ className="w-8 h-8 text-[var(--kyro-text-muted)]"
125
+ fill="none"
126
+ stroke="currentColor"
127
+ viewBox="0 0 24 24"
128
+ >
129
+ <path
130
+ strokeLinecap="round"
131
+ strokeLinejoin="round"
132
+ strokeWidth="1.5"
133
+ d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
134
+ />
135
+ </svg>
136
+ </div>
137
+ <p className="font-medium text-[var(--kyro-text-primary)] text-base">
138
+ No users yet
139
+ </p>
140
+ <p className="text-sm text-[var(--kyro-text-secondary)]">
141
+ Create your first user to get started.
142
+ </p>
143
+ <a
144
+ href={`${adminPath}/users/new`}
145
+ className="mt-2 inline-flex items-center gap-2 px-5 py-2.5 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-lg font-bold text-sm shadow-md"
146
+ >
147
+ <svg
148
+ className="w-3.5 h-3.5"
149
+ fill="none"
150
+ stroke="currentColor"
151
+ viewBox="0 0 24 24"
152
+ >
153
+ <path
154
+ strokeLinecap="round"
155
+ strokeLinejoin="round"
156
+ strokeWidth="2.5"
157
+ d="M12 5v14M5 12h14"
158
+ />
159
+ </svg>
160
+ Add User
161
+ </a>
162
+ </div>
163
+ </div>
164
+ ) : (
165
+ <table className="w-full text-left">
166
+ <thead>
167
+ <tr className="text-[var(--kyro-text-secondary)] font-bold text-[10px] tracking-[0.3em] border-b border-[var(--kyro-border)]">
168
+ <th className="px-8 py-6">Name</th>
169
+ <th className="px-6 py-6">Email</th>
170
+ <th className="px-6 py-6">Role</th>
171
+ <th className="px-6 py-6">Status</th>
172
+ <th className="px-6 py-6">Created</th>
173
+ <th className="px-6 py-6 text-right">Actions</th>
174
+ </tr>
175
+ </thead>
176
+ <tbody className="divide-y divide-[var(--kyro-border)]">
177
+ {users.map((user) => (
178
+ <tr
179
+ key={user.id}
180
+ className="group hover:bg-gray-50/50 transition-colors cursor-pointer"
181
+ onClick={() =>
182
+ (window.location.href = `${adminPath}/users/${user.id}`)
183
+ }
184
+ >
185
+ <td className="px-8 py-5">
186
+ <div className="flex items-center gap-4">
187
+ <div className="w-10 h-10 rounded-full bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] flex items-center justify-center font-bold text-sm">
188
+ {(user.name || user.email).charAt(0).toUpperCase()}
189
+ </div>
190
+ <div>
191
+ <div className="font-medium text-[var(--kyro-text-primary)]">
192
+ {user.name || "—"}
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </td>
197
+ <td className="px-6 py-5">
198
+ <div className="text-sm text-[var(--kyro-text-secondary)]">
199
+ {user.email}
200
+ </div>
201
+ {user.tenantId && (
202
+ <div className="text-xs text-[var(--kyro-text-muted)] mt-0.5">
203
+ Tenant: {user.tenantId}
204
+ </div>
205
+ )}
206
+ </td>
207
+ <td className="px-6 py-5">
208
+ <span
209
+ className={`inline-flex items-center px-3 py-1 rounded-lg text-xs font-bold ${roleColors[user.role] || "bg-gray-50 text-gray-600"}`}
210
+ >
211
+ {user.role}
212
+ </span>
213
+ </td>
214
+ <td className="px-6 py-5">
215
+ {user.locked ? (
216
+ <span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-lg text-xs font-bold bg-red-50 text-red-600">
217
+ <svg
218
+ className="w-3 h-3"
219
+ fill="currentColor"
220
+ viewBox="0 0 20 20"
221
+ >
222
+ <path
223
+ fillRule="evenodd"
224
+ d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
225
+ clipRule="evenodd"
226
+ />
227
+ </svg>
228
+ Locked
229
+ </span>
230
+ ) : (
231
+ <span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-lg text-xs font-bold bg-green-50 text-green-600">
232
+ <svg
233
+ className="w-3 h-3"
234
+ fill="currentColor"
235
+ viewBox="0 0 20 20"
236
+ >
237
+ <path
238
+ fillRule="evenodd"
239
+ d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
240
+ clipRule="evenodd"
241
+ />
242
+ </svg>
243
+ Active
244
+ </span>
245
+ )}
246
+ </td>
247
+ <td className="px-6 py-5 text-sm text-[#64748b]">
248
+ {formatDate(user.createdAt)}
249
+ </td>
250
+ <td className="px-6 py-5 text-right">
251
+ <div className="flex items-center justify-end gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
252
+ <a
253
+ href={`${adminPath}/users/${user.id}`}
254
+ className="inline-flex items-center justify-center w-8 h-8 rounded-md text-[#64748b] hover:bg-gray-100 hover:text-[#0b1222] transition-colors"
255
+ onClick={(e) => e.stopPropagation()}
256
+ >
257
+ <svg
258
+ className="w-4 h-4"
259
+ fill="none"
260
+ stroke="currentColor"
261
+ viewBox="0 0 24 24"
262
+ >
263
+ <path
264
+ strokeLinecap="round"
265
+ strokeLinejoin="round"
266
+ strokeWidth="2"
267
+ d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
268
+ />
269
+ </svg>
270
+ </a>
271
+ <button
272
+ onClick={(e) => {
273
+ e.stopPropagation();
274
+ handleDeleteClick(user);
275
+ }}
276
+ className="inline-flex items-center justify-center w-8 h-8 rounded-md text-[#64748b] hover:bg-red-50 hover:text-red-600 transition-colors"
277
+ >
278
+ <svg
279
+ className="w-4 h-4"
280
+ fill="none"
281
+ stroke="currentColor"
282
+ viewBox="0 0 24 24"
283
+ >
284
+ <path
285
+ strokeLinecap="round"
286
+ strokeLinejoin="round"
287
+ strokeWidth="2"
288
+ d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
289
+ />
290
+ </svg>
291
+ </button>
292
+ </div>
293
+ </td>
294
+ </tr>
295
+ ))}
296
+ </tbody>
297
+ </table>
298
+ )}
299
+ </div>
300
+
301
+ {errorMsg && (
302
+ <div className="surface-tile p-4 flex items-center gap-3 border border-red-200">
303
+ <svg
304
+ className="w-5 h-5 text-red-500 flex-shrink-0"
305
+ fill="currentColor"
306
+ viewBox="0 0 20 20"
307
+ >
308
+ <path
309
+ fillRule="evenodd"
310
+ d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
311
+ clipRule="evenodd"
312
+ />
313
+ </svg>
314
+ <p className="text-sm font-medium text-red-500">{errorMsg}</p>
315
+ <button
316
+ onClick={() => setErrorMsg(null)}
317
+ className="ml-auto text-red-400 hover:text-red-600"
318
+ >
319
+ <svg
320
+ className="w-4 h-4"
321
+ fill="none"
322
+ stroke="currentColor"
323
+ viewBox="0 0 24 24"
324
+ >
325
+ <path
326
+ strokeLinecap="round"
327
+ strokeLinejoin="round"
328
+ strokeWidth="2"
329
+ d="M6 18L18 6M6 6l12 12"
330
+ />
331
+ </svg>
332
+ </button>
333
+ </div>
334
+ )}
335
+
336
+ </div>
337
+ );
338
+ }
package/src/env.d.ts CHANGED
@@ -1,16 +1,16 @@
1
- /// <reference types="astro/client" />
1
+ declare const __KYRO_API_PATH__: string;
2
+ declare const __KYRO_ADMIN_PATH__: string;
3
+ declare const __KYRO_ADMIN_AUTH_DISABLED__: boolean;
2
4
 
3
- declare global {
4
- namespace App {
5
- interface Locals {
6
- user?: {
7
- id: string;
8
- email: string;
9
- role: string;
10
- tenantId?: string;
11
- };
12
- }
5
+ declare namespace App {
6
+ interface Locals {
7
+ user?: {
8
+ id: string;
9
+ email: string;
10
+ role: string;
11
+ permissions?: string[];
12
+ tenantId?: string;
13
+ };
14
+ sessionId?: string;
13
15
  }
14
16
  }
15
-
16
- export {};
@@ -29,5 +29,6 @@ export type {
29
29
  BlocksField,
30
30
  ArrayField,
31
31
  GroupField,
32
- ALL_FIELD_TYPES,
33
32
  } from "@kyro-cms/core";
33
+
34
+ export { ALL_FIELD_TYPES } from "@kyro-cms/core";
@@ -0,0 +1,7 @@
1
+ declare global {
2
+ const __KYRO_ADMIN_PATH__: string;
3
+ const __KYRO_API_PATH__: string;
4
+ const __KYRO_ADMIN_AUTH_DISABLED__: boolean;
5
+ }
6
+
7
+ export {};
package/src/hooks/data.ts CHANGED
@@ -28,11 +28,6 @@ function getApiUrl(path: string): string {
28
28
  return `${base}${path}`;
29
29
  }
30
30
 
31
- function getToken(): string | null {
32
- if (typeof window === "undefined") return null;
33
- return localStorage.getItem("kyro_token");
34
- }
35
-
36
31
  export function useKyroQuery<T = Record<string, unknown>>(
37
32
  slug: string,
38
33
  options: QueryOptions = {},
@@ -52,9 +47,8 @@ export function useKyroQuery<T = Record<string, unknown>>(
52
47
  if (options.order) params.set("order", options.order);
53
48
 
54
49
  const url = `${getApiUrl(`/api/${slug}`)}?${params.toString()}`;
55
- const token = getToken();
56
50
  const res = await fetch(url, {
57
- headers: token ? { Authorization: `Bearer ${token}` } : {},
51
+ credentials: "include",
58
52
  });
59
53
 
60
54
  if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
@@ -89,12 +83,11 @@ export function useKyroMutation(
89
83
  setError(null);
90
84
  try {
91
85
  const url = getApiUrl(`/api/${slug}`);
92
- const token = getToken();
93
86
  const res = await fetch(url, {
94
87
  method,
88
+ credentials: "include",
95
89
  headers: {
96
90
  "Content-Type": "application/json",
97
- ...(token ? { Authorization: `Bearer ${token}` } : {}),
98
91
  },
99
92
  body: data ? JSON.stringify(data) : undefined,
100
93
  });
@@ -0,0 +1,36 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+
3
+ export interface AsyncDataState<T> {
4
+ data: T | null;
5
+ loading: boolean;
6
+ error: string | null;
7
+ }
8
+
9
+ export function useAsyncData<T>(
10
+ fetcher: () => Promise<T>,
11
+ deps: unknown[] = [],
12
+ options?: { initialData?: T; onError?: (err: Error) => void }
13
+ ): AsyncDataState<T> & { refetch: () => void } {
14
+ const [state, setState] = useState<AsyncDataState<T>>({
15
+ data: options?.initialData ?? null,
16
+ loading: true,
17
+ error: null,
18
+ });
19
+
20
+ const fetch = useCallback(async () => {
21
+ setState(prev => ({ ...prev, loading: true, error: null }));
22
+ try {
23
+ const data = await fetcher();
24
+ setState({ data, loading: false, error: null });
25
+ } catch (err) {
26
+ const message = err instanceof Error ? err.message : "An error occurred";
27
+ setState(prev => ({ ...prev, loading: false, error: message }));
28
+ options?.onError?.(err instanceof Error ? err : new Error(message));
29
+ }
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31
+ }, deps);
32
+
33
+ useEffect(() => { fetch(); }, [fetch]);
34
+
35
+ return { ...state, refetch: fetch };
36
+ }