@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,319 +0,0 @@
1
- import type { AuthAdapter, AuthUser, Session, UserRole } from "@kyro-cms/core";
2
- import bcrypt from "bcryptjs";
3
- import { randomBytes } from "crypto";
4
- import Database from "better-sqlite3";
5
- import path from "path";
6
- import fs from "fs";
7
-
8
- const DB_DIR = path.join(process.cwd(), "data");
9
- const DB_PATH = path.join(DB_DIR, "kyro.db");
10
-
11
- if (!fs.existsSync(DB_DIR)) {
12
- fs.mkdirSync(DB_DIR, { recursive: true });
13
- }
14
-
15
- export const db = new Database(DB_PATH);
16
- db.pragma("journal_mode = WAL");
17
-
18
- db.exec(`
19
- CREATE TABLE IF NOT EXISTS users (
20
- id TEXT PRIMARY KEY,
21
- email TEXT UNIQUE NOT NULL,
22
- password_hash TEXT NOT NULL,
23
- name TEXT,
24
- role TEXT DEFAULT 'customer',
25
- created_at TEXT NOT NULL,
26
- updated_at TEXT NOT NULL
27
- );
28
-
29
- CREATE TABLE IF NOT EXISTS sessions (
30
- token TEXT PRIMARY KEY,
31
- user_id TEXT NOT NULL,
32
- expires_at TEXT NOT NULL,
33
- created_at TEXT NOT NULL
34
- );
35
-
36
- CREATE TABLE IF NOT EXISTS roles (
37
- id TEXT PRIMARY KEY,
38
- name TEXT UNIQUE NOT NULL,
39
- level INTEGER DEFAULT 50,
40
- inherits TEXT DEFAULT '[]',
41
- permissions TEXT DEFAULT '[]',
42
- description TEXT,
43
- created_at TEXT NOT NULL
44
- );
45
-
46
- CREATE TABLE IF NOT EXISTS audit_logs (
47
- id TEXT PRIMARY KEY,
48
- user_id TEXT,
49
- action TEXT NOT NULL,
50
- entity_type TEXT,
51
- entity_id TEXT,
52
- metadata TEXT DEFAULT '{}',
53
- ip_address TEXT,
54
- user_agent TEXT,
55
- created_at TEXT NOT NULL
56
- );
57
- `);
58
-
59
- export interface SQLiteAuthAdapterOptions {
60
- tokenExpiration?: number;
61
- refreshTokenExpiration?: number;
62
- }
63
-
64
- const DEFAULT_TOKEN_EXPIRATION = 86400;
65
- const DEFAULT_REFRESH_EXPIRATION = 604800;
66
-
67
- export class SQLiteAuthAdapter implements AuthAdapter {
68
- private tokenExpiration: number;
69
- private refreshExpiration: number;
70
-
71
- constructor(options: SQLiteAuthAdapterOptions = {}) {
72
- this.tokenExpiration = options.tokenExpiration || DEFAULT_TOKEN_EXPIRATION;
73
- this.refreshExpiration =
74
- options.refreshTokenExpiration || DEFAULT_REFRESH_EXPIRATION;
75
- }
76
-
77
- private getTimestamp(): string {
78
- return new Date().toISOString();
79
- }
80
-
81
- private generateId(): string {
82
- return randomBytes(16).toString("hex");
83
- }
84
-
85
- private getDb(): Database.Database {
86
- return db;
87
- }
88
-
89
- async findUserById(id: string): Promise<AuthUser | null> {
90
- const user = db.prepare("SELECT * FROM users WHERE id = ?").get(id) as any;
91
- if (!user) return null;
92
- return {
93
- id: user.id,
94
- email: user.email,
95
- name: user.name,
96
- role: user.role as UserRole,
97
- createdAt: user.created_at,
98
- updatedAt: user.updated_at,
99
- };
100
- }
101
-
102
- async findUserByEmail(email: string): Promise<AuthUser | null> {
103
- const user = db
104
- .prepare("SELECT * FROM users WHERE email = ?")
105
- .get(email) as any;
106
- if (!user) return null;
107
- return {
108
- id: user.id,
109
- email: user.email,
110
- name: user.name,
111
- role: user.role as UserRole,
112
- createdAt: user.created_at,
113
- updatedAt: user.updated_at,
114
- };
115
- }
116
-
117
- async createUser(
118
- userData: Partial<AuthUser> & { password: string },
119
- ): Promise<AuthUser> {
120
- const now = this.getTimestamp();
121
- const id = this.generateId();
122
- const passwordHash = await bcrypt.hash(userData.password, 10);
123
-
124
- db.prepare(
125
- "INSERT INTO users (id, email, password_hash, name, role, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
126
- ).run(
127
- id,
128
- userData.email,
129
- passwordHash,
130
- userData.name || null,
131
- userData.role || "customer",
132
- now,
133
- now,
134
- );
135
-
136
- return {
137
- id,
138
- email: userData.email,
139
- name: userData.name,
140
- role: userData.role || "customer",
141
- createdAt: now,
142
- updatedAt: now,
143
- };
144
- }
145
-
146
- async updateUser(
147
- id: string,
148
- data: Partial<AuthUser> & { password?: string },
149
- ): Promise<AuthUser | null> {
150
- const existing = await this.findUserById(id);
151
- if (!existing) return null;
152
-
153
- const now = this.getTimestamp();
154
- const updates: string[] = [];
155
- const values: any[] = [];
156
-
157
- if (data.email !== undefined) {
158
- updates.push("email = ?");
159
- values.push(data.email);
160
- }
161
- if (data.name !== undefined) {
162
- updates.push("name = ?");
163
- values.push(data.name);
164
- }
165
- if (data.role !== undefined) {
166
- updates.push("role = ?");
167
- values.push(data.role);
168
- }
169
- if (data.password !== undefined) {
170
- updates.push("password_hash = ?");
171
- values.push(await bcrypt.hash(data.password, 10));
172
- }
173
-
174
- updates.push("updated_at = ?");
175
- values.push(now);
176
- values.push(id);
177
-
178
- db.prepare(`UPDATE users SET ${updates.join(", ")} WHERE id = ?`).run(
179
- ...values,
180
- );
181
-
182
- return this.findUserById(id);
183
- }
184
-
185
- async deleteUser(id: string): Promise<boolean> {
186
- const result = db.prepare("DELETE FROM users WHERE id = ?").run(id);
187
- if (result.changes > 0) {
188
- db.prepare("DELETE FROM sessions WHERE user_id = ?").run(id);
189
- return true;
190
- }
191
- return false;
192
- }
193
-
194
- async verifyPassword(
195
- email: string,
196
- password: string,
197
- ): Promise<AuthUser | null> {
198
- const user = db
199
- .prepare("SELECT * FROM users WHERE email = ?")
200
- .get(email) as any;
201
- if (!user) return null;
202
-
203
- const valid = await bcrypt.compare(password, user.password_hash);
204
- if (!valid) return null;
205
-
206
- return {
207
- id: user.id,
208
- email: user.email,
209
- name: user.name,
210
- role: user.role as UserRole,
211
- createdAt: user.created_at,
212
- updatedAt: user.updated_at,
213
- };
214
- }
215
-
216
- async createSession(userId: string): Promise<Session> {
217
- const now = new Date();
218
- const expiresAt = new Date(now.getTime() + this.tokenExpiration * 1000);
219
- const refreshExpiresAt = new Date(
220
- now.getTime() + this.refreshExpiration * 1000,
221
- );
222
-
223
- const token = randomBytes(32).toString("hex");
224
- const refreshToken = randomBytes(32).toString("hex");
225
-
226
- db.prepare(
227
- "INSERT INTO sessions (token, user_id, expires_at, created_at) VALUES (?, ?, ?, ?)",
228
- ).run(token, userId, expiresAt.toISOString(), now.toISOString());
229
-
230
- return {
231
- token,
232
- refreshToken,
233
- expiresAt: expiresAt.toISOString(),
234
- userId,
235
- createdAt: now.toISOString(),
236
- };
237
- }
238
-
239
- async validateSession(token: string): Promise<Session | null> {
240
- const now = new Date().toISOString();
241
- const session = db
242
- .prepare("SELECT * FROM sessions WHERE token = ? AND expires_at > ?")
243
- .get(token, now) as any;
244
-
245
- if (!session) return null;
246
-
247
- return {
248
- token: session.token,
249
- userId: session.user_id,
250
- expiresAt: session.expires_at,
251
- createdAt: session.created_at,
252
- };
253
- }
254
-
255
- async refreshSession(token: string): Promise<Session | null> {
256
- const session = await this.validateSession(token);
257
- if (!session) return null;
258
-
259
- return this.createSession(session.userId);
260
- }
261
-
262
- async revokeSession(token: string): Promise<void> {
263
- db.prepare("DELETE FROM sessions WHERE token = ?").run(token);
264
- }
265
-
266
- async revokeAllUserSessions(userId: string): Promise<void> {
267
- db.prepare("DELETE FROM sessions WHERE user_id = ?").run(userId);
268
- }
269
-
270
- async findUserRoles(): Promise<UserRole[]> {
271
- const roles = db
272
- .prepare("SELECT * FROM roles ORDER BY level DESC")
273
- .all() as any[];
274
- return roles.map((r) => ({
275
- id: r.id,
276
- name: r.name,
277
- level: r.level,
278
- inherits: JSON.parse(r.inherits || "[]"),
279
- permissions: JSON.parse(r.permissions || "[]"),
280
- description: r.description,
281
- createdAt: r.created_at,
282
- }));
283
- }
284
-
285
- async createRole(role: Partial<UserRole>): Promise<UserRole> {
286
- const now = this.getTimestamp();
287
- const id = role.id || this.generateId();
288
-
289
- db.prepare(
290
- "INSERT INTO roles (id, name, level, inherits, permissions, description, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
291
- ).run(
292
- id,
293
- role.name,
294
- role.level || 50,
295
- JSON.stringify(role.inherits || []),
296
- JSON.stringify(role.permissions || []),
297
- role.description || null,
298
- now,
299
- );
300
-
301
- return {
302
- id,
303
- name: role.name!,
304
- level: role.level || 50,
305
- inherits: role.inherits || [],
306
- permissions: role.permissions || [],
307
- description: role.description,
308
- createdAt: now,
309
- };
310
- }
311
-
312
- async findUserByIdWithPassword(
313
- id: string,
314
- ): Promise<{ id: string; email: string; password_hash: string } | null> {
315
- return db
316
- .prepare("SELECT id, email, password_hash FROM users WHERE id = ?")
317
- .get(id) as any;
318
- }
319
- }
@@ -1,226 +0,0 @@
1
- import type { CollectionConfig } from "@kyro-cms/core/client";
2
- import { randomUUID } from "crypto";
3
- import {
4
- initializeDatabase,
5
- getDatabaseAdapter,
6
- isDatabaseInitialized,
7
- } from "./db";
8
- import type { Version, VersionDiff, DraftPublishConfig } from "@kyro-cms/core";
9
- import { VersionManager, createVersionManager } from "@kyro-cms/core";
10
- import { DataStoreVersionAdapter } from "./db/version-adapter.js";
11
-
12
- class DataStoreWrapper {
13
- private db: ReturnType<typeof getDatabaseAdapter> | null = null;
14
- private versionManager: VersionManager | null = null;
15
-
16
- private async getStore() {
17
- if (!isDatabaseInitialized()) {
18
- await initializeDatabase();
19
- }
20
- return getDatabaseAdapter();
21
- }
22
-
23
- private async getVersionManager(): Promise<VersionManager> {
24
- if (this.versionManager) return this.versionManager;
25
- const db = await this.getStore();
26
- const adapter = new DataStoreVersionAdapter(db);
27
- this.versionManager = createVersionManager(adapter, {
28
- versioningEnabled: true,
29
- maxVersionsPerDocument: 50,
30
- } as DraftPublishConfig);
31
- return this.versionManager;
32
- }
33
-
34
- initialize(collections: Record<string, CollectionConfig>) {
35
- initializeDatabase(collections);
36
- }
37
-
38
- private async getTimestamp(): Promise<string> {
39
- return new Date().toISOString();
40
- }
41
-
42
- private generateId(): string {
43
- return randomUUID();
44
- }
45
-
46
- async find<T = any>(
47
- slug: string,
48
- options: { page?: number; limit?: number } = {},
49
- ): Promise<{
50
- docs: T[];
51
- totalDocs: number;
52
- totalPages: number;
53
- page: number;
54
- }> {
55
- const store = await this.getStore();
56
- return store.find(slug, options);
57
- }
58
-
59
- async findById<T = any>(slug: string, id: string): Promise<T | null> {
60
- const store = await this.getStore();
61
- return store.findById(slug, id);
62
- }
63
-
64
- async create<T = any>(slug: string, data: Partial<T>): Promise<T> {
65
- const store = await this.getStore();
66
- const now = await this.getTimestamp();
67
- const id = (data as any)?.id || this.generateId();
68
- const newDoc = {
69
- ...data,
70
- id,
71
- createdAt: now,
72
- updatedAt: now,
73
- } as T;
74
- return store.create(slug, newDoc);
75
- }
76
-
77
- async update<T = any>(
78
- slug: string,
79
- id: string,
80
- data: Partial<T>,
81
- options?: {
82
- versionStatus?: "draft" | "published";
83
- changeDescription?: string;
84
- },
85
- ): Promise<T | null> {
86
- const store = await this.getStore();
87
- const existing = await store.findById(slug, id);
88
- if (!existing) return null;
89
-
90
- const now = await this.getTimestamp();
91
- const updated = {
92
- ...existing,
93
- ...data,
94
- id,
95
- updatedAt: now,
96
- };
97
-
98
- // Save version history before updating
99
- const versionStatus = options?.versionStatus || "draft";
100
- const changeDescription = options?.changeDescription;
101
-
102
- await this.createVersion(slug, id, existing, {
103
- status: versionStatus,
104
- changeDescription,
105
- });
106
-
107
- return store.update(slug, id, updated);
108
- }
109
-
110
- async findVersions(parentCollection: string, parentId: string) {
111
- const vm = await this.getVersionManager();
112
- const versions = await vm.getVersionHistory(
113
- parentCollection,
114
- parentId,
115
- 100,
116
- );
117
- return (versions as Version[])
118
- .map((v) => ({
119
- id: v.id,
120
- version: v.version,
121
- createdAt: v.createdAt,
122
- status: v.status,
123
- createdBy: v.createdBy,
124
- data: v.data,
125
- changeDescription: v.changeDescription,
126
- }))
127
- .sort((a, b) => b.version - a.version);
128
- }
129
-
130
- async createVersion(
131
- parentCollection: string,
132
- parentId: string,
133
- data: any,
134
- options?: {
135
- status?: string;
136
- createdBy?: string;
137
- changeDescription?: string;
138
- },
139
- ) {
140
- const vm = await this.getVersionManager();
141
- try {
142
- return await vm.createVersion({
143
- collection: parentCollection,
144
- documentId: parentId,
145
- data,
146
- status: (options?.status || "draft") as "draft" | "published",
147
- createdBy: options?.createdBy || "system",
148
- changeDescription: options?.changeDescription,
149
- });
150
- } catch (e) {
151
- console.error("Failed to create version snapshot:", e);
152
- return null;
153
- }
154
- }
155
-
156
- async restoreVersion(
157
- parentCollection: string,
158
- parentId: string,
159
- versionId: string,
160
- ) {
161
- const vm = await this.getVersionManager();
162
- const store = await this.getStore();
163
- const version = await store.findById("_versions", versionId);
164
- if (!version || version.parentId !== parentId) return null;
165
-
166
- return this.update(parentCollection, parentId, version.data);
167
- }
168
-
169
- async compareVersions(
170
- collection: string,
171
- documentId: string,
172
- versionA: string | number,
173
- versionB: string | number,
174
- ): Promise<VersionDiff[]> {
175
- const vm = await this.getVersionManager();
176
- return vm.compareTwoVersions(collection, documentId, versionA, versionB);
177
- }
178
-
179
- async delete(slug: string, id: string): Promise<boolean> {
180
- const store = await this.getStore();
181
- return store.delete(slug, id);
182
- }
183
-
184
- async findOne(
185
- slug: string,
186
- filter: Record<string, any>,
187
- ): Promise<any | null> {
188
- const store = await this.getStore();
189
- const results = await store.find(slug, { limit: 1 });
190
- return results.docs.length > 0 ? results.docs[0] : null;
191
- }
192
-
193
- async findGlobal<T = any>(slug: string): Promise<T> {
194
- const store = await this.getStore();
195
- return store.findGlobal(slug);
196
- }
197
-
198
- async updateGlobal<T = any>(slug: string, data: Partial<T>): Promise<T> {
199
- const store = await this.getStore();
200
- const current = await store.findGlobal(slug);
201
- const updated = { ...current, ...data };
202
- return store.updateGlobal(slug, updated);
203
- }
204
-
205
- async seedGlobal(slug: string, data: any): Promise<void> {
206
- const store = await this.getStore();
207
- return store.seedGlobal(slug, data);
208
- }
209
-
210
- async count(slug: string): Promise<number> {
211
- const store = await this.getStore();
212
- return store.count(slug);
213
- }
214
-
215
- async seed(slug: string, docs: any[]): Promise<void> {
216
- const store = await this.getStore();
217
- return store.seed(slug, docs);
218
- }
219
-
220
- async isSeeded(slug: string): Promise<boolean> {
221
- const store = await this.getStore();
222
- return store.isSeeded(slug);
223
- }
224
- }
225
-
226
- export const dataStore = new DataStoreWrapper();
@@ -1,54 +0,0 @@
1
- import type { CollectionConfig } from "@kyro-cms/core";
2
-
3
- export interface DatabaseAdapter {
4
- initialize(collections: Record<string, CollectionConfig>): void;
5
-
6
- find<T = any>(
7
- slug: string,
8
- options?: { page?: number; limit?: number },
9
- ): Promise<{
10
- docs: T[];
11
- totalDocs: number;
12
- totalPages: number;
13
- page: number;
14
- }>;
15
-
16
- findById<T = any>(slug: string, id: string): Promise<T | null>;
17
-
18
- create<T = any>(slug: string, data: Partial<T>): Promise<T>;
19
-
20
- update<T = any>(
21
- slug: string,
22
- id: string,
23
- data: Partial<T>,
24
- ): Promise<T | null>;
25
-
26
- delete(slug: string, id: string): Promise<boolean>;
27
-
28
- findGlobal<T = any>(slug: string): Promise<T>;
29
-
30
- updateGlobal<T = any>(slug: string, data: Partial<T>): Promise<T>;
31
-
32
- seedGlobal(slug: string, data: any): Promise<void>;
33
-
34
- count(slug: string): Promise<number>;
35
-
36
- seed(slug: string, docs: any[]): Promise<void>;
37
-
38
- isSeeded(slug: string): Promise<boolean>;
39
- }
40
-
41
- export type DatabaseType = "sqlite" | "postgres" | "mysql" | "mongodb";
42
-
43
- export interface DatabaseConfig {
44
- type: DatabaseType;
45
- connectionString?: string;
46
- host?: string;
47
- port?: number;
48
- database?: string;
49
- username?: string;
50
- password?: string;
51
- poolMin?: number;
52
- poolMax?: number;
53
- contentDbPath?: string;
54
- }