gavaengine 0.1.0

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.
package/dist/index.js ADDED
@@ -0,0 +1,495 @@
1
+ "use client";
2
+ import {
3
+ GavaEngineProvider,
4
+ SessionProvider,
5
+ ThemeProvider,
6
+ ThemeToggle
7
+ } from "./chunk-KCQJHXZP.js";
8
+ import {
9
+ ArticleEditor,
10
+ ArticleList,
11
+ CoverImageUpload,
12
+ DashboardNavbar,
13
+ DashboardSplashTrigger,
14
+ DraggableYoutube,
15
+ DraggableYoutubeView,
16
+ EditorToolbar,
17
+ ImageEditModal,
18
+ MediaGrid,
19
+ MediaPickerModal,
20
+ ResizableImage,
21
+ ResizableImageView,
22
+ RevisionPanel,
23
+ SplashScreen,
24
+ StatCard,
25
+ UserForm,
26
+ UserTable,
27
+ VideoExtension,
28
+ VideoView
29
+ } from "./chunk-CE7E5MAB.js";
30
+ import {
31
+ ActionsProvider,
32
+ ConfigProvider,
33
+ DEFAULT_CONFIG,
34
+ SplashProvider,
35
+ defineConfig,
36
+ useGavaActions,
37
+ useGavaConfig,
38
+ useSplash
39
+ } from "./chunk-GGD7I4JO.js";
40
+
41
+ // src/handlers/revisions.ts
42
+ function createRevisionHandlers(prisma, config) {
43
+ const throttleMs = config.editor.revisionThrottleMinutes * 60 * 1e3;
44
+ return {
45
+ async getRevisions(articleId) {
46
+ return prisma.articleRevision.findMany({
47
+ where: { articleId },
48
+ include: { editor: { select: { name: true } } },
49
+ orderBy: { createdAt: "desc" }
50
+ });
51
+ },
52
+ async restoreRevision(articleId, revisionId, editorId) {
53
+ const article = await prisma.article.findUnique({
54
+ where: { id: articleId }
55
+ });
56
+ if (!article) throw new Error("Article not found");
57
+ const revision = await prisma.articleRevision.findUnique({
58
+ where: { id: revisionId }
59
+ });
60
+ if (!revision || revision.articleId !== articleId) {
61
+ throw new Error("Revision not found");
62
+ }
63
+ await prisma.articleRevision.create({
64
+ data: {
65
+ articleId,
66
+ title: article.title,
67
+ content: article.content,
68
+ excerpt: article.excerpt,
69
+ coverImage: article.coverImage,
70
+ category: article.category,
71
+ editorId,
72
+ note: config.strings.beforeRestore
73
+ }
74
+ });
75
+ await prisma.article.update({
76
+ where: { id: articleId },
77
+ data: {
78
+ title: revision.title,
79
+ content: revision.content,
80
+ excerpt: revision.excerpt,
81
+ coverImage: revision.coverImage,
82
+ category: revision.category,
83
+ updatedAt: /* @__PURE__ */ new Date()
84
+ }
85
+ });
86
+ return { success: true };
87
+ },
88
+ async createRevisionSnapshot(articleId, editorId, note = "") {
89
+ const article = await prisma.article.findUnique({
90
+ where: { id: articleId }
91
+ });
92
+ if (!article) return;
93
+ const threshold = new Date(Date.now() - throttleMs);
94
+ const recent = await prisma.articleRevision.findFirst({
95
+ where: { articleId, createdAt: { gte: threshold } },
96
+ orderBy: { createdAt: "desc" }
97
+ });
98
+ if (recent && !note) return;
99
+ await prisma.articleRevision.create({
100
+ data: {
101
+ articleId,
102
+ title: article.title,
103
+ content: article.content,
104
+ excerpt: article.excerpt,
105
+ coverImage: article.coverImage,
106
+ category: article.category,
107
+ editorId,
108
+ note
109
+ }
110
+ });
111
+ }
112
+ };
113
+ }
114
+
115
+ // src/handlers/articles.ts
116
+ function createArticleHandlers(prisma, config) {
117
+ const revisionHandlers = createRevisionHandlers(prisma, config);
118
+ return {
119
+ async getArticles() {
120
+ return prisma.article.findMany({
121
+ orderBy: { updatedAt: "desc" }
122
+ });
123
+ },
124
+ async getArticleById(id) {
125
+ return prisma.article.findUnique({
126
+ where: { id }
127
+ });
128
+ },
129
+ async createArticle(authorName) {
130
+ const article = await prisma.article.create({
131
+ data: {
132
+ authorName
133
+ }
134
+ });
135
+ return article.id;
136
+ },
137
+ async updateArticle(userId, id, data) {
138
+ const article = await prisma.article.findUnique({ where: { id } });
139
+ if (!article) throw new Error("Article not found");
140
+ await revisionHandlers.createRevisionSnapshot(id, userId);
141
+ await prisma.article.update({
142
+ where: { id },
143
+ data: { ...data, updatedAt: /* @__PURE__ */ new Date() }
144
+ });
145
+ return { success: true };
146
+ },
147
+ async deleteArticle(id) {
148
+ const article = await prisma.article.findUnique({ where: { id } });
149
+ if (!article) throw new Error("Article not found");
150
+ await prisma.article.delete({ where: { id } });
151
+ return { success: true };
152
+ },
153
+ async publishArticle(userId, id) {
154
+ const article = await prisma.article.findUnique({ where: { id } });
155
+ if (!article) throw new Error("Article not found");
156
+ if (!article.title || !article.slug) {
157
+ throw new Error(
158
+ "Title and slug are required for publishing"
159
+ );
160
+ }
161
+ await revisionHandlers.createRevisionSnapshot(
162
+ id,
163
+ userId,
164
+ config.strings.publishedNote
165
+ );
166
+ await prisma.article.update({
167
+ where: { id },
168
+ data: {
169
+ status: "pubblicato",
170
+ publishedAt: /* @__PURE__ */ new Date()
171
+ }
172
+ });
173
+ return { success: true };
174
+ },
175
+ async unpublishArticle(id) {
176
+ const article = await prisma.article.findUnique({ where: { id } });
177
+ if (!article) throw new Error("Article not found");
178
+ await prisma.article.update({
179
+ where: { id },
180
+ data: {
181
+ status: "bozza",
182
+ publishedAt: null
183
+ }
184
+ });
185
+ return { success: true };
186
+ }
187
+ };
188
+ }
189
+
190
+ // src/handlers/users.ts
191
+ import bcrypt from "bcryptjs";
192
+ function createUserHandlers(prisma, config) {
193
+ return {
194
+ async getUsers() {
195
+ return prisma.user.findMany({
196
+ select: {
197
+ id: true,
198
+ name: true,
199
+ email: true,
200
+ role: true,
201
+ createdAt: true
202
+ },
203
+ orderBy: { createdAt: "desc" }
204
+ });
205
+ },
206
+ async getUserById(id) {
207
+ return prisma.user.findUnique({
208
+ where: { id },
209
+ select: {
210
+ id: true,
211
+ name: true,
212
+ email: true,
213
+ role: true
214
+ }
215
+ });
216
+ },
217
+ async createUser(formData) {
218
+ const name = formData.get("name");
219
+ const email = formData.get("email");
220
+ const password = formData.get("password");
221
+ const role = formData.get("role");
222
+ if (!name || !email || !password || !role) {
223
+ return { error: config.strings.allFieldsRequired };
224
+ }
225
+ if (!config.roles.list.includes(role)) {
226
+ return { error: config.strings.invalidRole };
227
+ }
228
+ if (password.length < 6) {
229
+ return { error: config.strings.passwordMinLength };
230
+ }
231
+ const existing = await prisma.user.findUnique({ where: { email } });
232
+ if (existing) {
233
+ return { error: config.strings.emailExists };
234
+ }
235
+ const hashedPassword = await bcrypt.hash(password, 10);
236
+ await prisma.user.create({
237
+ data: {
238
+ name,
239
+ email,
240
+ password: hashedPassword,
241
+ role
242
+ }
243
+ });
244
+ return { success: true };
245
+ },
246
+ async updateUser(id, formData) {
247
+ const name = formData.get("name");
248
+ const email = formData.get("email");
249
+ const password = formData.get("password");
250
+ const role = formData.get("role");
251
+ if (!name || !email || !role) {
252
+ return { error: config.strings.allFieldsRequired };
253
+ }
254
+ if (!config.roles.list.includes(role)) {
255
+ return { error: config.strings.invalidRole };
256
+ }
257
+ const existing = await prisma.user.findUnique({ where: { email } });
258
+ if (existing && existing.id !== id) {
259
+ return { error: config.strings.emailExists };
260
+ }
261
+ const data = {
262
+ name,
263
+ email,
264
+ role
265
+ };
266
+ if (password && password.length > 0) {
267
+ if (password.length < 6) {
268
+ return { error: config.strings.passwordMinLength };
269
+ }
270
+ data.password = await bcrypt.hash(password, 10);
271
+ }
272
+ await prisma.user.update({
273
+ where: { id },
274
+ data
275
+ });
276
+ return { success: true };
277
+ },
278
+ async deleteUser(currentUserId, id) {
279
+ if (currentUserId === id) {
280
+ return { error: config.strings.cannotDeleteSelf };
281
+ }
282
+ await prisma.user.delete({ where: { id } });
283
+ return { success: true };
284
+ }
285
+ };
286
+ }
287
+
288
+ // src/handlers/media.ts
289
+ function createMediaHandlers(prisma, _config) {
290
+ return {
291
+ async getMedia(search) {
292
+ return prisma.media.findMany({
293
+ where: search ? { filename: { contains: search } } : void 0,
294
+ include: { uploader: { select: { name: true } } },
295
+ orderBy: { createdAt: "desc" }
296
+ });
297
+ },
298
+ async deleteMedia(userId, userRole, id, deleteFileFromDisk) {
299
+ const media = await prisma.media.findUnique({ where: { id } });
300
+ if (!media) throw new Error("File not found");
301
+ if (userRole === "scrittore" && media.uploaderId !== userId) {
302
+ throw new Error("Unauthorized");
303
+ }
304
+ const usedInArticles = await prisma.article.findMany({
305
+ where: {
306
+ OR: [
307
+ { coverImage: media.path },
308
+ { content: { contains: media.path } }
309
+ ]
310
+ },
311
+ select: { id: true, title: true }
312
+ });
313
+ if (usedInArticles.length > 0) {
314
+ const titles = usedInArticles.map((a) => a.title || "Untitled").join(", ");
315
+ throw new Error(
316
+ `Cannot delete: image is used in ${usedInArticles.length} article(s) (${titles})`
317
+ );
318
+ }
319
+ if (deleteFileFromDisk) {
320
+ try {
321
+ await deleteFileFromDisk(media.path);
322
+ } catch {
323
+ }
324
+ }
325
+ await prisma.media.delete({ where: { id } });
326
+ return { success: true };
327
+ }
328
+ };
329
+ }
330
+
331
+ // src/handlers/upload.ts
332
+ function createUploadHandler(prisma, config, storage) {
333
+ const allowedTypes = [
334
+ ...config.upload.imageTypes,
335
+ ...config.upload.videoTypes
336
+ ];
337
+ return {
338
+ async handleUpload(file, uploaderId) {
339
+ if (!allowedTypes.includes(file.type)) {
340
+ return { error: "Unsupported file type" };
341
+ }
342
+ const isVideo = config.upload.videoTypes.includes(file.type);
343
+ const maxSize = isVideo ? config.upload.maxVideoSize : config.upload.maxImageSize;
344
+ if (file.size > maxSize) {
345
+ return {
346
+ error: `File too large. Max ${isVideo ? config.upload.maxVideoSize / (1024 * 1024) : config.upload.maxImageSize / (1024 * 1024)}MB.`
347
+ };
348
+ }
349
+ const buffer = Buffer.from(await file.arrayBuffer());
350
+ const url = await storage.save(file.name, buffer, file.type);
351
+ await prisma.media.create({
352
+ data: {
353
+ filename: file.name,
354
+ path: url,
355
+ mimeType: file.type,
356
+ size: file.size,
357
+ uploaderId
358
+ }
359
+ });
360
+ return { url };
361
+ }
362
+ };
363
+ }
364
+
365
+ // src/handlers/auth.ts
366
+ import bcrypt2 from "bcryptjs";
367
+ function buildCredentialsProvider(prisma) {
368
+ return {
369
+ credentials: {
370
+ email: {},
371
+ password: {}
372
+ },
373
+ async authorize(credentials) {
374
+ const email = credentials.email;
375
+ const password = credentials.password;
376
+ if (!email || !password) return null;
377
+ const user = await prisma.user.findUnique({
378
+ where: { email }
379
+ });
380
+ if (!user) return null;
381
+ const isValid = await bcrypt2.compare(password, user.password);
382
+ if (!isValid) return null;
383
+ return {
384
+ id: user.id,
385
+ name: user.name,
386
+ email: user.email,
387
+ role: user.role
388
+ };
389
+ }
390
+ };
391
+ }
392
+ function buildAuthCallbacks(config) {
393
+ return {
394
+ async jwt({
395
+ token,
396
+ user
397
+ }) {
398
+ if (user) {
399
+ token.id = user.id;
400
+ token.role = user.role;
401
+ }
402
+ return token;
403
+ },
404
+ async session({
405
+ session,
406
+ token
407
+ }) {
408
+ if (session.user) {
409
+ session.user.id = token.id;
410
+ session.user.role = token.role;
411
+ }
412
+ return session;
413
+ },
414
+ authorized({
415
+ auth,
416
+ request: { nextUrl }
417
+ }) {
418
+ const isLoggedIn = !!auth;
419
+ const role = auth?.user?.role;
420
+ const pathname = nextUrl.pathname;
421
+ if (pathname === config.routes.login && isLoggedIn) {
422
+ return Response.redirect(new URL(config.routes.articles, nextUrl));
423
+ }
424
+ if (pathname.startsWith(config.routes.dashboard)) {
425
+ if (!isLoggedIn) {
426
+ return Response.redirect(new URL(config.routes.login, nextUrl));
427
+ }
428
+ if (pathname.startsWith(config.routes.users) && role !== config.roles.adminRole) {
429
+ return Response.redirect(
430
+ new URL(config.routes.articles, nextUrl)
431
+ );
432
+ }
433
+ }
434
+ return true;
435
+ }
436
+ };
437
+ }
438
+
439
+ // src/handlers/auth-utils.ts
440
+ function createAuthUtils(config) {
441
+ return {
442
+ canEdit(role) {
443
+ return config.roles.canEdit(role);
444
+ },
445
+ canPublish(role) {
446
+ return config.roles.canPublish(role);
447
+ },
448
+ isAdmin(role) {
449
+ return role === config.roles.adminRole;
450
+ }
451
+ };
452
+ }
453
+ export {
454
+ ActionsProvider,
455
+ ArticleEditor,
456
+ ArticleList,
457
+ ConfigProvider,
458
+ CoverImageUpload,
459
+ DEFAULT_CONFIG,
460
+ DashboardNavbar,
461
+ DashboardSplashTrigger,
462
+ DraggableYoutube,
463
+ DraggableYoutubeView,
464
+ EditorToolbar,
465
+ GavaEngineProvider,
466
+ ImageEditModal,
467
+ MediaGrid,
468
+ MediaPickerModal,
469
+ ResizableImage,
470
+ ResizableImageView,
471
+ RevisionPanel,
472
+ SessionProvider,
473
+ SplashProvider,
474
+ SplashScreen,
475
+ StatCard,
476
+ ThemeProvider,
477
+ ThemeToggle,
478
+ UserForm,
479
+ UserTable,
480
+ VideoExtension,
481
+ VideoView,
482
+ buildAuthCallbacks,
483
+ buildCredentialsProvider,
484
+ createArticleHandlers,
485
+ createAuthUtils,
486
+ createMediaHandlers,
487
+ createRevisionHandlers,
488
+ createUploadHandler,
489
+ createUserHandlers,
490
+ defineConfig,
491
+ useGavaActions,
492
+ useGavaConfig,
493
+ useSplash
494
+ };
495
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/handlers/revisions.ts","../src/handlers/articles.ts","../src/handlers/users.ts","../src/handlers/media.ts","../src/handlers/upload.ts","../src/handlers/auth.ts","../src/handlers/auth-utils.ts"],"sourcesContent":["import type { GavaEngineConfig } from \"../config.js\";\n\nexport function createRevisionHandlers(prisma: any, config: GavaEngineConfig) {\n const throttleMs = config.editor.revisionThrottleMinutes * 60 * 1000;\n\n return {\n async getRevisions(articleId: string) {\n return prisma.articleRevision.findMany({\n where: { articleId },\n include: { editor: { select: { name: true } } },\n orderBy: { createdAt: \"desc\" },\n });\n },\n\n async restoreRevision(\n articleId: string,\n revisionId: string,\n editorId: string\n ) {\n const article = await prisma.article.findUnique({\n where: { id: articleId },\n });\n if (!article) throw new Error(\"Article not found\");\n\n const revision = await prisma.articleRevision.findUnique({\n where: { id: revisionId },\n });\n if (!revision || revision.articleId !== articleId) {\n throw new Error(\"Revision not found\");\n }\n\n // Save current state before restoring\n await prisma.articleRevision.create({\n data: {\n articleId,\n title: article.title,\n content: article.content,\n excerpt: article.excerpt,\n coverImage: article.coverImage,\n category: article.category,\n editorId,\n note: config.strings.beforeRestore,\n },\n });\n\n // Restore\n await prisma.article.update({\n where: { id: articleId },\n data: {\n title: revision.title,\n content: revision.content,\n excerpt: revision.excerpt,\n coverImage: revision.coverImage,\n category: revision.category,\n updatedAt: new Date(),\n },\n });\n\n return { success: true };\n },\n\n async createRevisionSnapshot(\n articleId: string,\n editorId: string,\n note: string = \"\"\n ) {\n const article = await prisma.article.findUnique({\n where: { id: articleId },\n });\n if (!article) return;\n\n // Throttle: only create if last revision was > threshold ago\n const threshold = new Date(Date.now() - throttleMs);\n const recent = await prisma.articleRevision.findFirst({\n where: { articleId, createdAt: { gte: threshold } },\n orderBy: { createdAt: \"desc\" },\n });\n\n if (recent && !note) return;\n\n await prisma.articleRevision.create({\n data: {\n articleId,\n title: article.title,\n content: article.content,\n excerpt: article.excerpt,\n coverImage: article.coverImage,\n category: article.category,\n editorId,\n note,\n },\n });\n },\n };\n}\n","import type { GavaEngineConfig } from \"../config.js\";\nimport { createRevisionHandlers } from \"./revisions.js\";\n\nexport function createArticleHandlers(prisma: any, config: GavaEngineConfig) {\n const revisionHandlers = createRevisionHandlers(prisma, config);\n\n return {\n async getArticles() {\n return prisma.article.findMany({\n orderBy: { updatedAt: \"desc\" },\n });\n },\n\n async getArticleById(id: string) {\n return prisma.article.findUnique({\n where: { id },\n });\n },\n\n async createArticle(authorName: string) {\n const article = await prisma.article.create({\n data: {\n authorName,\n },\n });\n return article.id;\n },\n\n async updateArticle(\n userId: string,\n id: string,\n data: {\n title?: string;\n slug?: string;\n excerpt?: string;\n content?: string;\n coverImage?: string;\n category?: string;\n authorName?: string;\n }\n ) {\n const article = await prisma.article.findUnique({ where: { id } });\n if (!article) throw new Error(\"Article not found\");\n\n await revisionHandlers.createRevisionSnapshot(id, userId);\n\n await prisma.article.update({\n where: { id },\n data: { ...data, updatedAt: new Date() },\n });\n\n return { success: true };\n },\n\n async deleteArticle(id: string) {\n const article = await prisma.article.findUnique({ where: { id } });\n if (!article) throw new Error(\"Article not found\");\n\n await prisma.article.delete({ where: { id } });\n return { success: true };\n },\n\n async publishArticle(userId: string, id: string) {\n const article = await prisma.article.findUnique({ where: { id } });\n if (!article) throw new Error(\"Article not found\");\n\n if (!article.title || !article.slug) {\n throw new Error(\n \"Title and slug are required for publishing\"\n );\n }\n\n await revisionHandlers.createRevisionSnapshot(\n id,\n userId,\n config.strings.publishedNote\n );\n\n await prisma.article.update({\n where: { id },\n data: {\n status: \"pubblicato\",\n publishedAt: new Date(),\n },\n });\n\n return { success: true };\n },\n\n async unpublishArticle(id: string) {\n const article = await prisma.article.findUnique({ where: { id } });\n if (!article) throw new Error(\"Article not found\");\n\n await prisma.article.update({\n where: { id },\n data: {\n status: \"bozza\",\n publishedAt: null,\n },\n });\n\n return { success: true };\n },\n };\n}\n","import bcrypt from \"bcryptjs\";\nimport type { GavaEngineConfig } from \"../config.js\";\n\nexport function createUserHandlers(prisma: any, config: GavaEngineConfig) {\n return {\n async getUsers() {\n return prisma.user.findMany({\n select: {\n id: true,\n name: true,\n email: true,\n role: true,\n createdAt: true,\n },\n orderBy: { createdAt: \"desc\" },\n });\n },\n\n async getUserById(id: string) {\n return prisma.user.findUnique({\n where: { id },\n select: {\n id: true,\n name: true,\n email: true,\n role: true,\n },\n });\n },\n\n async createUser(formData: FormData) {\n const name = formData.get(\"name\") as string;\n const email = formData.get(\"email\") as string;\n const password = formData.get(\"password\") as string;\n const role = formData.get(\"role\") as string;\n\n if (!name || !email || !password || !role) {\n return { error: config.strings.allFieldsRequired };\n }\n\n if (!config.roles.list.includes(role)) {\n return { error: config.strings.invalidRole };\n }\n\n if (password.length < 6) {\n return { error: config.strings.passwordMinLength };\n }\n\n const existing = await prisma.user.findUnique({ where: { email } });\n if (existing) {\n return { error: config.strings.emailExists };\n }\n\n const hashedPassword = await bcrypt.hash(password, 10);\n\n await prisma.user.create({\n data: {\n name,\n email,\n password: hashedPassword,\n role,\n },\n });\n\n return { success: true };\n },\n\n async updateUser(id: string, formData: FormData) {\n const name = formData.get(\"name\") as string;\n const email = formData.get(\"email\") as string;\n const password = formData.get(\"password\") as string;\n const role = formData.get(\"role\") as string;\n\n if (!name || !email || !role) {\n return { error: config.strings.allFieldsRequired };\n }\n\n if (!config.roles.list.includes(role)) {\n return { error: config.strings.invalidRole };\n }\n\n const existing = await prisma.user.findUnique({ where: { email } });\n if (existing && existing.id !== id) {\n return { error: config.strings.emailExists };\n }\n\n const data: {\n name: string;\n email: string;\n role: string;\n password?: string;\n } = {\n name,\n email,\n role,\n };\n\n if (password && password.length > 0) {\n if (password.length < 6) {\n return { error: config.strings.passwordMinLength };\n }\n data.password = await bcrypt.hash(password, 10);\n }\n\n await prisma.user.update({\n where: { id },\n data,\n });\n\n return { success: true };\n },\n\n async deleteUser(currentUserId: string, id: string) {\n if (currentUserId === id) {\n return { error: config.strings.cannotDeleteSelf };\n }\n\n await prisma.user.delete({ where: { id } });\n return { success: true };\n },\n };\n}\n","import type { GavaEngineConfig } from \"../config.js\";\n\nexport function createMediaHandlers(prisma: any, _config: GavaEngineConfig) {\n return {\n async getMedia(search?: string) {\n return prisma.media.findMany({\n where: search ? { filename: { contains: search } } : undefined,\n include: { uploader: { select: { name: true } } },\n orderBy: { createdAt: \"desc\" },\n });\n },\n\n async deleteMedia(\n userId: string,\n userRole: string,\n id: string,\n deleteFileFromDisk?: (path: string) => Promise<void>\n ) {\n const media = await prisma.media.findUnique({ where: { id } });\n if (!media) throw new Error(\"File not found\");\n\n // Writers can only delete their own media\n if (userRole === \"scrittore\" && media.uploaderId !== userId) {\n throw new Error(\"Unauthorized\");\n }\n\n // Check if image is used in articles\n const usedInArticles = await prisma.article.findMany({\n where: {\n OR: [\n { coverImage: media.path },\n { content: { contains: media.path } },\n ],\n },\n select: { id: true, title: true },\n });\n\n if (usedInArticles.length > 0) {\n const titles = usedInArticles\n .map((a: { title: string }) => a.title || \"Untitled\")\n .join(\", \");\n throw new Error(\n `Cannot delete: image is used in ${usedInArticles.length} article(s) (${titles})`\n );\n }\n\n // Delete file from disk if handler provided\n if (deleteFileFromDisk) {\n try {\n await deleteFileFromDisk(media.path);\n } catch {\n // File may already be missing\n }\n }\n\n await prisma.media.delete({ where: { id } });\n return { success: true };\n },\n };\n}\n","import type { GavaEngineConfig } from \"../config.js\";\n\nexport interface UploadResult {\n url?: string;\n error?: string;\n}\n\nexport interface FileStorage {\n save(filename: string, buffer: Buffer, mimeType: string): Promise<string>;\n}\n\nexport function createUploadHandler(\n prisma: any,\n config: GavaEngineConfig,\n storage: FileStorage\n) {\n const allowedTypes = [\n ...config.upload.imageTypes,\n ...config.upload.videoTypes,\n ];\n\n return {\n async handleUpload(\n file: {\n name: string;\n type: string;\n size: number;\n arrayBuffer: () => Promise<ArrayBuffer>;\n },\n uploaderId: string\n ): Promise<UploadResult> {\n if (!allowedTypes.includes(file.type)) {\n return { error: \"Unsupported file type\" };\n }\n\n const isVideo = config.upload.videoTypes.includes(file.type);\n const maxSize = isVideo\n ? config.upload.maxVideoSize\n : config.upload.maxImageSize;\n\n if (file.size > maxSize) {\n return {\n error: `File too large. Max ${isVideo ? config.upload.maxVideoSize / (1024 * 1024) : config.upload.maxImageSize / (1024 * 1024)}MB.`,\n };\n }\n\n const buffer = Buffer.from(await file.arrayBuffer());\n const url = await storage.save(file.name, buffer, file.type);\n\n await prisma.media.create({\n data: {\n filename: file.name,\n path: url,\n mimeType: file.type,\n size: file.size,\n uploaderId,\n },\n });\n\n return { url };\n },\n };\n}\n","import bcrypt from \"bcryptjs\";\nimport type { GavaEngineConfig } from \"../config.js\";\n\nexport function buildCredentialsProvider(prisma: any) {\n return {\n credentials: {\n email: {},\n password: {},\n },\n async authorize(credentials: Record<string, unknown>) {\n const email = credentials.email as string;\n const password = credentials.password as string;\n\n if (!email || !password) return null;\n\n const user = await prisma.user.findUnique({\n where: { email },\n });\n\n if (!user) return null;\n\n const isValid = await bcrypt.compare(password, user.password);\n if (!isValid) return null;\n\n return {\n id: user.id,\n name: user.name,\n email: user.email,\n role: user.role,\n };\n },\n };\n}\n\nexport function buildAuthCallbacks(config: GavaEngineConfig) {\n return {\n async jwt({\n token,\n user,\n }: {\n token: Record<string, unknown>;\n user?: Record<string, unknown>;\n }) {\n if (user) {\n token.id = user.id as string;\n token.role = user.role as string;\n }\n return token;\n },\n async session({\n session,\n token,\n }: {\n session: Record<string, any>;\n token: Record<string, unknown>;\n }) {\n if (session.user) {\n session.user.id = token.id as string;\n session.user.role = token.role as string;\n }\n return session;\n },\n authorized({\n auth,\n request: { nextUrl },\n }: {\n auth: Record<string, any> | null;\n request: { nextUrl: URL };\n }) {\n const isLoggedIn = !!auth;\n const role = auth?.user?.role;\n const pathname = nextUrl.pathname;\n\n if (pathname === config.routes.login && isLoggedIn) {\n return Response.redirect(new URL(config.routes.articles, nextUrl));\n }\n\n if (pathname.startsWith(config.routes.dashboard)) {\n if (!isLoggedIn) {\n return Response.redirect(new URL(config.routes.login, nextUrl));\n }\n\n if (\n pathname.startsWith(config.routes.users) &&\n role !== config.roles.adminRole\n ) {\n return Response.redirect(\n new URL(config.routes.articles, nextUrl)\n );\n }\n }\n\n return true;\n },\n };\n}\n","import type { GavaEngineConfig } from \"../config.js\";\n\nexport function createAuthUtils(config: GavaEngineConfig) {\n return {\n canEdit(role: string): boolean {\n return config.roles.canEdit(role);\n },\n canPublish(role: string): boolean {\n return config.roles.canPublish(role);\n },\n isAdmin(role: string): boolean {\n return role === config.roles.adminRole;\n },\n };\n}\n"],"mappings":"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","names":["bcrypt"]}
@@ -0,0 +1,4 @@
1
+ export { A as ActionsProvider, C as ConfigProvider, a as GavaEngineProvider, S as SessionProvider, b as SplashProvider, T as ThemeProvider, c as ThemeToggle, u as useGavaActions, e as useGavaConfig, f as useSplash } from '../index-CIX0MBHm.js';
2
+ import 'react/jsx-runtime';
3
+ import 'react';
4
+ import '../types-BZgSeTU8.js';
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import {
3
+ GavaEngineProvider,
4
+ SessionProvider,
5
+ ThemeProvider,
6
+ ThemeToggle
7
+ } from "../chunk-KCQJHXZP.js";
8
+ import {
9
+ ActionsProvider,
10
+ ConfigProvider,
11
+ SplashProvider,
12
+ useGavaActions,
13
+ useGavaConfig,
14
+ useSplash
15
+ } from "../chunk-GGD7I4JO.js";
16
+ export {
17
+ ActionsProvider,
18
+ ConfigProvider,
19
+ GavaEngineProvider,
20
+ SessionProvider,
21
+ SplashProvider,
22
+ ThemeProvider,
23
+ ThemeToggle,
24
+ useGavaActions,
25
+ useGavaConfig,
26
+ useSplash
27
+ };
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}