@sonicjs-cms/core 2.2.0 → 2.3.1

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 (105) hide show
  1. package/README.md +75 -1
  2. package/dist/app-Db0AfT5F.d.cts +100 -0
  3. package/dist/app-Db0AfT5F.d.ts +100 -0
  4. package/dist/chunk-23VPL6VI.cjs +1828 -0
  5. package/dist/chunk-23VPL6VI.cjs.map +1 -0
  6. package/dist/chunk-3MPQII4R.js +1826 -0
  7. package/dist/chunk-3MPQII4R.js.map +1 -0
  8. package/dist/{chunk-YTMFJLJZ.cjs → chunk-44LBCF3B.cjs} +5 -3
  9. package/dist/chunk-44LBCF3B.cjs.map +1 -0
  10. package/dist/{chunk-2DIWLDCA.cjs → chunk-5QJX2VMP.cjs} +541 -533
  11. package/dist/chunk-5QJX2VMP.cjs.map +1 -0
  12. package/dist/{chunk-UEYMFNBN.cjs → chunk-5UUYHAZT.cjs} +7 -36
  13. package/dist/chunk-5UUYHAZT.cjs.map +1 -0
  14. package/dist/{chunk-ZUK55KZB.js → chunk-6RJU7HL5.js} +5 -3
  15. package/dist/chunk-6RJU7HL5.js.map +1 -0
  16. package/dist/{chunk-K4Z3IHOK.js → chunk-7CXL5K7N.js} +5 -248
  17. package/dist/chunk-7CXL5K7N.js.map +1 -0
  18. package/dist/{chunk-WBX5YMTB.cjs → chunk-7KCDFDRI.cjs} +27 -15
  19. package/dist/chunk-7KCDFDRI.cjs.map +1 -0
  20. package/dist/{chunk-HKEK7UNV.js → chunk-CPXAVWCU.js} +3 -3
  21. package/dist/{chunk-HKEK7UNV.js.map → chunk-CPXAVWCU.js.map} +1 -1
  22. package/dist/{chunk-F5ESJXI2.cjs → chunk-DTLB6UIH.cjs} +3 -3
  23. package/dist/{chunk-F5ESJXI2.cjs.map → chunk-DTLB6UIH.cjs.map} +1 -1
  24. package/dist/{chunk-AINTFRTC.cjs → chunk-ES3BRZQJ.cjs} +252 -2
  25. package/dist/chunk-ES3BRZQJ.cjs.map +1 -0
  26. package/dist/{chunk-HV2I6API.cjs → chunk-NAYD76QF.cjs} +4 -251
  27. package/dist/chunk-NAYD76QF.cjs.map +1 -0
  28. package/dist/{chunk-L232U757.js → chunk-Q52ZQFMB.js} +249 -3
  29. package/dist/chunk-Q52ZQFMB.js.map +1 -0
  30. package/dist/{chunk-NMVOTNSL.js → chunk-RRKXFGIO.js} +28 -16
  31. package/dist/chunk-RRKXFGIO.js.map +1 -0
  32. package/dist/{chunk-OORGXYDA.js → chunk-WK5EUGBO.js} +5 -32
  33. package/dist/chunk-WK5EUGBO.js.map +1 -0
  34. package/dist/{chunk-R57VFNP3.js → chunk-ZPERJATF.js} +441 -433
  35. package/dist/chunk-ZPERJATF.js.map +1 -0
  36. package/dist/collection-config-FLlGtsh9.d.cts +107 -0
  37. package/dist/collection-config-FLlGtsh9.d.ts +107 -0
  38. package/dist/filter-bar.template-By4jeiw_.d.cts +140 -0
  39. package/dist/filter-bar.template-By4jeiw_.d.ts +140 -0
  40. package/dist/index.cjs +146 -165
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +44 -0
  43. package/dist/index.d.ts +43 -5
  44. package/dist/index.js +19 -14
  45. package/dist/index.js.map +1 -1
  46. package/dist/middleware.cjs +24 -33
  47. package/dist/middleware.d.cts +89 -0
  48. package/dist/middleware.d.ts +89 -2
  49. package/dist/middleware.js +3 -4
  50. package/dist/migrations-CCLAGJGP.js +4 -0
  51. package/dist/{migrations-IHERIQVD.js.map → migrations-CCLAGJGP.js.map} +1 -1
  52. package/dist/migrations-O6INOHRD.cjs +13 -0
  53. package/dist/{migrations-POFD5KNG.cjs.map → migrations-O6INOHRD.cjs.map} +1 -1
  54. package/dist/plugin-bootstrap-C0E3jdz-.d.cts +8339 -0
  55. package/dist/plugin-bootstrap-CDh0JHtW.d.ts +8339 -0
  56. package/dist/plugin-manifest-BCMx9CAq.d.cts +35 -0
  57. package/dist/plugin-manifest-BCMx9CAq.d.ts +35 -0
  58. package/dist/plugin-zvZpaiP5.d.cts +357 -0
  59. package/dist/plugin-zvZpaiP5.d.ts +357 -0
  60. package/dist/plugins.cjs +7 -7
  61. package/dist/plugins.d.cts +330 -0
  62. package/dist/plugins.d.ts +330 -2
  63. package/dist/plugins.js +1 -1
  64. package/dist/routes.cjs +27 -27
  65. package/dist/routes.d.cts +224 -0
  66. package/dist/routes.d.ts +224 -2
  67. package/dist/routes.js +7 -7
  68. package/dist/services.cjs +41 -41
  69. package/dist/services.d.cts +236 -0
  70. package/dist/services.d.ts +236 -2
  71. package/dist/services.js +4 -4
  72. package/dist/telemetry-BFBIjBxK.d.cts +36 -0
  73. package/dist/telemetry-BFBIjBxK.d.ts +36 -0
  74. package/dist/templates.d.cts +133 -0
  75. package/dist/templates.d.ts +133 -2
  76. package/dist/types.d.cts +7 -0
  77. package/dist/types.d.ts +7 -2
  78. package/dist/utils.cjs +27 -27
  79. package/dist/utils.d.cts +53 -0
  80. package/dist/utils.d.ts +53 -2
  81. package/dist/utils.js +2 -2
  82. package/dist/version-vktVAxhe.d.cts +195 -0
  83. package/dist/version-vktVAxhe.d.ts +195 -0
  84. package/migrations/001_initial_schema.sql +1 -1
  85. package/migrations/002_faq_plugin.sql +86 -0
  86. package/package.json +3 -1
  87. package/dist/chunk-2DIWLDCA.cjs.map +0 -1
  88. package/dist/chunk-AINTFRTC.cjs.map +0 -1
  89. package/dist/chunk-HV2I6API.cjs.map +0 -1
  90. package/dist/chunk-K4Z3IHOK.js.map +0 -1
  91. package/dist/chunk-L232U757.js.map +0 -1
  92. package/dist/chunk-NMVOTNSL.js.map +0 -1
  93. package/dist/chunk-OORGXYDA.js.map +0 -1
  94. package/dist/chunk-R57VFNP3.js.map +0 -1
  95. package/dist/chunk-T7IYBGGO.cjs +0 -746
  96. package/dist/chunk-T7IYBGGO.cjs.map +0 -1
  97. package/dist/chunk-UEYMFNBN.cjs.map +0 -1
  98. package/dist/chunk-WBX5YMTB.cjs.map +0 -1
  99. package/dist/chunk-YTMFJLJZ.cjs.map +0 -1
  100. package/dist/chunk-ZPMFT2JW.js +0 -744
  101. package/dist/chunk-ZPMFT2JW.js.map +0 -1
  102. package/dist/chunk-ZUK55KZB.js.map +0 -1
  103. package/dist/migrations-IHERIQVD.js +0 -4
  104. package/dist/migrations-POFD5KNG.cjs +0 -13
  105. /package/migrations/{021_add_otp_login.sql → 026_add_otp_login.sql} +0 -0
@@ -1,744 +0,0 @@
1
- // src/services/migrations.ts
2
- var MigrationService = class {
3
- constructor(db) {
4
- this.db = db;
5
- }
6
- /**
7
- * Initialize the migrations tracking table
8
- */
9
- async initializeMigrationsTable() {
10
- const createTableQuery = `
11
- CREATE TABLE IF NOT EXISTS migrations (
12
- id TEXT PRIMARY KEY,
13
- name TEXT NOT NULL,
14
- filename TEXT NOT NULL,
15
- applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
16
- checksum TEXT
17
- )
18
- `;
19
- await this.db.prepare(createTableQuery).run();
20
- }
21
- /**
22
- * Get all available migrations from the migrations directory
23
- */
24
- async getAvailableMigrations() {
25
- const migrations = [];
26
- const migrationFiles = [
27
- { id: "001", name: "Initial Schema", filename: "001_initial_schema.sql", description: "Initial database schema with users, content, collections, and media tables" },
28
- { id: "002", name: "FAQ Plugin", filename: "002_faq_plugin.sql", description: "FAQ plugin tables and initial data" },
29
- { id: "003", name: "Stage 5 Enhancements", filename: "003_stage5_enhancements.sql", description: "Enhanced content management and media handling" },
30
- { id: "004", name: "User Management", filename: "004_stage6_user_management.sql", description: "Advanced user management with roles and permissions" },
31
- { id: "005", name: "Workflow & Automation", filename: "005_stage7_workflow_automation.sql", description: "Workflow states, automation rules, and scheduled content" },
32
- { id: "006", name: "Plugin System", filename: "006_plugin_system.sql", description: "Plugin registration and configuration system" },
33
- { id: "007", name: "Demo Login Plugin", filename: "007_demo_login_plugin.sql", description: "Demo login functionality" },
34
- { id: "008", name: "Fix Slug Validation", filename: "008_fix_slug_validation.sql", description: "Fix slug validation in content" },
35
- { id: "009", name: "System Logging", filename: "009_system_logging.sql", description: "System logging and audit trails" },
36
- { id: "011", name: "Config Managed Collections", filename: "011_config_managed_collections.sql", description: "Configuration for managed collections" },
37
- { id: "012", name: "Testimonials Plugin", filename: "012_testimonials_plugin.sql", description: "Testimonials plugin and collection" },
38
- { id: "013", name: "Code Examples Plugin", filename: "013_code_examples_plugin.sql", description: "Code examples plugin and collection" },
39
- { id: "014", name: "Fix Plugin Registry", filename: "014_fix_plugin_registry.sql", description: "Fix plugin registry issues" },
40
- { id: "015", name: "Add Remaining Plugins", filename: "015_add_remaining_plugins.sql", description: "Add remaining core plugins" },
41
- { id: "016", name: "Remove Duplicate Cache Plugin", filename: "016_remove_duplicate_cache_plugin.sql", description: "Remove duplicate cache plugin entries" },
42
- { id: "017", name: "Auth Configurable Fields", filename: "017_auth_configurable_fields.sql", description: "Configurable authentication fields" }
43
- ];
44
- const appliedResult = await this.db.prepare(
45
- "SELECT id, name, filename, applied_at FROM migrations ORDER BY applied_at ASC"
46
- ).all();
47
- const appliedMigrations = new Map(
48
- appliedResult.results?.map((row) => [row.id, row]) || []
49
- );
50
- await this.autoDetectAppliedMigrations(appliedMigrations);
51
- for (const file of migrationFiles) {
52
- const applied = appliedMigrations.has(file.id);
53
- const appliedData = appliedMigrations.get(file.id);
54
- migrations.push({
55
- id: file.id,
56
- name: file.name,
57
- filename: file.filename,
58
- description: file.description,
59
- applied,
60
- appliedAt: applied ? appliedData?.applied_at : void 0,
61
- size: await this.getMigrationFileSize(file.filename)
62
- });
63
- }
64
- return migrations;
65
- }
66
- /**
67
- * Auto-detect applied migrations by checking if their tables exist
68
- */
69
- async autoDetectAppliedMigrations(appliedMigrations) {
70
- if (!appliedMigrations.has("001")) {
71
- const hasBasicTables = await this.checkTablesExist(["users", "content", "collections", "media"]);
72
- if (hasBasicTables) {
73
- appliedMigrations.set("001", {
74
- id: "001",
75
- applied_at: (/* @__PURE__ */ new Date()).toISOString(),
76
- name: "Initial Schema",
77
- filename: "001_initial_schema.sql"
78
- });
79
- await this.markMigrationApplied("001", "Initial Schema", "001_initial_schema.sql");
80
- }
81
- }
82
- if (!appliedMigrations.has("002")) {
83
- const hasFaqTables = await this.checkTablesExist(["faqs", "faq_categories"]);
84
- if (hasFaqTables) {
85
- appliedMigrations.set("002", {
86
- id: "002",
87
- applied_at: (/* @__PURE__ */ new Date()).toISOString(),
88
- name: "FAQ Plugin",
89
- filename: "002_faq_plugin.sql"
90
- });
91
- await this.markMigrationApplied("002", "FAQ Plugin", "002_faq_plugin.sql");
92
- }
93
- }
94
- if (!appliedMigrations.has("003")) {
95
- const hasEnhancedTables = await this.checkTablesExist(["content_versions", "email_themes", "email_templates"]);
96
- if (hasEnhancedTables) {
97
- appliedMigrations.set("003", {
98
- id: "003",
99
- applied_at: (/* @__PURE__ */ new Date()).toISOString(),
100
- name: "Stage 5 Enhancements",
101
- filename: "003_stage5_enhancements.sql"
102
- });
103
- await this.markMigrationApplied("003", "Stage 5 Enhancements", "003_stage5_enhancements.sql");
104
- }
105
- }
106
- if (!appliedMigrations.has("004")) {
107
- const hasUserTables = await this.checkTablesExist(["api_tokens", "workflow_history"]);
108
- if (hasUserTables) {
109
- appliedMigrations.set("004", {
110
- id: "004",
111
- applied_at: (/* @__PURE__ */ new Date()).toISOString(),
112
- name: "User Management",
113
- filename: "004_stage6_user_management.sql"
114
- });
115
- await this.markMigrationApplied("004", "User Management", "004_stage6_user_management.sql");
116
- }
117
- }
118
- if (!appliedMigrations.has("006")) {
119
- const hasPluginTables = await this.checkTablesExist(["plugins", "plugin_hooks"]);
120
- if (hasPluginTables) {
121
- appliedMigrations.set("006", {
122
- id: "006",
123
- applied_at: (/* @__PURE__ */ new Date()).toISOString(),
124
- name: "Plugin System",
125
- filename: "006_plugin_system.sql"
126
- });
127
- await this.markMigrationApplied("006", "Plugin System", "006_plugin_system.sql");
128
- }
129
- }
130
- }
131
- /**
132
- * Check if specific tables exist in the database
133
- */
134
- async checkTablesExist(tableNames) {
135
- try {
136
- for (const tableName of tableNames) {
137
- const result = await this.db.prepare(
138
- `SELECT name FROM sqlite_master WHERE type='table' AND name=?`
139
- ).bind(tableName).first();
140
- if (!result) {
141
- return false;
142
- }
143
- }
144
- return true;
145
- } catch (error) {
146
- return false;
147
- }
148
- }
149
- /**
150
- * Get migration status summary
151
- */
152
- async getMigrationStatus() {
153
- await this.initializeMigrationsTable();
154
- const migrations = await this.getAvailableMigrations();
155
- const appliedMigrations = migrations.filter((m) => m.applied);
156
- const pendingMigrations = migrations.filter((m) => !m.applied);
157
- const lastApplied = appliedMigrations.length > 0 ? appliedMigrations[appliedMigrations.length - 1]?.appliedAt : void 0;
158
- return {
159
- totalMigrations: migrations.length,
160
- appliedMigrations: appliedMigrations.length,
161
- pendingMigrations: pendingMigrations.length,
162
- lastApplied,
163
- migrations
164
- };
165
- }
166
- /**
167
- * Mark a migration as applied
168
- */
169
- async markMigrationApplied(migrationId, name, filename) {
170
- await this.initializeMigrationsTable();
171
- await this.db.prepare(
172
- "INSERT OR REPLACE INTO migrations (id, name, filename, applied_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP)"
173
- ).bind(migrationId, name, filename).run();
174
- }
175
- /**
176
- * Check if a specific migration has been applied
177
- */
178
- async isMigrationApplied(migrationId) {
179
- await this.initializeMigrationsTable();
180
- const result = await this.db.prepare(
181
- "SELECT COUNT(*) as count FROM migrations WHERE id = ?"
182
- ).bind(migrationId).first();
183
- return result?.count > 0;
184
- }
185
- /**
186
- * Get the last applied migration
187
- */
188
- async getLastAppliedMigration() {
189
- await this.initializeMigrationsTable();
190
- const result = await this.db.prepare(
191
- "SELECT id, name, filename, applied_at FROM migrations ORDER BY applied_at DESC LIMIT 1"
192
- ).first();
193
- if (!result) return null;
194
- return {
195
- id: result.id,
196
- name: result.name,
197
- filename: result.filename,
198
- applied: true,
199
- appliedAt: result.applied_at
200
- };
201
- }
202
- /**
203
- * Get migration file size (simulated)
204
- */
205
- async getMigrationFileSize(filename) {
206
- const sizesMap = {
207
- "001_initial_schema.sql": 15420,
208
- "002_faq_plugin.sql": 2340,
209
- "003_stage5_enhancements.sql": 8920,
210
- "004_stage6_user_management.sql": 12680,
211
- "005_stage7_workflow_automation.sql": 18750,
212
- "006_plugin_system.sql": 5430
213
- };
214
- return sizesMap[filename] || 1e3;
215
- }
216
- /**
217
- * Run pending migrations
218
- */
219
- async runPendingMigrations() {
220
- const status = await this.getMigrationStatus();
221
- const pendingMigrations = status.migrations.filter((m) => !m.applied);
222
- if (pendingMigrations.length === 0) {
223
- return {
224
- success: true,
225
- message: "All migrations are up to date",
226
- applied: []
227
- };
228
- }
229
- const applied = [];
230
- for (const migration of pendingMigrations) {
231
- try {
232
- await this.applyMigration(migration);
233
- await this.markMigrationApplied(migration.id, migration.name, migration.filename);
234
- applied.push(migration.id);
235
- } catch (error) {
236
- console.error(`Failed to apply migration ${migration.id}:`, error);
237
- break;
238
- }
239
- }
240
- return {
241
- success: true,
242
- message: `Applied ${applied.length} migration(s)`,
243
- applied
244
- };
245
- }
246
- /**
247
- * Apply a specific migration
248
- */
249
- async applyMigration(migration) {
250
- console.log(`Applying migration ${migration.id}: ${migration.name}`);
251
- const migrationSQL = await this.getMigrationSQL(migration.id);
252
- if (migrationSQL === null) {
253
- throw new Error(`Migration SQL not found for ${migration.id}`);
254
- }
255
- if (migrationSQL === "") {
256
- console.log(`Skipping migration ${migration.id} (empty/obsolete)`);
257
- return;
258
- }
259
- const statements = this.splitSQLStatements(migrationSQL);
260
- for (const statement of statements) {
261
- if (statement.trim()) {
262
- try {
263
- await this.db.prepare(statement).run();
264
- } catch (error) {
265
- console.error(`Error executing statement: ${statement}`, error);
266
- throw error;
267
- }
268
- }
269
- }
270
- }
271
- /**
272
- * Split SQL into statements, handling CREATE TRIGGER properly
273
- */
274
- splitSQLStatements(sql) {
275
- const statements = [];
276
- let current = "";
277
- let inTrigger = false;
278
- const lines = sql.split("\n");
279
- for (const line of lines) {
280
- const trimmed = line.trim();
281
- if (trimmed.startsWith("--") || trimmed.length === 0) {
282
- continue;
283
- }
284
- if (trimmed.toUpperCase().includes("CREATE TRIGGER")) {
285
- inTrigger = true;
286
- }
287
- current += line + "\n";
288
- if (inTrigger && trimmed.toUpperCase() === "END;") {
289
- statements.push(current.trim());
290
- current = "";
291
- inTrigger = false;
292
- } else if (!inTrigger && trimmed.endsWith(";")) {
293
- statements.push(current.trim());
294
- current = "";
295
- }
296
- }
297
- if (current.trim()) {
298
- statements.push(current.trim());
299
- }
300
- return statements.filter((s) => s.length > 0);
301
- }
302
- /**
303
- * Get migration SQL by ID
304
- */
305
- async getMigrationSQL(migrationId) {
306
- switch (migrationId) {
307
- case "001":
308
- return `
309
- -- Initial schema for SonicJS AI
310
- -- Create users table for authentication
311
- CREATE TABLE IF NOT EXISTS users (
312
- id TEXT PRIMARY KEY,
313
- email TEXT NOT NULL UNIQUE,
314
- username TEXT NOT NULL UNIQUE,
315
- first_name TEXT NOT NULL,
316
- last_name TEXT NOT NULL,
317
- password_hash TEXT,
318
- role TEXT NOT NULL DEFAULT 'viewer',
319
- avatar TEXT,
320
- is_active INTEGER NOT NULL DEFAULT 1,
321
- last_login_at INTEGER,
322
- created_at INTEGER NOT NULL,
323
- updated_at INTEGER NOT NULL
324
- );
325
-
326
- -- Create collections table for content schema definitions
327
- CREATE TABLE IF NOT EXISTS collections (
328
- id TEXT PRIMARY KEY,
329
- name TEXT NOT NULL UNIQUE,
330
- display_name TEXT NOT NULL,
331
- description TEXT,
332
- schema TEXT NOT NULL,
333
- is_active INTEGER NOT NULL DEFAULT 1,
334
- created_at INTEGER NOT NULL,
335
- updated_at INTEGER NOT NULL
336
- );
337
-
338
- -- Create content table for actual content data
339
- CREATE TABLE IF NOT EXISTS content (
340
- id TEXT PRIMARY KEY,
341
- collection_id TEXT NOT NULL REFERENCES collections(id),
342
- slug TEXT NOT NULL,
343
- title TEXT NOT NULL,
344
- data TEXT NOT NULL,
345
- status TEXT NOT NULL DEFAULT 'draft',
346
- published_at INTEGER,
347
- author_id TEXT NOT NULL REFERENCES users(id),
348
- created_by TEXT NOT NULL REFERENCES users(id),
349
- created_at INTEGER NOT NULL,
350
- updated_at INTEGER NOT NULL
351
- );
352
-
353
- -- Create content_versions table for versioning
354
- CREATE TABLE IF NOT EXISTS content_versions (
355
- id TEXT PRIMARY KEY,
356
- content_id TEXT NOT NULL REFERENCES content(id),
357
- version INTEGER NOT NULL,
358
- data TEXT NOT NULL,
359
- author_id TEXT NOT NULL REFERENCES users(id),
360
- created_at INTEGER NOT NULL
361
- );
362
-
363
- -- Create media/files table with comprehensive R2 integration
364
- CREATE TABLE IF NOT EXISTS media (
365
- id TEXT PRIMARY KEY,
366
- filename TEXT NOT NULL,
367
- original_name TEXT NOT NULL,
368
- mime_type TEXT NOT NULL,
369
- size INTEGER NOT NULL,
370
- width INTEGER,
371
- height INTEGER,
372
- folder TEXT NOT NULL DEFAULT 'uploads',
373
- r2_key TEXT NOT NULL,
374
- public_url TEXT NOT NULL,
375
- thumbnail_url TEXT,
376
- alt TEXT,
377
- caption TEXT,
378
- tags TEXT,
379
- uploaded_by TEXT NOT NULL REFERENCES users(id),
380
- uploaded_at INTEGER NOT NULL,
381
- updated_at INTEGER,
382
- published_at INTEGER,
383
- scheduled_at INTEGER,
384
- archived_at INTEGER,
385
- deleted_at INTEGER
386
- );
387
-
388
- -- Create API tokens table for programmatic access
389
- CREATE TABLE IF NOT EXISTS api_tokens (
390
- id TEXT PRIMARY KEY,
391
- name TEXT NOT NULL,
392
- token TEXT NOT NULL UNIQUE,
393
- user_id TEXT NOT NULL REFERENCES users(id),
394
- permissions TEXT NOT NULL,
395
- expires_at INTEGER,
396
- last_used_at INTEGER,
397
- created_at INTEGER NOT NULL
398
- );
399
-
400
- -- Create workflow history table for content workflow tracking
401
- CREATE TABLE IF NOT EXISTS workflow_history (
402
- id TEXT PRIMARY KEY,
403
- content_id TEXT NOT NULL REFERENCES content(id),
404
- action TEXT NOT NULL,
405
- from_status TEXT NOT NULL,
406
- to_status TEXT NOT NULL,
407
- user_id TEXT NOT NULL REFERENCES users(id),
408
- comment TEXT,
409
- created_at INTEGER NOT NULL
410
- );
411
-
412
- -- Create indexes for better performance
413
- CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
414
- CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
415
- CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);
416
-
417
- CREATE INDEX IF NOT EXISTS idx_collections_name ON collections(name);
418
- CREATE INDEX IF NOT EXISTS idx_collections_active ON collections(is_active);
419
-
420
- CREATE INDEX IF NOT EXISTS idx_content_collection ON content(collection_id);
421
- CREATE INDEX IF NOT EXISTS idx_content_author ON content(author_id);
422
- CREATE INDEX IF NOT EXISTS idx_content_status ON content(status);
423
- CREATE INDEX IF NOT EXISTS idx_content_published ON content(published_at);
424
- CREATE INDEX IF NOT EXISTS idx_content_slug ON content(slug);
425
-
426
- CREATE INDEX IF NOT EXISTS idx_content_versions_content ON content_versions(content_id);
427
- CREATE INDEX IF NOT EXISTS idx_content_versions_version ON content_versions(version);
428
-
429
- CREATE INDEX IF NOT EXISTS idx_media_folder ON media(folder);
430
- CREATE INDEX IF NOT EXISTS idx_media_type ON media(mime_type);
431
- CREATE INDEX IF NOT EXISTS idx_media_uploaded_by ON media(uploaded_by);
432
- CREATE INDEX IF NOT EXISTS idx_media_uploaded_at ON media(uploaded_at);
433
- CREATE INDEX IF NOT EXISTS idx_media_deleted ON media(deleted_at);
434
-
435
- CREATE INDEX IF NOT EXISTS idx_api_tokens_user ON api_tokens(user_id);
436
- CREATE INDEX IF NOT EXISTS idx_api_tokens_token ON api_tokens(token);
437
-
438
- CREATE INDEX IF NOT EXISTS idx_workflow_history_content ON workflow_history(content_id);
439
- CREATE INDEX IF NOT EXISTS idx_workflow_history_user ON workflow_history(user_id);
440
-
441
- -- Insert default admin user (password: sonicjs!)
442
- INSERT OR IGNORE INTO users (
443
- id, email, username, first_name, last_name, password_hash,
444
- role, is_active, created_at, updated_at
445
- ) VALUES (
446
- 'admin-user-id',
447
- 'admin@sonicjs.com',
448
- 'admin',
449
- 'Admin',
450
- 'User',
451
- 'd1c379e871838f44e21d5a55841349e50636f06df139bfef11870eec74c381db',
452
- 'admin',
453
- 1,
454
- strftime('%s', 'now') * 1000,
455
- strftime('%s', 'now') * 1000
456
- );
457
-
458
- -- Insert sample collections
459
- INSERT OR IGNORE INTO collections (
460
- id, name, display_name, description, schema,
461
- is_active, created_at, updated_at
462
- ) VALUES (
463
- 'blog-posts-collection',
464
- 'blog_posts',
465
- 'Blog Posts',
466
- 'Blog post content collection',
467
- '{"type":"object","properties":{"title":{"type":"string","title":"Title","required":true},"content":{"type":"string","title":"Content","format":"richtext"},"excerpt":{"type":"string","title":"Excerpt"},"featured_image":{"type":"string","title":"Featured Image","format":"media"},"tags":{"type":"array","title":"Tags","items":{"type":"string"}},"status":{"type":"string","title":"Status","enum":["draft","published","archived"],"default":"draft"}},"required":["title"]}',
468
- 1,
469
- strftime('%s', 'now') * 1000,
470
- strftime('%s', 'now') * 1000
471
- ),
472
- (
473
- 'pages-collection',
474
- 'pages',
475
- 'Pages',
476
- 'Static page content collection',
477
- '{"type":"object","properties":{"title":{"type":"string","title":"Title","required":true},"content":{"type":"string","title":"Content","format":"richtext"},"slug":{"type":"string","title":"Slug"},"meta_description":{"type":"string","title":"Meta Description"},"featured_image":{"type":"string","title":"Featured Image","format":"media"}},"required":["title"]}',
478
- 1,
479
- strftime('%s', 'now') * 1000,
480
- strftime('%s', 'now') * 1000
481
- ),
482
- (
483
- 'news-collection',
484
- 'news',
485
- 'News',
486
- 'News article content collection',
487
- '{"type":"object","properties":{"title":{"type":"string","title":"Title","required":true},"content":{"type":"string","title":"Content","format":"richtext"},"publish_date":{"type":"string","title":"Publish Date","format":"date"},"author":{"type":"string","title":"Author"},"category":{"type":"string","title":"Category","enum":["technology","business","general"]}},"required":["title"]}',
488
- 1,
489
- strftime('%s', 'now') * 1000,
490
- strftime('%s', 'now') * 1000
491
- );
492
-
493
- -- Insert sample content
494
- INSERT OR IGNORE INTO content (
495
- id, collection_id, slug, title, data, status,
496
- author_id, created_by, created_at, updated_at
497
- ) VALUES (
498
- 'welcome-blog-post',
499
- 'blog-posts-collection',
500
- 'welcome-to-sonicjs-ai',
501
- 'Welcome to SonicJS AI',
502
- '{"title":"Welcome to SonicJS AI","content":"<h1>Welcome to SonicJS AI</h1><p>This is your first blog post created with SonicJS AI, a modern headless CMS built on Cloudflare Workers.</p><h2>Features</h2><ul><li>Cloudflare-native architecture</li><li>TypeScript-first development</li><li>Hono.js framework</li><li>D1 database</li><li>R2 media storage</li><li>Edge computing</li></ul><p>Get started by exploring the admin interface and creating your own content!</p>","excerpt":"Welcome to SonicJS AI, a modern headless CMS built on Cloudflare Workers with TypeScript and Hono.js.","status":"published","tags":["welcome","cms","cloudflare"]}',
503
- 'published',
504
- 'admin-user-id',
505
- 'admin-user-id',
506
- strftime('%s', 'now') * 1000,
507
- strftime('%s', 'now') * 1000
508
- );
509
- `;
510
- case "002":
511
- return `
512
- CREATE TABLE IF NOT EXISTS faqs (
513
- id INTEGER PRIMARY KEY AUTOINCREMENT,
514
- question TEXT NOT NULL,
515
- answer TEXT NOT NULL,
516
- category TEXT,
517
- tags TEXT,
518
- isPublished INTEGER NOT NULL DEFAULT 1,
519
- sortOrder INTEGER NOT NULL DEFAULT 0,
520
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
521
- updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
522
- );
523
-
524
- CREATE INDEX IF NOT EXISTS idx_faqs_category ON faqs(category);
525
- CREATE INDEX IF NOT EXISTS idx_faqs_published ON faqs(isPublished);
526
- CREATE INDEX IF NOT EXISTS idx_faqs_sort_order ON faqs(sortOrder);
527
-
528
- CREATE TRIGGER IF NOT EXISTS faqs_updated_at
529
- AFTER UPDATE ON faqs
530
- BEGIN
531
- UPDATE faqs SET updated_at = strftime('%s', 'now') WHERE id = NEW.id;
532
- END;
533
- `;
534
- case "006":
535
- return `
536
- -- Plugin System Tables
537
- CREATE TABLE IF NOT EXISTS plugins (
538
- id TEXT PRIMARY KEY,
539
- name TEXT NOT NULL UNIQUE,
540
- display_name TEXT NOT NULL,
541
- description TEXT,
542
- version TEXT NOT NULL,
543
- author TEXT NOT NULL,
544
- category TEXT NOT NULL,
545
- icon TEXT,
546
- status TEXT DEFAULT 'inactive' CHECK (status IN ('active', 'inactive', 'error')),
547
- is_core BOOLEAN DEFAULT FALSE,
548
- settings JSON,
549
- permissions JSON,
550
- dependencies JSON,
551
- download_count INTEGER DEFAULT 0,
552
- rating REAL DEFAULT 0,
553
- installed_at INTEGER NOT NULL,
554
- activated_at INTEGER,
555
- last_updated INTEGER NOT NULL,
556
- error_message TEXT,
557
- created_at INTEGER DEFAULT (unixepoch()),
558
- updated_at INTEGER DEFAULT (unixepoch())
559
- );
560
-
561
- CREATE TABLE IF NOT EXISTS plugin_hooks (
562
- id TEXT PRIMARY KEY,
563
- plugin_id TEXT NOT NULL,
564
- hook_name TEXT NOT NULL,
565
- handler_name TEXT NOT NULL,
566
- priority INTEGER DEFAULT 10,
567
- is_active BOOLEAN DEFAULT TRUE,
568
- created_at INTEGER DEFAULT (unixepoch()),
569
- FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE,
570
- UNIQUE(plugin_id, hook_name, handler_name)
571
- );
572
-
573
- CREATE TABLE IF NOT EXISTS plugin_routes (
574
- id TEXT PRIMARY KEY,
575
- plugin_id TEXT NOT NULL,
576
- path TEXT NOT NULL,
577
- method TEXT NOT NULL,
578
- handler_name TEXT NOT NULL,
579
- middleware JSON,
580
- is_active BOOLEAN DEFAULT TRUE,
581
- created_at INTEGER DEFAULT (unixepoch()),
582
- FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE,
583
- UNIQUE(plugin_id, path, method)
584
- );
585
-
586
- CREATE TABLE IF NOT EXISTS plugin_assets (
587
- id TEXT PRIMARY KEY,
588
- plugin_id TEXT NOT NULL,
589
- asset_type TEXT NOT NULL CHECK (asset_type IN ('css', 'js', 'image', 'font')),
590
- asset_path TEXT NOT NULL,
591
- load_order INTEGER DEFAULT 100,
592
- load_location TEXT DEFAULT 'footer' CHECK (load_location IN ('header', 'footer')),
593
- is_active BOOLEAN DEFAULT TRUE,
594
- created_at INTEGER DEFAULT (unixepoch()),
595
- FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE
596
- );
597
-
598
- CREATE TABLE IF NOT EXISTS plugin_activity_log (
599
- id TEXT PRIMARY KEY,
600
- plugin_id TEXT NOT NULL,
601
- action TEXT NOT NULL,
602
- user_id TEXT,
603
- details JSON,
604
- timestamp INTEGER DEFAULT (unixepoch()),
605
- FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE
606
- );
607
-
608
- -- Create indexes
609
- CREATE INDEX IF NOT EXISTS idx_plugins_status ON plugins(status);
610
- CREATE INDEX IF NOT EXISTS idx_plugins_category ON plugins(category);
611
- CREATE INDEX IF NOT EXISTS idx_plugin_hooks_plugin ON plugin_hooks(plugin_id);
612
- CREATE INDEX IF NOT EXISTS idx_plugin_routes_plugin ON plugin_routes(plugin_id);
613
- CREATE INDEX IF NOT EXISTS idx_plugin_assets_plugin ON plugin_assets(plugin_id);
614
- CREATE INDEX IF NOT EXISTS idx_plugin_activity_plugin ON plugin_activity_log(plugin_id);
615
- CREATE INDEX IF NOT EXISTS idx_plugin_activity_timestamp ON plugin_activity_log(timestamp);
616
-
617
- -- Insert core plugins
618
- INSERT OR IGNORE INTO plugins (
619
- id, name, display_name, description, version, author, category, icon,
620
- status, is_core, permissions, installed_at, last_updated
621
- ) VALUES
622
- (
623
- 'core-auth',
624
- 'core-auth',
625
- 'Authentication System',
626
- 'Core authentication and user management system',
627
- '1.0.0',
628
- 'SonicJS Team',
629
- 'security',
630
- '\u{1F510}',
631
- 'active',
632
- TRUE,
633
- '["manage:users", "manage:roles", "manage:permissions"]',
634
- unixepoch(),
635
- unixepoch()
636
- ),
637
- (
638
- 'core-media',
639
- 'core-media',
640
- 'Media Manager',
641
- 'Core media upload and management system',
642
- '1.0.0',
643
- 'SonicJS Team',
644
- 'media',
645
- '\u{1F4F8}',
646
- 'active',
647
- TRUE,
648
- '["manage:media", "upload:files"]',
649
- unixepoch(),
650
- unixepoch()
651
- ),
652
- (
653
- 'core-workflow',
654
- 'core-workflow',
655
- 'Workflow Engine',
656
- 'Content workflow and approval system',
657
- '1.0.0',
658
- 'SonicJS Team',
659
- 'content',
660
- '\u{1F504}',
661
- 'active',
662
- TRUE,
663
- '["manage:workflows", "approve:content"]',
664
- unixepoch(),
665
- unixepoch()
666
- ),
667
- (
668
- 'cache',
669
- 'cache',
670
- 'Cache System',
671
- 'Three-tiered caching system with memory, KV, and database layers',
672
- '1.0.0',
673
- 'SonicJS Team',
674
- 'performance',
675
- '\u26A1',
676
- 'active',
677
- TRUE,
678
- '["manage:cache","view:stats"]',
679
- unixepoch(),
680
- unixepoch()
681
- ),
682
- (
683
- 'design',
684
- 'design-plugin',
685
- 'Design System',
686
- 'Design system management including themes, components, and UI customization. Provides a visual interface for managing design tokens, typography, colors, and component library.',
687
- '1.0.0',
688
- 'SonicJS',
689
- 'ui',
690
- '\u{1F3A8}',
691
- 'active',
692
- TRUE,
693
- '["design.view", "design.edit"]',
694
- unixepoch(),
695
- unixepoch()
696
- );
697
- `;
698
- case "003":
699
- case "004":
700
- case "005":
701
- case "007":
702
- case "008":
703
- case "009":
704
- case "011":
705
- case "012":
706
- case "013":
707
- case "014":
708
- case "015":
709
- case "016":
710
- case "017":
711
- return "";
712
- default:
713
- return null;
714
- }
715
- }
716
- /**
717
- * Validate database schema (placeholder)
718
- */
719
- async validateSchema() {
720
- const issues = [];
721
- const requiredTables = [
722
- "users",
723
- "content",
724
- "collections",
725
- "media",
726
- "sessions"
727
- ];
728
- for (const table of requiredTables) {
729
- try {
730
- await this.db.prepare(`SELECT COUNT(*) FROM ${table} LIMIT 1`).first();
731
- } catch (error) {
732
- issues.push(`Missing table: ${table}`);
733
- }
734
- }
735
- return {
736
- valid: issues.length === 0,
737
- issues
738
- };
739
- }
740
- };
741
-
742
- export { MigrationService };
743
- //# sourceMappingURL=chunk-ZPMFT2JW.js.map
744
- //# sourceMappingURL=chunk-ZPMFT2JW.js.map