@sonicjs-cms/core 2.14.0 → 2.16.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.
Files changed (86) hide show
  1. package/dist/admin-layout-catalyst.template-HFD37TY5.cjs +17 -0
  2. package/dist/admin-layout-catalyst.template-HFD37TY5.cjs.map +1 -0
  3. package/dist/admin-layout-catalyst.template-UMTIN66R.js +7 -0
  4. package/dist/admin-layout-catalyst.template-UMTIN66R.js.map +1 -0
  5. package/dist/{chunk-3QCEYJLK.cjs → chunk-4ZSNJDLS.cjs} +9 -9
  6. package/dist/{chunk-3QCEYJLK.cjs.map → chunk-4ZSNJDLS.cjs.map} +1 -1
  7. package/dist/chunk-55RDMDOP.js +684 -0
  8. package/dist/chunk-55RDMDOP.js.map +1 -0
  9. package/dist/{chunk-6FHNRRJ3.cjs → chunk-635JAMSE.cjs} +76 -17
  10. package/dist/chunk-635JAMSE.cjs.map +1 -0
  11. package/dist/{chunk-DRWSHIFG.cjs → chunk-6ENX7QSA.cjs} +228 -658
  12. package/dist/chunk-6ENX7QSA.cjs.map +1 -0
  13. package/dist/{chunk-56GUBLJE.cjs → chunk-ABB34XUS.cjs} +13 -13
  14. package/dist/{chunk-56GUBLJE.cjs.map → chunk-ABB34XUS.cjs.map} +1 -1
  15. package/dist/{chunk-YYMPHM3I.cjs → chunk-CZ6BVQZX.cjs} +19 -9
  16. package/dist/chunk-CZ6BVQZX.cjs.map +1 -0
  17. package/dist/{chunk-J5WGMRSU.js → chunk-EXNEW5US.js} +76 -17
  18. package/dist/chunk-EXNEW5US.js.map +1 -0
  19. package/dist/{chunk-H3XXBAMO.js → chunk-INSDRCG3.js} +722 -212
  20. package/dist/chunk-INSDRCG3.js.map +1 -0
  21. package/dist/{chunk-GAVTTYMC.js → chunk-MVSCB4E3.js} +3 -3
  22. package/dist/{chunk-GAVTTYMC.js.map → chunk-MVSCB4E3.js.map} +1 -1
  23. package/dist/{chunk-KZ2MFGET.cjs → chunk-OCLUXJ7E.cjs} +9 -2
  24. package/dist/chunk-OCLUXJ7E.cjs.map +1 -0
  25. package/dist/{chunk-QP3OHHON.cjs → chunk-OHYBNCVL.cjs} +18 -696
  26. package/dist/chunk-OHYBNCVL.cjs.map +1 -0
  27. package/dist/{chunk-CB7ONLGB.js → chunk-ON5ZMSU4.js} +3 -3
  28. package/dist/{chunk-CB7ONLGB.js.map → chunk-ON5ZMSU4.js.map} +1 -1
  29. package/dist/{chunk-I6FFGQIT.cjs → chunk-Q5VFZUXV.cjs} +723 -211
  30. package/dist/chunk-Q5VFZUXV.cjs.map +1 -0
  31. package/dist/{chunk-2MXF4RYZ.js → chunk-TFNTM3OA.js} +3 -3
  32. package/dist/{chunk-2MXF4RYZ.js.map → chunk-TFNTM3OA.js.map} +1 -1
  33. package/dist/chunk-UYJ6TJHX.cjs +691 -0
  34. package/dist/chunk-UYJ6TJHX.cjs.map +1 -0
  35. package/dist/{chunk-JKNKO6LA.js → chunk-VFQUULAV.js} +9 -2
  36. package/dist/chunk-VFQUULAV.js.map +1 -0
  37. package/dist/{chunk-23DP6TO5.js → chunk-WLSIUKNM.js} +44 -474
  38. package/dist/chunk-WLSIUKNM.js.map +1 -0
  39. package/dist/{chunk-JTUCC6WZ.js → chunk-XWIA3HVX.js} +9 -683
  40. package/dist/chunk-XWIA3HVX.js.map +1 -0
  41. package/dist/{chunk-AFGOH2F6.js → chunk-Y5EH32F5.js} +15 -5
  42. package/dist/chunk-Y5EH32F5.js.map +1 -0
  43. package/dist/{chunk-YULUPQZV.cjs → chunk-YQW2GCJ3.cjs} +3 -3
  44. package/dist/{chunk-YULUPQZV.cjs.map → chunk-YQW2GCJ3.cjs.map} +1 -1
  45. package/dist/index.cjs +1591 -236
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.cts +2 -2
  48. package/dist/index.d.ts +2 -2
  49. package/dist/index.js +1464 -109
  50. package/dist/index.js.map +1 -1
  51. package/dist/middleware.cjs +29 -29
  52. package/dist/middleware.js +3 -3
  53. package/dist/migrations-7HQ7LYAL.js +4 -0
  54. package/dist/{migrations-WKONKRN7.js.map → migrations-7HQ7LYAL.js.map} +1 -1
  55. package/dist/migrations-SVQTT7NV.cjs +13 -0
  56. package/dist/{migrations-F7KVA74T.cjs.map → migrations-SVQTT7NV.cjs.map} +1 -1
  57. package/dist/{plugin-bootstrap-BGwBraaN.d.cts → plugin-bootstrap-DfVerYV4.d.cts} +2 -1
  58. package/dist/{plugin-bootstrap-Drns7X9w.d.ts → plugin-bootstrap-P_ciLp_C.d.ts} +2 -1
  59. package/dist/plugins.cjs +11 -11
  60. package/dist/plugins.js +2 -2
  61. package/dist/routes.cjs +31 -30
  62. package/dist/routes.js +8 -7
  63. package/dist/services.cjs +23 -23
  64. package/dist/services.d.cts +1 -1
  65. package/dist/services.d.ts +1 -1
  66. package/dist/services.js +2 -2
  67. package/dist/templates.cjs +26 -25
  68. package/dist/templates.js +3 -2
  69. package/dist/utils.cjs +11 -11
  70. package/dist/utils.js +1 -1
  71. package/migrations/036_analytics_events.sql +22 -0
  72. package/package.json +1 -1
  73. package/dist/chunk-23DP6TO5.js.map +0 -1
  74. package/dist/chunk-6FHNRRJ3.cjs.map +0 -1
  75. package/dist/chunk-AFGOH2F6.js.map +0 -1
  76. package/dist/chunk-DRWSHIFG.cjs.map +0 -1
  77. package/dist/chunk-H3XXBAMO.js.map +0 -1
  78. package/dist/chunk-I6FFGQIT.cjs.map +0 -1
  79. package/dist/chunk-J5WGMRSU.js.map +0 -1
  80. package/dist/chunk-JKNKO6LA.js.map +0 -1
  81. package/dist/chunk-JTUCC6WZ.js.map +0 -1
  82. package/dist/chunk-KZ2MFGET.cjs.map +0 -1
  83. package/dist/chunk-QP3OHHON.cjs.map +0 -1
  84. package/dist/chunk-YYMPHM3I.cjs.map +0 -1
  85. package/dist/migrations-F7KVA74T.cjs +0 -13
  86. package/dist/migrations-WKONKRN7.js +0 -4
package/dist/index.cjs CHANGED
@@ -1,15 +1,16 @@
1
1
  'use strict';
2
2
 
3
- var chunkDRWSHIFG_cjs = require('./chunk-DRWSHIFG.cjs');
3
+ var chunk6ENX7QSA_cjs = require('./chunk-6ENX7QSA.cjs');
4
4
  var chunkNZWFCUDA_cjs = require('./chunk-NZWFCUDA.cjs');
5
- var chunkYYMPHM3I_cjs = require('./chunk-YYMPHM3I.cjs');
6
- var chunkI6FFGQIT_cjs = require('./chunk-I6FFGQIT.cjs');
7
- var chunkKZ2MFGET_cjs = require('./chunk-KZ2MFGET.cjs');
8
- var chunk3QCEYJLK_cjs = require('./chunk-3QCEYJLK.cjs');
9
- var chunkQP3OHHON_cjs = require('./chunk-QP3OHHON.cjs');
10
- var chunk56GUBLJE_cjs = require('./chunk-56GUBLJE.cjs');
11
- var chunk6FHNRRJ3_cjs = require('./chunk-6FHNRRJ3.cjs');
12
- var chunkYULUPQZV_cjs = require('./chunk-YULUPQZV.cjs');
5
+ var chunkCZ6BVQZX_cjs = require('./chunk-CZ6BVQZX.cjs');
6
+ var chunkQ5VFZUXV_cjs = require('./chunk-Q5VFZUXV.cjs');
7
+ var chunkOCLUXJ7E_cjs = require('./chunk-OCLUXJ7E.cjs');
8
+ var chunk4ZSNJDLS_cjs = require('./chunk-4ZSNJDLS.cjs');
9
+ var chunkOHYBNCVL_cjs = require('./chunk-OHYBNCVL.cjs');
10
+ var chunkUYJ6TJHX_cjs = require('./chunk-UYJ6TJHX.cjs');
11
+ var chunkABB34XUS_cjs = require('./chunk-ABB34XUS.cjs');
12
+ var chunk635JAMSE_cjs = require('./chunk-635JAMSE.cjs');
13
+ var chunkYQW2GCJ3_cjs = require('./chunk-YQW2GCJ3.cjs');
13
14
  require('./chunk-P3XDZL6Q.cjs');
14
15
  var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
15
16
  var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
@@ -235,7 +236,7 @@ var DatabaseToolsService = class {
235
236
  };
236
237
 
237
238
  // src/templates/pages/admin-database-table.template.ts
238
- chunkQP3OHHON_cjs.init_admin_layout_catalyst_template();
239
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
239
240
  function renderDatabaseTablePage(data) {
240
241
  const totalPages = Math.ceil(data.totalRows / data.pageSize);
241
242
  const startRow = (data.currentPage - 1) * data.pageSize + 1;
@@ -484,7 +485,7 @@ function renderDatabaseTablePage(data) {
484
485
  user: data.user,
485
486
  content: pageContent
486
487
  };
487
- return chunkQP3OHHON_cjs.renderAdminLayoutCatalyst(layoutData);
488
+ return chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst(layoutData);
488
489
  }
489
490
  function generatePageNumbers(currentPage, totalPages) {
490
491
  const pages = [];
@@ -559,7 +560,7 @@ function formatCellValue(value) {
559
560
  // src/plugins/core-plugins/database-tools-plugin/admin-routes.ts
560
561
  function createDatabaseToolsAdminRoutes() {
561
562
  const router3 = new hono.Hono();
562
- router3.use("*", chunkYYMPHM3I_cjs.requireAuth());
563
+ router3.use("*", chunkCZ6BVQZX_cjs.requireAuth());
563
564
  router3.get("/api/stats", async (c) => {
564
565
  try {
565
566
  const user = c.get("user");
@@ -1307,7 +1308,7 @@ function createSeedDataAdminRoutes() {
1307
1308
  return routes;
1308
1309
  }
1309
1310
  function createEmailPlugin() {
1310
- const builder = chunk6FHNRRJ3_cjs.PluginBuilder.create({
1311
+ const builder = chunk635JAMSE_cjs.PluginBuilder.create({
1311
1312
  name: "email",
1312
1313
  version: "1.0.0-beta.1",
1313
1314
  description: "Send transactional emails using Resend"
@@ -1736,7 +1737,7 @@ var DEFAULT_SETTINGS = {
1736
1737
  allowNewUserRegistration: false
1737
1738
  };
1738
1739
  function createOTPLoginPlugin() {
1739
- const builder = chunk6FHNRRJ3_cjs.PluginBuilder.create({
1740
+ const builder = chunk635JAMSE_cjs.PluginBuilder.create({
1740
1741
  name: "otp-login",
1741
1742
  version: "1.0.0-beta.1",
1742
1743
  description: "Passwordless authentication via email one-time codes"
@@ -1938,7 +1939,7 @@ function createOTPLoginPlugin() {
1938
1939
  error: "Account is deactivated"
1939
1940
  }, 403);
1940
1941
  }
1941
- const token = await chunkYYMPHM3I_cjs.AuthManager.generateToken(user.id, user.email, user.role, c.env.JWT_SECRET);
1942
+ const token = await chunkCZ6BVQZX_cjs.AuthManager.generateToken(user.id, user.email, user.role, c.env.JWT_SECRET);
1942
1943
  cookie.setCookie(c, "auth_token", token, {
1943
1944
  httpOnly: true,
1944
1945
  secure: true,
@@ -2272,7 +2273,7 @@ var OAuthService = class {
2272
2273
  var STATE_COOKIE_NAME = "oauth_state";
2273
2274
  var STATE_COOKIE_MAX_AGE = 600;
2274
2275
  function createOAuthProvidersPlugin() {
2275
- const builder = chunk6FHNRRJ3_cjs.PluginBuilder.create({
2276
+ const builder = chunk635JAMSE_cjs.PluginBuilder.create({
2276
2277
  name: "oauth-providers",
2277
2278
  version: "1.0.0-beta.1",
2278
2279
  description: "OAuth2/OIDC social login with GitHub, Google, and more"
@@ -2408,13 +2409,13 @@ function createOAuthProvidersPlugin() {
2408
2409
  if (!user || !user.is_active) {
2409
2410
  return c.redirect("/auth/login?error=Account is deactivated");
2410
2411
  }
2411
- const jwt2 = await chunkYYMPHM3I_cjs.AuthManager.generateToken(
2412
+ const jwt2 = await chunkCZ6BVQZX_cjs.AuthManager.generateToken(
2412
2413
  user.id,
2413
2414
  user.email,
2414
2415
  user.role,
2415
2416
  c.env.JWT_SECRET
2416
2417
  );
2417
- chunkYYMPHM3I_cjs.AuthManager.setAuthCookie(c, jwt2, { sameSite: "Lax" });
2418
+ chunkCZ6BVQZX_cjs.AuthManager.setAuthCookie(c, jwt2, { sameSite: "Lax" });
2418
2419
  return c.redirect("/admin");
2419
2420
  }
2420
2421
  const existingUser = await oauthService.findUserByEmail(profile.email);
@@ -2431,13 +2432,13 @@ function createOAuthProvidersPlugin() {
2431
2432
  tokenExpiresAt: tokenExpiresAt ?? void 0,
2432
2433
  profileData: JSON.stringify(profile)
2433
2434
  });
2434
- const jwt2 = await chunkYYMPHM3I_cjs.AuthManager.generateToken(
2435
+ const jwt2 = await chunkCZ6BVQZX_cjs.AuthManager.generateToken(
2435
2436
  existingUser.id,
2436
2437
  existingUser.email,
2437
2438
  existingUser.role,
2438
2439
  c.env.JWT_SECRET
2439
2440
  );
2440
- chunkYYMPHM3I_cjs.AuthManager.setAuthCookie(c, jwt2, { sameSite: "Lax" });
2441
+ chunkCZ6BVQZX_cjs.AuthManager.setAuthCookie(c, jwt2, { sameSite: "Lax" });
2441
2442
  return c.redirect("/admin");
2442
2443
  }
2443
2444
  const newUserId = await oauthService.createUserFromOAuth(profile);
@@ -2450,13 +2451,13 @@ function createOAuthProvidersPlugin() {
2450
2451
  tokenExpiresAt: tokenExpiresAt ?? void 0,
2451
2452
  profileData: JSON.stringify(profile)
2452
2453
  });
2453
- const jwt = await chunkYYMPHM3I_cjs.AuthManager.generateToken(
2454
+ const jwt = await chunkCZ6BVQZX_cjs.AuthManager.generateToken(
2454
2455
  newUserId,
2455
2456
  profile.email.toLowerCase(),
2456
2457
  "viewer",
2457
2458
  c.env.JWT_SECRET
2458
2459
  );
2459
- chunkYYMPHM3I_cjs.AuthManager.setAuthCookie(c, jwt, { sameSite: "Lax" });
2460
+ chunkCZ6BVQZX_cjs.AuthManager.setAuthCookie(c, jwt, { sameSite: "Lax" });
2460
2461
  return c.redirect("/admin");
2461
2462
  } catch (error) {
2462
2463
  console.error("OAuth callback error:", error);
@@ -4138,7 +4139,7 @@ function renderSettingsPage(data) {
4138
4139
  }, 30000);
4139
4140
  </script>
4140
4141
  `;
4141
- return chunkQP3OHHON_cjs.renderAdminLayout({
4142
+ return chunkOHYBNCVL_cjs.renderAdminLayout({
4142
4143
  title: "AI Search Settings",
4143
4144
  pageTitle: "AI Search Settings",
4144
4145
  currentPath: "/admin/plugins/ai-search/settings",
@@ -4149,7 +4150,7 @@ function renderSettingsPage(data) {
4149
4150
 
4150
4151
  // src/plugins/core-plugins/ai-search-plugin/routes/admin.ts
4151
4152
  var adminRoutes = new hono.Hono();
4152
- adminRoutes.use("*", chunkYYMPHM3I_cjs.requireAuth());
4153
+ adminRoutes.use("*", chunkCZ6BVQZX_cjs.requireAuth());
4153
4154
  adminRoutes.get("/", async (c) => {
4154
4155
  try {
4155
4156
  const user = c.get("user");
@@ -4395,7 +4396,7 @@ var manifest_default = {
4395
4396
  author: "SonicJS"};
4396
4397
 
4397
4398
  // src/plugins/core-plugins/ai-search-plugin/index.ts
4398
- var aiSearchPlugin = new chunk6FHNRRJ3_cjs.PluginBuilder({
4399
+ var aiSearchPlugin = new chunk635JAMSE_cjs.PluginBuilder({
4399
4400
  name: manifest_default.name,
4400
4401
  version: manifest_default.version,
4401
4402
  description: manifest_default.description,
@@ -4550,13 +4551,13 @@ function createMagicLinkAuthPlugin() {
4550
4551
  SET used = 1, used_at = ?
4551
4552
  WHERE id = ?
4552
4553
  `).bind(Date.now(), magicLink.id).run();
4553
- const jwtToken = await chunkYYMPHM3I_cjs.AuthManager.generateToken(
4554
+ const jwtToken = await chunkCZ6BVQZX_cjs.AuthManager.generateToken(
4554
4555
  user.id,
4555
4556
  user.email,
4556
4557
  user.role,
4557
4558
  c.env.JWT_SECRET
4558
4559
  );
4559
- chunkYYMPHM3I_cjs.AuthManager.setAuthCookie(c, jwtToken);
4560
+ chunkCZ6BVQZX_cjs.AuthManager.setAuthCookie(c, jwtToken);
4560
4561
  await db.prepare(`
4561
4562
  UPDATE users SET last_login_at = ? WHERE id = ?
4562
4563
  `).bind(Date.now(), user.id).run();
@@ -4994,7 +4995,7 @@ var SecurityAuditService = class {
4994
4995
  };
4995
4996
 
4996
4997
  // src/plugins/core-plugins/security-audit-plugin/components/dashboard-page.ts
4997
- chunkQP3OHHON_cjs.init_admin_layout_catalyst_template();
4998
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
4998
4999
  function formatTimestamp(ts) {
4999
5000
  const date = new Date(ts);
5000
5001
  const now = Date.now();
@@ -5193,11 +5194,11 @@ function renderSecurityDashboard(data) {
5193
5194
  version,
5194
5195
  dynamicMenuItems
5195
5196
  };
5196
- return chunkQP3OHHON_cjs.renderAdminLayoutCatalyst(layoutData);
5197
+ return chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst(layoutData);
5197
5198
  }
5198
5199
 
5199
5200
  // src/plugins/core-plugins/security-audit-plugin/components/event-log-page.ts
5200
- chunkQP3OHHON_cjs.init_admin_layout_catalyst_template();
5201
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
5201
5202
  function formatTimestamp2(ts) {
5202
5203
  const date = new Date(ts);
5203
5204
  return date.toLocaleDateString("en-US", {
@@ -5404,11 +5405,11 @@ function renderEventLogPage(data) {
5404
5405
  version,
5405
5406
  dynamicMenuItems
5406
5407
  };
5407
- return chunkQP3OHHON_cjs.renderAdminLayoutCatalyst(layoutData);
5408
+ return chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst(layoutData);
5408
5409
  }
5409
5410
 
5410
5411
  // src/plugins/core-plugins/security-audit-plugin/components/settings-page.ts
5411
- chunkQP3OHHON_cjs.init_admin_layout_catalyst_template();
5412
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
5412
5413
  function renderSecuritySettingsPage(data) {
5413
5414
  const { settings, user, version, message, dynamicMenuItems } = data;
5414
5415
  const content2 = `
@@ -5561,12 +5562,12 @@ function renderSecuritySettingsPage(data) {
5561
5562
  version,
5562
5563
  dynamicMenuItems
5563
5564
  };
5564
- return chunkQP3OHHON_cjs.renderAdminLayoutCatalyst(layoutData);
5565
+ return chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst(layoutData);
5565
5566
  }
5566
5567
 
5567
5568
  // src/plugins/core-plugins/security-audit-plugin/routes/admin.ts
5568
5569
  var adminRoutes2 = new hono.Hono();
5569
- adminRoutes2.use("*", chunkYYMPHM3I_cjs.requireAuth());
5570
+ adminRoutes2.use("*", chunkCZ6BVQZX_cjs.requireAuth());
5570
5571
  adminRoutes2.use("*", async (c, next) => {
5571
5572
  const user = c.get("user");
5572
5573
  if (user?.role !== "admin") {
@@ -5576,7 +5577,7 @@ adminRoutes2.use("*", async (c, next) => {
5576
5577
  });
5577
5578
  async function getSettings(db) {
5578
5579
  try {
5579
- const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
5580
+ const pluginService = new chunkQ5VFZUXV_cjs.PluginService(db);
5580
5581
  const plugin2 = await pluginService.getPlugin("security-audit");
5581
5582
  if (plugin2?.settings) {
5582
5583
  const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
@@ -5681,7 +5682,7 @@ adminRoutes2.post("/settings", async (c) => {
5681
5682
  autoPurge: body["retention.autoPurge"] === "true"
5682
5683
  }
5683
5684
  };
5684
- const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
5685
+ const pluginService = new chunkQ5VFZUXV_cjs.PluginService(db);
5685
5686
  await pluginService.updatePluginSettings("security-audit", settings);
5686
5687
  if (c.req.header("HX-Request")) {
5687
5688
  return c.json({ success: true });
@@ -5699,7 +5700,7 @@ var BruteForceDetector = class {
5699
5700
  }
5700
5701
  settings;
5701
5702
  async recordFailedAttempt(ip, email) {
5702
- if (!this.settings.enabled) {
5703
+ if (!this.settings.enabled || !this.kv) {
5703
5704
  return { ipCount: 0, emailCount: 0, shouldLockIP: false, shouldLockEmail: false, isSuspicious: false };
5704
5705
  }
5705
5706
  const windowMs = this.settings.windowMinutes * 60 * 1e3;
@@ -5716,7 +5717,7 @@ var BruteForceDetector = class {
5716
5717
  return { ipCount, emailCount, shouldLockIP, shouldLockEmail, isSuspicious };
5717
5718
  }
5718
5719
  async isLocked(ip, email) {
5719
- if (!this.settings.enabled) {
5720
+ if (!this.settings.enabled || !this.kv) {
5720
5721
  return { locked: false };
5721
5722
  }
5722
5723
  const ipLocked = await this.kv.get(`${LOCK_PREFIX}ip:${ip}`);
@@ -5730,6 +5731,7 @@ var BruteForceDetector = class {
5730
5731
  return { locked: false };
5731
5732
  }
5732
5733
  async lockIP(ip) {
5734
+ if (!this.kv) return;
5733
5735
  const ttl = this.settings.lockoutDurationMinutes * 60;
5734
5736
  await this.kv.put(`${LOCK_PREFIX}ip:${ip}`, JSON.stringify({
5735
5737
  lockedAt: Date.now(),
@@ -5737,6 +5739,7 @@ var BruteForceDetector = class {
5737
5739
  }), { expirationTtl: ttl });
5738
5740
  }
5739
5741
  async lockEmail(email) {
5742
+ if (!this.kv) return;
5740
5743
  const ttl = this.settings.lockoutDurationMinutes * 60;
5741
5744
  await this.kv.put(`${LOCK_PREFIX}email:${email}`, JSON.stringify({
5742
5745
  lockedAt: Date.now(),
@@ -5744,12 +5747,15 @@ var BruteForceDetector = class {
5744
5747
  }), { expirationTtl: ttl });
5745
5748
  }
5746
5749
  async unlockIP(ip) {
5750
+ if (!this.kv) return;
5747
5751
  await this.kv.delete(`${LOCK_PREFIX}ip:${ip}`);
5748
5752
  }
5749
5753
  async unlockEmail(email) {
5754
+ if (!this.kv) return;
5750
5755
  await this.kv.delete(`${LOCK_PREFIX}email:${email}`);
5751
5756
  }
5752
5757
  async getActiveLockouts() {
5758
+ if (!this.kv) return [];
5753
5759
  const ipLocks = await this.kv.list({ prefix: `${LOCK_PREFIX}ip:` });
5754
5760
  const emailLocks = await this.kv.list({ prefix: `${LOCK_PREFIX}email:` });
5755
5761
  const lockouts = [];
@@ -5780,6 +5786,7 @@ var BruteForceDetector = class {
5780
5786
  return lockouts;
5781
5787
  }
5782
5788
  async releaseLockout(key) {
5789
+ if (!this.kv) return;
5783
5790
  await this.kv.delete(key);
5784
5791
  }
5785
5792
  isAboveAlertThreshold(count) {
@@ -5836,7 +5843,7 @@ var BruteForceDetector = class {
5836
5843
 
5837
5844
  // src/plugins/core-plugins/security-audit-plugin/routes/api.ts
5838
5845
  var apiRoutes2 = new hono.Hono();
5839
- apiRoutes2.use("*", chunkYYMPHM3I_cjs.requireAuth());
5846
+ apiRoutes2.use("*", chunkCZ6BVQZX_cjs.requireAuth());
5840
5847
  apiRoutes2.use("*", async (c, next) => {
5841
5848
  const user = c.get("user");
5842
5849
  if (user?.role !== "admin") {
@@ -5846,7 +5853,7 @@ apiRoutes2.use("*", async (c, next) => {
5846
5853
  });
5847
5854
  async function getSettings2(db) {
5848
5855
  try {
5849
- const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
5856
+ const pluginService = new chunkQ5VFZUXV_cjs.PluginService(db);
5850
5857
  const plugin2 = await pluginService.getPlugin("security-audit");
5851
5858
  if (plugin2?.settings) {
5852
5859
  const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
@@ -5994,7 +6001,7 @@ function generateFingerprint(ip, userAgent) {
5994
6001
  }
5995
6002
  async function getPluginSettings(db) {
5996
6003
  try {
5997
- const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
6004
+ const pluginService = new chunkQ5VFZUXV_cjs.PluginService(db);
5998
6005
  const plugin2 = await pluginService.getPlugin("security-audit");
5999
6006
  if (plugin2?.settings) {
6000
6007
  const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
@@ -6225,7 +6232,7 @@ async function logAuthEvent(c, db, settings, ip, userAgent, countryCode, fingerp
6225
6232
 
6226
6233
  // src/plugins/core-plugins/security-audit-plugin/index.ts
6227
6234
  function createSecurityAuditPlugin() {
6228
- const builder = chunk6FHNRRJ3_cjs.PluginBuilder.create({
6235
+ const builder = chunk635JAMSE_cjs.PluginBuilder.create({
6229
6236
  name: "security-audit",
6230
6237
  version: "1.0.0-beta.1",
6231
6238
  description: "Security event logging, brute-force detection, and analytics dashboard"
@@ -6323,6 +6330,33 @@ var SubscriptionService = class {
6323
6330
  ).first();
6324
6331
  return this.mapRow(result);
6325
6332
  }
6333
+ /**
6334
+ * Upsert a subscription by stripe_subscription_id (INSERT or UPDATE on conflict)
6335
+ */
6336
+ async upsert(data) {
6337
+ const result = await this.db.prepare(`
6338
+ INSERT INTO subscriptions (user_id, stripe_customer_id, stripe_subscription_id, stripe_price_id, status, current_period_start, current_period_end, cancel_at_period_end)
6339
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
6340
+ ON CONFLICT(stripe_subscription_id) DO UPDATE SET
6341
+ status = excluded.status,
6342
+ stripe_price_id = excluded.stripe_price_id,
6343
+ current_period_start = excluded.current_period_start,
6344
+ current_period_end = excluded.current_period_end,
6345
+ cancel_at_period_end = excluded.cancel_at_period_end,
6346
+ updated_at = unixepoch()
6347
+ RETURNING *
6348
+ `).bind(
6349
+ data.userId,
6350
+ data.stripeCustomerId,
6351
+ data.stripeSubscriptionId,
6352
+ data.stripePriceId,
6353
+ data.status,
6354
+ data.currentPeriodStart,
6355
+ data.currentPeriodEnd,
6356
+ data.cancelAtPeriodEnd ? 1 : 0
6357
+ ).first();
6358
+ return this.mapRow(result);
6359
+ }
6326
6360
  /**
6327
6361
  * Update a subscription by its Stripe subscription ID
6328
6362
  */
@@ -6477,24 +6511,183 @@ var SubscriptionService = class {
6477
6511
  }
6478
6512
  };
6479
6513
 
6514
+ // src/plugins/core-plugins/stripe-plugin/services/stripe-event-service.ts
6515
+ var StripeEventService = class {
6516
+ constructor(db) {
6517
+ this.db = db;
6518
+ }
6519
+ async ensureTable() {
6520
+ await this.db.prepare(`
6521
+ CREATE TABLE IF NOT EXISTS stripe_events (
6522
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
6523
+ stripe_event_id TEXT NOT NULL UNIQUE,
6524
+ type TEXT NOT NULL,
6525
+ object_id TEXT NOT NULL DEFAULT '',
6526
+ object_type TEXT NOT NULL DEFAULT '',
6527
+ data TEXT NOT NULL DEFAULT '{}',
6528
+ processed_at INTEGER NOT NULL DEFAULT (unixepoch()),
6529
+ status TEXT NOT NULL DEFAULT 'processed',
6530
+ error TEXT
6531
+ )
6532
+ `).run();
6533
+ await this.db.prepare(`
6534
+ CREATE INDEX IF NOT EXISTS idx_stripe_events_type ON stripe_events(type)
6535
+ `).run();
6536
+ await this.db.prepare(`
6537
+ CREATE INDEX IF NOT EXISTS idx_stripe_events_status ON stripe_events(status)
6538
+ `).run();
6539
+ await this.db.prepare(`
6540
+ CREATE INDEX IF NOT EXISTS idx_stripe_events_processed_at ON stripe_events(processed_at DESC)
6541
+ `).run();
6542
+ }
6543
+ async log(event) {
6544
+ await this.db.prepare(`
6545
+ INSERT INTO stripe_events (stripe_event_id, type, object_id, object_type, data, status, error)
6546
+ VALUES (?, ?, ?, ?, ?, ?, ?)
6547
+ ON CONFLICT(stripe_event_id) DO UPDATE SET
6548
+ status = excluded.status,
6549
+ error = excluded.error,
6550
+ processed_at = unixepoch()
6551
+ `).bind(
6552
+ event.stripeEventId,
6553
+ event.type,
6554
+ event.objectId,
6555
+ event.objectType,
6556
+ JSON.stringify(event.data),
6557
+ event.status,
6558
+ event.error || null
6559
+ ).run();
6560
+ }
6561
+ async list(filters = {}) {
6562
+ const where = [];
6563
+ const values = [];
6564
+ if (filters.type) {
6565
+ where.push("type = ?");
6566
+ values.push(filters.type);
6567
+ }
6568
+ if (filters.status) {
6569
+ where.push("status = ?");
6570
+ values.push(filters.status);
6571
+ }
6572
+ if (filters.objectId) {
6573
+ where.push("object_id = ?");
6574
+ values.push(filters.objectId);
6575
+ }
6576
+ const whereClause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
6577
+ const limit = Math.min(filters.limit || 50, 100);
6578
+ const page = filters.page || 1;
6579
+ const offset = (page - 1) * limit;
6580
+ const countResult = await this.db.prepare(
6581
+ `SELECT COUNT(*) as count FROM stripe_events ${whereClause}`
6582
+ ).bind(...values).first();
6583
+ const results = await this.db.prepare(
6584
+ `SELECT * FROM stripe_events ${whereClause} ORDER BY processed_at DESC LIMIT ? OFFSET ?`
6585
+ ).bind(...values, limit, offset).all();
6586
+ return {
6587
+ events: (results.results || []).map((r) => this.mapRow(r)),
6588
+ total: countResult?.count || 0
6589
+ };
6590
+ }
6591
+ async getStats() {
6592
+ const result = await this.db.prepare(`
6593
+ SELECT
6594
+ COUNT(*) as total,
6595
+ SUM(CASE WHEN status = 'processed' THEN 1 ELSE 0 END) as processed,
6596
+ SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
6597
+ SUM(CASE WHEN status = 'ignored' THEN 1 ELSE 0 END) as ignored
6598
+ FROM stripe_events
6599
+ `).first();
6600
+ return {
6601
+ total: result?.total || 0,
6602
+ processed: result?.processed || 0,
6603
+ failed: result?.failed || 0,
6604
+ ignored: result?.ignored || 0
6605
+ };
6606
+ }
6607
+ async getDistinctTypes() {
6608
+ const results = await this.db.prepare(
6609
+ "SELECT DISTINCT type FROM stripe_events ORDER BY type"
6610
+ ).all();
6611
+ return (results.results || []).map((r) => r.type);
6612
+ }
6613
+ mapRow(row) {
6614
+ return {
6615
+ id: row.id,
6616
+ stripeEventId: row.stripe_event_id,
6617
+ type: row.type,
6618
+ objectId: row.object_id,
6619
+ objectType: row.object_type,
6620
+ data: row.data,
6621
+ processedAt: row.processed_at,
6622
+ status: row.status,
6623
+ error: row.error || void 0
6624
+ };
6625
+ }
6626
+ };
6627
+
6480
6628
  // src/plugins/core-plugins/stripe-plugin/components/subscriptions-page.ts
6481
- function renderSubscriptionsPage(subscriptions, stats, filters) {
6629
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
6630
+
6631
+ // src/plugins/core-plugins/stripe-plugin/components/tab-bar.ts
6632
+ var TABS = [
6633
+ { label: "Subscriptions", path: "/admin/plugins/stripe" },
6634
+ { label: "Events", path: "/admin/plugins/stripe/events" },
6635
+ { label: "Settings", path: "/admin/plugins/stripe/settings" }
6636
+ ];
6637
+ function renderStripeTabBar(currentPath) {
6638
+ const tabs = TABS.map((tab) => {
6639
+ const isActive = currentPath === tab.path || tab.path === "/admin/plugins/stripe" && currentPath === "/admin/plugins/stripe/";
6640
+ return `
6641
+ <a href="${tab.path}"
6642
+ class="${isActive ? "border-cyan-500 text-zinc-950 dark:text-white" : "border-transparent text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-300 hover:border-zinc-300 dark:hover:border-zinc-600"} whitespace-nowrap border-b-2 px-4 py-3 text-sm font-medium transition-colors">
6643
+ ${tab.label}
6644
+ </a>`;
6645
+ }).join("");
6482
6646
  return `
6483
- <div class="space-y-6">
6647
+ <div class="border-b border-zinc-950/5 dark:border-white/10 mb-6">
6648
+ <nav class="-mb-px flex gap-x-2" aria-label="Stripe tabs">
6649
+ ${tabs}
6650
+ </nav>
6651
+ </div>
6652
+ `;
6653
+ }
6654
+
6655
+ // src/plugins/core-plugins/stripe-plugin/components/subscriptions-page.ts
6656
+ function renderSubscriptionsPage(data) {
6657
+ const { subscriptions, stats, filters, user, version, dynamicMenuItems } = data;
6658
+ const content2 = `
6659
+ <div>
6660
+ <div class="sm:flex sm:items-center sm:justify-between mb-6">
6661
+ <div class="sm:flex-auto">
6662
+ <h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Stripe</h1>
6663
+ <p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
6664
+ Manage subscriptions, view billing status, and monitor payment events.
6665
+ </p>
6666
+ </div>
6667
+ <div class="mt-4 sm:mt-0 sm:ml-16">
6668
+ <button id="sync-btn" onclick="syncSubscriptions()"
6669
+ class="inline-flex items-center justify-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm">
6670
+ Sync from Stripe
6671
+ </button>
6672
+ </div>
6673
+ </div>
6674
+
6675
+ ${renderStripeTabBar("/admin/plugins/stripe")}
6676
+
6484
6677
  <!-- Stats Cards -->
6485
- <div class="grid grid-cols-1 md:grid-cols-5 gap-4">
6486
- ${statsCard("Total", stats.total, "text-gray-700")}
6487
- ${statsCard("Active", stats.active, "text-green-600")}
6488
- ${statsCard("Trialing", stats.trialing, "text-blue-600")}
6489
- ${statsCard("Past Due", stats.pastDue, "text-yellow-600")}
6490
- ${statsCard("Canceled", stats.canceled, "text-red-600")}
6678
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-5 mb-6">
6679
+ ${statsCard("Total", stats.total, "text-zinc-950 dark:text-white")}
6680
+ ${statsCard("Active", stats.active, "text-emerald-600 dark:text-emerald-400")}
6681
+ ${statsCard("Trialing", stats.trialing, "text-blue-600 dark:text-blue-400")}
6682
+ ${statsCard("Past Due", stats.pastDue, "text-amber-600 dark:text-amber-400")}
6683
+ ${statsCard("Canceled", stats.canceled, "text-red-600 dark:text-red-400")}
6491
6684
  </div>
6492
6685
 
6493
6686
  <!-- Filters -->
6494
- <div class="bg-white rounded-lg shadow p-4">
6687
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-4 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm mb-6">
6495
6688
  <form method="GET" class="flex items-center gap-4">
6496
- <label class="text-sm font-medium text-gray-700">Status:</label>
6497
- <select name="status" class="border rounded px-3 py-1.5 text-sm" onchange="this.form.submit()">
6689
+ <label class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Status:</label>
6690
+ <select name="status" class="rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-1.5 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10" onchange="this.form.submit()">
6498
6691
  <option value="">All</option>
6499
6692
  ${statusOption("active", filters.status)}
6500
6693
  ${statusOption("trialing", filters.status)}
@@ -6507,33 +6700,72 @@ function renderSubscriptionsPage(subscriptions, stats, filters) {
6507
6700
  </div>
6508
6701
 
6509
6702
  <!-- Subscriptions Table -->
6510
- <div class="bg-white rounded-lg shadow overflow-hidden">
6511
- <table class="min-w-full divide-y divide-gray-200">
6512
- <thead class="bg-gray-50">
6703
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm overflow-hidden">
6704
+ <table class="min-w-full divide-y divide-zinc-950/5 dark:divide-white/5">
6705
+ <thead>
6513
6706
  <tr>
6514
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
6515
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
6516
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Price ID</th>
6517
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Current Period</th>
6518
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Cancel at End</th>
6519
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Stripe</th>
6707
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">User</th>
6708
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Status</th>
6709
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Price ID</th>
6710
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Current Period</th>
6711
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Cancel at End</th>
6712
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Stripe</th>
6520
6713
  </tr>
6521
6714
  </thead>
6522
- <tbody class="bg-white divide-y divide-gray-200">
6523
- ${subscriptions.length === 0 ? '<tr><td colspan="6" class="px-6 py-8 text-center text-gray-500">No subscriptions found</td></tr>' : subscriptions.map(renderRow).join("")}
6715
+ <tbody class="divide-y divide-zinc-950/5 dark:divide-white/5">
6716
+ ${subscriptions.length === 0 ? '<tr><td colspan="6" class="px-6 py-8 text-center text-zinc-500 dark:text-zinc-400">No subscriptions found</td></tr>' : subscriptions.map(renderRow).join("")}
6524
6717
  </tbody>
6525
6718
  </table>
6526
6719
 
6527
6720
  ${renderPagination2(filters.page, filters.totalPages, filters.status)}
6528
6721
  </div>
6722
+
6723
+ <div id="sync-message" class="hidden mt-4 rounded-lg p-4 text-sm"></div>
6529
6724
  </div>
6725
+
6726
+ <script>
6727
+ async function syncSubscriptions() {
6728
+ const btn = document.getElementById('sync-btn')
6729
+ const msg = document.getElementById('sync-message')
6730
+ btn.disabled = true
6731
+ btn.textContent = 'Syncing...'
6732
+ msg.className = 'hidden mt-4 rounded-lg p-4 text-sm'
6733
+ try {
6734
+ const res = await fetch('/api/stripe/sync-subscriptions', { method: 'POST' })
6735
+ const result = await res.json()
6736
+ if (result.success) {
6737
+ msg.className = 'mt-4 rounded-lg p-4 text-sm bg-emerald-400/10 text-emerald-500 dark:text-emerald-400 ring-1 ring-inset ring-emerald-400/20'
6738
+ msg.textContent = 'Synced ' + result.synced + ' of ' + result.total + ' subscriptions from Stripe.' + (result.errors > 0 ? ' (' + result.errors + ' errors)' : '')
6739
+ setTimeout(() => location.reload(), 1500)
6740
+ } else {
6741
+ msg.className = 'mt-4 rounded-lg p-4 text-sm bg-red-400/10 text-red-500 dark:text-red-400 ring-1 ring-inset ring-red-400/20'
6742
+ msg.textContent = result.error || 'Sync failed.'
6743
+ }
6744
+ } catch {
6745
+ msg.className = 'mt-4 rounded-lg p-4 text-sm bg-red-400/10 text-red-500 dark:text-red-400 ring-1 ring-inset ring-red-400/20'
6746
+ msg.textContent = 'Network error. Please try again.'
6747
+ }
6748
+ btn.disabled = false
6749
+ btn.textContent = 'Sync from Stripe'
6750
+ }
6751
+ </script>
6530
6752
  `;
6753
+ const layoutData = {
6754
+ title: "Stripe Subscriptions",
6755
+ pageTitle: "Stripe Subscriptions",
6756
+ currentPath: "/admin/plugins/stripe",
6757
+ user,
6758
+ content: content2,
6759
+ version,
6760
+ dynamicMenuItems
6761
+ };
6762
+ return chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst(layoutData);
6531
6763
  }
6532
6764
  function statsCard(label, value, colorClass) {
6533
6765
  return `
6534
- <div class="bg-white rounded-lg shadow p-4">
6535
- <div class="text-sm font-medium text-gray-500">${label}</div>
6536
- <div class="text-2xl font-bold ${colorClass}">${value}</div>
6766
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
6767
+ <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">${label}</p>
6768
+ <p class="mt-2 text-3xl font-bold ${colorClass}">${value}</p>
6537
6769
  </div>
6538
6770
  `;
6539
6771
  }
@@ -6544,18 +6776,18 @@ function statusOption(value, current) {
6544
6776
  }
6545
6777
  function statusBadge(status) {
6546
6778
  const colors = {
6547
- active: "bg-green-100 text-green-800",
6548
- trialing: "bg-blue-100 text-blue-800",
6549
- past_due: "bg-yellow-100 text-yellow-800",
6550
- canceled: "bg-red-100 text-red-800",
6551
- unpaid: "bg-orange-100 text-orange-800",
6552
- paused: "bg-gray-100 text-gray-800",
6553
- incomplete: "bg-gray-100 text-gray-500",
6554
- incomplete_expired: "bg-red-100 text-red-500"
6779
+ active: "bg-emerald-400/10 text-emerald-500 dark:text-emerald-400 ring-emerald-400/20",
6780
+ trialing: "bg-blue-400/10 text-blue-500 dark:text-blue-400 ring-blue-400/20",
6781
+ past_due: "bg-amber-400/10 text-amber-500 dark:text-amber-400 ring-amber-400/20",
6782
+ canceled: "bg-red-400/10 text-red-500 dark:text-red-400 ring-red-400/20",
6783
+ unpaid: "bg-orange-400/10 text-orange-500 dark:text-orange-400 ring-orange-400/20",
6784
+ paused: "bg-zinc-400/10 text-zinc-500 dark:text-zinc-400 ring-zinc-400/20",
6785
+ incomplete: "bg-zinc-400/10 text-zinc-500 dark:text-zinc-400 ring-zinc-400/20",
6786
+ incomplete_expired: "bg-red-400/10 text-red-500 dark:text-red-400 ring-red-400/20"
6555
6787
  };
6556
- const color = colors[status] || "bg-gray-100 text-gray-800";
6788
+ const color = colors[status] || "bg-zinc-400/10 text-zinc-500 ring-zinc-400/20";
6557
6789
  const label = status.replace("_", " ");
6558
- return `<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${color}">${label}</span>`;
6790
+ return `<span class="inline-flex items-center rounded-full px-2 py-1 text-xs font-medium ring-1 ring-inset ${color}">${label}</span>`;
6559
6791
  }
6560
6792
  function formatDate(timestamp) {
6561
6793
  if (!timestamp) return "-";
@@ -6567,23 +6799,23 @@ function formatDate(timestamp) {
6567
6799
  }
6568
6800
  function renderRow(sub) {
6569
6801
  return `
6570
- <tr>
6802
+ <tr class="hover:bg-zinc-950/[0.025] dark:hover:bg-white/[0.025]">
6571
6803
  <td class="px-6 py-4 whitespace-nowrap">
6572
- <div class="text-sm font-medium text-gray-900">${sub.userEmail || sub.userId}</div>
6573
- <div class="text-xs text-gray-500">${sub.stripeCustomerId}</div>
6804
+ <div class="text-sm font-medium text-zinc-950 dark:text-white">${sub.userEmail || sub.userId}</div>
6805
+ <div class="text-xs text-zinc-500 dark:text-zinc-400">${sub.stripeCustomerId}</div>
6574
6806
  </td>
6575
6807
  <td class="px-6 py-4 whitespace-nowrap">${statusBadge(sub.status)}</td>
6576
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${sub.stripePriceId}</td>
6577
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
6808
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400">${sub.stripePriceId}</td>
6809
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400">
6578
6810
  ${formatDate(sub.currentPeriodStart)} - ${formatDate(sub.currentPeriodEnd)}
6579
6811
  </td>
6580
6812
  <td class="px-6 py-4 whitespace-nowrap text-sm">
6581
- ${sub.cancelAtPeriodEnd ? '<span class="text-yellow-600 font-medium">Yes</span>' : '<span class="text-gray-400">No</span>'}
6813
+ ${sub.cancelAtPeriodEnd ? '<span class="text-amber-500 dark:text-amber-400 font-medium">Yes</span>' : '<span class="text-zinc-400 dark:text-zinc-500">No</span>'}
6582
6814
  </td>
6583
6815
  <td class="px-6 py-4 whitespace-nowrap text-sm">
6584
6816
  <a href="https://dashboard.stripe.com/subscriptions/${sub.stripeSubscriptionId}"
6585
6817
  target="_blank" rel="noopener noreferrer"
6586
- class="text-indigo-600 hover:text-indigo-800">
6818
+ class="text-cyan-600 dark:text-cyan-400 hover:text-cyan-500 dark:hover:text-cyan-300">
6587
6819
  View in Stripe
6588
6820
  </a>
6589
6821
  </td>
@@ -6594,13 +6826,161 @@ function renderPagination2(page, totalPages, status) {
6594
6826
  if (totalPages <= 1) return "";
6595
6827
  const params = status ? `&status=${status}` : "";
6596
6828
  return `
6597
- <div class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
6598
- <div class="text-sm text-gray-700">
6829
+ <div class="px-6 py-3 flex items-center justify-between border-t border-zinc-950/5 dark:border-white/5">
6830
+ <div class="text-sm text-zinc-500 dark:text-zinc-400">
6831
+ Page ${page} of ${totalPages}
6832
+ </div>
6833
+ <div class="flex gap-2">
6834
+ ${page > 1 ? `<a href="?page=${page - 1}${params}" class="px-3 py-1 rounded-lg text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-800">Previous</a>` : ""}
6835
+ ${page < totalPages ? `<a href="?page=${page + 1}${params}" class="px-3 py-1 rounded-lg text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-800">Next</a>` : ""}
6836
+ </div>
6837
+ </div>
6838
+ `;
6839
+ }
6840
+
6841
+ // src/plugins/core-plugins/stripe-plugin/components/events-page.ts
6842
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
6843
+ function renderEventsPage(data) {
6844
+ const { events, stats, types, filters, user, version, dynamicMenuItems } = data;
6845
+ const content2 = `
6846
+ <div>
6847
+ <div class="sm:flex sm:items-center sm:justify-between mb-6">
6848
+ <div class="sm:flex-auto">
6849
+ <h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Stripe</h1>
6850
+ <p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
6851
+ Webhook event log showing all processed, failed, and ignored Stripe events.
6852
+ </p>
6853
+ </div>
6854
+ </div>
6855
+
6856
+ ${renderStripeTabBar("/admin/plugins/stripe/events")}
6857
+
6858
+ <!-- Stats Cards -->
6859
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 mb-6">
6860
+ ${eventStatsCard("Total Events", stats.total, "text-zinc-950 dark:text-white")}
6861
+ ${eventStatsCard("Processed", stats.processed, "text-emerald-600 dark:text-emerald-400")}
6862
+ ${eventStatsCard("Failed", stats.failed, "text-red-600 dark:text-red-400")}
6863
+ ${eventStatsCard("Ignored", stats.ignored, "text-zinc-500 dark:text-zinc-400")}
6864
+ </div>
6865
+
6866
+ <!-- Filters -->
6867
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-4 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm mb-6">
6868
+ <form method="GET" class="flex items-center gap-4 flex-wrap">
6869
+ <label class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Type:</label>
6870
+ <select name="type" class="rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-1.5 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10" onchange="this.form.submit()">
6871
+ <option value="">All</option>
6872
+ ${types.map((t) => `<option value="${t}" ${t === filters.type ? "selected" : ""}>${t}</option>`).join("")}
6873
+ </select>
6874
+
6875
+ <label class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Status:</label>
6876
+ <select name="status" class="rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-1.5 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10" onchange="this.form.submit()">
6877
+ <option value="">All</option>
6878
+ ${eventStatusOption("processed", filters.status)}
6879
+ ${eventStatusOption("failed", filters.status)}
6880
+ ${eventStatusOption("ignored", filters.status)}
6881
+ </select>
6882
+ </form>
6883
+ </div>
6884
+
6885
+ <!-- Events Table -->
6886
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm overflow-hidden">
6887
+ <table class="min-w-full divide-y divide-zinc-950/5 dark:divide-white/5">
6888
+ <thead>
6889
+ <tr>
6890
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Time</th>
6891
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Type</th>
6892
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Object</th>
6893
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Status</th>
6894
+ <th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Event ID</th>
6895
+ </tr>
6896
+ </thead>
6897
+ <tbody class="divide-y divide-zinc-950/5 dark:divide-white/5">
6898
+ ${events.length === 0 ? '<tr><td colspan="5" class="px-6 py-8 text-center text-zinc-500 dark:text-zinc-400">No events recorded yet</td></tr>' : events.map(renderEventRow).join("")}
6899
+ </tbody>
6900
+ </table>
6901
+
6902
+ ${renderEventPagination(filters.page, filters.totalPages, filters.type, filters.status)}
6903
+ </div>
6904
+ </div>
6905
+ `;
6906
+ const layoutData = {
6907
+ title: "Stripe Events",
6908
+ pageTitle: "Stripe Events",
6909
+ currentPath: "/admin/plugins/stripe",
6910
+ user,
6911
+ content: content2,
6912
+ version,
6913
+ dynamicMenuItems
6914
+ };
6915
+ return chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst(layoutData);
6916
+ }
6917
+ function eventStatsCard(label, value, colorClass) {
6918
+ return `
6919
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
6920
+ <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">${label}</p>
6921
+ <p class="mt-2 text-3xl font-bold ${colorClass}">${value}</p>
6922
+ </div>
6923
+ `;
6924
+ }
6925
+ function eventStatusOption(value, current) {
6926
+ const selected = value === current ? "selected" : "";
6927
+ const label = value.charAt(0).toUpperCase() + value.slice(1);
6928
+ return `<option value="${value}" ${selected}>${label}</option>`;
6929
+ }
6930
+ function eventStatusBadge(status) {
6931
+ const colors = {
6932
+ processed: "bg-emerald-400/10 text-emerald-500 dark:text-emerald-400 ring-emerald-400/20",
6933
+ failed: "bg-red-400/10 text-red-500 dark:text-red-400 ring-red-400/20",
6934
+ ignored: "bg-zinc-400/10 text-zinc-500 dark:text-zinc-400 ring-zinc-400/20"
6935
+ };
6936
+ const color = colors[status] || "bg-zinc-400/10 text-zinc-500 ring-zinc-400/20";
6937
+ return `<span class="inline-flex items-center rounded-full px-2 py-1 text-xs font-medium ring-1 ring-inset ${color}">${status}</span>`;
6938
+ }
6939
+ function formatTimestamp3(timestamp) {
6940
+ if (!timestamp) return "-";
6941
+ const d = new Date(timestamp * 1e3);
6942
+ return d.toLocaleString("en-US", {
6943
+ month: "short",
6944
+ day: "numeric",
6945
+ year: "numeric",
6946
+ hour: "2-digit",
6947
+ minute: "2-digit",
6948
+ second: "2-digit"
6949
+ });
6950
+ }
6951
+ function renderEventRow(event) {
6952
+ const errorTooltip = event.error ? ` title="${event.error.replace(/"/g, "&quot;")}"` : "";
6953
+ return `
6954
+ <tr class="hover:bg-zinc-950/[0.025] dark:hover:bg-white/[0.025]"${errorTooltip}>
6955
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400">
6956
+ ${formatTimestamp3(event.processedAt)}
6957
+ </td>
6958
+ <td class="px-6 py-4 whitespace-nowrap">
6959
+ <span class="text-sm font-mono text-zinc-950 dark:text-white">${event.type}</span>
6960
+ </td>
6961
+ <td class="px-6 py-4 whitespace-nowrap">
6962
+ <div class="text-sm font-mono text-zinc-500 dark:text-zinc-400">${event.objectId || "-"}</div>
6963
+ <div class="text-xs text-zinc-400 dark:text-zinc-500">${event.objectType}</div>
6964
+ </td>
6965
+ <td class="px-6 py-4 whitespace-nowrap">${eventStatusBadge(event.status)}</td>
6966
+ <td class="px-6 py-4 whitespace-nowrap text-xs font-mono text-zinc-400 dark:text-zinc-500">${event.stripeEventId}</td>
6967
+ </tr>
6968
+ `;
6969
+ }
6970
+ function renderEventPagination(page, totalPages, type, status) {
6971
+ if (totalPages <= 1) return "";
6972
+ const params = [];
6973
+ if (type) params.push(`type=${type}`);
6974
+ if (status) params.push(`status=${status}`);
6975
+ const extra = params.length > 0 ? `&${params.join("&")}` : "";
6976
+ return `
6977
+ <div class="px-6 py-3 flex items-center justify-between border-t border-zinc-950/5 dark:border-white/5">
6978
+ <div class="text-sm text-zinc-500 dark:text-zinc-400">
6599
6979
  Page ${page} of ${totalPages}
6600
6980
  </div>
6601
6981
  <div class="flex gap-2">
6602
- ${page > 1 ? `<a href="?page=${page - 1}${params}" class="px-3 py-1 border rounded text-sm hover:bg-gray-50">Previous</a>` : ""}
6603
- ${page < totalPages ? `<a href="?page=${page + 1}${params}" class="px-3 py-1 border rounded text-sm hover:bg-gray-50">Next</a>` : ""}
6982
+ ${page > 1 ? `<a href="?page=${page - 1}${extra}" class="px-3 py-1 rounded-lg text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-800">Previous</a>` : ""}
6983
+ ${page < totalPages ? `<a href="?page=${page + 1}${extra}" class="px-3 py-1 rounded-lg text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-800">Next</a>` : ""}
6604
6984
  </div>
6605
6985
  </div>
6606
6986
  `;
@@ -6608,6 +6988,7 @@ function renderPagination2(page, totalPages, status) {
6608
6988
 
6609
6989
  // src/plugins/core-plugins/stripe-plugin/types.ts
6610
6990
  var DEFAULT_SETTINGS3 = {
6991
+ stripePublishableKey: "",
6611
6992
  stripeSecretKey: "",
6612
6993
  stripeWebhookSecret: "",
6613
6994
  stripePriceId: "",
@@ -6617,7 +6998,7 @@ var DEFAULT_SETTINGS3 = {
6617
6998
 
6618
6999
  // src/plugins/core-plugins/stripe-plugin/routes/admin.ts
6619
7000
  var adminRoutes3 = new hono.Hono();
6620
- adminRoutes3.use("*", chunkYYMPHM3I_cjs.requireAuth());
7001
+ adminRoutes3.use("*", chunkCZ6BVQZX_cjs.requireAuth());
6621
7002
  adminRoutes3.use("*", async (c, next) => {
6622
7003
  const user = c.get("user");
6623
7004
  if (user?.role !== "admin") {
@@ -6625,8 +7006,21 @@ adminRoutes3.use("*", async (c, next) => {
6625
7006
  }
6626
7007
  return next();
6627
7008
  });
7009
+ async function getSettings3(db) {
7010
+ try {
7011
+ const pluginService = new chunkQ5VFZUXV_cjs.PluginService(db);
7012
+ const plugin2 = await pluginService.getPlugin("stripe");
7013
+ if (plugin2?.settings) {
7014
+ const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
7015
+ return { ...DEFAULT_SETTINGS3, ...settings };
7016
+ }
7017
+ } catch {
7018
+ }
7019
+ return DEFAULT_SETTINGS3;
7020
+ }
6628
7021
  adminRoutes3.get("/", async (c) => {
6629
7022
  const db = c.env.DB;
7023
+ const user = c.get("user");
6630
7024
  const subscriptionService = new SubscriptionService(db);
6631
7025
  await subscriptionService.ensureTable();
6632
7026
  const page = parseInt(c.req.query("page") || "1");
@@ -6637,13 +7031,152 @@ adminRoutes3.get("/", async (c) => {
6637
7031
  subscriptionService.getStats()
6638
7032
  ]);
6639
7033
  const totalPages = Math.ceil(total / limit);
6640
- const html = renderSubscriptionsPage(subscriptions, stats, {
6641
- status: statusFilter,
6642
- page,
6643
- totalPages
7034
+ const html = renderSubscriptionsPage({
7035
+ subscriptions,
7036
+ stats,
7037
+ filters: { status: statusFilter, page, totalPages },
7038
+ user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
7039
+ version: c.get("appVersion"),
7040
+ dynamicMenuItems: c.get("pluginMenuItems")
6644
7041
  });
6645
7042
  return c.html(html);
6646
7043
  });
7044
+ adminRoutes3.get("/events", async (c) => {
7045
+ const db = c.env.DB;
7046
+ const user = c.get("user");
7047
+ const eventService = new StripeEventService(db);
7048
+ await eventService.ensureTable();
7049
+ const page = parseInt(c.req.query("page") || "1");
7050
+ const limit = 50;
7051
+ const typeFilter = c.req.query("type") || void 0;
7052
+ const statusFilter = c.req.query("status");
7053
+ const [{ events, total }, stats, types] = await Promise.all([
7054
+ eventService.list({ type: typeFilter, status: statusFilter, page, limit }),
7055
+ eventService.getStats(),
7056
+ eventService.getDistinctTypes()
7057
+ ]);
7058
+ const totalPages = Math.ceil(total / limit);
7059
+ const html = renderEventsPage({
7060
+ events,
7061
+ stats,
7062
+ types,
7063
+ filters: { type: typeFilter, status: statusFilter, page, totalPages },
7064
+ user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
7065
+ version: c.get("appVersion"),
7066
+ dynamicMenuItems: c.get("pluginMenuItems")
7067
+ });
7068
+ return c.html(html);
7069
+ });
7070
+ adminRoutes3.get("/settings", async (c) => {
7071
+ const db = c.env.DB;
7072
+ const user = c.get("user");
7073
+ const settings = await getSettings3(db);
7074
+ const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-HFD37TY5.cjs');
7075
+ const content2 = `
7076
+ <div>
7077
+ <div class="mb-6">
7078
+ <h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Stripe</h1>
7079
+ <p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
7080
+ Configure your Stripe API keys and checkout options.
7081
+ </p>
7082
+ </div>
7083
+
7084
+ ${renderStripeTabBar("/admin/plugins/stripe/settings")}
7085
+
7086
+ <div id="settings-message" class="hidden mb-4 rounded-lg p-4 text-sm"></div>
7087
+
7088
+ <form id="stripe-settings-form" class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm divide-y divide-zinc-950/5 dark:divide-white/5">
7089
+ <div class="p-6 space-y-5">
7090
+ <div>
7091
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-1.5">Publishable Key</label>
7092
+ <input type="text" name="stripePublishableKey" value="${settings.stripePublishableKey}"
7093
+ placeholder="pk_..."
7094
+ class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3.5 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:ring-2 focus:ring-cyan-500" />
7095
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Your Stripe publishable key (starts with pk_)</p>
7096
+ </div>
7097
+
7098
+ <div>
7099
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-1.5">Secret Key</label>
7100
+ <input type="password" name="stripeSecretKey" value="${settings.stripeSecretKey}"
7101
+ placeholder="sk_..."
7102
+ class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3.5 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:ring-2 focus:ring-cyan-500" />
7103
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Your Stripe secret API key (starts with sk_)</p>
7104
+ </div>
7105
+
7106
+ <div>
7107
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-1.5">Webhook Signing Secret</label>
7108
+ <input type="password" name="stripeWebhookSecret" value="${settings.stripeWebhookSecret}"
7109
+ placeholder="whsec_..."
7110
+ class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3.5 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:ring-2 focus:ring-cyan-500" />
7111
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Stripe webhook endpoint signing secret (starts with whsec_)</p>
7112
+ </div>
7113
+
7114
+ <div>
7115
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-1.5">Default Price ID</label>
7116
+ <input type="text" name="stripePriceId" value="${settings.stripePriceId || ""}"
7117
+ placeholder="price_..."
7118
+ class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3.5 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:ring-2 focus:ring-cyan-500" />
7119
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Default Stripe Price ID for checkout sessions (optional)</p>
7120
+ </div>
7121
+
7122
+ <div>
7123
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-1.5">Checkout Success URL</label>
7124
+ <input type="text" name="successUrl" value="${settings.successUrl}"
7125
+ class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3.5 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:ring-2 focus:ring-cyan-500" />
7126
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Redirect URL after successful checkout</p>
7127
+ </div>
7128
+
7129
+ <div>
7130
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-1.5">Checkout Cancel URL</label>
7131
+ <input type="text" name="cancelUrl" value="${settings.cancelUrl}"
7132
+ class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3.5 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:ring-2 focus:ring-cyan-500" />
7133
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Redirect URL if checkout is cancelled</p>
7134
+ </div>
7135
+ </div>
7136
+
7137
+ <div class="px-6 py-4 flex justify-end">
7138
+ <button type="submit"
7139
+ class="inline-flex items-center justify-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm">
7140
+ Save Settings
7141
+ </button>
7142
+ </div>
7143
+ </form>
7144
+ </div>
7145
+
7146
+ <script>
7147
+ document.getElementById('stripe-settings-form').addEventListener('submit', async (e) => {
7148
+ e.preventDefault()
7149
+ const form = e.target
7150
+ const data = Object.fromEntries(new FormData(form))
7151
+ const msg = document.getElementById('settings-message')
7152
+ try {
7153
+ const res = await fetch('/admin/plugins/stripe/settings', {
7154
+ method: 'POST',
7155
+ headers: { 'Content-Type': 'application/json' },
7156
+ body: JSON.stringify(data)
7157
+ })
7158
+ const result = await res.json()
7159
+ msg.className = result.success
7160
+ ? 'mb-4 rounded-lg p-4 text-sm bg-emerald-400/10 text-emerald-500 dark:text-emerald-400 ring-1 ring-inset ring-emerald-400/20'
7161
+ : 'mb-4 rounded-lg p-4 text-sm bg-red-400/10 text-red-500 dark:text-red-400 ring-1 ring-inset ring-red-400/20'
7162
+ msg.textContent = result.success ? 'Settings saved successfully.' : (result.error || 'Failed to save settings.')
7163
+ } catch {
7164
+ msg.className = 'mb-4 rounded-lg p-4 text-sm bg-red-400/10 text-red-500 dark:text-red-400 ring-1 ring-inset ring-red-400/20'
7165
+ msg.textContent = 'Network error. Please try again.'
7166
+ }
7167
+ })
7168
+ </script>
7169
+ `;
7170
+ return c.html(renderAdminLayoutCatalyst2({
7171
+ title: "Stripe Settings",
7172
+ pageTitle: "Stripe Settings",
7173
+ currentPath: "/admin/plugins/stripe",
7174
+ user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
7175
+ content: content2,
7176
+ version: c.get("appVersion"),
7177
+ dynamicMenuItems: c.get("pluginMenuItems")
7178
+ }));
7179
+ });
6647
7180
  adminRoutes3.post("/settings", async (c) => {
6648
7181
  try {
6649
7182
  const body = await c.req.json();
@@ -6731,7 +7264,31 @@ var StripeAPI = class {
6731
7264
  body.append(`metadata[${key}]`, value);
6732
7265
  }
6733
7266
  }
6734
- return this.request("POST", "/customers", body);
7267
+ return this.request("POST", "/customers", body);
7268
+ }
7269
+ /**
7270
+ * List subscriptions with pagination (auto-expands across pages)
7271
+ */
7272
+ async listSubscriptions(params) {
7273
+ const qs = new URLSearchParams();
7274
+ qs.append("limit", String(params?.limit || 100));
7275
+ if (params?.status) qs.append("status", params.status);
7276
+ if (params?.startingAfter) qs.append("starting_after", params.startingAfter);
7277
+ return this.request("GET", `/subscriptions?${qs.toString()}`);
7278
+ }
7279
+ /**
7280
+ * Fetch ALL subscriptions from Stripe (handles pagination automatically)
7281
+ */
7282
+ async listAllSubscriptions() {
7283
+ const all = [];
7284
+ let startingAfter;
7285
+ while (true) {
7286
+ const result = await this.listSubscriptions({ limit: 100, startingAfter });
7287
+ all.push(...result.data);
7288
+ if (!result.has_more || result.data.length === 0) break;
7289
+ startingAfter = result.data[result.data.length - 1].id;
7290
+ }
7291
+ return all;
6735
7292
  }
6736
7293
  /**
6737
7294
  * Search for a customer by email
@@ -6771,9 +7328,9 @@ function timingSafeEqual(a, b) {
6771
7328
 
6772
7329
  // src/plugins/core-plugins/stripe-plugin/routes/api.ts
6773
7330
  var apiRoutes3 = new hono.Hono();
6774
- async function getSettings3(db) {
7331
+ async function getSettings4(db) {
6775
7332
  try {
6776
- const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
7333
+ const pluginService = new chunkQ5VFZUXV_cjs.PluginService(db);
6777
7334
  const plugin2 = await pluginService.getPlugin("stripe");
6778
7335
  if (plugin2?.settings) {
6779
7336
  const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
@@ -6798,7 +7355,7 @@ function mapStripeStatus(status) {
6798
7355
  }
6799
7356
  apiRoutes3.post("/webhook", async (c) => {
6800
7357
  const db = c.env.DB;
6801
- const settings = await getSettings3(db);
7358
+ const settings = await getSettings4(db);
6802
7359
  if (!settings.stripeWebhookSecret) {
6803
7360
  return c.json({ error: "Webhook secret not configured" }, 500);
6804
7361
  }
@@ -6811,7 +7368,11 @@ apiRoutes3.post("/webhook", async (c) => {
6811
7368
  }
6812
7369
  const event = JSON.parse(rawBody);
6813
7370
  const subscriptionService = new SubscriptionService(db);
6814
- await subscriptionService.ensureTable();
7371
+ const eventService = new StripeEventService(db);
7372
+ await Promise.all([subscriptionService.ensureTable(), eventService.ensureTable()]);
7373
+ const obj = event.data.object;
7374
+ const objectId = obj?.id || "";
7375
+ const objectType = obj?.object || event.type.split(".")[0] || "";
6815
7376
  try {
6816
7377
  switch (event.type) {
6817
7378
  case "customer.subscription.created": {
@@ -6886,18 +7447,45 @@ apiRoutes3.post("/webhook", async (c) => {
6886
7447
  }
6887
7448
  default:
6888
7449
  console.log(`[Stripe] Unhandled event type: ${event.type}`);
6889
- }
7450
+ await eventService.log({
7451
+ stripeEventId: event.id,
7452
+ type: event.type,
7453
+ objectId,
7454
+ objectType,
7455
+ data: event.data.object,
7456
+ status: "ignored"
7457
+ });
7458
+ return c.json({ received: true });
7459
+ }
7460
+ await eventService.log({
7461
+ stripeEventId: event.id,
7462
+ type: event.type,
7463
+ objectId,
7464
+ objectType,
7465
+ data: event.data.object,
7466
+ status: "processed"
7467
+ });
6890
7468
  } catch (error) {
7469
+ await eventService.log({
7470
+ stripeEventId: event.id,
7471
+ type: event.type,
7472
+ objectId,
7473
+ objectType,
7474
+ data: event.data.object,
7475
+ status: "failed",
7476
+ error: error instanceof Error ? error.message : String(error)
7477
+ }).catch(() => {
7478
+ });
6891
7479
  console.error(`[Stripe] Error processing webhook event ${event.type}:`, error);
6892
7480
  return c.json({ error: "Webhook processing failed" }, 500);
6893
7481
  }
6894
7482
  return c.json({ received: true });
6895
7483
  });
6896
- apiRoutes3.post("/create-checkout-session", chunkYYMPHM3I_cjs.requireAuth(), async (c) => {
7484
+ apiRoutes3.post("/create-checkout-session", chunkCZ6BVQZX_cjs.requireAuth(), async (c) => {
6897
7485
  const db = c.env.DB;
6898
7486
  const user = c.get("user");
6899
7487
  if (!user) return c.json({ error: "Unauthorized" }, 401);
6900
- const settings = await getSettings3(db);
7488
+ const settings = await getSettings4(db);
6901
7489
  if (!settings.stripeSecretKey) {
6902
7490
  return c.json({ error: "Stripe not configured" }, 500);
6903
7491
  }
@@ -6933,7 +7521,7 @@ apiRoutes3.post("/create-checkout-session", chunkYYMPHM3I_cjs.requireAuth(), asy
6933
7521
  });
6934
7522
  return c.json({ sessionId: session.id, url: session.url });
6935
7523
  });
6936
- apiRoutes3.get("/subscription", chunkYYMPHM3I_cjs.requireAuth(), async (c) => {
7524
+ apiRoutes3.get("/subscription", chunkCZ6BVQZX_cjs.requireAuth(), async (c) => {
6937
7525
  const user = c.get("user");
6938
7526
  if (!user) return c.json({ error: "Unauthorized" }, 401);
6939
7527
  const db = c.env.DB;
@@ -6945,7 +7533,7 @@ apiRoutes3.get("/subscription", chunkYYMPHM3I_cjs.requireAuth(), async (c) => {
6945
7533
  }
6946
7534
  return c.json({ subscription });
6947
7535
  });
6948
- apiRoutes3.get("/subscriptions", chunkYYMPHM3I_cjs.requireAuth(), async (c) => {
7536
+ apiRoutes3.get("/subscriptions", chunkCZ6BVQZX_cjs.requireAuth(), async (c) => {
6949
7537
  const user = c.get("user");
6950
7538
  if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
6951
7539
  const db = c.env.DB;
@@ -6961,7 +7549,7 @@ apiRoutes3.get("/subscriptions", chunkYYMPHM3I_cjs.requireAuth(), async (c) => {
6961
7549
  const result = await subscriptionService.list(filters);
6962
7550
  return c.json(result);
6963
7551
  });
6964
- apiRoutes3.get("/stats", chunkYYMPHM3I_cjs.requireAuth(), async (c) => {
7552
+ apiRoutes3.get("/stats", chunkCZ6BVQZX_cjs.requireAuth(), async (c) => {
6965
7553
  const user = c.get("user");
6966
7554
  if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
6967
7555
  const db = c.env.DB;
@@ -6970,10 +7558,78 @@ apiRoutes3.get("/stats", chunkYYMPHM3I_cjs.requireAuth(), async (c) => {
6970
7558
  const stats = await subscriptionService.getStats();
6971
7559
  return c.json(stats);
6972
7560
  });
7561
+ apiRoutes3.post("/sync-subscriptions", chunkCZ6BVQZX_cjs.requireAuth(), async (c) => {
7562
+ const user = c.get("user");
7563
+ if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
7564
+ const db = c.env.DB;
7565
+ const settings = await getSettings4(db);
7566
+ if (!settings.stripeSecretKey) {
7567
+ return c.json({ error: "Stripe secret key not configured" }, 400);
7568
+ }
7569
+ const stripeApi = new StripeAPI(settings.stripeSecretKey);
7570
+ const subscriptionService = new SubscriptionService(db);
7571
+ await subscriptionService.ensureTable();
7572
+ try {
7573
+ const allSubs = await stripeApi.listAllSubscriptions();
7574
+ let synced = 0;
7575
+ let errors = 0;
7576
+ for (const sub of allSubs) {
7577
+ try {
7578
+ const userId = sub.metadata?.sonicjs_user_id || await subscriptionService.getUserIdByStripeCustomer(sub.customer) || "";
7579
+ await subscriptionService.upsert({
7580
+ userId,
7581
+ stripeCustomerId: typeof sub.customer === "string" ? sub.customer : sub.customer.id,
7582
+ stripeSubscriptionId: sub.id,
7583
+ stripePriceId: sub.items?.data?.[0]?.price?.id || "",
7584
+ status: mapStripeStatus(sub.status),
7585
+ currentPeriodStart: sub.current_period_start,
7586
+ currentPeriodEnd: sub.current_period_end,
7587
+ cancelAtPeriodEnd: sub.cancel_at_period_end
7588
+ });
7589
+ synced++;
7590
+ } catch (err) {
7591
+ console.error(`[Stripe Sync] Failed to upsert subscription ${sub.id}:`, err);
7592
+ errors++;
7593
+ }
7594
+ }
7595
+ return c.json({
7596
+ success: true,
7597
+ total: allSubs.length,
7598
+ synced,
7599
+ errors
7600
+ });
7601
+ } catch (error) {
7602
+ console.error("[Stripe Sync] Error:", error);
7603
+ return c.json({
7604
+ success: false,
7605
+ error: error instanceof Error ? error.message : "Sync failed"
7606
+ }, 500);
7607
+ }
7608
+ });
7609
+ apiRoutes3.get("/events", chunkCZ6BVQZX_cjs.requireAuth(), async (c) => {
7610
+ const user = c.get("user");
7611
+ if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
7612
+ const db = c.env.DB;
7613
+ const eventService = new StripeEventService(db);
7614
+ await eventService.ensureTable();
7615
+ const filters = {
7616
+ type: c.req.query("type") || void 0,
7617
+ status: c.req.query("status") || void 0,
7618
+ objectId: c.req.query("objectId") || void 0,
7619
+ page: c.req.query("page") ? parseInt(c.req.query("page")) : 1,
7620
+ limit: c.req.query("limit") ? parseInt(c.req.query("limit")) : 50
7621
+ };
7622
+ const [result, stats, types] = await Promise.all([
7623
+ eventService.list(filters),
7624
+ eventService.getStats(),
7625
+ eventService.getDistinctTypes()
7626
+ ]);
7627
+ return c.json({ ...result, stats, types });
7628
+ });
6973
7629
 
6974
7630
  // src/plugins/core-plugins/stripe-plugin/index.ts
6975
7631
  function createStripePlugin() {
6976
- const builder = chunk6FHNRRJ3_cjs.PluginBuilder.create({
7632
+ const builder = chunk635JAMSE_cjs.PluginBuilder.create({
6977
7633
  name: "stripe",
6978
7634
  version: "1.0.0-beta.1",
6979
7635
  description: "Stripe subscription management with webhook handling, checkout sessions, and subscription gating"
@@ -7016,13 +7672,35 @@ function createStripePlugin() {
7016
7672
  var stripePlugin = createStripePlugin();
7017
7673
 
7018
7674
  // src/middleware/plugin-menu.ts
7019
- var MENU_PLUGINS = [
7020
- securityAuditPlugin
7021
- ];
7675
+ var REGISTRY_MENU_PLUGINS = Object.values(chunkQ5VFZUXV_cjs.PLUGIN_REGISTRY).filter((p) => p.adminMenu !== null).map((p) => ({
7676
+ codeName: p.codeName,
7677
+ label: p.adminMenu.label,
7678
+ path: p.adminMenu.path,
7679
+ icon: p.adminMenu.icon,
7680
+ order: p.adminMenu.order
7681
+ }));
7682
+ var ICON_SVG = {
7683
+ "magnifying-glass": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/></svg>',
7684
+ "chart-bar": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z"/></svg>',
7685
+ "image": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z"/></svg>',
7686
+ "palette": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.098 19.902a3.75 3.75 0 0 0 5.304 0l6.401-6.402M6.75 21A3.75 3.75 0 0 1 3 17.25V4.125C3 3.504 3.504 3 4.125 3h5.25c.621 0 1.125.504 1.125 1.125v4.072M6.75 21a3.75 3.75 0 0 0 3.75-3.75V8.197M6.75 21h13.125c.621 0 1.125-.504 1.125-1.125v-5.25c0-.621-.504-1.125-1.125-1.125h-4.072M10.5 8.197l2.88-2.88c.438-.439 1.15-.439 1.59 0l3.712 3.713c.44.44.44 1.152 0 1.59l-2.879 2.88M6.75 17.25h.008v.008H6.75v-.008Z"/></svg>',
7687
+ "envelope": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75"/></svg>',
7688
+ "hand-raised": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.05 4.575a1.575 1.575 0 1 0-3.15 0v3m3.15-3v-1.5a1.575 1.575 0 0 1 3.15 0v1.5m-3.15 0 .075 5.925m3.075-5.925v2.925m0-2.925a1.575 1.575 0 0 1 3.15 0V9.9m-3.15-2.4v5.325M16.5 9.9a1.575 1.575 0 0 1 3.15 0V15a6.15 6.15 0 0 1-6.15 6.15H12A6.15 6.15 0 0 1 5.85 15V9.525"/></svg>',
7689
+ "key": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.75 5.25a3 3 0 0 1 3 3m3 0a6 6 0 0 1-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1 1 21.75 8.25Z"/></svg>',
7690
+ "arrow-right": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3"/></svg>',
7691
+ "shield-check": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/></svg>',
7692
+ "credit-card": '<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 8.25h19.5M2.25 9h19.5m-16.5 5.25h6m-6 2.25h3m-3.75 3h15a2.25 2.25 0 0 0 2.25-2.25V6.75A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25v10.5A2.25 2.25 0 0 0 4.5 19.5Z"/></svg>'
7693
+ };
7694
+ function resolveIcon(iconName) {
7695
+ if (!iconName) return "";
7696
+ if (iconName.startsWith("<svg") || iconName.startsWith("<")) return iconName;
7697
+ return ICON_SVG[iconName] || "";
7698
+ }
7022
7699
  var MARKER = "<!-- DYNAMIC_PLUGIN_MENU -->";
7023
7700
  function renderMenuItem(item, currentPath) {
7024
7701
  const isActive = currentPath === item.path || currentPath.startsWith(item.path);
7025
7702
  const fallbackIcon = `<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg>`;
7703
+ const resolvedIcon = resolveIcon(item.icon) || fallbackIcon;
7026
7704
  return `
7027
7705
  <span class="relative">
7028
7706
  ${isActive ? '<span class="absolute inset-y-2 -left-4 w-0.5 rounded-full bg-cyan-500 dark:bg-cyan-400"></span>' : ""}
@@ -7032,7 +7710,7 @@ function renderMenuItem(item, currentPath) {
7032
7710
  ${isActive ? 'data-current="true"' : ""}
7033
7711
  >
7034
7712
  <span class="shrink-0 ${isActive ? "fill-zinc-950 dark:fill-white" : "fill-zinc-500 dark:fill-zinc-400"}">
7035
- ${item.icon || fallbackIcon}
7713
+ ${resolvedIcon}
7036
7714
  </span>
7037
7715
  <span class="truncate">${item.label}</span>
7038
7716
  </a>
@@ -7047,23 +7725,28 @@ function pluginMenuMiddleware() {
7047
7725
  let activeMenuItems = [];
7048
7726
  try {
7049
7727
  const db = c.env.DB;
7050
- const pluginNames = MENU_PLUGINS.map((p) => p.name);
7051
- if (pluginNames.length > 0) {
7052
- const placeholders = pluginNames.map(() => "?").join(",");
7728
+ const pluginCodeNames = REGISTRY_MENU_PLUGINS.map((p) => p.codeName);
7729
+ if (pluginCodeNames.length > 0) {
7730
+ const placeholders = pluginCodeNames.map(() => "?").join(",");
7053
7731
  const result = await db.prepare(
7054
7732
  `SELECT name FROM plugins WHERE name IN (${placeholders}) AND status = 'active'`
7055
- ).bind(...pluginNames).all();
7733
+ ).bind(...pluginCodeNames).all();
7056
7734
  const activeNames = new Set((result.results || []).map((r) => r.name));
7057
- for (const plugin2 of MENU_PLUGINS) {
7058
- if (activeNames.has(plugin2.name) && plugin2.menuItems) {
7059
- activeMenuItems.push(...plugin2.menuItems);
7735
+ for (const plugin2 of REGISTRY_MENU_PLUGINS) {
7736
+ if (activeNames.has(plugin2.codeName)) {
7737
+ activeMenuItems.push({
7738
+ label: plugin2.label,
7739
+ path: plugin2.path,
7740
+ icon: plugin2.icon,
7741
+ order: plugin2.order
7742
+ });
7060
7743
  }
7061
7744
  }
7062
- activeMenuItems.sort((a, b) => (a.order || 0) - (b.order || 0));
7745
+ activeMenuItems.sort((a, b) => a.order - b.order);
7063
7746
  }
7064
7747
  } catch {
7065
7748
  }
7066
- c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: m.icon || "" })));
7749
+ c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: resolveIcon(m.icon) || "" })));
7067
7750
  await next();
7068
7751
  if (activeMenuItems.length > 0 && c.res.headers.get("content-type")?.includes("text/html")) {
7069
7752
  const status = c.res.status;
@@ -7080,6 +7763,672 @@ function pluginMenuMiddleware() {
7080
7763
  };
7081
7764
  }
7082
7765
 
7766
+ // src/plugins/types.ts
7767
+ var HOOKS2 = {
7768
+ // Request lifecycle
7769
+ REQUEST_START: "request:start",
7770
+ REQUEST_END: "request:end",
7771
+ USER_LOGIN: "user:login"};
7772
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
7773
+ var adminRoutes4 = new hono.Hono();
7774
+ adminRoutes4.use("*", chunkCZ6BVQZX_cjs.requireAuth());
7775
+ adminRoutes4.use("*", async (c, next) => {
7776
+ const user = c.get("user");
7777
+ if (user?.role !== "admin") {
7778
+ return c.text("Access denied", 403);
7779
+ }
7780
+ return next();
7781
+ });
7782
+ adminRoutes4.get("/", async (c) => {
7783
+ const user = c.get("user");
7784
+ const db = c.env.DB;
7785
+ let totalRequests = 0;
7786
+ let uniqueIPs = 0;
7787
+ let avgDuration = 0;
7788
+ let errorCount = 0;
7789
+ let topPages = [];
7790
+ let recentActivity = [];
7791
+ try {
7792
+ const now = Math.floor(Date.now() / 1e3);
7793
+ const dayAgo = now - 86400;
7794
+ const [requestsResult, ipsResult, durationResult, errorsResult, pagesResult, activityResult] = await Promise.all([
7795
+ db.prepare("SELECT COUNT(*) as count FROM system_logs WHERE category = ? AND created_at > ?").bind("api", dayAgo).first(),
7796
+ db.prepare("SELECT COUNT(DISTINCT ip_address) as count FROM system_logs WHERE category = ? AND created_at > ?").bind("api", dayAgo).first(),
7797
+ db.prepare("SELECT AVG(duration) as avg FROM system_logs WHERE category = ? AND created_at > ? AND duration IS NOT NULL").bind("api", dayAgo).first(),
7798
+ db.prepare("SELECT COUNT(*) as count FROM system_logs WHERE level IN (?, ?) AND created_at > ?").bind("error", "fatal", dayAgo).first(),
7799
+ db.prepare("SELECT url, COUNT(*) as views FROM system_logs WHERE category = ? AND created_at > ? AND url IS NOT NULL GROUP BY url ORDER BY views DESC LIMIT 10").bind("api", dayAgo).all(),
7800
+ db.prepare("SELECT url, method, status_code, duration, created_at FROM system_logs WHERE category = ? ORDER BY created_at DESC LIMIT 20").bind("api").all()
7801
+ ]);
7802
+ totalRequests = requestsResult?.count || 0;
7803
+ uniqueIPs = ipsResult?.count || 0;
7804
+ avgDuration = Math.round(durationResult?.avg || 0);
7805
+ errorCount = errorsResult?.count || 0;
7806
+ topPages = (pagesResult.results || []).map((r) => ({ path: r.url, views: r.views }));
7807
+ recentActivity = activityResult.results || [];
7808
+ } catch {
7809
+ }
7810
+ const content2 = `
7811
+ <div class="space-y-8">
7812
+ <div>
7813
+ <h1 class="text-2xl font-semibold text-zinc-950 dark:text-white">Analytics Dashboard</h1>
7814
+ <p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">Last 24 hours overview from system logs</p>
7815
+ </div>
7816
+
7817
+ <!-- Stats Cards -->
7818
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
7819
+ <div class="rounded-lg bg-white dark:bg-zinc-800 p-6 ring-1 ring-zinc-950/5 dark:ring-white/10">
7820
+ <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Total Requests</p>
7821
+ <p class="mt-2 text-3xl font-semibold text-zinc-950 dark:text-white">${totalRequests.toLocaleString()}</p>
7822
+ </div>
7823
+ <div class="rounded-lg bg-white dark:bg-zinc-800 p-6 ring-1 ring-zinc-950/5 dark:ring-white/10">
7824
+ <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Unique Visitors</p>
7825
+ <p class="mt-2 text-3xl font-semibold text-zinc-950 dark:text-white">${uniqueIPs.toLocaleString()}</p>
7826
+ </div>
7827
+ <div class="rounded-lg bg-white dark:bg-zinc-800 p-6 ring-1 ring-zinc-950/5 dark:ring-white/10">
7828
+ <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Avg Response Time</p>
7829
+ <p class="mt-2 text-3xl font-semibold text-zinc-950 dark:text-white">${avgDuration}ms</p>
7830
+ </div>
7831
+ <div class="rounded-lg bg-white dark:bg-zinc-800 p-6 ring-1 ring-zinc-950/5 dark:ring-white/10">
7832
+ <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Errors</p>
7833
+ <p class="mt-2 text-3xl font-semibold ${errorCount > 0 ? "text-red-600 dark:text-red-400" : "text-zinc-950 dark:text-white"}">${errorCount.toLocaleString()}</p>
7834
+ </div>
7835
+ </div>
7836
+
7837
+ <!-- Top Pages -->
7838
+ <div class="rounded-lg bg-white dark:bg-zinc-800 ring-1 ring-zinc-950/5 dark:ring-white/10">
7839
+ <div class="px-6 py-4 border-b border-zinc-950/5 dark:border-white/10">
7840
+ <h2 class="text-lg font-semibold text-zinc-950 dark:text-white">Top Pages</h2>
7841
+ </div>
7842
+ <div class="divide-y divide-zinc-950/5 dark:divide-white/10">
7843
+ ${topPages.length > 0 ? topPages.map((p) => `
7844
+ <div class="flex items-center justify-between px-6 py-3">
7845
+ <span class="text-sm text-zinc-700 dark:text-zinc-300 font-mono truncate">${escapeHtml3(p.path)}</span>
7846
+ <span class="text-sm font-medium text-zinc-500 dark:text-zinc-400">${p.views}</span>
7847
+ </div>
7848
+ `).join("") : `
7849
+ <div class="px-6 py-8 text-center text-sm text-zinc-500 dark:text-zinc-400">
7850
+ No page views recorded yet. Analytics data will appear once requests are logged.
7851
+ </div>
7852
+ `}
7853
+ </div>
7854
+ </div>
7855
+
7856
+ <!-- Recent Activity -->
7857
+ <div class="rounded-lg bg-white dark:bg-zinc-800 ring-1 ring-zinc-950/5 dark:ring-white/10">
7858
+ <div class="px-6 py-4 border-b border-zinc-950/5 dark:border-white/10">
7859
+ <h2 class="text-lg font-semibold text-zinc-950 dark:text-white">Recent Activity</h2>
7860
+ </div>
7861
+ <div class="overflow-x-auto">
7862
+ <table class="w-full text-sm">
7863
+ <thead class="bg-zinc-50 dark:bg-zinc-800/50">
7864
+ <tr>
7865
+ <th class="px-6 py-2 text-left font-medium text-zinc-500 dark:text-zinc-400">Path</th>
7866
+ <th class="px-6 py-2 text-left font-medium text-zinc-500 dark:text-zinc-400">Method</th>
7867
+ <th class="px-6 py-2 text-left font-medium text-zinc-500 dark:text-zinc-400">Status</th>
7868
+ <th class="px-6 py-2 text-left font-medium text-zinc-500 dark:text-zinc-400">Duration</th>
7869
+ </tr>
7870
+ </thead>
7871
+ <tbody class="divide-y divide-zinc-950/5 dark:divide-white/10">
7872
+ ${recentActivity.length > 0 ? recentActivity.map((a) => `
7873
+ <tr>
7874
+ <td class="px-6 py-2 font-mono text-zinc-700 dark:text-zinc-300 truncate max-w-xs">${escapeHtml3(a.url || "")}</td>
7875
+ <td class="px-6 py-2"><span class="inline-flex items-center rounded px-1.5 py-0.5 text-xs font-medium ${a.method === "GET" ? "bg-green-50 text-green-700 dark:bg-green-900/30 dark:text-green-400" : "bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}">${a.method || ""}</span></td>
7876
+ <td class="px-6 py-2"><span class="inline-flex items-center rounded px-1.5 py-0.5 text-xs font-medium ${(a.status_code || 0) >= 400 ? "bg-red-50 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-green-50 text-green-700 dark:bg-green-900/30 dark:text-green-400"}">${a.status_code || ""}</span></td>
7877
+ <td class="px-6 py-2 text-zinc-500 dark:text-zinc-400">${a.duration || 0}ms</td>
7878
+ </tr>
7879
+ `).join("") : `
7880
+ <tr>
7881
+ <td colspan="4" class="px-6 py-8 text-center text-zinc-500 dark:text-zinc-400">No activity recorded yet.</td>
7882
+ </tr>
7883
+ `}
7884
+ </tbody>
7885
+ </table>
7886
+ </div>
7887
+ </div>
7888
+ </div>
7889
+ `;
7890
+ return c.html(chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst({
7891
+ title: "Analytics",
7892
+ pageTitle: "Analytics Dashboard",
7893
+ currentPath: "/admin/analytics",
7894
+ version: c.get("appVersion"),
7895
+ user: user ? {
7896
+ name: user.email.split("@")[0] || "Admin",
7897
+ email: user.email,
7898
+ role: user.role
7899
+ } : void 0,
7900
+ content: content2,
7901
+ dynamicMenuItems: c.get("pluginMenuItems")
7902
+ }));
7903
+ });
7904
+ function escapeHtml3(str) {
7905
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
7906
+ }
7907
+
7908
+ // src/plugins/core-plugins/analytics/index.ts
7909
+ function createAnalyticsPlugin() {
7910
+ const builder = chunk635JAMSE_cjs.PluginBuilder.create({
7911
+ name: "core-analytics",
7912
+ version: "1.0.0-beta.1",
7913
+ description: "Core analytics tracking and reporting plugin"
7914
+ });
7915
+ builder.metadata({
7916
+ author: {
7917
+ name: "SonicJS Team",
7918
+ email: "team@sonicjs.com"
7919
+ },
7920
+ license: "MIT",
7921
+ compatibility: "^0.1.0",
7922
+ dependencies: ["core-auth"]
7923
+ // Requires auth for admin access
7924
+ });
7925
+ const analyticsAPI = new hono.Hono();
7926
+ analyticsAPI.get("/stats", async (c) => {
7927
+ const timeRange = c.req.query("range") || "7d";
7928
+ c.req.query("metric") || "all";
7929
+ return c.json({
7930
+ message: "Analytics stats",
7931
+ data: {
7932
+ pageviews: 12500,
7933
+ uniqueVisitors: 3200,
7934
+ sessions: 4800,
7935
+ avgSessionDuration: 245,
7936
+ bounceRate: 0.35,
7937
+ topPages: [
7938
+ { path: "/", views: 3200 },
7939
+ { path: "/about", views: 1800 },
7940
+ { path: "/contact", views: 950 }
7941
+ ],
7942
+ timeRange
7943
+ }
7944
+ });
7945
+ });
7946
+ analyticsAPI.post("/track", async (c) => {
7947
+ const event = await c.req.json();
7948
+ console.info("Analytics event tracked:", event);
7949
+ return c.json({
7950
+ message: "Event tracked successfully",
7951
+ eventId: `event-${Date.now()}`
7952
+ });
7953
+ });
7954
+ analyticsAPI.get("/reports", async (c) => {
7955
+ const reportType = c.req.query("type") || "traffic";
7956
+ const startDate = c.req.query("start");
7957
+ const endDate = c.req.query("end");
7958
+ return c.json({
7959
+ message: "Analytics report",
7960
+ data: {
7961
+ reportType,
7962
+ dateRange: { start: startDate, end: endDate },
7963
+ data: []
7964
+ }
7965
+ });
7966
+ });
7967
+ analyticsAPI.get("/realtime", async (c) => {
7968
+ return c.json({
7969
+ message: "Real-time analytics",
7970
+ data: {
7971
+ activeUsers: 23,
7972
+ activePages: [
7973
+ { path: "/", users: 8 },
7974
+ { path: "/blog", users: 5 },
7975
+ { path: "/products", users: 4 }
7976
+ ],
7977
+ recentEvents: []
7978
+ }
7979
+ });
7980
+ });
7981
+ builder.addRoute("/api/analytics", analyticsAPI, {
7982
+ description: "Analytics tracking and reporting API",
7983
+ requiresAuth: true,
7984
+ roles: ["admin", "analytics:read"],
7985
+ priority: 3
7986
+ });
7987
+ builder.addRoute("/admin/analytics", adminRoutes4, {
7988
+ description: "Analytics admin dashboard",
7989
+ requiresAuth: true,
7990
+ priority: 50
7991
+ });
7992
+ builder.addSingleMiddleware("analytics-tracker", async (c, next) => {
7993
+ const start = Date.now();
7994
+ const path = c.req.path;
7995
+ const method = c.req.method;
7996
+ const userAgent = c.req.header("user-agent");
7997
+ const referer = c.req.header("referer");
7998
+ const ip = c.req.header("CF-Connecting-IP") || c.req.header("x-forwarded-for");
7999
+ await next();
8000
+ const duration = Date.now() - start;
8001
+ const status = c.res.status;
8002
+ const analyticsData = {
8003
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
8004
+ path,
8005
+ method,
8006
+ status,
8007
+ duration,
8008
+ userAgent,
8009
+ referer,
8010
+ ip,
8011
+ responseSize: c.res.headers.get("content-length") || 0
8012
+ };
8013
+ console.debug("Analytics tracking:", analyticsData);
8014
+ }, {
8015
+ description: "Track page views and request analytics",
8016
+ global: true,
8017
+ priority: 99
8018
+ // Run last to capture response data
8019
+ });
8020
+ builder.addService("analyticsService", {
8021
+ trackEvent: async (event) => {
8022
+ console.info("Tracking event:", event);
8023
+ return { eventId: `event-${Date.now()}` };
8024
+ },
8025
+ trackPageView: async (data) => {
8026
+ console.info("Tracking pageview:", data.path);
8027
+ return { viewId: `view-${Date.now()}` };
8028
+ },
8029
+ getStats: async (_timeRange) => {
8030
+ return {
8031
+ pageviews: 12500,
8032
+ sessions: 4800,
8033
+ uniqueVisitors: 3200
8034
+ };
8035
+ },
8036
+ generateReport: async (type, options) => {
8037
+ console.info(`Generating ${type} report with options:`, options);
8038
+ return { reportId: `report-${Date.now()}` };
8039
+ }
8040
+ }, {
8041
+ description: "Core analytics tracking service",
8042
+ singleton: true
8043
+ });
8044
+ const pageViewSchema = chunk635JAMSE_cjs.PluginHelpers.createSchema([
8045
+ { name: "path", type: "string", optional: false },
8046
+ { name: "title", type: "string", optional: true },
8047
+ { name: "referrer", type: "string", optional: true },
8048
+ { name: "userAgent", type: "string", optional: true },
8049
+ { name: "ipAddress", type: "string", optional: true },
8050
+ { name: "sessionId", type: "string", optional: true },
8051
+ { name: "userId", type: "number", optional: true },
8052
+ { name: "duration", type: "number", optional: true }
8053
+ ]);
8054
+ const eventSchema = chunk635JAMSE_cjs.PluginHelpers.createSchema([
8055
+ { name: "eventType", type: "string", optional: false },
8056
+ { name: "eventName", type: "string", optional: false },
8057
+ { name: "eventData", type: "object", optional: true },
8058
+ { name: "path", type: "string", optional: true },
8059
+ { name: "sessionId", type: "string", optional: true },
8060
+ { name: "userId", type: "number", optional: true }
8061
+ ]);
8062
+ const pageViewMigration = chunk635JAMSE_cjs.PluginHelpers.createMigration("analytics_pageviews", [
8063
+ { name: "id", type: "INTEGER", primaryKey: true },
8064
+ { name: "path", type: "TEXT", nullable: false },
8065
+ { name: "title", type: "TEXT", nullable: true },
8066
+ { name: "referrer", type: "TEXT", nullable: true },
8067
+ { name: "user_agent", type: "TEXT", nullable: true },
8068
+ { name: "ip_address", type: "TEXT", nullable: true },
8069
+ { name: "session_id", type: "TEXT", nullable: true },
8070
+ { name: "user_id", type: "INTEGER", nullable: true },
8071
+ { name: "duration", type: "INTEGER", nullable: true }
8072
+ ]);
8073
+ const eventMigration = chunk635JAMSE_cjs.PluginHelpers.createMigration("analytics_events", [
8074
+ { name: "id", type: "INTEGER", primaryKey: true },
8075
+ { name: "event_type", type: "TEXT", nullable: false },
8076
+ { name: "event_name", type: "TEXT", nullable: false },
8077
+ { name: "event_data", type: "TEXT", nullable: true },
8078
+ { name: "path", type: "TEXT", nullable: true },
8079
+ { name: "session_id", type: "TEXT", nullable: true },
8080
+ { name: "user_id", type: "INTEGER", nullable: true }
8081
+ ]);
8082
+ builder.addModel("PageView", {
8083
+ tableName: "analytics_pageviews",
8084
+ schema: pageViewSchema,
8085
+ migrations: [pageViewMigration]
8086
+ });
8087
+ builder.addModel("AnalyticsEvent", {
8088
+ tableName: "analytics_events",
8089
+ schema: eventSchema,
8090
+ migrations: [eventMigration]
8091
+ });
8092
+ builder.addHook(HOOKS2.REQUEST_START, async (data, _context) => {
8093
+ data.analytics = {
8094
+ startTime: Date.now(),
8095
+ sessionId: `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
8096
+ };
8097
+ return data;
8098
+ }, {
8099
+ priority: 1,
8100
+ description: "Initialize analytics tracking for requests"
8101
+ });
8102
+ builder.addHook(HOOKS2.REQUEST_END, async (data, _context) => {
8103
+ if (data.analytics) {
8104
+ const duration = Date.now() - data.analytics.startTime;
8105
+ console.debug(`Request completed in ${duration}ms`);
8106
+ }
8107
+ return data;
8108
+ }, {
8109
+ priority: 1,
8110
+ description: "Complete analytics tracking for requests"
8111
+ });
8112
+ builder.addHook(HOOKS2.USER_LOGIN, async (data, context) => {
8113
+ await context.services?.analyticsService?.trackEvent({
8114
+ eventType: "auth",
8115
+ eventName: "user_login",
8116
+ userId: data.userId,
8117
+ eventData: { loginMethod: data.method }
8118
+ });
8119
+ return data;
8120
+ }, {
8121
+ priority: 8,
8122
+ description: "Track user login events"
8123
+ });
8124
+ builder.addHook("content:view", async (data, context) => {
8125
+ await context.services?.analyticsService?.trackEvent({
8126
+ eventType: "content",
8127
+ eventName: "content_view",
8128
+ eventData: {
8129
+ contentId: data.id,
8130
+ contentType: data.type,
8131
+ title: data.title
8132
+ }
8133
+ });
8134
+ return data;
8135
+ }, {
8136
+ priority: 8,
8137
+ description: "Track content view events"
8138
+ });
8139
+ builder.addAdminPage(
8140
+ "/analytics",
8141
+ "Analytics Dashboard",
8142
+ "AnalyticsDashboardView",
8143
+ {
8144
+ description: "View analytics overview and key metrics",
8145
+ permissions: ["admin", "analytics:read"],
8146
+ icon: "chart-bar"
8147
+ }
8148
+ );
8149
+ builder.addAdminPage(
8150
+ "/analytics/reports",
8151
+ "Analytics Reports",
8152
+ "AnalyticsReportsView",
8153
+ {
8154
+ description: "Generate and view detailed analytics reports",
8155
+ permissions: ["admin", "analytics:read"],
8156
+ icon: "document-report"
8157
+ }
8158
+ );
8159
+ builder.addAdminPage(
8160
+ "/analytics/realtime",
8161
+ "Real-time Analytics",
8162
+ "AnalyticsRealtimeView",
8163
+ {
8164
+ description: "View real-time visitor activity",
8165
+ permissions: ["admin", "analytics:read"],
8166
+ icon: "lightning-bolt"
8167
+ }
8168
+ );
8169
+ builder.addAdminPage(
8170
+ "/analytics/settings",
8171
+ "Analytics Settings",
8172
+ "AnalyticsSettingsView",
8173
+ {
8174
+ description: "Configure analytics tracking and data collection",
8175
+ permissions: ["admin", "analytics:configure"],
8176
+ icon: "cog"
8177
+ }
8178
+ );
8179
+ builder.addMenuItem("Analytics", "/admin/analytics", {
8180
+ icon: "chart-bar",
8181
+ order: 40,
8182
+ permissions: ["admin", "analytics:read"]
8183
+ });
8184
+ builder.addMenuItem("Dashboard", "/admin/analytics", {
8185
+ icon: "chart-bar",
8186
+ parent: "Analytics",
8187
+ order: 1,
8188
+ permissions: ["admin", "analytics:read"]
8189
+ });
8190
+ builder.addMenuItem("Reports", "/admin/analytics/reports", {
8191
+ icon: "document-report",
8192
+ parent: "Analytics",
8193
+ order: 2,
8194
+ permissions: ["admin", "analytics:read"]
8195
+ });
8196
+ builder.addMenuItem("Real-time", "/admin/analytics/realtime", {
8197
+ icon: "lightning-bolt",
8198
+ parent: "Analytics",
8199
+ order: 3,
8200
+ permissions: ["admin", "analytics:read"]
8201
+ });
8202
+ builder.addMenuItem("Settings", "/admin/analytics/settings", {
8203
+ icon: "cog",
8204
+ parent: "Analytics",
8205
+ order: 4,
8206
+ permissions: ["admin", "analytics:configure"]
8207
+ });
8208
+ builder.lifecycle({
8209
+ install: async () => {
8210
+ console.info("Installing analytics plugin...");
8211
+ },
8212
+ activate: async () => {
8213
+ console.info("Activating analytics plugin...");
8214
+ },
8215
+ deactivate: async () => {
8216
+ console.info("Deactivating analytics plugin...");
8217
+ },
8218
+ configure: async (config) => {
8219
+ console.info("Configuring analytics plugin...", config);
8220
+ }
8221
+ });
8222
+ return builder.build();
8223
+ }
8224
+ var analyticsPlugin = createAnalyticsPlugin();
8225
+
8226
+ // src/plugins/core-plugins/analytics/services/event-tracking-service.ts
8227
+ var EventTrackingService = class {
8228
+ constructor(db) {
8229
+ this.db = db;
8230
+ }
8231
+ async trackEvent(input) {
8232
+ const id = crypto.randomUUID();
8233
+ const category = input.category || "user-activity";
8234
+ await this.db.prepare(`
8235
+ INSERT INTO analytics_events (id, event, category, properties, user_id, session_id, ip_address, user_agent, path)
8236
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
8237
+ `).bind(
8238
+ id,
8239
+ input.event,
8240
+ category,
8241
+ input.properties ? JSON.stringify(input.properties) : null,
8242
+ input.userId || null,
8243
+ input.sessionId || null,
8244
+ input.ipAddress || null,
8245
+ input.userAgent || null,
8246
+ input.path || null
8247
+ ).run();
8248
+ return id;
8249
+ }
8250
+ async trackBatch(events) {
8251
+ const ids = [];
8252
+ const stmts = events.map((input) => {
8253
+ const id = crypto.randomUUID();
8254
+ ids.push(id);
8255
+ const category = input.category || "user-activity";
8256
+ return this.db.prepare(`
8257
+ INSERT INTO analytics_events (id, event, category, properties, user_id, session_id, ip_address, user_agent, path)
8258
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
8259
+ `).bind(
8260
+ id,
8261
+ input.event,
8262
+ category,
8263
+ input.properties ? JSON.stringify(input.properties) : null,
8264
+ input.userId || null,
8265
+ input.sessionId || null,
8266
+ input.ipAddress || null,
8267
+ input.userAgent || null,
8268
+ input.path || null
8269
+ );
8270
+ });
8271
+ await this.db.batch(stmts);
8272
+ return ids;
8273
+ }
8274
+ async queryEvents(filters = {}) {
8275
+ const conditions = [];
8276
+ const params = [];
8277
+ if (filters.event) {
8278
+ conditions.push("event = ?");
8279
+ params.push(filters.event);
8280
+ }
8281
+ if (filters.category) {
8282
+ conditions.push("category = ?");
8283
+ params.push(filters.category);
8284
+ }
8285
+ if (filters.userId) {
8286
+ conditions.push("user_id = ?");
8287
+ params.push(filters.userId);
8288
+ }
8289
+ if (filters.sessionId) {
8290
+ conditions.push("session_id = ?");
8291
+ params.push(filters.sessionId);
8292
+ }
8293
+ if (filters.startDate) {
8294
+ conditions.push("created_at >= ?");
8295
+ params.push(filters.startDate);
8296
+ }
8297
+ if (filters.endDate) {
8298
+ conditions.push("created_at <= ?");
8299
+ params.push(filters.endDate);
8300
+ }
8301
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
8302
+ const limit = filters.limit || 50;
8303
+ const offset = filters.offset || 0;
8304
+ const [countResult, eventsResult] = await Promise.all([
8305
+ this.db.prepare(`SELECT COUNT(*) as total FROM analytics_events ${where}`).bind(...params).first(),
8306
+ this.db.prepare(`SELECT * FROM analytics_events ${where} ORDER BY created_at DESC LIMIT ? OFFSET ?`).bind(...params, limit, offset).all()
8307
+ ]);
8308
+ const events = (eventsResult.results || []).map((e) => ({
8309
+ ...e,
8310
+ properties: e.properties ? JSON.parse(e.properties) : null
8311
+ }));
8312
+ return { events, total: countResult?.total || 0 };
8313
+ }
8314
+ async getStats(startDate, endDate) {
8315
+ const conditions = [];
8316
+ const params = [];
8317
+ if (startDate) {
8318
+ conditions.push("created_at >= ?");
8319
+ params.push(startDate);
8320
+ }
8321
+ if (endDate) {
8322
+ conditions.push("created_at <= ?");
8323
+ params.push(endDate);
8324
+ }
8325
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
8326
+ const [totals, topEvents] = await Promise.all([
8327
+ this.db.prepare(`
8328
+ SELECT
8329
+ COUNT(*) as total_events,
8330
+ COUNT(DISTINCT user_id) as unique_users,
8331
+ COUNT(DISTINCT session_id) as unique_sessions
8332
+ FROM analytics_events ${where}
8333
+ `).bind(...params).first(),
8334
+ this.db.prepare(`
8335
+ SELECT event, COUNT(*) as count
8336
+ FROM analytics_events ${where}
8337
+ GROUP BY event ORDER BY count DESC LIMIT 20
8338
+ `).bind(...params).all()
8339
+ ]);
8340
+ return {
8341
+ totalEvents: totals?.total_events || 0,
8342
+ uniqueUsers: totals?.unique_users || 0,
8343
+ uniqueSessions: totals?.unique_sessions || 0,
8344
+ topEvents: (topEvents.results || []).map((r) => ({ event: r.event, count: r.count }))
8345
+ };
8346
+ }
8347
+ };
8348
+
8349
+ // src/plugins/core-plugins/analytics/routes/api.ts
8350
+ var apiRoutes4 = new hono.Hono();
8351
+ apiRoutes4.post("/", async (c) => {
8352
+ const db = c.env.DB;
8353
+ const service = new EventTrackingService(db);
8354
+ const ip = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for")?.split(",")[0]?.trim() || "unknown";
8355
+ const userAgent = c.req.header("user-agent") || "";
8356
+ const user = c.get("user");
8357
+ let body;
8358
+ try {
8359
+ body = await c.req.json();
8360
+ } catch {
8361
+ return c.json({ error: "Invalid JSON body" }, 400);
8362
+ }
8363
+ if (Array.isArray(body)) {
8364
+ if (body.length > 100) {
8365
+ return c.json({ error: "Batch size limit is 100 events" }, 400);
8366
+ }
8367
+ const events = body.map((e) => ({
8368
+ event: e.event,
8369
+ category: e.category || "user-activity",
8370
+ properties: e.properties,
8371
+ userId: user?.userId || e.userId,
8372
+ sessionId: e.sessionId,
8373
+ ipAddress: ip,
8374
+ userAgent,
8375
+ path: e.path
8376
+ }));
8377
+ const invalid = events.find((e) => !e.event || typeof e.event !== "string");
8378
+ if (invalid) {
8379
+ return c.json({ error: 'Each event must have an "event" string field' }, 400);
8380
+ }
8381
+ const ids = await service.trackBatch(events);
8382
+ return c.json({ success: true, eventIds: ids, count: ids.length });
8383
+ }
8384
+ if (!body.event || typeof body.event !== "string") {
8385
+ return c.json({ error: '"event" field is required and must be a string' }, 400);
8386
+ }
8387
+ const eventId = await service.trackEvent({
8388
+ event: body.event,
8389
+ category: body.category || "user-activity",
8390
+ properties: body.properties,
8391
+ userId: user?.userId || body.userId,
8392
+ sessionId: body.sessionId,
8393
+ ipAddress: ip,
8394
+ userAgent,
8395
+ path: body.path
8396
+ });
8397
+ return c.json({ success: true, eventId });
8398
+ });
8399
+ apiRoutes4.get("/", async (c) => {
8400
+ const user = c.get("user");
8401
+ if (!user || user.role !== "admin") {
8402
+ return c.json({ error: "Admin access required" }, 403);
8403
+ }
8404
+ const db = c.env.DB;
8405
+ const service = new EventTrackingService(db);
8406
+ const filters = {
8407
+ event: c.req.query("event") || void 0,
8408
+ category: c.req.query("category") || void 0,
8409
+ userId: c.req.query("userId") || void 0,
8410
+ sessionId: c.req.query("sessionId") || void 0,
8411
+ startDate: c.req.query("startDate") ? parseInt(c.req.query("startDate")) : void 0,
8412
+ endDate: c.req.query("endDate") ? parseInt(c.req.query("endDate")) : void 0,
8413
+ limit: c.req.query("limit") ? parseInt(c.req.query("limit")) : 50,
8414
+ offset: c.req.query("offset") ? parseInt(c.req.query("offset")) : 0
8415
+ };
8416
+ const result = await service.queryEvents(filters);
8417
+ return c.json(result);
8418
+ });
8419
+ apiRoutes4.get("/stats", async (c) => {
8420
+ const user = c.get("user");
8421
+ if (!user || user.role !== "admin") {
8422
+ return c.json({ error: "Admin access required" }, 403);
8423
+ }
8424
+ const db = c.env.DB;
8425
+ const service = new EventTrackingService(db);
8426
+ const startDate = c.req.query("startDate") ? parseInt(c.req.query("startDate")) : void 0;
8427
+ const endDate = c.req.query("endDate") ? parseInt(c.req.query("endDate")) : void 0;
8428
+ const stats = await service.getStats(startDate, endDate);
8429
+ return c.json(stats);
8430
+ });
8431
+
7083
8432
  // src/plugins/cache/services/cache-config.ts
7084
8433
  var CACHE_CONFIGS = {
7085
8434
  // Content (high read, low write)
@@ -8042,7 +9391,7 @@ async function warmNamespace(namespace, entries) {
8042
9391
  }
8043
9392
 
8044
9393
  // src/templates/pages/admin-cache.template.ts
8045
- chunkQP3OHHON_cjs.init_admin_layout_catalyst_template();
9394
+ chunkUYJ6TJHX_cjs.init_admin_layout_catalyst_template();
8046
9395
  function renderCacheDashboard(data) {
8047
9396
  const pageContent = `
8048
9397
  <div class="space-y-6">
@@ -8221,7 +9570,7 @@ function renderCacheDashboard(data) {
8221
9570
  </script>
8222
9571
 
8223
9572
  <!-- Confirmation Dialogs -->
8224
- ${chunkDRWSHIFG_cjs.renderConfirmationDialog({
9573
+ ${chunk6ENX7QSA_cjs.renderConfirmationDialog({
8225
9574
  id: "clear-all-cache-confirm",
8226
9575
  title: "Clear All Cache",
8227
9576
  message: "Are you sure you want to clear all cache entries? This cannot be undone.",
@@ -8232,7 +9581,7 @@ function renderCacheDashboard(data) {
8232
9581
  onConfirm: "performClearAllCaches()"
8233
9582
  })}
8234
9583
 
8235
- ${chunkDRWSHIFG_cjs.renderConfirmationDialog({
9584
+ ${chunk6ENX7QSA_cjs.renderConfirmationDialog({
8236
9585
  id: "clear-namespace-cache-confirm",
8237
9586
  title: "Clear Namespace Cache",
8238
9587
  message: "Clear cache for this namespace?",
@@ -8243,7 +9592,7 @@ function renderCacheDashboard(data) {
8243
9592
  onConfirm: "performClearNamespaceCache()"
8244
9593
  })}
8245
9594
 
8246
- ${chunkDRWSHIFG_cjs.getConfirmationDialogScript()}
9595
+ ${chunk6ENX7QSA_cjs.getConfirmationDialogScript()}
8247
9596
  `;
8248
9597
  const layoutData = {
8249
9598
  title: "Cache System",
@@ -8253,7 +9602,7 @@ function renderCacheDashboard(data) {
8253
9602
  version: data.version,
8254
9603
  content: pageContent
8255
9604
  };
8256
- return chunkQP3OHHON_cjs.renderAdminLayoutCatalyst(layoutData);
9605
+ return chunkUYJ6TJHX_cjs.renderAdminLayoutCatalyst(layoutData);
8257
9606
  }
8258
9607
  function renderStatCard(label, value, color, icon, colorOverride) {
8259
9608
  const finalColor = colorOverride || color;
@@ -8929,14 +10278,14 @@ var faviconSvg = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
8929
10278
  // src/app.ts
8930
10279
  function createSonicJSApp(config = {}) {
8931
10280
  const app2 = new hono.Hono();
8932
- const appVersion = config.version || chunkYULUPQZV_cjs.getCoreVersion();
10281
+ const appVersion = config.version || chunkYQW2GCJ3_cjs.getCoreVersion();
8933
10282
  const appName = config.name || "SonicJS AI";
8934
10283
  app2.use("*", async (c, next) => {
8935
10284
  c.set("appVersion", appVersion);
8936
10285
  await next();
8937
10286
  });
8938
- app2.use("*", chunkYYMPHM3I_cjs.metricsMiddleware());
8939
- app2.use("*", chunkYYMPHM3I_cjs.bootstrapMiddleware(config));
10287
+ app2.use("*", chunkCZ6BVQZX_cjs.metricsMiddleware());
10288
+ app2.use("*", chunkCZ6BVQZX_cjs.bootstrapMiddleware(config));
8940
10289
  if (config.middleware?.beforeAuth) {
8941
10290
  for (const middleware of config.middleware.beforeAuth) {
8942
10291
  app2.use("*", middleware);
@@ -8945,29 +10294,29 @@ function createSonicJSApp(config = {}) {
8945
10294
  app2.use("*", async (_c, next) => {
8946
10295
  await next();
8947
10296
  });
8948
- app2.use("*", chunkYYMPHM3I_cjs.securityHeadersMiddleware());
8949
- app2.use("*", chunkYYMPHM3I_cjs.csrfProtection());
10297
+ app2.use("*", chunkCZ6BVQZX_cjs.securityHeadersMiddleware());
10298
+ app2.use("*", chunkCZ6BVQZX_cjs.csrfProtection());
8950
10299
  if (config.middleware?.afterAuth) {
8951
10300
  for (const middleware of config.middleware.afterAuth) {
8952
10301
  app2.use("*", middleware);
8953
10302
  }
8954
10303
  }
8955
10304
  app2.use("/admin/*", pluginMenuMiddleware());
8956
- app2.route("/api", chunkDRWSHIFG_cjs.api_default);
8957
- app2.route("/api/media", chunkDRWSHIFG_cjs.api_media_default);
8958
- app2.route("/api/system", chunkDRWSHIFG_cjs.api_system_default);
8959
- app2.route("/admin/api", chunkDRWSHIFG_cjs.admin_api_default);
8960
- app2.route("/admin/dashboard", chunkDRWSHIFG_cjs.router);
8961
- app2.route("/admin/collections", chunkDRWSHIFG_cjs.adminCollectionsRoutes);
8962
- app2.route("/admin/forms", chunkDRWSHIFG_cjs.adminFormsRoutes);
8963
- app2.route("/admin/settings", chunkDRWSHIFG_cjs.adminSettingsRoutes);
8964
- app2.route("/forms", chunkDRWSHIFG_cjs.public_forms_default);
8965
- app2.route("/api/forms", chunkDRWSHIFG_cjs.public_forms_default);
8966
- app2.route("/admin/api-reference", chunkDRWSHIFG_cjs.router2);
10305
+ app2.route("/api", chunk6ENX7QSA_cjs.api_default);
10306
+ app2.route("/api/media", chunk6ENX7QSA_cjs.api_media_default);
10307
+ app2.route("/api/system", chunk6ENX7QSA_cjs.api_system_default);
10308
+ app2.route("/admin/api", chunk6ENX7QSA_cjs.admin_api_default);
10309
+ app2.route("/admin/dashboard", chunk6ENX7QSA_cjs.router);
10310
+ app2.route("/admin/collections", chunk6ENX7QSA_cjs.adminCollectionsRoutes);
10311
+ app2.route("/admin/forms", chunk6ENX7QSA_cjs.adminFormsRoutes);
10312
+ app2.route("/admin/settings", chunk6ENX7QSA_cjs.adminSettingsRoutes);
10313
+ app2.route("/forms", chunk6ENX7QSA_cjs.public_forms_default);
10314
+ app2.route("/api/forms", chunk6ENX7QSA_cjs.public_forms_default);
10315
+ app2.route("/admin/api-reference", chunk6ENX7QSA_cjs.router2);
8967
10316
  app2.route("/admin/database-tools", createDatabaseToolsAdminRoutes());
8968
10317
  app2.route("/admin/seed-data", createSeedDataAdminRoutes());
8969
- app2.route("/admin/content", chunkDRWSHIFG_cjs.admin_content_default);
8970
- app2.route("/admin/media", chunkDRWSHIFG_cjs.adminMediaRoutes);
10318
+ app2.route("/admin/content", chunk6ENX7QSA_cjs.admin_content_default);
10319
+ app2.route("/admin/media", chunk6ENX7QSA_cjs.adminMediaRoutes);
8971
10320
  app2.use("/auth/*", securityAuditMiddleware());
8972
10321
  if (securityAuditPlugin.routes && securityAuditPlugin.routes.length > 0) {
8973
10322
  for (const route of securityAuditPlugin.routes) {
@@ -8985,8 +10334,8 @@ function createSonicJSApp(config = {}) {
8985
10334
  app2.route(route.path, route.handler);
8986
10335
  }
8987
10336
  }
8988
- if (chunkDRWSHIFG_cjs.userProfilesPlugin.routes && chunkDRWSHIFG_cjs.userProfilesPlugin.routes.length > 0) {
8989
- for (const route of chunkDRWSHIFG_cjs.userProfilesPlugin.routes) {
10337
+ if (chunk6ENX7QSA_cjs.userProfilesPlugin.routes && chunk6ENX7QSA_cjs.userProfilesPlugin.routes.length > 0) {
10338
+ for (const route of chunk6ENX7QSA_cjs.userProfilesPlugin.routes) {
8990
10339
  app2.route(route.path, route.handler);
8991
10340
  }
8992
10341
  }
@@ -8995,16 +10344,22 @@ function createSonicJSApp(config = {}) {
8995
10344
  app2.route(route.path, route.handler);
8996
10345
  }
8997
10346
  }
8998
- app2.route("/admin/plugins", chunkDRWSHIFG_cjs.adminPluginRoutes);
8999
- app2.route("/admin/logs", chunkDRWSHIFG_cjs.adminLogsRoutes);
9000
- app2.route("/admin", chunkDRWSHIFG_cjs.userRoutes);
9001
- app2.route("/auth", chunkDRWSHIFG_cjs.auth_default);
9002
- app2.route("/", chunkDRWSHIFG_cjs.test_cleanup_default);
10347
+ if (analyticsPlugin.routes && analyticsPlugin.routes.length > 0) {
10348
+ for (const route of analyticsPlugin.routes) {
10349
+ app2.route(route.path, route.handler);
10350
+ }
10351
+ }
10352
+ app2.route("/api/events", apiRoutes4);
9003
10353
  if (stripePlugin.routes && stripePlugin.routes.length > 0) {
9004
10354
  for (const route of stripePlugin.routes) {
9005
10355
  app2.route(route.path, route.handler);
9006
10356
  }
9007
10357
  }
10358
+ app2.route("/admin/plugins", chunk6ENX7QSA_cjs.adminPluginRoutes);
10359
+ app2.route("/admin/logs", chunk6ENX7QSA_cjs.adminLogsRoutes);
10360
+ app2.route("/admin", chunk6ENX7QSA_cjs.userRoutes);
10361
+ app2.route("/auth", chunk6ENX7QSA_cjs.auth_default);
10362
+ app2.route("/", chunk6ENX7QSA_cjs.test_cleanup_default);
9008
10363
  if (emailPlugin.routes && emailPlugin.routes.length > 0) {
9009
10364
  for (const route of emailPlugin.routes) {
9010
10365
  app2.route(route.path, route.handler);
@@ -9088,99 +10443,99 @@ function createDb(d1$1) {
9088
10443
  }
9089
10444
 
9090
10445
  // src/index.ts
9091
- var VERSION = chunkYULUPQZV_cjs.package_default.version;
10446
+ var VERSION = chunkYQW2GCJ3_cjs.package_default.version;
9092
10447
 
9093
10448
  Object.defineProperty(exports, "ROUTES_INFO", {
9094
10449
  enumerable: true,
9095
- get: function () { return chunkDRWSHIFG_cjs.ROUTES_INFO; }
10450
+ get: function () { return chunk6ENX7QSA_cjs.ROUTES_INFO; }
9096
10451
  });
9097
10452
  Object.defineProperty(exports, "adminApiRoutes", {
9098
10453
  enumerable: true,
9099
- get: function () { return chunkDRWSHIFG_cjs.admin_api_default; }
10454
+ get: function () { return chunk6ENX7QSA_cjs.admin_api_default; }
9100
10455
  });
9101
10456
  Object.defineProperty(exports, "adminCheckboxRoutes", {
9102
10457
  enumerable: true,
9103
- get: function () { return chunkDRWSHIFG_cjs.adminCheckboxRoutes; }
10458
+ get: function () { return chunk6ENX7QSA_cjs.adminCheckboxRoutes; }
9104
10459
  });
9105
10460
  Object.defineProperty(exports, "adminCodeExamplesRoutes", {
9106
10461
  enumerable: true,
9107
- get: function () { return chunkDRWSHIFG_cjs.admin_code_examples_default; }
10462
+ get: function () { return chunk6ENX7QSA_cjs.admin_code_examples_default; }
9108
10463
  });
9109
10464
  Object.defineProperty(exports, "adminCollectionsRoutes", {
9110
10465
  enumerable: true,
9111
- get: function () { return chunkDRWSHIFG_cjs.adminCollectionsRoutes; }
10466
+ get: function () { return chunk6ENX7QSA_cjs.adminCollectionsRoutes; }
9112
10467
  });
9113
10468
  Object.defineProperty(exports, "adminContentRoutes", {
9114
10469
  enumerable: true,
9115
- get: function () { return chunkDRWSHIFG_cjs.admin_content_default; }
10470
+ get: function () { return chunk6ENX7QSA_cjs.admin_content_default; }
9116
10471
  });
9117
10472
  Object.defineProperty(exports, "adminDashboardRoutes", {
9118
10473
  enumerable: true,
9119
- get: function () { return chunkDRWSHIFG_cjs.router; }
10474
+ get: function () { return chunk6ENX7QSA_cjs.router; }
9120
10475
  });
9121
10476
  Object.defineProperty(exports, "adminDesignRoutes", {
9122
10477
  enumerable: true,
9123
- get: function () { return chunkDRWSHIFG_cjs.adminDesignRoutes; }
10478
+ get: function () { return chunk6ENX7QSA_cjs.adminDesignRoutes; }
9124
10479
  });
9125
10480
  Object.defineProperty(exports, "adminLogsRoutes", {
9126
10481
  enumerable: true,
9127
- get: function () { return chunkDRWSHIFG_cjs.adminLogsRoutes; }
10482
+ get: function () { return chunk6ENX7QSA_cjs.adminLogsRoutes; }
9128
10483
  });
9129
10484
  Object.defineProperty(exports, "adminMediaRoutes", {
9130
10485
  enumerable: true,
9131
- get: function () { return chunkDRWSHIFG_cjs.adminMediaRoutes; }
10486
+ get: function () { return chunk6ENX7QSA_cjs.adminMediaRoutes; }
9132
10487
  });
9133
10488
  Object.defineProperty(exports, "adminPluginRoutes", {
9134
10489
  enumerable: true,
9135
- get: function () { return chunkDRWSHIFG_cjs.adminPluginRoutes; }
10490
+ get: function () { return chunk6ENX7QSA_cjs.adminPluginRoutes; }
9136
10491
  });
9137
10492
  Object.defineProperty(exports, "adminSettingsRoutes", {
9138
10493
  enumerable: true,
9139
- get: function () { return chunkDRWSHIFG_cjs.adminSettingsRoutes; }
10494
+ get: function () { return chunk6ENX7QSA_cjs.adminSettingsRoutes; }
9140
10495
  });
9141
10496
  Object.defineProperty(exports, "adminTestimonialsRoutes", {
9142
10497
  enumerable: true,
9143
- get: function () { return chunkDRWSHIFG_cjs.admin_testimonials_default; }
10498
+ get: function () { return chunk6ENX7QSA_cjs.admin_testimonials_default; }
9144
10499
  });
9145
10500
  Object.defineProperty(exports, "adminUsersRoutes", {
9146
10501
  enumerable: true,
9147
- get: function () { return chunkDRWSHIFG_cjs.userRoutes; }
10502
+ get: function () { return chunk6ENX7QSA_cjs.userRoutes; }
9148
10503
  });
9149
10504
  Object.defineProperty(exports, "apiContentCrudRoutes", {
9150
10505
  enumerable: true,
9151
- get: function () { return chunkDRWSHIFG_cjs.api_content_crud_default; }
10506
+ get: function () { return chunk6ENX7QSA_cjs.api_content_crud_default; }
9152
10507
  });
9153
10508
  Object.defineProperty(exports, "apiMediaRoutes", {
9154
10509
  enumerable: true,
9155
- get: function () { return chunkDRWSHIFG_cjs.api_media_default; }
10510
+ get: function () { return chunk6ENX7QSA_cjs.api_media_default; }
9156
10511
  });
9157
10512
  Object.defineProperty(exports, "apiRoutes", {
9158
10513
  enumerable: true,
9159
- get: function () { return chunkDRWSHIFG_cjs.api_default; }
10514
+ get: function () { return chunk6ENX7QSA_cjs.api_default; }
9160
10515
  });
9161
10516
  Object.defineProperty(exports, "apiSystemRoutes", {
9162
10517
  enumerable: true,
9163
- get: function () { return chunkDRWSHIFG_cjs.api_system_default; }
10518
+ get: function () { return chunk6ENX7QSA_cjs.api_system_default; }
9164
10519
  });
9165
10520
  Object.defineProperty(exports, "authRoutes", {
9166
10521
  enumerable: true,
9167
- get: function () { return chunkDRWSHIFG_cjs.auth_default; }
10522
+ get: function () { return chunk6ENX7QSA_cjs.auth_default; }
9168
10523
  });
9169
10524
  Object.defineProperty(exports, "createUserProfilesPlugin", {
9170
10525
  enumerable: true,
9171
- get: function () { return chunkDRWSHIFG_cjs.createUserProfilesPlugin; }
10526
+ get: function () { return chunk6ENX7QSA_cjs.createUserProfilesPlugin; }
9172
10527
  });
9173
10528
  Object.defineProperty(exports, "defineUserProfile", {
9174
10529
  enumerable: true,
9175
- get: function () { return chunkDRWSHIFG_cjs.defineUserProfile; }
10530
+ get: function () { return chunk6ENX7QSA_cjs.defineUserProfile; }
9176
10531
  });
9177
10532
  Object.defineProperty(exports, "getUserProfileConfig", {
9178
10533
  enumerable: true,
9179
- get: function () { return chunkDRWSHIFG_cjs.getUserProfileConfig; }
10534
+ get: function () { return chunk6ENX7QSA_cjs.getUserProfileConfig; }
9180
10535
  });
9181
10536
  Object.defineProperty(exports, "userProfilesPlugin", {
9182
10537
  enumerable: true,
9183
- get: function () { return chunkDRWSHIFG_cjs.userProfilesPlugin; }
10538
+ get: function () { return chunk6ENX7QSA_cjs.userProfilesPlugin; }
9184
10539
  });
9185
10540
  Object.defineProperty(exports, "Logger", {
9186
10541
  enumerable: true,
@@ -9348,259 +10703,259 @@ Object.defineProperty(exports, "workflowHistory", {
9348
10703
  });
9349
10704
  Object.defineProperty(exports, "AuthManager", {
9350
10705
  enumerable: true,
9351
- get: function () { return chunkYYMPHM3I_cjs.AuthManager; }
10706
+ get: function () { return chunkCZ6BVQZX_cjs.AuthManager; }
9352
10707
  });
9353
10708
  Object.defineProperty(exports, "PermissionManager", {
9354
10709
  enumerable: true,
9355
- get: function () { return chunkYYMPHM3I_cjs.PermissionManager; }
10710
+ get: function () { return chunkCZ6BVQZX_cjs.PermissionManager; }
9356
10711
  });
9357
10712
  Object.defineProperty(exports, "bootstrapMiddleware", {
9358
10713
  enumerable: true,
9359
- get: function () { return chunkYYMPHM3I_cjs.bootstrapMiddleware; }
10714
+ get: function () { return chunkCZ6BVQZX_cjs.bootstrapMiddleware; }
9360
10715
  });
9361
10716
  Object.defineProperty(exports, "cacheHeaders", {
9362
10717
  enumerable: true,
9363
- get: function () { return chunkYYMPHM3I_cjs.cacheHeaders; }
10718
+ get: function () { return chunkCZ6BVQZX_cjs.cacheHeaders; }
9364
10719
  });
9365
10720
  Object.defineProperty(exports, "compressionMiddleware", {
9366
10721
  enumerable: true,
9367
- get: function () { return chunkYYMPHM3I_cjs.compressionMiddleware; }
10722
+ get: function () { return chunkCZ6BVQZX_cjs.compressionMiddleware; }
9368
10723
  });
9369
10724
  Object.defineProperty(exports, "detailedLoggingMiddleware", {
9370
10725
  enumerable: true,
9371
- get: function () { return chunkYYMPHM3I_cjs.detailedLoggingMiddleware; }
10726
+ get: function () { return chunkCZ6BVQZX_cjs.detailedLoggingMiddleware; }
9372
10727
  });
9373
10728
  Object.defineProperty(exports, "getActivePlugins", {
9374
10729
  enumerable: true,
9375
- get: function () { return chunkYYMPHM3I_cjs.getActivePlugins; }
10730
+ get: function () { return chunkCZ6BVQZX_cjs.getActivePlugins; }
9376
10731
  });
9377
10732
  Object.defineProperty(exports, "isPluginActive", {
9378
10733
  enumerable: true,
9379
- get: function () { return chunkYYMPHM3I_cjs.isPluginActive; }
10734
+ get: function () { return chunkCZ6BVQZX_cjs.isPluginActive; }
9380
10735
  });
9381
10736
  Object.defineProperty(exports, "logActivity", {
9382
10737
  enumerable: true,
9383
- get: function () { return chunkYYMPHM3I_cjs.logActivity; }
10738
+ get: function () { return chunkCZ6BVQZX_cjs.logActivity; }
9384
10739
  });
9385
10740
  Object.defineProperty(exports, "loggingMiddleware", {
9386
10741
  enumerable: true,
9387
- get: function () { return chunkYYMPHM3I_cjs.loggingMiddleware; }
10742
+ get: function () { return chunkCZ6BVQZX_cjs.loggingMiddleware; }
9388
10743
  });
9389
10744
  Object.defineProperty(exports, "optionalAuth", {
9390
10745
  enumerable: true,
9391
- get: function () { return chunkYYMPHM3I_cjs.optionalAuth; }
10746
+ get: function () { return chunkCZ6BVQZX_cjs.optionalAuth; }
9392
10747
  });
9393
10748
  Object.defineProperty(exports, "performanceLoggingMiddleware", {
9394
10749
  enumerable: true,
9395
- get: function () { return chunkYYMPHM3I_cjs.performanceLoggingMiddleware; }
10750
+ get: function () { return chunkCZ6BVQZX_cjs.performanceLoggingMiddleware; }
9396
10751
  });
9397
10752
  Object.defineProperty(exports, "requireActivePlugin", {
9398
10753
  enumerable: true,
9399
- get: function () { return chunkYYMPHM3I_cjs.requireActivePlugin; }
10754
+ get: function () { return chunkCZ6BVQZX_cjs.requireActivePlugin; }
9400
10755
  });
9401
10756
  Object.defineProperty(exports, "requireActivePlugins", {
9402
10757
  enumerable: true,
9403
- get: function () { return chunkYYMPHM3I_cjs.requireActivePlugins; }
10758
+ get: function () { return chunkCZ6BVQZX_cjs.requireActivePlugins; }
9404
10759
  });
9405
10760
  Object.defineProperty(exports, "requireAnyPermission", {
9406
10761
  enumerable: true,
9407
- get: function () { return chunkYYMPHM3I_cjs.requireAnyPermission; }
10762
+ get: function () { return chunkCZ6BVQZX_cjs.requireAnyPermission; }
9408
10763
  });
9409
10764
  Object.defineProperty(exports, "requireAuth", {
9410
10765
  enumerable: true,
9411
- get: function () { return chunkYYMPHM3I_cjs.requireAuth; }
10766
+ get: function () { return chunkCZ6BVQZX_cjs.requireAuth; }
9412
10767
  });
9413
10768
  Object.defineProperty(exports, "requirePermission", {
9414
10769
  enumerable: true,
9415
- get: function () { return chunkYYMPHM3I_cjs.requirePermission; }
10770
+ get: function () { return chunkCZ6BVQZX_cjs.requirePermission; }
9416
10771
  });
9417
10772
  Object.defineProperty(exports, "requireRole", {
9418
10773
  enumerable: true,
9419
- get: function () { return chunkYYMPHM3I_cjs.requireRole; }
10774
+ get: function () { return chunkCZ6BVQZX_cjs.requireRole; }
9420
10775
  });
9421
10776
  Object.defineProperty(exports, "securityHeaders", {
9422
10777
  enumerable: true,
9423
- get: function () { return chunkYYMPHM3I_cjs.securityHeadersMiddleware; }
10778
+ get: function () { return chunkCZ6BVQZX_cjs.securityHeadersMiddleware; }
9424
10779
  });
9425
10780
  Object.defineProperty(exports, "securityLoggingMiddleware", {
9426
10781
  enumerable: true,
9427
- get: function () { return chunkYYMPHM3I_cjs.securityLoggingMiddleware; }
10782
+ get: function () { return chunkCZ6BVQZX_cjs.securityLoggingMiddleware; }
9428
10783
  });
9429
10784
  Object.defineProperty(exports, "PluginBootstrapService", {
9430
10785
  enumerable: true,
9431
- get: function () { return chunkI6FFGQIT_cjs.PluginBootstrapService; }
10786
+ get: function () { return chunkQ5VFZUXV_cjs.PluginBootstrapService; }
9432
10787
  });
9433
10788
  Object.defineProperty(exports, "PluginServiceClass", {
9434
10789
  enumerable: true,
9435
- get: function () { return chunkI6FFGQIT_cjs.PluginService; }
10790
+ get: function () { return chunkQ5VFZUXV_cjs.PluginService; }
9436
10791
  });
9437
10792
  Object.defineProperty(exports, "backfillFormSubmissions", {
9438
10793
  enumerable: true,
9439
- get: function () { return chunkI6FFGQIT_cjs.backfillFormSubmissions; }
10794
+ get: function () { return chunkQ5VFZUXV_cjs.backfillFormSubmissions; }
9440
10795
  });
9441
10796
  Object.defineProperty(exports, "cleanupRemovedCollections", {
9442
10797
  enumerable: true,
9443
- get: function () { return chunkI6FFGQIT_cjs.cleanupRemovedCollections; }
10798
+ get: function () { return chunkQ5VFZUXV_cjs.cleanupRemovedCollections; }
9444
10799
  });
9445
10800
  Object.defineProperty(exports, "createContentFromSubmission", {
9446
10801
  enumerable: true,
9447
- get: function () { return chunkI6FFGQIT_cjs.createContentFromSubmission; }
10802
+ get: function () { return chunkQ5VFZUXV_cjs.createContentFromSubmission; }
9448
10803
  });
9449
10804
  Object.defineProperty(exports, "deriveCollectionSchemaFromFormio", {
9450
10805
  enumerable: true,
9451
- get: function () { return chunkI6FFGQIT_cjs.deriveCollectionSchemaFromFormio; }
10806
+ get: function () { return chunkQ5VFZUXV_cjs.deriveCollectionSchemaFromFormio; }
9452
10807
  });
9453
10808
  Object.defineProperty(exports, "deriveSubmissionTitle", {
9454
10809
  enumerable: true,
9455
- get: function () { return chunkI6FFGQIT_cjs.deriveSubmissionTitle; }
10810
+ get: function () { return chunkQ5VFZUXV_cjs.deriveSubmissionTitle; }
9456
10811
  });
9457
10812
  Object.defineProperty(exports, "fullCollectionSync", {
9458
10813
  enumerable: true,
9459
- get: function () { return chunkI6FFGQIT_cjs.fullCollectionSync; }
10814
+ get: function () { return chunkQ5VFZUXV_cjs.fullCollectionSync; }
9460
10815
  });
9461
10816
  Object.defineProperty(exports, "getAvailableCollectionNames", {
9462
10817
  enumerable: true,
9463
- get: function () { return chunkI6FFGQIT_cjs.getAvailableCollectionNames; }
10818
+ get: function () { return chunkQ5VFZUXV_cjs.getAvailableCollectionNames; }
9464
10819
  });
9465
10820
  Object.defineProperty(exports, "getManagedCollections", {
9466
10821
  enumerable: true,
9467
- get: function () { return chunkI6FFGQIT_cjs.getManagedCollections; }
10822
+ get: function () { return chunkQ5VFZUXV_cjs.getManagedCollections; }
9468
10823
  });
9469
10824
  Object.defineProperty(exports, "isCollectionManaged", {
9470
10825
  enumerable: true,
9471
- get: function () { return chunkI6FFGQIT_cjs.isCollectionManaged; }
10826
+ get: function () { return chunkQ5VFZUXV_cjs.isCollectionManaged; }
9472
10827
  });
9473
10828
  Object.defineProperty(exports, "loadCollectionConfig", {
9474
10829
  enumerable: true,
9475
- get: function () { return chunkI6FFGQIT_cjs.loadCollectionConfig; }
10830
+ get: function () { return chunkQ5VFZUXV_cjs.loadCollectionConfig; }
9476
10831
  });
9477
10832
  Object.defineProperty(exports, "loadCollectionConfigs", {
9478
10833
  enumerable: true,
9479
- get: function () { return chunkI6FFGQIT_cjs.loadCollectionConfigs; }
10834
+ get: function () { return chunkQ5VFZUXV_cjs.loadCollectionConfigs; }
9480
10835
  });
9481
10836
  Object.defineProperty(exports, "mapFormStatusToContentStatus", {
9482
10837
  enumerable: true,
9483
- get: function () { return chunkI6FFGQIT_cjs.mapFormStatusToContentStatus; }
10838
+ get: function () { return chunkQ5VFZUXV_cjs.mapFormStatusToContentStatus; }
9484
10839
  });
9485
10840
  Object.defineProperty(exports, "registerCollections", {
9486
10841
  enumerable: true,
9487
- get: function () { return chunkI6FFGQIT_cjs.registerCollections; }
10842
+ get: function () { return chunkQ5VFZUXV_cjs.registerCollections; }
9488
10843
  });
9489
10844
  Object.defineProperty(exports, "syncAllFormCollections", {
9490
10845
  enumerable: true,
9491
- get: function () { return chunkI6FFGQIT_cjs.syncAllFormCollections; }
10846
+ get: function () { return chunkQ5VFZUXV_cjs.syncAllFormCollections; }
9492
10847
  });
9493
10848
  Object.defineProperty(exports, "syncCollection", {
9494
10849
  enumerable: true,
9495
- get: function () { return chunkI6FFGQIT_cjs.syncCollection; }
10850
+ get: function () { return chunkQ5VFZUXV_cjs.syncCollection; }
9496
10851
  });
9497
10852
  Object.defineProperty(exports, "syncCollections", {
9498
10853
  enumerable: true,
9499
- get: function () { return chunkI6FFGQIT_cjs.syncCollections; }
10854
+ get: function () { return chunkQ5VFZUXV_cjs.syncCollections; }
9500
10855
  });
9501
10856
  Object.defineProperty(exports, "syncFormCollection", {
9502
10857
  enumerable: true,
9503
- get: function () { return chunkI6FFGQIT_cjs.syncFormCollection; }
10858
+ get: function () { return chunkQ5VFZUXV_cjs.syncFormCollection; }
9504
10859
  });
9505
10860
  Object.defineProperty(exports, "validateCollectionConfig", {
9506
10861
  enumerable: true,
9507
- get: function () { return chunkI6FFGQIT_cjs.validateCollectionConfig; }
10862
+ get: function () { return chunkQ5VFZUXV_cjs.validateCollectionConfig; }
9508
10863
  });
9509
10864
  Object.defineProperty(exports, "MigrationService", {
9510
10865
  enumerable: true,
9511
- get: function () { return chunkKZ2MFGET_cjs.MigrationService; }
10866
+ get: function () { return chunkOCLUXJ7E_cjs.MigrationService; }
9512
10867
  });
9513
10868
  Object.defineProperty(exports, "renderFilterBar", {
9514
10869
  enumerable: true,
9515
- get: function () { return chunk3QCEYJLK_cjs.renderFilterBar; }
10870
+ get: function () { return chunk4ZSNJDLS_cjs.renderFilterBar; }
9516
10871
  });
9517
10872
  Object.defineProperty(exports, "getConfirmationDialogScript", {
9518
10873
  enumerable: true,
9519
- get: function () { return chunkQP3OHHON_cjs.getConfirmationDialogScript; }
10874
+ get: function () { return chunkOHYBNCVL_cjs.getConfirmationDialogScript; }
9520
10875
  });
9521
10876
  Object.defineProperty(exports, "renderAlert", {
9522
10877
  enumerable: true,
9523
- get: function () { return chunkQP3OHHON_cjs.renderAlert; }
10878
+ get: function () { return chunkOHYBNCVL_cjs.renderAlert; }
9524
10879
  });
9525
10880
  Object.defineProperty(exports, "renderConfirmationDialog", {
9526
10881
  enumerable: true,
9527
- get: function () { return chunkQP3OHHON_cjs.renderConfirmationDialog; }
10882
+ get: function () { return chunkOHYBNCVL_cjs.renderConfirmationDialog; }
9528
10883
  });
9529
10884
  Object.defineProperty(exports, "renderForm", {
9530
10885
  enumerable: true,
9531
- get: function () { return chunkQP3OHHON_cjs.renderForm; }
10886
+ get: function () { return chunkOHYBNCVL_cjs.renderForm; }
9532
10887
  });
9533
10888
  Object.defineProperty(exports, "renderFormField", {
9534
10889
  enumerable: true,
9535
- get: function () { return chunkQP3OHHON_cjs.renderFormField; }
10890
+ get: function () { return chunkOHYBNCVL_cjs.renderFormField; }
9536
10891
  });
9537
10892
  Object.defineProperty(exports, "renderPagination", {
9538
10893
  enumerable: true,
9539
- get: function () { return chunkQP3OHHON_cjs.renderPagination; }
10894
+ get: function () { return chunkOHYBNCVL_cjs.renderPagination; }
9540
10895
  });
9541
10896
  Object.defineProperty(exports, "renderTable", {
9542
10897
  enumerable: true,
9543
- get: function () { return chunkQP3OHHON_cjs.renderTable; }
10898
+ get: function () { return chunkOHYBNCVL_cjs.renderTable; }
9544
10899
  });
9545
10900
  Object.defineProperty(exports, "HookSystemImpl", {
9546
10901
  enumerable: true,
9547
- get: function () { return chunk56GUBLJE_cjs.HookSystemImpl; }
10902
+ get: function () { return chunkABB34XUS_cjs.HookSystemImpl; }
9548
10903
  });
9549
10904
  Object.defineProperty(exports, "HookUtils", {
9550
10905
  enumerable: true,
9551
- get: function () { return chunk56GUBLJE_cjs.HookUtils; }
10906
+ get: function () { return chunkABB34XUS_cjs.HookUtils; }
9552
10907
  });
9553
10908
  Object.defineProperty(exports, "PluginManagerClass", {
9554
10909
  enumerable: true,
9555
- get: function () { return chunk56GUBLJE_cjs.PluginManager; }
10910
+ get: function () { return chunkABB34XUS_cjs.PluginManager; }
9556
10911
  });
9557
10912
  Object.defineProperty(exports, "PluginRegistryImpl", {
9558
10913
  enumerable: true,
9559
- get: function () { return chunk56GUBLJE_cjs.PluginRegistryImpl; }
10914
+ get: function () { return chunkABB34XUS_cjs.PluginRegistryImpl; }
9560
10915
  });
9561
10916
  Object.defineProperty(exports, "PluginValidatorClass", {
9562
10917
  enumerable: true,
9563
- get: function () { return chunk56GUBLJE_cjs.PluginValidator; }
10918
+ get: function () { return chunkABB34XUS_cjs.PluginValidator; }
9564
10919
  });
9565
10920
  Object.defineProperty(exports, "ScopedHookSystemClass", {
9566
10921
  enumerable: true,
9567
- get: function () { return chunk56GUBLJE_cjs.ScopedHookSystem; }
10922
+ get: function () { return chunkABB34XUS_cjs.ScopedHookSystem; }
9568
10923
  });
9569
10924
  Object.defineProperty(exports, "PluginBuilder", {
9570
10925
  enumerable: true,
9571
- get: function () { return chunk6FHNRRJ3_cjs.PluginBuilder; }
10926
+ get: function () { return chunk635JAMSE_cjs.PluginBuilder; }
9572
10927
  });
9573
10928
  Object.defineProperty(exports, "PluginHelpers", {
9574
10929
  enumerable: true,
9575
- get: function () { return chunk6FHNRRJ3_cjs.PluginHelpers; }
10930
+ get: function () { return chunk635JAMSE_cjs.PluginHelpers; }
9576
10931
  });
9577
10932
  Object.defineProperty(exports, "QueryFilterBuilder", {
9578
10933
  enumerable: true,
9579
- get: function () { return chunkYULUPQZV_cjs.QueryFilterBuilder; }
10934
+ get: function () { return chunkYQW2GCJ3_cjs.QueryFilterBuilder; }
9580
10935
  });
9581
10936
  Object.defineProperty(exports, "SONICJS_VERSION", {
9582
10937
  enumerable: true,
9583
- get: function () { return chunkYULUPQZV_cjs.SONICJS_VERSION; }
10938
+ get: function () { return chunkYQW2GCJ3_cjs.SONICJS_VERSION; }
9584
10939
  });
9585
10940
  Object.defineProperty(exports, "TemplateRenderer", {
9586
10941
  enumerable: true,
9587
- get: function () { return chunkYULUPQZV_cjs.TemplateRenderer; }
10942
+ get: function () { return chunkYQW2GCJ3_cjs.TemplateRenderer; }
9588
10943
  });
9589
10944
  Object.defineProperty(exports, "buildQuery", {
9590
10945
  enumerable: true,
9591
- get: function () { return chunkYULUPQZV_cjs.buildQuery; }
10946
+ get: function () { return chunkYQW2GCJ3_cjs.buildQuery; }
9592
10947
  });
9593
10948
  Object.defineProperty(exports, "getCoreVersion", {
9594
10949
  enumerable: true,
9595
- get: function () { return chunkYULUPQZV_cjs.getCoreVersion; }
10950
+ get: function () { return chunkYQW2GCJ3_cjs.getCoreVersion; }
9596
10951
  });
9597
10952
  Object.defineProperty(exports, "renderTemplate", {
9598
10953
  enumerable: true,
9599
- get: function () { return chunkYULUPQZV_cjs.renderTemplate; }
10954
+ get: function () { return chunkYQW2GCJ3_cjs.renderTemplate; }
9600
10955
  });
9601
10956
  Object.defineProperty(exports, "templateRenderer", {
9602
10957
  enumerable: true,
9603
- get: function () { return chunkYULUPQZV_cjs.templateRenderer; }
10958
+ get: function () { return chunkYQW2GCJ3_cjs.templateRenderer; }
9604
10959
  });
9605
10960
  Object.defineProperty(exports, "metricsTracker", {
9606
10961
  enumerable: true,