@sonicjs-cms/core 2.3.15 → 2.3.17
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/{chunk-H2X4BFCW.cjs → chunk-2XCJ3HT5.cjs} +3 -3
- package/dist/{chunk-H2X4BFCW.cjs.map → chunk-2XCJ3HT5.cjs.map} +1 -1
- package/dist/{chunk-5OLN5JO3.cjs → chunk-74DP754U.cjs} +90 -90
- package/dist/{chunk-5OLN5JO3.cjs.map → chunk-74DP754U.cjs.map} +1 -1
- package/dist/{chunk-72I2MOSH.js → chunk-B6YJRVFQ.js} +2 -2
- package/dist/{chunk-72I2MOSH.js.map → chunk-B6YJRVFQ.js.map} +1 -1
- package/dist/{chunk-63LV4YVI.cjs → chunk-IEWLOVP3.cjs} +2 -2
- package/dist/{chunk-63LV4YVI.cjs.map → chunk-IEWLOVP3.cjs.map} +1 -1
- package/dist/{chunk-4M2UOUXV.js → chunk-QBWD6FKH.js} +8 -8
- package/dist/{chunk-4M2UOUXV.js.map → chunk-QBWD6FKH.js.map} +1 -1
- package/dist/{chunk-67SKO5RQ.js → chunk-TMQOLXLY.js} +3 -3
- package/dist/{chunk-67SKO5RQ.js.map → chunk-TMQOLXLY.js.map} +1 -1
- package/dist/{chunk-A27RBGBA.js → chunk-VYL6RIV6.js} +3 -3
- package/dist/{chunk-A27RBGBA.js.map → chunk-VYL6RIV6.js.map} +1 -1
- package/dist/{chunk-QG3YQKL4.cjs → chunk-YHJB26RJ.cjs} +4 -4
- package/dist/{chunk-QG3YQKL4.cjs.map → chunk-YHJB26RJ.cjs.map} +1 -1
- package/dist/index.cjs +656 -78
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +586 -8
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +23 -23
- package/dist/middleware.js +2 -2
- package/dist/migrations-6HKPNPTK.js +4 -0
- package/dist/{migrations-H3Q5FZGZ.js.map → migrations-6HKPNPTK.js.map} +1 -1
- package/dist/migrations-EOV7NJZ7.cjs +13 -0
- package/dist/{migrations-VN5VTX3C.cjs.map → migrations-EOV7NJZ7.cjs.map} +1 -1
- package/dist/routes.cjs +24 -24
- package/dist/routes.js +4 -4
- package/dist/services.cjs +2 -2
- package/dist/services.js +1 -1
- package/dist/utils.cjs +11 -11
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/dist/migrations-H3Q5FZGZ.js +0 -4
- package/dist/migrations-VN5VTX3C.cjs +0 -13
package/dist/index.js
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import { PluginBuilder, api_default, api_media_default, api_system_default, admin_api_default, router, adminCollectionsRoutes, adminSettingsRoutes, admin_content_default, adminMediaRoutes, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-
|
|
2
|
-
export { ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, admin_code_examples_default as adminCodeExamplesRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminDesignRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_testimonials_default as adminTestimonialsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes } from './chunk-
|
|
1
|
+
import { PluginBuilder, api_default, api_media_default, api_system_default, admin_api_default, router, adminCollectionsRoutes, adminSettingsRoutes, admin_content_default, adminMediaRoutes, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-QBWD6FKH.js';
|
|
2
|
+
export { ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, admin_code_examples_default as adminCodeExamplesRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminDesignRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_testimonials_default as adminTestimonialsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes } from './chunk-QBWD6FKH.js';
|
|
3
3
|
import { schema_exports } from './chunk-3YNNVSMC.js';
|
|
4
4
|
export { Logger, apiTokens, collections, content, contentVersions, getLogger, initLogger, insertCollectionSchema, insertContentSchema, insertLogConfigSchema, insertMediaSchema, insertPluginActivityLogSchema, insertPluginAssetSchema, insertPluginHookSchema, insertPluginRouteSchema, insertPluginSchema, insertSystemLogSchema, insertUserSchema, insertWorkflowHistorySchema, logConfig, media, pluginActivityLog, pluginAssets, pluginHooks, pluginRoutes, plugins, selectCollectionSchema, selectContentSchema, selectLogConfigSchema, selectMediaSchema, selectPluginActivityLogSchema, selectPluginAssetSchema, selectPluginHookSchema, selectPluginRouteSchema, selectPluginSchema, selectSystemLogSchema, selectUserSchema, selectWorkflowHistorySchema, systemLogs, users, workflowHistory } from './chunk-3YNNVSMC.js';
|
|
5
|
-
import { AuthManager, metricsMiddleware, bootstrapMiddleware, requireAuth } from './chunk-
|
|
6
|
-
export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeaders, securityLoggingMiddleware } from './chunk-
|
|
5
|
+
import { AuthManager, metricsMiddleware, bootstrapMiddleware, requireAuth } from './chunk-VYL6RIV6.js';
|
|
6
|
+
export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeaders, securityLoggingMiddleware } from './chunk-VYL6RIV6.js';
|
|
7
7
|
export { PluginBootstrapService, PluginService as PluginServiceClass, cleanupRemovedCollections, fullCollectionSync, getAvailableCollectionNames, getManagedCollections, isCollectionManaged, loadCollectionConfig, loadCollectionConfigs, registerCollections, syncCollection, syncCollections, validateCollectionConfig } from './chunk-SGAG6FD3.js';
|
|
8
|
-
export { MigrationService } from './chunk-
|
|
8
|
+
export { MigrationService } from './chunk-B6YJRVFQ.js';
|
|
9
9
|
export { renderFilterBar } from './chunk-AVPUX57O.js';
|
|
10
10
|
import { init_admin_layout_catalyst_template, renderAdminLayout, adminLayoutV2, renderAdminLayoutCatalyst } from './chunk-V5LBQN3I.js';
|
|
11
11
|
export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-V5LBQN3I.js';
|
|
12
12
|
export { HookSystemImpl, HookUtils, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, ScopedHookSystem as ScopedHookSystemClass } from './chunk-CPXAVWCU.js';
|
|
13
|
-
import { package_default, getCoreVersion } from './chunk-
|
|
14
|
-
export { QueryFilterBuilder, SONICJS_VERSION, TemplateRenderer, buildQuery, escapeHtml, getCoreVersion, renderTemplate, sanitizeInput, sanitizeObject, templateRenderer } from './chunk-
|
|
13
|
+
import { package_default, getCoreVersion } from './chunk-TMQOLXLY.js';
|
|
14
|
+
export { QueryFilterBuilder, SONICJS_VERSION, TemplateRenderer, buildQuery, escapeHtml, getCoreVersion, renderTemplate, sanitizeInput, sanitizeObject, templateRenderer } from './chunk-TMQOLXLY.js';
|
|
15
15
|
import './chunk-X7ZAEI5S.js';
|
|
16
16
|
export { metricsTracker } from './chunk-FICTAGD4.js';
|
|
17
17
|
export { HOOKS } from './chunk-LOUJRBXV.js';
|
|
18
18
|
import './chunk-V4OQ3NZ2.js';
|
|
19
19
|
import { Hono } from 'hono';
|
|
20
20
|
import { html } from 'hono/html';
|
|
21
|
+
import { setCookie } from 'hono/cookie';
|
|
21
22
|
import { z } from 'zod';
|
|
22
23
|
import { drizzle } from 'drizzle-orm/d1';
|
|
23
24
|
|
|
@@ -740,6 +741,573 @@ function createDatabaseToolsAdminRoutes() {
|
|
|
740
741
|
});
|
|
741
742
|
return router2;
|
|
742
743
|
}
|
|
744
|
+
|
|
745
|
+
// src/plugins/core-plugins/seed-data-plugin/services/seed-data-service.ts
|
|
746
|
+
var SeedDataService = class {
|
|
747
|
+
constructor(db) {
|
|
748
|
+
this.db = db;
|
|
749
|
+
}
|
|
750
|
+
// First names for generating realistic users
|
|
751
|
+
firstNames = [
|
|
752
|
+
"Emma",
|
|
753
|
+
"Liam",
|
|
754
|
+
"Olivia",
|
|
755
|
+
"Noah",
|
|
756
|
+
"Ava",
|
|
757
|
+
"Ethan",
|
|
758
|
+
"Sophia",
|
|
759
|
+
"Mason",
|
|
760
|
+
"Isabella",
|
|
761
|
+
"William",
|
|
762
|
+
"Mia",
|
|
763
|
+
"James",
|
|
764
|
+
"Charlotte",
|
|
765
|
+
"Benjamin",
|
|
766
|
+
"Amelia",
|
|
767
|
+
"Lucas",
|
|
768
|
+
"Harper",
|
|
769
|
+
"Henry",
|
|
770
|
+
"Evelyn",
|
|
771
|
+
"Alexander"
|
|
772
|
+
];
|
|
773
|
+
// Last names for generating realistic users
|
|
774
|
+
lastNames = [
|
|
775
|
+
"Smith",
|
|
776
|
+
"Johnson",
|
|
777
|
+
"Williams",
|
|
778
|
+
"Brown",
|
|
779
|
+
"Jones",
|
|
780
|
+
"Garcia",
|
|
781
|
+
"Miller",
|
|
782
|
+
"Davis",
|
|
783
|
+
"Rodriguez",
|
|
784
|
+
"Martinez",
|
|
785
|
+
"Hernandez",
|
|
786
|
+
"Lopez",
|
|
787
|
+
"Gonzalez",
|
|
788
|
+
"Wilson",
|
|
789
|
+
"Anderson",
|
|
790
|
+
"Thomas",
|
|
791
|
+
"Taylor",
|
|
792
|
+
"Moore",
|
|
793
|
+
"Jackson",
|
|
794
|
+
"Martin"
|
|
795
|
+
];
|
|
796
|
+
// Content titles for blog posts
|
|
797
|
+
blogTitles = [
|
|
798
|
+
"Getting Started with Modern Web Development",
|
|
799
|
+
"The Future of JavaScript Frameworks",
|
|
800
|
+
"Building Scalable Applications with Microservices",
|
|
801
|
+
"Understanding TypeScript: A Complete Guide",
|
|
802
|
+
"Best Practices for API Design",
|
|
803
|
+
"Introduction to Cloud Computing",
|
|
804
|
+
"Mastering Git and Version Control",
|
|
805
|
+
"The Art of Code Review",
|
|
806
|
+
"Performance Optimization Techniques",
|
|
807
|
+
"Security Best Practices for Web Apps",
|
|
808
|
+
"Exploring Serverless Architecture",
|
|
809
|
+
"Database Design Fundamentals",
|
|
810
|
+
"Testing Strategies for Modern Apps",
|
|
811
|
+
"CI/CD Pipeline Implementation",
|
|
812
|
+
"Mobile-First Development Approach"
|
|
813
|
+
];
|
|
814
|
+
// Content titles for pages
|
|
815
|
+
pageTitles = [
|
|
816
|
+
"About Us",
|
|
817
|
+
"Contact",
|
|
818
|
+
"Privacy Policy",
|
|
819
|
+
"Terms of Service",
|
|
820
|
+
"FAQ",
|
|
821
|
+
"Our Team",
|
|
822
|
+
"Careers",
|
|
823
|
+
"Press Kit",
|
|
824
|
+
"Support",
|
|
825
|
+
"Documentation",
|
|
826
|
+
"Pricing",
|
|
827
|
+
"Features"
|
|
828
|
+
];
|
|
829
|
+
// Content titles for products
|
|
830
|
+
productTitles = [
|
|
831
|
+
"Premium Wireless Headphones",
|
|
832
|
+
"Smart Watch Pro",
|
|
833
|
+
"Laptop Stand Adjustable",
|
|
834
|
+
"Mechanical Keyboard RGB",
|
|
835
|
+
"HD Webcam 4K",
|
|
836
|
+
"USB-C Hub 7-in-1",
|
|
837
|
+
"Portable SSD 1TB",
|
|
838
|
+
"Wireless Mouse Ergonomic",
|
|
839
|
+
'Monitor 27" 4K',
|
|
840
|
+
"Desk Lamp LED",
|
|
841
|
+
"Phone Case Premium",
|
|
842
|
+
"Tablet Stand Aluminum",
|
|
843
|
+
"Cable Management Kit",
|
|
844
|
+
"Power Bank 20000mAh",
|
|
845
|
+
"Bluetooth Speaker Portable"
|
|
846
|
+
];
|
|
847
|
+
// Content for generating blog posts
|
|
848
|
+
blogContent = [
|
|
849
|
+
"This comprehensive guide covers everything you need to know about modern development practices and tools.",
|
|
850
|
+
"Learn the fundamentals and advanced concepts that will help you build better applications.",
|
|
851
|
+
"Discover the latest trends and best practices used by industry professionals.",
|
|
852
|
+
"A deep dive into the technologies and methodologies shaping the future of software development.",
|
|
853
|
+
"Practical tips and real-world examples to improve your development workflow.",
|
|
854
|
+
"Explore cutting-edge techniques and proven strategies for building robust applications.",
|
|
855
|
+
"Master the essential skills needed to excel in modern software development.",
|
|
856
|
+
"An in-depth look at the tools and frameworks that power today's web applications.",
|
|
857
|
+
"Step-by-step instructions and expert insights for developers of all levels.",
|
|
858
|
+
"Understanding the core principles that drive successful software projects."
|
|
859
|
+
];
|
|
860
|
+
// Generate a random ID
|
|
861
|
+
generateId() {
|
|
862
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
863
|
+
}
|
|
864
|
+
// Generate a slug from a title
|
|
865
|
+
generateSlug(title) {
|
|
866
|
+
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
867
|
+
}
|
|
868
|
+
// Generate random date within the last year
|
|
869
|
+
randomDate() {
|
|
870
|
+
const now = /* @__PURE__ */ new Date();
|
|
871
|
+
const yearAgo = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
|
|
872
|
+
const randomTime = yearAgo.getTime() + Math.random() * (now.getTime() - yearAgo.getTime());
|
|
873
|
+
return new Date(randomTime);
|
|
874
|
+
}
|
|
875
|
+
// Create 20 example users
|
|
876
|
+
async createUsers() {
|
|
877
|
+
const roles = ["admin", "editor", "author", "viewer"];
|
|
878
|
+
const hashedPassword = "password123";
|
|
879
|
+
let count = 0;
|
|
880
|
+
for (let i = 0; i < 20; i++) {
|
|
881
|
+
const firstName = this.firstNames[Math.floor(Math.random() * this.firstNames.length)] || "John";
|
|
882
|
+
const lastName = this.lastNames[Math.floor(Math.random() * this.lastNames.length)] || "Doe";
|
|
883
|
+
const username = `${firstName.toLowerCase()}${lastName.toLowerCase()}${i}`;
|
|
884
|
+
const email = `${username}@example.com`;
|
|
885
|
+
const createdAt = this.randomDate();
|
|
886
|
+
const createdAtTimestamp = Math.floor(createdAt.getTime() / 1e3);
|
|
887
|
+
const stmt = this.db.prepare(`
|
|
888
|
+
INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, last_login_at, created_at, updated_at)
|
|
889
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
890
|
+
`);
|
|
891
|
+
await stmt.bind(
|
|
892
|
+
this.generateId(),
|
|
893
|
+
email,
|
|
894
|
+
username,
|
|
895
|
+
firstName,
|
|
896
|
+
lastName,
|
|
897
|
+
hashedPassword,
|
|
898
|
+
roles[Math.floor(Math.random() * roles.length)],
|
|
899
|
+
Math.random() > 0.1 ? 1 : 0,
|
|
900
|
+
// 90% active
|
|
901
|
+
Math.random() > 0.3 ? createdAtTimestamp : null,
|
|
902
|
+
createdAtTimestamp,
|
|
903
|
+
createdAtTimestamp
|
|
904
|
+
).run();
|
|
905
|
+
count++;
|
|
906
|
+
}
|
|
907
|
+
return count;
|
|
908
|
+
}
|
|
909
|
+
// Create 200 content items across different types
|
|
910
|
+
async createContent() {
|
|
911
|
+
const usersStmt = this.db.prepare("SELECT * FROM users");
|
|
912
|
+
const { results: allUsers } = await usersStmt.all();
|
|
913
|
+
const collectionsStmt = this.db.prepare("SELECT * FROM collections");
|
|
914
|
+
const { results: allCollections } = await collectionsStmt.all();
|
|
915
|
+
if (!allUsers || allUsers.length === 0) {
|
|
916
|
+
throw new Error("No users found. Please create users first.");
|
|
917
|
+
}
|
|
918
|
+
if (!allCollections || allCollections.length === 0) {
|
|
919
|
+
throw new Error("No collections found. Please create collections first.");
|
|
920
|
+
}
|
|
921
|
+
const statuses = ["draft", "published", "archived"];
|
|
922
|
+
let count = 0;
|
|
923
|
+
for (let i = 0; i < 200; i++) {
|
|
924
|
+
const collection = allCollections[Math.floor(Math.random() * allCollections.length)];
|
|
925
|
+
const author = allUsers[Math.floor(Math.random() * allUsers.length)];
|
|
926
|
+
const status = statuses[Math.floor(Math.random() * statuses.length)];
|
|
927
|
+
let title;
|
|
928
|
+
let contentData;
|
|
929
|
+
if (collection.name === "blog_posts" || collection.name.includes("blog")) {
|
|
930
|
+
title = this.blogTitles[Math.floor(Math.random() * this.blogTitles.length)] || "Untitled Blog Post";
|
|
931
|
+
contentData = {
|
|
932
|
+
body: this.blogContent[Math.floor(Math.random() * this.blogContent.length)] || "Blog content here",
|
|
933
|
+
excerpt: "A brief introduction to this article that provides an overview of the main topics covered.",
|
|
934
|
+
tags: this.generateTags(),
|
|
935
|
+
featured: Math.random() > 0.7
|
|
936
|
+
};
|
|
937
|
+
} else if (collection.name === "pages" || collection.name.includes("page")) {
|
|
938
|
+
title = this.pageTitles[Math.floor(Math.random() * this.pageTitles.length)] || "Untitled Page";
|
|
939
|
+
contentData = {
|
|
940
|
+
body: "This is a standard page with important information about our services and policies.",
|
|
941
|
+
template: "default",
|
|
942
|
+
showInMenu: Math.random() > 0.5
|
|
943
|
+
};
|
|
944
|
+
} else if (collection.name === "products" || collection.name.includes("product")) {
|
|
945
|
+
title = this.productTitles[Math.floor(Math.random() * this.productTitles.length)] || "Untitled Product";
|
|
946
|
+
contentData = {
|
|
947
|
+
description: "High-quality product with excellent features and great value for money.",
|
|
948
|
+
price: (Math.random() * 500 + 10).toFixed(2),
|
|
949
|
+
sku: `SKU-${Math.random().toString(36).substr(2, 9).toUpperCase()}`,
|
|
950
|
+
inStock: Math.random() > 0.2,
|
|
951
|
+
rating: (Math.random() * 2 + 3).toFixed(1)
|
|
952
|
+
// 3.0 - 5.0
|
|
953
|
+
};
|
|
954
|
+
} else {
|
|
955
|
+
title = `${collection.display_name || collection.name} Item ${i + 1}`;
|
|
956
|
+
contentData = {
|
|
957
|
+
description: "This is a sample content item with generic data.",
|
|
958
|
+
value: Math.floor(Math.random() * 1e3)
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
const slug = `${this.generateSlug(title)}-${i}`;
|
|
962
|
+
const createdAt = this.randomDate();
|
|
963
|
+
const createdAtTimestamp = Math.floor(createdAt.getTime() / 1e3);
|
|
964
|
+
const publishedAtTimestamp = status === "published" ? createdAtTimestamp : null;
|
|
965
|
+
const stmt = this.db.prepare(`
|
|
966
|
+
INSERT INTO content (id, collection_id, slug, title, data, status, published_at, author_id, created_at, updated_at)
|
|
967
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
968
|
+
`);
|
|
969
|
+
await stmt.bind(
|
|
970
|
+
this.generateId(),
|
|
971
|
+
collection.id,
|
|
972
|
+
slug,
|
|
973
|
+
`${title} ${i}`,
|
|
974
|
+
JSON.stringify(contentData),
|
|
975
|
+
status,
|
|
976
|
+
publishedAtTimestamp,
|
|
977
|
+
author.id,
|
|
978
|
+
createdAtTimestamp,
|
|
979
|
+
createdAtTimestamp
|
|
980
|
+
).run();
|
|
981
|
+
count++;
|
|
982
|
+
}
|
|
983
|
+
return count;
|
|
984
|
+
}
|
|
985
|
+
// Generate random tags for blog posts
|
|
986
|
+
generateTags() {
|
|
987
|
+
const allTags = [
|
|
988
|
+
"tutorial",
|
|
989
|
+
"guide",
|
|
990
|
+
"javascript",
|
|
991
|
+
"typescript",
|
|
992
|
+
"web-dev",
|
|
993
|
+
"backend",
|
|
994
|
+
"frontend",
|
|
995
|
+
"best-practices",
|
|
996
|
+
"security",
|
|
997
|
+
"performance",
|
|
998
|
+
"testing",
|
|
999
|
+
"deployment",
|
|
1000
|
+
"cloud",
|
|
1001
|
+
"database",
|
|
1002
|
+
"api"
|
|
1003
|
+
];
|
|
1004
|
+
const numTags = Math.floor(Math.random() * 4) + 1;
|
|
1005
|
+
const shuffled = allTags.sort(() => 0.5 - Math.random());
|
|
1006
|
+
return shuffled.slice(0, numTags);
|
|
1007
|
+
}
|
|
1008
|
+
// Seed all data
|
|
1009
|
+
async seedAll() {
|
|
1010
|
+
const userCount = await this.createUsers();
|
|
1011
|
+
const contentCount = await this.createContent();
|
|
1012
|
+
return {
|
|
1013
|
+
users: userCount,
|
|
1014
|
+
content: contentCount
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
// Clear all seed data (optional cleanup method)
|
|
1018
|
+
async clearSeedData() {
|
|
1019
|
+
const deleteContentStmt = this.db.prepare("DELETE FROM content");
|
|
1020
|
+
await deleteContentStmt.run();
|
|
1021
|
+
const deleteUsersStmt = this.db.prepare(
|
|
1022
|
+
"DELETE FROM users WHERE role != 'admin'"
|
|
1023
|
+
);
|
|
1024
|
+
await deleteUsersStmt.run();
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
|
|
1028
|
+
// src/plugins/core-plugins/seed-data-plugin/admin-routes.ts
|
|
1029
|
+
function createSeedDataAdminRoutes() {
|
|
1030
|
+
const routes = new Hono();
|
|
1031
|
+
routes.get("/", async (c) => {
|
|
1032
|
+
const html3 = `
|
|
1033
|
+
<!DOCTYPE html>
|
|
1034
|
+
<html>
|
|
1035
|
+
<head>
|
|
1036
|
+
<title>Seed Data - SonicJS Admin</title>
|
|
1037
|
+
<meta charset="utf-8">
|
|
1038
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1039
|
+
<style>
|
|
1040
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
1041
|
+
body {
|
|
1042
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1043
|
+
background: #f5f5f5;
|
|
1044
|
+
padding: 2rem;
|
|
1045
|
+
}
|
|
1046
|
+
.container {
|
|
1047
|
+
max-width: 800px;
|
|
1048
|
+
margin: 0 auto;
|
|
1049
|
+
background: white;
|
|
1050
|
+
border-radius: 8px;
|
|
1051
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
1052
|
+
padding: 2rem;
|
|
1053
|
+
}
|
|
1054
|
+
h1 {
|
|
1055
|
+
color: #333;
|
|
1056
|
+
margin-bottom: 1rem;
|
|
1057
|
+
font-size: 2rem;
|
|
1058
|
+
}
|
|
1059
|
+
.description {
|
|
1060
|
+
color: #666;
|
|
1061
|
+
margin-bottom: 2rem;
|
|
1062
|
+
line-height: 1.6;
|
|
1063
|
+
}
|
|
1064
|
+
.card {
|
|
1065
|
+
background: #f9f9f9;
|
|
1066
|
+
border-radius: 6px;
|
|
1067
|
+
padding: 1.5rem;
|
|
1068
|
+
margin-bottom: 1.5rem;
|
|
1069
|
+
}
|
|
1070
|
+
.card h2 {
|
|
1071
|
+
color: #333;
|
|
1072
|
+
font-size: 1.25rem;
|
|
1073
|
+
margin-bottom: 0.75rem;
|
|
1074
|
+
}
|
|
1075
|
+
.card p {
|
|
1076
|
+
color: #666;
|
|
1077
|
+
line-height: 1.6;
|
|
1078
|
+
margin-bottom: 1rem;
|
|
1079
|
+
}
|
|
1080
|
+
.card ul {
|
|
1081
|
+
color: #666;
|
|
1082
|
+
margin-left: 1.5rem;
|
|
1083
|
+
margin-bottom: 1rem;
|
|
1084
|
+
}
|
|
1085
|
+
.card li {
|
|
1086
|
+
margin-bottom: 0.5rem;
|
|
1087
|
+
}
|
|
1088
|
+
button {
|
|
1089
|
+
background: #3b82f6;
|
|
1090
|
+
color: white;
|
|
1091
|
+
border: none;
|
|
1092
|
+
padding: 0.75rem 1.5rem;
|
|
1093
|
+
border-radius: 6px;
|
|
1094
|
+
font-size: 1rem;
|
|
1095
|
+
cursor: pointer;
|
|
1096
|
+
transition: background 0.2s;
|
|
1097
|
+
}
|
|
1098
|
+
button:hover {
|
|
1099
|
+
background: #2563eb;
|
|
1100
|
+
}
|
|
1101
|
+
button:disabled {
|
|
1102
|
+
background: #94a3b8;
|
|
1103
|
+
cursor: not-allowed;
|
|
1104
|
+
}
|
|
1105
|
+
.danger {
|
|
1106
|
+
background: #ef4444;
|
|
1107
|
+
}
|
|
1108
|
+
.danger:hover {
|
|
1109
|
+
background: #dc2626;
|
|
1110
|
+
}
|
|
1111
|
+
.warning {
|
|
1112
|
+
background: #f59e0b;
|
|
1113
|
+
color: #fff;
|
|
1114
|
+
padding: 1rem;
|
|
1115
|
+
border-radius: 6px;
|
|
1116
|
+
margin-bottom: 1.5rem;
|
|
1117
|
+
}
|
|
1118
|
+
.success {
|
|
1119
|
+
background: #10b981;
|
|
1120
|
+
color: #fff;
|
|
1121
|
+
padding: 1rem;
|
|
1122
|
+
border-radius: 6px;
|
|
1123
|
+
margin-bottom: 1.5rem;
|
|
1124
|
+
display: none;
|
|
1125
|
+
}
|
|
1126
|
+
.error {
|
|
1127
|
+
background: #ef4444;
|
|
1128
|
+
color: #fff;
|
|
1129
|
+
padding: 1rem;
|
|
1130
|
+
border-radius: 6px;
|
|
1131
|
+
margin-bottom: 1.5rem;
|
|
1132
|
+
display: none;
|
|
1133
|
+
}
|
|
1134
|
+
.loading {
|
|
1135
|
+
display: none;
|
|
1136
|
+
margin-left: 1rem;
|
|
1137
|
+
}
|
|
1138
|
+
.back-link {
|
|
1139
|
+
display: inline-block;
|
|
1140
|
+
margin-bottom: 1rem;
|
|
1141
|
+
color: #3b82f6;
|
|
1142
|
+
text-decoration: none;
|
|
1143
|
+
font-size: 0.9rem;
|
|
1144
|
+
}
|
|
1145
|
+
.back-link:hover {
|
|
1146
|
+
text-decoration: underline;
|
|
1147
|
+
}
|
|
1148
|
+
</style>
|
|
1149
|
+
</head>
|
|
1150
|
+
<body>
|
|
1151
|
+
<div class="container">
|
|
1152
|
+
<a href="/admin/plugins/seed-data" class="back-link">\u2190 Back to Plugin Settings</a>
|
|
1153
|
+
<h1>\u{1F331} Seed Data Generator</h1>
|
|
1154
|
+
<p class="description">
|
|
1155
|
+
Generate realistic example data for testing and development. This will create 20 users and 200 content items with realistic data.
|
|
1156
|
+
</p>
|
|
1157
|
+
|
|
1158
|
+
<div class="warning">
|
|
1159
|
+
<strong>\u26A0\uFE0F Warning:</strong> This will create new data in your database. Make sure you're not running this in production!
|
|
1160
|
+
</div>
|
|
1161
|
+
|
|
1162
|
+
<div class="success" id="successMessage"></div>
|
|
1163
|
+
<div class="error" id="errorMessage"></div>
|
|
1164
|
+
|
|
1165
|
+
<div class="card">
|
|
1166
|
+
<h2>What will be created?</h2>
|
|
1167
|
+
<ul>
|
|
1168
|
+
<li><strong>20 Users:</strong> With realistic names, emails, and various roles (admin, editor, author, viewer)</li>
|
|
1169
|
+
<li><strong>200 Content Items:</strong> Including blog posts, pages, and products with realistic titles and data</li>
|
|
1170
|
+
<li><strong>All passwords:</strong> Set to "password123" for testing</li>
|
|
1171
|
+
<li><strong>Random dates:</strong> Created within the last year</li>
|
|
1172
|
+
<li><strong>Various statuses:</strong> Draft, published, and archived content</li>
|
|
1173
|
+
</ul>
|
|
1174
|
+
</div>
|
|
1175
|
+
|
|
1176
|
+
<div class="card">
|
|
1177
|
+
<h2>Generate Seed Data</h2>
|
|
1178
|
+
<p>Click the button below to generate example data. This may take a few moments.</p>
|
|
1179
|
+
<button id="seedButton" onclick="generateSeedData()">
|
|
1180
|
+
Generate Data
|
|
1181
|
+
<span class="loading" id="loading">...</span>
|
|
1182
|
+
</button>
|
|
1183
|
+
</div>
|
|
1184
|
+
|
|
1185
|
+
<div class="card">
|
|
1186
|
+
<h2>Clear Seed Data</h2>
|
|
1187
|
+
<p>Remove all users and content from the database (except admin users).</p>
|
|
1188
|
+
<button class="danger" id="clearButton" onclick="clearSeedData()">
|
|
1189
|
+
Clear All Data
|
|
1190
|
+
<span class="loading" id="clearLoading">...</span>
|
|
1191
|
+
</button>
|
|
1192
|
+
</div>
|
|
1193
|
+
</div>
|
|
1194
|
+
|
|
1195
|
+
<script>
|
|
1196
|
+
async function generateSeedData() {
|
|
1197
|
+
const button = document.getElementById('seedButton');
|
|
1198
|
+
const loading = document.getElementById('loading');
|
|
1199
|
+
const success = document.getElementById('successMessage');
|
|
1200
|
+
const error = document.getElementById('errorMessage');
|
|
1201
|
+
|
|
1202
|
+
button.disabled = true;
|
|
1203
|
+
loading.style.display = 'inline';
|
|
1204
|
+
success.style.display = 'none';
|
|
1205
|
+
error.style.display = 'none';
|
|
1206
|
+
|
|
1207
|
+
try {
|
|
1208
|
+
const response = await fetch('/admin/seed-data/generate', {
|
|
1209
|
+
method: 'POST',
|
|
1210
|
+
headers: {
|
|
1211
|
+
'Content-Type': 'application/json'
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
const data = await response.json();
|
|
1216
|
+
|
|
1217
|
+
if (response.ok) {
|
|
1218
|
+
success.textContent = \`\u2705 Successfully created \${data.users} users and \${data.content} content items!\`;
|
|
1219
|
+
success.style.display = 'block';
|
|
1220
|
+
} else {
|
|
1221
|
+
throw new Error(data.error || 'Failed to generate seed data');
|
|
1222
|
+
}
|
|
1223
|
+
} catch (err) {
|
|
1224
|
+
error.textContent = \`\u274C Error: \${err.message}\`;
|
|
1225
|
+
error.style.display = 'block';
|
|
1226
|
+
} finally {
|
|
1227
|
+
button.disabled = false;
|
|
1228
|
+
loading.style.display = 'none';
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
async function clearSeedData() {
|
|
1233
|
+
if (!confirm('Are you sure you want to clear all data? This cannot be undone!')) {
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const button = document.getElementById('clearButton');
|
|
1238
|
+
const loading = document.getElementById('clearLoading');
|
|
1239
|
+
const success = document.getElementById('successMessage');
|
|
1240
|
+
const error = document.getElementById('errorMessage');
|
|
1241
|
+
|
|
1242
|
+
button.disabled = true;
|
|
1243
|
+
loading.style.display = 'inline';
|
|
1244
|
+
success.style.display = 'none';
|
|
1245
|
+
error.style.display = 'none';
|
|
1246
|
+
|
|
1247
|
+
try {
|
|
1248
|
+
const response = await fetch('/admin/seed-data/clear', {
|
|
1249
|
+
method: 'POST',
|
|
1250
|
+
headers: {
|
|
1251
|
+
'Content-Type': 'application/json'
|
|
1252
|
+
}
|
|
1253
|
+
});
|
|
1254
|
+
|
|
1255
|
+
const data = await response.json();
|
|
1256
|
+
|
|
1257
|
+
if (response.ok) {
|
|
1258
|
+
success.textContent = '\u2705 Successfully cleared all seed data!';
|
|
1259
|
+
success.style.display = 'block';
|
|
1260
|
+
} else {
|
|
1261
|
+
throw new Error(data.error || 'Failed to clear seed data');
|
|
1262
|
+
}
|
|
1263
|
+
} catch (err) {
|
|
1264
|
+
error.textContent = \`\u274C Error: \${err.message}\`;
|
|
1265
|
+
error.style.display = 'block';
|
|
1266
|
+
} finally {
|
|
1267
|
+
button.disabled = false;
|
|
1268
|
+
loading.style.display = 'none';
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
</script>
|
|
1272
|
+
</body>
|
|
1273
|
+
</html>
|
|
1274
|
+
`;
|
|
1275
|
+
return c.html(html3);
|
|
1276
|
+
});
|
|
1277
|
+
routes.post("/generate", async (c) => {
|
|
1278
|
+
try {
|
|
1279
|
+
const db = c.env.DB;
|
|
1280
|
+
const seedService = new SeedDataService(db);
|
|
1281
|
+
const result = await seedService.seedAll();
|
|
1282
|
+
return c.json({
|
|
1283
|
+
success: true,
|
|
1284
|
+
users: result.users,
|
|
1285
|
+
content: result.content
|
|
1286
|
+
});
|
|
1287
|
+
} catch (error) {
|
|
1288
|
+
return c.json({
|
|
1289
|
+
success: false,
|
|
1290
|
+
error: error.message
|
|
1291
|
+
}, 500);
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
routes.post("/clear", async (c) => {
|
|
1295
|
+
try {
|
|
1296
|
+
const db = c.env.DB;
|
|
1297
|
+
const seedService = new SeedDataService(db);
|
|
1298
|
+
await seedService.clearSeedData();
|
|
1299
|
+
return c.json({
|
|
1300
|
+
success: true
|
|
1301
|
+
});
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
return c.json({
|
|
1304
|
+
success: false,
|
|
1305
|
+
error: error.message
|
|
1306
|
+
}, 500);
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
return routes;
|
|
1310
|
+
}
|
|
743
1311
|
function createEmailPlugin() {
|
|
744
1312
|
const builder = PluginBuilder.create({
|
|
745
1313
|
name: "email",
|
|
@@ -1493,7 +2061,7 @@ function createOTPLoginPlugin() {
|
|
|
1493
2061
|
appName: settings.appName
|
|
1494
2062
|
});
|
|
1495
2063
|
const emailPlugin2 = await db.prepare(`
|
|
1496
|
-
SELECT settings FROM plugins WHERE id = 'email'
|
|
2064
|
+
SELECT settings FROM plugins WHERE id = 'email'
|
|
1497
2065
|
`).first();
|
|
1498
2066
|
if (emailPlugin2?.settings) {
|
|
1499
2067
|
const emailSettings = JSON.parse(emailPlugin2.settings);
|
|
@@ -1582,6 +2150,14 @@ function createOTPLoginPlugin() {
|
|
|
1582
2150
|
error: "Account is deactivated"
|
|
1583
2151
|
}, 403);
|
|
1584
2152
|
}
|
|
2153
|
+
const token = await AuthManager.generateToken(user.id, user.email, user.role);
|
|
2154
|
+
setCookie(c, "auth_token", token, {
|
|
2155
|
+
httpOnly: true,
|
|
2156
|
+
secure: true,
|
|
2157
|
+
sameSite: "Strict",
|
|
2158
|
+
maxAge: 60 * 60 * 24
|
|
2159
|
+
// 24 hours
|
|
2160
|
+
});
|
|
1585
2161
|
return c.json({
|
|
1586
2162
|
success: true,
|
|
1587
2163
|
user: {
|
|
@@ -1589,6 +2165,7 @@ function createOTPLoginPlugin() {
|
|
|
1589
2165
|
email: user.email,
|
|
1590
2166
|
role: user.role
|
|
1591
2167
|
},
|
|
2168
|
+
token,
|
|
1592
2169
|
message: "Authentication successful"
|
|
1593
2170
|
});
|
|
1594
2171
|
} catch (error) {
|
|
@@ -2161,6 +2738,7 @@ function createSonicJSApp(config = {}) {
|
|
|
2161
2738
|
app.route("/admin/collections", adminCollectionsRoutes);
|
|
2162
2739
|
app.route("/admin/settings", adminSettingsRoutes);
|
|
2163
2740
|
app.route("/admin/database-tools", createDatabaseToolsAdminRoutes());
|
|
2741
|
+
app.route("/admin/seed-data", createSeedDataAdminRoutes());
|
|
2164
2742
|
app.route("/admin/content", admin_content_default);
|
|
2165
2743
|
app.route("/admin/media", adminMediaRoutes);
|
|
2166
2744
|
app.route("/admin/plugins", adminPluginRoutes);
|