@sonicjs-cms/core 2.18.1 → 3.0.0-beta.2

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 (225) hide show
  1. package/README.md +4 -3
  2. package/dist/admin-documents-form.template-KN7JF66Q.cjs +19 -0
  3. package/dist/{admin-layout-catalyst.template-UMTIN66R.js.map → admin-documents-form.template-KN7JF66Q.cjs.map} +1 -1
  4. package/dist/admin-documents-form.template-NLSI6Z42.js +6 -0
  5. package/dist/{admin-layout-catalyst.template-HFD37TY5.cjs.map → admin-documents-form.template-NLSI6Z42.js.map} +1 -1
  6. package/dist/admin-layout-catalyst.template-WHJGSWWD.js +7 -0
  7. package/dist/admin-layout-catalyst.template-WHJGSWWD.js.map +1 -0
  8. package/dist/admin-layout-catalyst.template-ZK5HD545.cjs +17 -0
  9. package/dist/admin-layout-catalyst.template-ZK5HD545.cjs.map +1 -0
  10. package/dist/app-Bo0X1OWX.d.ts +1268 -0
  11. package/dist/app-Do66yCcV.d.cts +1268 -0
  12. package/dist/cache-DDARE4QE.js +4 -0
  13. package/dist/cache-DDARE4QE.js.map +1 -0
  14. package/dist/cache-LVYS4BPL.cjs +33 -0
  15. package/dist/cache-LVYS4BPL.cjs.map +1 -0
  16. package/dist/chunk-2CB4KY7I.cjs +771 -0
  17. package/dist/chunk-2CB4KY7I.cjs.map +1 -0
  18. package/dist/{chunk-55RDMDOP.js → chunk-3TB6AT6X.js} +148 -55
  19. package/dist/chunk-3TB6AT6X.js.map +1 -0
  20. package/dist/{chunk-ON5ZMSU4.js → chunk-6JQOUUOB.js} +3 -3
  21. package/dist/chunk-6JQOUUOB.js.map +1 -0
  22. package/dist/chunk-6OUHGKFD.js +387 -0
  23. package/dist/chunk-6OUHGKFD.js.map +1 -0
  24. package/dist/{chunk-DSUJ5YQH.cjs → chunk-AAWNRBRB.cjs} +537 -92
  25. package/dist/chunk-AAWNRBRB.cjs.map +1 -0
  26. package/dist/chunk-AI663NBO.js +821 -0
  27. package/dist/chunk-AI663NBO.js.map +1 -0
  28. package/dist/chunk-BDDABDAB.cjs +1149 -0
  29. package/dist/chunk-BDDABDAB.cjs.map +1 -0
  30. package/dist/chunk-BLMTL57B.js +767 -0
  31. package/dist/chunk-BLMTL57B.js.map +1 -0
  32. package/dist/chunk-DNQCEKUK.cjs +327 -0
  33. package/dist/chunk-DNQCEKUK.cjs.map +1 -0
  34. package/dist/chunk-DSA4UX5B.cjs +276 -0
  35. package/dist/chunk-DSA4UX5B.cjs.map +1 -0
  36. package/dist/chunk-EF2NQUIQ.js +323 -0
  37. package/dist/chunk-EF2NQUIQ.js.map +1 -0
  38. package/dist/chunk-GCDZZNIN.js +192 -0
  39. package/dist/chunk-GCDZZNIN.js.map +1 -0
  40. package/dist/{chunk-ABB34XUS.cjs → chunk-H2AXVCLS.cjs} +667 -19
  41. package/dist/chunk-H2AXVCLS.cjs.map +1 -0
  42. package/dist/{chunk-XWIA3HVX.js → chunk-HDWE5FRJ.js} +6 -1249
  43. package/dist/chunk-HDWE5FRJ.js.map +1 -0
  44. package/dist/chunk-HIKBY7MS.cjs +70 -0
  45. package/dist/chunk-HIKBY7MS.cjs.map +1 -0
  46. package/dist/chunk-IESEVHXL.js +66 -0
  47. package/dist/chunk-IESEVHXL.js.map +1 -0
  48. package/dist/chunk-IVPRUGTY.js +242 -0
  49. package/dist/chunk-IVPRUGTY.js.map +1 -0
  50. package/dist/{chunk-SQ6FNXU2.cjs → chunk-IXUHXTHW.cjs} +2 -151
  51. package/dist/chunk-IXUHXTHW.cjs.map +1 -0
  52. package/dist/chunk-J6JTWD2A.cjs +100 -0
  53. package/dist/chunk-J6JTWD2A.cjs.map +1 -0
  54. package/dist/chunk-JEQ7FLOD.cjs +199 -0
  55. package/dist/chunk-JEQ7FLOD.cjs.map +1 -0
  56. package/dist/chunk-K25XHMM3.js +566 -0
  57. package/dist/chunk-K25XHMM3.js.map +1 -0
  58. package/dist/chunk-LRZIAW7U.cjs +158 -0
  59. package/dist/chunk-LRZIAW7U.cjs.map +1 -0
  60. package/dist/{chunk-OHYBNCVL.cjs → chunk-MVIZJOO5.cjs} +10 -1256
  61. package/dist/chunk-MVIZJOO5.cjs.map +1 -0
  62. package/dist/{chunk-UYJ6TJHX.cjs → chunk-NAVPFIG5.cjs} +148 -55
  63. package/dist/chunk-NAVPFIG5.cjs.map +1 -0
  64. package/dist/chunk-NLJVSER2.js +273 -0
  65. package/dist/chunk-NLJVSER2.js.map +1 -0
  66. package/dist/chunk-NMPEMSU4.js +154 -0
  67. package/dist/chunk-NMPEMSU4.js.map +1 -0
  68. package/dist/chunk-NUKJ54GA.cjs +245 -0
  69. package/dist/chunk-NUKJ54GA.cjs.map +1 -0
  70. package/dist/{chunk-T3Q5V33G.cjs → chunk-QAYFOER6.cjs} +621 -829
  71. package/dist/chunk-QAYFOER6.cjs.map +1 -0
  72. package/dist/{chunk-MGFRZO24.js → chunk-QZGABF2M.js} +3 -149
  73. package/dist/chunk-QZGABF2M.js.map +1 -0
  74. package/dist/chunk-RNZFGN4R.js +88 -0
  75. package/dist/chunk-RNZFGN4R.js.map +1 -0
  76. package/dist/chunk-RZ6H7OZK.js +1134 -0
  77. package/dist/chunk-RZ6H7OZK.js.map +1 -0
  78. package/dist/{chunk-XXDFQERJ.js → chunk-VD2EA3WT.js} +7192 -9806
  79. package/dist/chunk-VD2EA3WT.js.map +1 -0
  80. package/dist/{chunk-SXXTQETM.cjs → chunk-VXE42MYF.cjs} +8722 -11323
  81. package/dist/chunk-VXE42MYF.cjs.map +1 -0
  82. package/dist/{chunk-4ZSNJDLS.cjs → chunk-WULONYGB.cjs} +9 -9
  83. package/dist/chunk-WULONYGB.cjs.map +1 -0
  84. package/dist/chunk-XW56B23A.cjs +408 -0
  85. package/dist/chunk-XW56B23A.cjs.map +1 -0
  86. package/dist/chunk-YA3TJ65D.cjs +575 -0
  87. package/dist/chunk-YA3TJ65D.cjs.map +1 -0
  88. package/dist/{chunk-TFNTM3OA.js → chunk-YHSQVQXX.js} +645 -15
  89. package/dist/chunk-YHSQVQXX.js.map +1 -0
  90. package/dist/chunk-YP7GW2G5.cjs +866 -0
  91. package/dist/chunk-YP7GW2G5.cjs.map +1 -0
  92. package/dist/{chunk-QFWHAFEO.js → chunk-ZEZ245PW.js} +148 -858
  93. package/dist/chunk-ZEZ245PW.js.map +1 -0
  94. package/dist/{chunk-EW5NOBVU.js → chunk-ZGGXCFR6.js} +611 -817
  95. package/dist/chunk-ZGGXCFR6.js.map +1 -0
  96. package/dist/{collection-config-B4PG-AaF.d.cts → collection-config-JgHOpFCG.d.cts} +30 -2
  97. package/dist/{collection-config-B4PG-AaF.d.ts → collection-config-JgHOpFCG.d.ts} +30 -2
  98. package/dist/config-HFXANXCC.js +6 -0
  99. package/dist/config-HFXANXCC.js.map +1 -0
  100. package/dist/config-ON6FNMYX.cjs +19 -0
  101. package/dist/config-ON6FNMYX.cjs.map +1 -0
  102. package/dist/define-plugin-BzNHc1ZI.d.ts +1321 -0
  103. package/dist/define-plugin-IWDKYaVm.d.cts +1321 -0
  104. package/dist/document-projection-TDWRJX3Z.cjs +13 -0
  105. package/dist/document-projection-TDWRJX3Z.cjs.map +1 -0
  106. package/dist/document-projection-YYMC6I4U.js +4 -0
  107. package/dist/document-projection-YYMC6I4U.js.map +1 -0
  108. package/dist/index.cjs +13735 -4329
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.d.cts +329 -492
  111. package/dist/index.d.ts +329 -492
  112. package/dist/index.js +13386 -3999
  113. package/dist/index.js.map +1 -1
  114. package/dist/middleware.cjs +36 -32
  115. package/dist/middleware.d.cts +69 -7
  116. package/dist/middleware.d.ts +69 -7
  117. package/dist/middleware.js +7 -3
  118. package/dist/migrations-NJJWQUKK.cjs +13 -0
  119. package/dist/{migrations-IYNTWDC6.cjs.map → migrations-NJJWQUKK.cjs.map} +1 -1
  120. package/dist/migrations-WCAVBD7C.js +4 -0
  121. package/dist/{migrations-R337UD46.js.map → migrations-WCAVBD7C.js.map} +1 -1
  122. package/dist/{plugin-bootstrap-DfVerYV4.d.cts → plugin-bootstrap-B8ThJU21.d.cts} +4315 -1661
  123. package/dist/{plugin-bootstrap-P_ciLp_C.d.ts → plugin-bootstrap-qu8hJgUt.d.ts} +4315 -1661
  124. package/dist/plugins.cjs +171 -12
  125. package/dist/plugins.d.cts +36 -2
  126. package/dist/plugins.d.ts +36 -2
  127. package/dist/plugins.js +5 -2
  128. package/dist/rbac-O73MFKDA.js +5 -0
  129. package/dist/rbac-O73MFKDA.js.map +1 -0
  130. package/dist/rbac-VONLJJKB.cjs +14 -0
  131. package/dist/rbac-VONLJJKB.cjs.map +1 -0
  132. package/dist/routes.cjs +41 -45
  133. package/dist/routes.d.cts +56 -146
  134. package/dist/routes.d.ts +56 -146
  135. package/dist/routes.js +17 -9
  136. package/dist/services.cjs +39 -72
  137. package/dist/services.d.cts +79 -54
  138. package/dist/services.d.ts +79 -54
  139. package/dist/services.js +6 -3
  140. package/dist/templates.cjs +17 -29
  141. package/dist/templates.d.cts +1 -66
  142. package/dist/templates.d.ts +1 -66
  143. package/dist/templates.js +3 -3
  144. package/dist/types-Dea1eNxU.d.cts +286 -0
  145. package/dist/types-Dea1eNxU.d.ts +286 -0
  146. package/dist/types.d.cts +1 -1
  147. package/dist/types.d.ts +1 -1
  148. package/dist/utils.cjs +18 -17
  149. package/dist/utils.d.cts +1 -1
  150. package/dist/utils.d.ts +1 -1
  151. package/dist/utils.js +2 -1
  152. package/migrations/0001_core.sql +184 -0
  153. package/migrations/0002_documents.sql +163 -0
  154. package/package.json +12 -7
  155. package/dist/admin-layout-catalyst.template-HFD37TY5.cjs +0 -17
  156. package/dist/admin-layout-catalyst.template-UMTIN66R.js +0 -7
  157. package/dist/app-C9esKLmh.d.cts +0 -112
  158. package/dist/app-C9esKLmh.d.ts +0 -112
  159. package/dist/chunk-4R3NOOL3.js +0 -2217
  160. package/dist/chunk-4R3NOOL3.js.map +0 -1
  161. package/dist/chunk-4ZSNJDLS.cjs.map +0 -1
  162. package/dist/chunk-55RDMDOP.js.map +0 -1
  163. package/dist/chunk-635JAMSE.cjs +0 -653
  164. package/dist/chunk-635JAMSE.cjs.map +0 -1
  165. package/dist/chunk-ABB34XUS.cjs.map +0 -1
  166. package/dist/chunk-C54YUA23.cjs +0 -2219
  167. package/dist/chunk-C54YUA23.cjs.map +0 -1
  168. package/dist/chunk-DSUJ5YQH.cjs.map +0 -1
  169. package/dist/chunk-EW5NOBVU.js.map +0 -1
  170. package/dist/chunk-EXNEW5US.js +0 -648
  171. package/dist/chunk-EXNEW5US.js.map +0 -1
  172. package/dist/chunk-I2H5NGJQ.js +0 -692
  173. package/dist/chunk-I2H5NGJQ.js.map +0 -1
  174. package/dist/chunk-MGFRZO24.js.map +0 -1
  175. package/dist/chunk-OHYBNCVL.cjs.map +0 -1
  176. package/dist/chunk-ON5ZMSU4.js.map +0 -1
  177. package/dist/chunk-QFWHAFEO.js.map +0 -1
  178. package/dist/chunk-SQ6FNXU2.cjs.map +0 -1
  179. package/dist/chunk-SXXTQETM.cjs.map +0 -1
  180. package/dist/chunk-T3Q5V33G.cjs.map +0 -1
  181. package/dist/chunk-TFNTM3OA.js.map +0 -1
  182. package/dist/chunk-UYJ6TJHX.cjs.map +0 -1
  183. package/dist/chunk-WAEQXGCX.cjs +0 -1898
  184. package/dist/chunk-WAEQXGCX.cjs.map +0 -1
  185. package/dist/chunk-XWIA3HVX.js.map +0 -1
  186. package/dist/chunk-XXDFQERJ.js.map +0 -1
  187. package/dist/migrations-IYNTWDC6.cjs +0 -13
  188. package/dist/migrations-R337UD46.js +0 -4
  189. package/dist/plugin-manager-BoM3Q7o7.d.cts +0 -328
  190. package/dist/plugin-manager-Efx9RyDX.d.ts +0 -328
  191. package/migrations/001_initial_schema.sql +0 -170
  192. package/migrations/002_faq_plugin.sql +0 -86
  193. package/migrations/003_stage5_enhancements.sql +0 -121
  194. package/migrations/004_stage6_user_management.sql +0 -183
  195. package/migrations/005_stage7_workflow_automation.sql +0 -294
  196. package/migrations/006_plugin_system.sql +0 -155
  197. package/migrations/007_demo_login_plugin.sql +0 -23
  198. package/migrations/008_fix_slug_validation.sql +0 -22
  199. package/migrations/009_system_logging.sql +0 -57
  200. package/migrations/011_config_managed_collections.sql +0 -15
  201. package/migrations/012_testimonials_plugin.sql +0 -80
  202. package/migrations/013_code_examples_plugin.sql +0 -177
  203. package/migrations/014_fix_plugin_registry.sql +0 -88
  204. package/migrations/015_add_remaining_plugins.sql +0 -89
  205. package/migrations/016_remove_duplicate_cache_plugin.sql +0 -17
  206. package/migrations/017_auth_configurable_fields.sql +0 -49
  207. package/migrations/018_settings_table.sql +0 -23
  208. package/migrations/019_remove_blog_posts_collection.sql +0 -15
  209. package/migrations/020_add_email_plugin.sql +0 -22
  210. package/migrations/021_add_magic_link_auth_plugin.sql +0 -42
  211. package/migrations/022_add_tinymce_plugin.sql +0 -25
  212. package/migrations/023_add_easy_mdx_plugin.sql +0 -25
  213. package/migrations/024_add_quill_editor_plugin.sql +0 -25
  214. package/migrations/025_add_easymde_plugin.sql +0 -25
  215. package/migrations/026_add_otp_login.sql +0 -42
  216. package/migrations/027_fix_slug_field_type.sql +0 -18
  217. package/migrations/028_fix_slug_field_type_in_schemas.sql +0 -30
  218. package/migrations/029_add_forms_system.sql +0 -184
  219. package/migrations/030_add_turnstile_to_forms.sql +0 -14
  220. package/migrations/031_ai_search_plugin.sql +0 -45
  221. package/migrations/032_user_profiles.sql +0 -37
  222. package/migrations/033_form_content_integration.sql +0 -19
  223. package/migrations/034_security_audit_plugin.sql +0 -27
  224. package/migrations/035_user_profiles_data_column.sql +0 -16
  225. package/migrations/036_analytics_events.sql +0 -22
@@ -0,0 +1,1149 @@
1
+ 'use strict';
2
+
3
+ var chunkYA3TJ65D_cjs = require('./chunk-YA3TJ65D.cjs');
4
+ var chunkYP7GW2G5_cjs = require('./chunk-YP7GW2G5.cjs');
5
+ var chunkP3XDZL6Q_cjs = require('./chunk-P3XDZL6Q.cjs');
6
+ var d1 = require('drizzle-orm/d1');
7
+ var drizzleOrm = require('drizzle-orm');
8
+ var dev = require('hono/dev');
9
+
10
+ var Logger = class {
11
+ db;
12
+ enabled = true;
13
+ configCache = /* @__PURE__ */ new Map();
14
+ lastConfigRefresh = 0;
15
+ configRefreshInterval = 6e4;
16
+ // 1 minute
17
+ constructor(database) {
18
+ this.db = d1.drizzle(database);
19
+ }
20
+ /**
21
+ * Log a debug message
22
+ */
23
+ async debug(category, message, data, context) {
24
+ return this.log("debug", category, message, data, context);
25
+ }
26
+ /**
27
+ * Log an info message
28
+ */
29
+ async info(category, message, data, context) {
30
+ return this.log("info", category, message, data, context);
31
+ }
32
+ /**
33
+ * Log a warning message
34
+ */
35
+ async warn(category, message, data, context) {
36
+ return this.log("warn", category, message, data, context);
37
+ }
38
+ /**
39
+ * Log an error message
40
+ */
41
+ async error(category, message, error, context) {
42
+ const errorData = error instanceof Error ? {
43
+ name: error.name,
44
+ message: error.message,
45
+ stack: error.stack
46
+ } : error;
47
+ return this.log("error", category, message, errorData, {
48
+ ...context,
49
+ stackTrace: error instanceof Error ? error.stack : void 0
50
+ });
51
+ }
52
+ /**
53
+ * Log a fatal message
54
+ */
55
+ async fatal(category, message, error, context) {
56
+ const errorData = error instanceof Error ? {
57
+ name: error.name,
58
+ message: error.message,
59
+ stack: error.stack
60
+ } : error;
61
+ return this.log("fatal", category, message, errorData, {
62
+ ...context,
63
+ stackTrace: error instanceof Error ? error.stack : void 0
64
+ });
65
+ }
66
+ /**
67
+ * Log an API request
68
+ */
69
+ async logRequest(method, url, statusCode, duration, context) {
70
+ const level = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "info";
71
+ return this.log(level, "api", `${method} ${url} - ${statusCode}`, {
72
+ method,
73
+ url,
74
+ statusCode,
75
+ duration
76
+ }, {
77
+ ...context,
78
+ method,
79
+ url,
80
+ statusCode,
81
+ duration
82
+ });
83
+ }
84
+ /**
85
+ * Log an authentication event
86
+ */
87
+ async logAuth(action, userId, success = true, context) {
88
+ const level = success ? "info" : "warn";
89
+ return this.log(level, "auth", `Authentication ${action}: ${success ? "success" : "failed"}`, {
90
+ action,
91
+ success,
92
+ userId
93
+ }, {
94
+ ...context,
95
+ userId,
96
+ tags: ["authentication", action]
97
+ });
98
+ }
99
+ /**
100
+ * Log a security event
101
+ */
102
+ async logSecurity(event, severity, context) {
103
+ const level = severity === "critical" ? "fatal" : severity === "high" ? "error" : "warn";
104
+ return this.log(level, "security", `Security event: ${event}`, {
105
+ event,
106
+ severity
107
+ }, {
108
+ ...context,
109
+ tags: ["security", severity]
110
+ });
111
+ }
112
+ /**
113
+ * Core logging method
114
+ */
115
+ async log(level, category, message, data, context) {
116
+ if (!this.enabled) return;
117
+ try {
118
+ const config = await this.getConfig(category);
119
+ if (!config || !config.enabled || !this.shouldLog(level, config.level)) {
120
+ return;
121
+ }
122
+ const logEntry = {
123
+ id: crypto.randomUUID(),
124
+ level,
125
+ category,
126
+ message,
127
+ data: data ? JSON.stringify(data) : null,
128
+ userId: context?.userId || null,
129
+ sessionId: context?.sessionId || null,
130
+ requestId: context?.requestId || null,
131
+ ipAddress: context?.ipAddress || null,
132
+ userAgent: context?.userAgent || null,
133
+ method: context?.method || null,
134
+ url: context?.url || null,
135
+ statusCode: context?.statusCode || null,
136
+ duration: context?.duration || null,
137
+ stackTrace: context?.stackTrace || null,
138
+ tags: context?.tags ? JSON.stringify(context.tags) : null,
139
+ source: context?.source || null,
140
+ createdAt: /* @__PURE__ */ new Date()
141
+ };
142
+ await this.db.insert(chunkYP7GW2G5_cjs.systemLogs).values(logEntry);
143
+ if (config.maxSize) {
144
+ await this.cleanupCategory(category, config.maxSize);
145
+ }
146
+ } catch (error) {
147
+ console.error("Logger error:", error);
148
+ }
149
+ }
150
+ /**
151
+ * Get logs with filtering and pagination
152
+ */
153
+ async getLogs(filter = {}) {
154
+ try {
155
+ const conditions = [];
156
+ if (filter.level && filter.level.length > 0) {
157
+ conditions.push(drizzleOrm.inArray(chunkYP7GW2G5_cjs.systemLogs.level, filter.level));
158
+ }
159
+ if (filter.category && filter.category.length > 0) {
160
+ conditions.push(drizzleOrm.inArray(chunkYP7GW2G5_cjs.systemLogs.category, filter.category));
161
+ }
162
+ if (filter.userId) {
163
+ conditions.push(drizzleOrm.eq(chunkYP7GW2G5_cjs.systemLogs.userId, filter.userId));
164
+ }
165
+ if (filter.source) {
166
+ conditions.push(drizzleOrm.eq(chunkYP7GW2G5_cjs.systemLogs.source, filter.source));
167
+ }
168
+ if (filter.search) {
169
+ conditions.push(
170
+ drizzleOrm.like(chunkYP7GW2G5_cjs.systemLogs.message, `%${filter.search}%`)
171
+ );
172
+ }
173
+ if (filter.startDate) {
174
+ conditions.push(drizzleOrm.gte(chunkYP7GW2G5_cjs.systemLogs.createdAt, filter.startDate));
175
+ }
176
+ if (filter.endDate) {
177
+ conditions.push(drizzleOrm.lte(chunkYP7GW2G5_cjs.systemLogs.createdAt, filter.endDate));
178
+ }
179
+ const whereClause = conditions.length > 0 ? drizzleOrm.and(...conditions) : void 0;
180
+ const totalResult = await this.db.select({ count: drizzleOrm.count() }).from(chunkYP7GW2G5_cjs.systemLogs).where(whereClause);
181
+ const total = totalResult[0]?.count || 0;
182
+ const sortColumn = filter.sortBy === "level" ? chunkYP7GW2G5_cjs.systemLogs.level : filter.sortBy === "category" ? chunkYP7GW2G5_cjs.systemLogs.category : chunkYP7GW2G5_cjs.systemLogs.createdAt;
183
+ const sortFn = filter.sortOrder === "asc" ? drizzleOrm.asc : drizzleOrm.desc;
184
+ const logs = await this.db.select().from(chunkYP7GW2G5_cjs.systemLogs).where(whereClause).orderBy(sortFn(sortColumn)).limit(filter.limit || 50).offset(filter.offset || 0);
185
+ return { logs, total };
186
+ } catch (error) {
187
+ console.error("Error getting logs:", error);
188
+ return { logs: [], total: 0 };
189
+ }
190
+ }
191
+ /**
192
+ * Get log configuration for a category
193
+ */
194
+ async getConfig(category) {
195
+ try {
196
+ const now = Date.now();
197
+ if (this.configCache.has(category) && now - this.lastConfigRefresh < this.configRefreshInterval) {
198
+ return this.configCache.get(category) || null;
199
+ }
200
+ const configs = await this.db.select().from(chunkYP7GW2G5_cjs.logConfig).where(drizzleOrm.eq(chunkYP7GW2G5_cjs.logConfig.category, category));
201
+ const config = configs[0] || null;
202
+ if (config) {
203
+ this.configCache.set(category, config);
204
+ this.lastConfigRefresh = now;
205
+ }
206
+ return config;
207
+ } catch (error) {
208
+ console.error("Error getting log config:", error);
209
+ return null;
210
+ }
211
+ }
212
+ /**
213
+ * Update log configuration
214
+ */
215
+ async updateConfig(category, updates) {
216
+ try {
217
+ await this.db.update(chunkYP7GW2G5_cjs.logConfig).set({
218
+ ...updates,
219
+ updatedAt: /* @__PURE__ */ new Date()
220
+ }).where(drizzleOrm.eq(chunkYP7GW2G5_cjs.logConfig.category, category));
221
+ this.configCache.delete(category);
222
+ } catch (error) {
223
+ console.error("Error updating log config:", error);
224
+ }
225
+ }
226
+ /**
227
+ * Get all log configurations
228
+ */
229
+ async getAllConfigs() {
230
+ try {
231
+ return await this.db.select().from(chunkYP7GW2G5_cjs.logConfig);
232
+ } catch (error) {
233
+ console.error("Error getting log configs:", error);
234
+ return [];
235
+ }
236
+ }
237
+ /**
238
+ * Clean up old logs for a category
239
+ */
240
+ async cleanupCategory(category, maxSize) {
241
+ try {
242
+ const countResult = await this.db.select({ count: drizzleOrm.count() }).from(chunkYP7GW2G5_cjs.systemLogs).where(drizzleOrm.eq(chunkYP7GW2G5_cjs.systemLogs.category, category));
243
+ const currentCount = countResult[0]?.count || 0;
244
+ if (currentCount > maxSize) {
245
+ const cutoffLogs = await this.db.select({ createdAt: chunkYP7GW2G5_cjs.systemLogs.createdAt }).from(chunkYP7GW2G5_cjs.systemLogs).where(drizzleOrm.eq(chunkYP7GW2G5_cjs.systemLogs.category, category)).orderBy(drizzleOrm.desc(chunkYP7GW2G5_cjs.systemLogs.createdAt)).limit(1).offset(maxSize - 1);
246
+ if (cutoffLogs[0]) {
247
+ await this.db.delete(chunkYP7GW2G5_cjs.systemLogs).where(
248
+ drizzleOrm.and(
249
+ drizzleOrm.eq(chunkYP7GW2G5_cjs.systemLogs.category, category),
250
+ drizzleOrm.lte(chunkYP7GW2G5_cjs.systemLogs.createdAt, cutoffLogs[0].createdAt)
251
+ )
252
+ );
253
+ }
254
+ }
255
+ } catch (error) {
256
+ console.error("Error cleaning up logs:", error);
257
+ }
258
+ }
259
+ /**
260
+ * Clean up logs based on retention policy
261
+ */
262
+ async cleanupByRetention() {
263
+ try {
264
+ const configs = await this.getAllConfigs();
265
+ for (const config of configs) {
266
+ if (config.retention > 0) {
267
+ const cutoffDate = /* @__PURE__ */ new Date();
268
+ cutoffDate.setDate(cutoffDate.getDate() - config.retention);
269
+ await this.db.delete(chunkYP7GW2G5_cjs.systemLogs).where(
270
+ drizzleOrm.and(
271
+ drizzleOrm.eq(chunkYP7GW2G5_cjs.systemLogs.category, config.category),
272
+ drizzleOrm.lte(chunkYP7GW2G5_cjs.systemLogs.createdAt, cutoffDate)
273
+ )
274
+ );
275
+ }
276
+ }
277
+ } catch (error) {
278
+ console.error("Error cleaning up logs by retention:", error);
279
+ }
280
+ }
281
+ /**
282
+ * Check if a log level should be recorded based on configuration
283
+ */
284
+ shouldLog(level, configLevel) {
285
+ const levels = ["debug", "info", "warn", "error", "fatal"];
286
+ const levelIndex = levels.indexOf(level);
287
+ const configLevelIndex = levels.indexOf(configLevel);
288
+ return levelIndex >= configLevelIndex;
289
+ }
290
+ /**
291
+ * Enable or disable logging
292
+ */
293
+ setEnabled(enabled) {
294
+ this.enabled = enabled;
295
+ }
296
+ /**
297
+ * Check if logging is enabled
298
+ */
299
+ isEnabled() {
300
+ return this.enabled;
301
+ }
302
+ };
303
+ var loggerInstance = null;
304
+ function getLogger(database) {
305
+ if (!loggerInstance && database) {
306
+ loggerInstance = new Logger(database);
307
+ }
308
+ if (!loggerInstance) {
309
+ throw new Error("Logger not initialized. Call getLogger with a database instance first.");
310
+ }
311
+ return loggerInstance;
312
+ }
313
+ function initLogger(database) {
314
+ loggerInstance = new Logger(database);
315
+ return loggerInstance;
316
+ }
317
+
318
+ // src/services/cache.ts
319
+ function toPluginConfig(config) {
320
+ return {
321
+ ttl: config.ttl,
322
+ namespace: config.keyPrefix,
323
+ // KV survives isolate evictions — required for the dashboard to show non-zero
324
+ // counts across requests in production. Falls back to memory-only when the
325
+ // CACHE_KV binding is missing (cache plugin handles the null case).
326
+ kvEnabled: true,
327
+ memoryEnabled: true,
328
+ invalidateOn: [],
329
+ version: "v1"
330
+ };
331
+ }
332
+ var CacheService = class {
333
+ config;
334
+ inner;
335
+ // Tracks expiry times so getWithSource can distinguish 'none' vs 'expired'.
336
+ // The plugin returns source:'miss' for both cases; we differentiate here.
337
+ keyExpiry = /* @__PURE__ */ new Map();
338
+ constructor(config) {
339
+ this.config = config;
340
+ this.inner = chunkYA3TJ65D_cjs.getCacheService(toPluginConfig(config));
341
+ }
342
+ generateKey(type, identifier) {
343
+ const parts = [this.config.keyPrefix, type];
344
+ if (identifier !== void 0 && identifier !== "") parts.push(identifier);
345
+ return parts.join(":");
346
+ }
347
+ async get(key) {
348
+ return this.inner.get(key);
349
+ }
350
+ async getWithSource(key) {
351
+ const result = await this.inner.getWithSource(key);
352
+ if (result.hit) {
353
+ const out = {
354
+ hit: true,
355
+ data: result.data,
356
+ source: result.source
357
+ };
358
+ if (result.ttl !== void 0) out.ttl = result.ttl;
359
+ return out;
360
+ }
361
+ const expiry = this.keyExpiry.get(key);
362
+ if (expiry !== void 0) {
363
+ this.keyExpiry.delete(key);
364
+ return { hit: false, data: null, source: "expired" };
365
+ }
366
+ return { hit: false, data: null, source: "none" };
367
+ }
368
+ async set(key, value, ttl) {
369
+ const effectiveTtl = ttl ?? this.config.ttl;
370
+ this.keyExpiry.set(key, Date.now() + effectiveTtl * 1e3);
371
+ await this.inner.set(key, value, ttl !== void 0 ? { ttl } : void 0);
372
+ }
373
+ async delete(key) {
374
+ this.keyExpiry.delete(key);
375
+ await this.inner.delete(key);
376
+ }
377
+ async invalidate(pattern) {
378
+ if (pattern.includes("*") || pattern.includes("?")) {
379
+ const regex = new RegExp("^" + pattern.replace(/\*/g, ".*").replace(/\?/g, ".") + "$");
380
+ for (const k of this.keyExpiry.keys()) {
381
+ if (regex.test(k)) this.keyExpiry.delete(k);
382
+ }
383
+ } else {
384
+ this.keyExpiry.delete(pattern);
385
+ }
386
+ await this.inner.invalidate(pattern);
387
+ }
388
+ async clear() {
389
+ this.keyExpiry.clear();
390
+ await this.inner.clear();
391
+ }
392
+ async getOrSet(key, callback, ttl) {
393
+ const cached = await this.get(key);
394
+ if (cached !== null) return cached;
395
+ const value = await callback();
396
+ await this.set(key, value, ttl);
397
+ return value;
398
+ }
399
+ };
400
+ var CACHE_CONFIGS = {
401
+ api: {
402
+ ttl: 300,
403
+ // 5 minutes
404
+ keyPrefix: "api"
405
+ },
406
+ user: {
407
+ ttl: 600,
408
+ // 10 minutes
409
+ keyPrefix: "user"
410
+ },
411
+ content: {
412
+ ttl: 300,
413
+ // 5 minutes
414
+ keyPrefix: "content"
415
+ },
416
+ collection: {
417
+ ttl: 600,
418
+ // 10 minutes
419
+ keyPrefix: "collection"
420
+ }
421
+ };
422
+ function getCacheService2(config) {
423
+ return new CacheService(config);
424
+ }
425
+
426
+ // src/services/settings.ts
427
+ var TYPE_ID = "site_settings";
428
+ var TENANT = "default";
429
+ var SettingsService = class {
430
+ constructor(db) {
431
+ this.db = db;
432
+ }
433
+ /**
434
+ * Get settings document for a category (general or security)
435
+ */
436
+ async getSettingsDocument(category) {
437
+ try {
438
+ const row = await this.db.prepare(`
439
+ SELECT data FROM documents
440
+ WHERE type_id = ? AND slug = ? AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL
441
+ `).bind(TYPE_ID, category, TENANT).first();
442
+ if (!row) {
443
+ return null;
444
+ }
445
+ return JSON.parse(row.data);
446
+ } catch (error) {
447
+ console.error(`Error getting settings document for ${category}:`, error);
448
+ return null;
449
+ }
450
+ }
451
+ /**
452
+ * Save settings document for a category (general or security)
453
+ */
454
+ async saveSettingsDocument(category, data) {
455
+ try {
456
+ const now = Math.floor(Date.now() / 1e3);
457
+ const jsonData = JSON.stringify(data);
458
+ await this.db.prepare(`
459
+ INSERT OR IGNORE INTO document_types (id, name, display_name, description, schema, source, is_system, is_active, created_at, updated_at)
460
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
461
+ `).bind(
462
+ TYPE_ID,
463
+ TYPE_ID,
464
+ "Site Settings",
465
+ "Global site configuration settings",
466
+ "{}",
467
+ "system",
468
+ 1,
469
+ 1,
470
+ now,
471
+ now
472
+ ).run();
473
+ const existing = await this.db.prepare(`
474
+ SELECT id FROM documents
475
+ WHERE type_id = ? AND slug = ? AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL
476
+ `).bind(TYPE_ID, category, TENANT).first();
477
+ if (existing) {
478
+ await this.db.prepare(`
479
+ UPDATE documents
480
+ SET data = ?, updated_at = ?
481
+ WHERE id = ? AND is_current_draft = 1
482
+ `).bind(jsonData, now, existing.id).run();
483
+ } else {
484
+ const docId = crypto.randomUUID();
485
+ const rootId = docId;
486
+ const title = category === "general" ? "General Settings" : "Security Settings";
487
+ await this.db.prepare(`
488
+ INSERT INTO documents (
489
+ id, root_id, type_id, version_number, is_current_draft, is_published, status,
490
+ parent_root_id, slug, title, tenant_id, locale, translation_group_id,
491
+ data, metadata, created_at, updated_at
492
+ ) VALUES (
493
+ ?, ?, ?, 1, 1, 1, 'published',
494
+ '', ?, ?, ?, 'default', '',
495
+ ?, '{}', ?, ?
496
+ )
497
+ `).bind(
498
+ docId,
499
+ rootId,
500
+ TYPE_ID,
501
+ category,
502
+ title,
503
+ TENANT,
504
+ jsonData,
505
+ now,
506
+ now
507
+ ).run();
508
+ }
509
+ return true;
510
+ } catch (error) {
511
+ console.error(`Error saving settings document for ${category}:`, error);
512
+ return false;
513
+ }
514
+ }
515
+ /**
516
+ * Get general settings with defaults
517
+ */
518
+ async getGeneralSettings(userEmail) {
519
+ const settings = await this.getSettingsDocument("general");
520
+ return {
521
+ siteName: settings?.siteName || "SonicJS AI",
522
+ siteDescription: settings?.siteDescription || "A modern headless CMS powered by AI",
523
+ adminEmail: settings?.adminEmail || userEmail || "admin@example.com",
524
+ timezone: settings?.timezone || "UTC",
525
+ language: settings?.language || "en",
526
+ maintenanceMode: settings?.maintenanceMode || false
527
+ };
528
+ }
529
+ /**
530
+ * Save general settings
531
+ */
532
+ async saveGeneralSettings(settings) {
533
+ const existing = await this.getSettingsDocument("general");
534
+ const merged = { ...existing, ...settings };
535
+ return await this.saveSettingsDocument("general", merged);
536
+ }
537
+ /**
538
+ * Get security settings with defaults
539
+ */
540
+ async getSecuritySettings() {
541
+ const settings = await this.getSettingsDocument("security");
542
+ return {
543
+ jwtExpiresIn: settings?.jwtExpiresIn || "30d",
544
+ jwtRefreshGraceSeconds: typeof settings?.jwtRefreshGraceSeconds === "number" ? settings.jwtRefreshGraceSeconds : 60 * 60 * 24 * 7
545
+ };
546
+ }
547
+ /**
548
+ * Save security settings
549
+ */
550
+ async saveSecuritySettings(settings) {
551
+ const existing = await this.getSettingsDocument("security");
552
+ const merged = { ...existing, ...settings };
553
+ return await this.saveSettingsDocument("security", merged);
554
+ }
555
+ };
556
+
557
+ // src/services/telemetry-service.ts
558
+ var TelemetryService = class {
559
+ config;
560
+ identity = null;
561
+ enabled = true;
562
+ eventQueue = [];
563
+ isInitialized = false;
564
+ constructor(config) {
565
+ this.config = {
566
+ ...chunkP3XDZL6Q_cjs.getTelemetryConfig(),
567
+ ...config
568
+ };
569
+ this.enabled = this.config.enabled;
570
+ }
571
+ /**
572
+ * Initialize the telemetry service
573
+ */
574
+ async initialize(identity) {
575
+ if (!this.enabled) {
576
+ if (this.config.debug) {
577
+ console.log("[Telemetry] Disabled via configuration");
578
+ }
579
+ return;
580
+ }
581
+ try {
582
+ this.identity = identity;
583
+ if (this.config.debug) {
584
+ console.log("[Telemetry] Initialized with installation ID:", identity.installationId);
585
+ }
586
+ this.isInitialized = true;
587
+ await this.flushQueue();
588
+ } catch (error) {
589
+ if (this.config.debug) {
590
+ console.error("[Telemetry] Initialization failed:", error);
591
+ }
592
+ this.enabled = false;
593
+ }
594
+ }
595
+ /**
596
+ * Track a telemetry event
597
+ */
598
+ async track(event, properties) {
599
+ if (!this.enabled) return;
600
+ try {
601
+ const sanitizedProps = this.sanitizeProperties(properties);
602
+ const enrichedProps = {
603
+ ...sanitizedProps,
604
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
605
+ version: this.getVersion()
606
+ };
607
+ if (!this.isInitialized) {
608
+ this.eventQueue.push({ event, properties: enrichedProps });
609
+ if (this.config.debug) {
610
+ console.log("[Telemetry] Queued event:", event, enrichedProps);
611
+ }
612
+ return;
613
+ }
614
+ if (this.identity && this.config.host) {
615
+ const payload = {
616
+ data: {
617
+ installation_id: this.identity.installationId,
618
+ event_type: event,
619
+ properties: enrichedProps,
620
+ timestamp: enrichedProps.timestamp
621
+ }
622
+ };
623
+ fetch(`${this.config.host}/v1/events`, {
624
+ method: "POST",
625
+ headers: { "Content-Type": "application/json" },
626
+ body: JSON.stringify(payload)
627
+ }).catch(() => {
628
+ });
629
+ if (this.config.debug) {
630
+ console.log("[Telemetry] Tracked event:", event, enrichedProps);
631
+ }
632
+ } else if (this.config.debug) {
633
+ console.log("[Telemetry] Event (no endpoint):", event, enrichedProps);
634
+ }
635
+ } catch (error) {
636
+ if (this.config.debug) {
637
+ console.error("[Telemetry] Failed to track event:", error);
638
+ }
639
+ }
640
+ }
641
+ /**
642
+ * Track installation started
643
+ */
644
+ async trackInstallationStarted(properties) {
645
+ await this.track("installation_started", properties);
646
+ }
647
+ /**
648
+ * Track installation completed
649
+ */
650
+ async trackInstallationCompleted(properties) {
651
+ await this.track("installation_completed", properties);
652
+ }
653
+ /**
654
+ * Track installation failed
655
+ */
656
+ async trackInstallationFailed(error, properties) {
657
+ await this.track("installation_failed", {
658
+ ...properties,
659
+ errorType: chunkP3XDZL6Q_cjs.sanitizeErrorMessage(error)
660
+ });
661
+ }
662
+ /**
663
+ * Track dev server started
664
+ */
665
+ async trackDevServerStarted(properties) {
666
+ await this.track("dev_server_started", properties);
667
+ }
668
+ /**
669
+ * Track page view in admin UI
670
+ */
671
+ async trackPageView(route, properties) {
672
+ await this.track("page_viewed", {
673
+ ...properties,
674
+ route: chunkP3XDZL6Q_cjs.sanitizeRoute(route)
675
+ });
676
+ }
677
+ /**
678
+ * Track error (sanitized)
679
+ */
680
+ async trackError(error, properties) {
681
+ await this.track("error_occurred", {
682
+ ...properties,
683
+ errorType: chunkP3XDZL6Q_cjs.sanitizeErrorMessage(error)
684
+ });
685
+ }
686
+ /**
687
+ * Track plugin activation
688
+ */
689
+ async trackPluginActivated(properties) {
690
+ await this.track("plugin_activated", properties);
691
+ }
692
+ /**
693
+ * Track migration run
694
+ */
695
+ async trackMigrationRun(properties) {
696
+ await this.track("migration_run", properties);
697
+ }
698
+ /**
699
+ * Flush queued events
700
+ */
701
+ async flushQueue() {
702
+ if (this.eventQueue.length === 0) return;
703
+ const queue = [...this.eventQueue];
704
+ this.eventQueue = [];
705
+ for (const { event, properties } of queue) {
706
+ await this.track(event, properties);
707
+ }
708
+ }
709
+ /**
710
+ * Sanitize properties to ensure no PII
711
+ */
712
+ sanitizeProperties(properties) {
713
+ if (!properties) return {};
714
+ const sanitized = {};
715
+ for (const [key, value] of Object.entries(properties)) {
716
+ if (value === void 0) continue;
717
+ if (key === "route" && typeof value === "string") {
718
+ sanitized[key] = chunkP3XDZL6Q_cjs.sanitizeRoute(value);
719
+ continue;
720
+ }
721
+ if (key.toLowerCase().includes("error") && typeof value === "string") {
722
+ sanitized[key] = chunkP3XDZL6Q_cjs.sanitizeErrorMessage(value);
723
+ continue;
724
+ }
725
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
726
+ sanitized[key] = value;
727
+ }
728
+ }
729
+ return sanitized;
730
+ }
731
+ /**
732
+ * Get SonicJS version
733
+ */
734
+ getVersion() {
735
+ try {
736
+ if (typeof process !== "undefined" && process.env) {
737
+ return process.env.SONICJS_VERSION || "2.0.0";
738
+ }
739
+ return "2.0.0";
740
+ } catch {
741
+ return "unknown";
742
+ }
743
+ }
744
+ /**
745
+ * Shutdown the telemetry service (no-op for fetch-based telemetry)
746
+ */
747
+ async shutdown() {
748
+ }
749
+ /**
750
+ * Enable telemetry
751
+ */
752
+ enable() {
753
+ this.enabled = true;
754
+ }
755
+ /**
756
+ * Disable telemetry
757
+ */
758
+ disable() {
759
+ this.enabled = false;
760
+ }
761
+ /**
762
+ * Check if telemetry is enabled
763
+ */
764
+ isEnabled() {
765
+ return this.enabled;
766
+ }
767
+ };
768
+ var telemetryInstance = null;
769
+ function getTelemetryService(config) {
770
+ if (!telemetryInstance) {
771
+ telemetryInstance = new TelemetryService(config);
772
+ }
773
+ return telemetryInstance;
774
+ }
775
+ async function initTelemetry(identity, config) {
776
+ const service = getTelemetryService(config);
777
+ await service.initialize(identity);
778
+ return service;
779
+ }
780
+ function createInstallationIdentity(projectName) {
781
+ const installationId = chunkP3XDZL6Q_cjs.generateInstallationId();
782
+ const identity = { installationId };
783
+ if (projectName) {
784
+ identity.projectId = chunkP3XDZL6Q_cjs.generateProjectId(projectName);
785
+ }
786
+ return identity;
787
+ }
788
+ var appInstance = null;
789
+ function setAppInstance(app) {
790
+ appInstance = app;
791
+ }
792
+ function getAppInstance() {
793
+ return appInstance;
794
+ }
795
+ var CATEGORY_INFO = {
796
+ "Auth": {
797
+ title: "Authentication",
798
+ description: "User authentication and authorization endpoints",
799
+ icon: "&#x1f510;"
800
+ },
801
+ "Content": {
802
+ title: "Content Management",
803
+ description: "Content creation, retrieval, and management",
804
+ icon: "&#x1f4dd;"
805
+ },
806
+ "Media": {
807
+ title: "Media Management",
808
+ description: "File upload, storage, and media operations",
809
+ icon: "&#x1f5bc;&#xfe0f;"
810
+ },
811
+ "Admin": {
812
+ title: "Admin Interface",
813
+ description: "Administrative panel and management features",
814
+ icon: "&#x2699;&#xfe0f;"
815
+ },
816
+ "System": {
817
+ title: "System",
818
+ description: "Health checks and system information",
819
+ icon: "&#x1f527;"
820
+ },
821
+ "Search": {
822
+ title: "Search",
823
+ description: "AI-powered search, full-text search, and analytics",
824
+ icon: "&#x1f50d;"
825
+ },
826
+ "API Keys": {
827
+ title: "API Keys",
828
+ description: "API key management and authentication",
829
+ icon: "&#x1f511;"
830
+ },
831
+ "Workflow": {
832
+ title: "Workflow",
833
+ description: "Content workflow and approval processes",
834
+ icon: "&#x1f504;"
835
+ },
836
+ "Cache": {
837
+ title: "Cache",
838
+ description: "Cache management and invalidation",
839
+ icon: "&#x26a1;"
840
+ },
841
+ "Forms": {
842
+ title: "Forms",
843
+ description: "Form submissions and management",
844
+ icon: "&#x1f4cb;"
845
+ },
846
+ "Files": {
847
+ title: "Files",
848
+ description: "File serving from R2 storage",
849
+ icon: "&#x1f4c1;"
850
+ },
851
+ "Collections": {
852
+ title: "Collections",
853
+ description: "Per-collection REST endpoints (auto-generated from registered collections)",
854
+ icon: "&#x1f4da;"
855
+ }
856
+ };
857
+ var ROUTE_METADATA = {
858
+ // Auth endpoints
859
+ "POST /auth/login": { description: "Authenticate user with email and password (returns JWT)", category: "Auth", authentication: false },
860
+ "POST /auth/login/form": { description: "Form-based login (sets session cookie)", category: "Auth", authentication: false },
861
+ "POST /auth/register": { description: "Register a new user account", category: "Auth", authentication: false },
862
+ "POST /auth/logout": { description: "Log out the current user and invalidate session", category: "Auth", authentication: true },
863
+ "GET /auth/me": { description: "Get current authenticated user information", category: "Auth", authentication: true },
864
+ "POST /auth/refresh": { description: "Refresh authentication token", category: "Auth", authentication: true },
865
+ "POST /auth/seed-admin": { description: "Create or reset the admin user account", category: "Auth", authentication: false },
866
+ "POST /auth/magic-link/request": { description: "Request a magic link login email", category: "Auth", authentication: false },
867
+ "GET /auth/magic-link/verify": { description: "Verify magic link token and authenticate", category: "Auth", authentication: false },
868
+ "POST /auth/otp/request": { description: "Request a one-time password via email", category: "Auth", authentication: false },
869
+ "POST /auth/otp/verify": { description: "Verify OTP code and authenticate", category: "Auth", authentication: false },
870
+ // Content endpoints
871
+ "GET /api/collections": { description: "List all available collections", category: "Content", authentication: false },
872
+ "GET /api/collections/:collection/content": { description: "Get all content items from a specific collection", category: "Content", authentication: false },
873
+ "GET /api/content/:id": { description: "Get a specific content item by ID", category: "Content", authentication: false },
874
+ "POST /api/content": { description: "Create a new content item", category: "Content", authentication: true },
875
+ "PUT /api/content/:id": { description: "Update an existing content item", category: "Content", authentication: true },
876
+ "DELETE /api/content/:id": { description: "Delete a content item", category: "Content", authentication: true },
877
+ "GET /api/content/:id/versions": { description: "Get version history for a content item", category: "Content", authentication: true },
878
+ "POST /api/content/:id/restore/:versionId": { description: "Restore a content item to a previous version", category: "Content", authentication: true },
879
+ // Media endpoints
880
+ "GET /api/media": { description: "List all media files with pagination", category: "Media", authentication: false },
881
+ "GET /api/media/:id": { description: "Get a specific media file by ID", category: "Media", authentication: false },
882
+ "POST /api/media/upload": { description: "Upload a new media file to R2 storage", category: "Media", authentication: true },
883
+ "DELETE /api/media/:id": { description: "Delete a media file from storage", category: "Media", authentication: true },
884
+ // Admin API endpoints
885
+ "GET /admin/api/stats": { description: "Get dashboard statistics (collections, content, media, users)", category: "Admin", authentication: true },
886
+ "GET /admin/api/storage": { description: "Get storage usage information", category: "Admin", authentication: true },
887
+ "GET /admin/api/activity": { description: "Get recent activity logs", category: "Admin", authentication: true },
888
+ "GET /admin/api/collections": { description: "List all collections with field counts", category: "Admin", authentication: true },
889
+ "POST /admin/api/collections": { description: "Create a new collection", category: "Admin", authentication: true },
890
+ "GET /admin/api/collections/:id": { description: "Get a specific collection with its fields", category: "Admin", authentication: true },
891
+ "PATCH /admin/api/collections/:id": { description: "Update an existing collection", category: "Admin", authentication: true },
892
+ "DELETE /admin/api/collections/:id": { description: "Delete a collection (must be empty)", category: "Admin", authentication: true },
893
+ "GET /admin/api/collections/:id/fields": { description: "Get fields for a specific collection", category: "Admin", authentication: true },
894
+ "POST /admin/api/collections/:id/fields": { description: "Add a field to a collection", category: "Admin", authentication: true },
895
+ "PATCH /admin/api/collections/:id/fields/:fieldId": { description: "Update a collection field", category: "Admin", authentication: true },
896
+ "DELETE /admin/api/collections/:id/fields/:fieldId": { description: "Remove a field from a collection", category: "Admin", authentication: true },
897
+ "POST /admin/api/collections/:id/fields/reorder": { description: "Reorder fields in a collection", category: "Admin", authentication: true },
898
+ "GET /admin/api/migrations/status": { description: "Get database migration status", category: "Admin", authentication: true },
899
+ "POST /admin/api/migrations/run": { description: "Explain how to run D1 migrations with Wrangler", category: "Admin", authentication: true },
900
+ "GET /admin/api/content": { description: "List content items with filtering and pagination", category: "Admin", authentication: true },
901
+ "GET /admin/api/content/:id": { description: "Get a content item for admin editing", category: "Admin", authentication: true },
902
+ "POST /admin/api/content": { description: "Create content via admin API", category: "Admin", authentication: true },
903
+ "PUT /admin/api/content/:id": { description: "Update content via admin API", category: "Admin", authentication: true },
904
+ "DELETE /admin/api/content/:id": { description: "Delete content via admin API", category: "Admin", authentication: true },
905
+ "GET /admin/api/media": { description: "List media files for admin management", category: "Admin", authentication: true },
906
+ "POST /admin/api/media/upload": { description: "Upload media via admin interface", category: "Admin", authentication: true },
907
+ "DELETE /admin/api/media/:id": { description: "Delete media via admin interface", category: "Admin", authentication: true },
908
+ "GET /admin/api/users": { description: "List all users", category: "Admin", authentication: true },
909
+ "POST /admin/api/users": { description: "Create a new user", category: "Admin", authentication: true },
910
+ "PUT /admin/api/users/:id": { description: "Update a user", category: "Admin", authentication: true },
911
+ "DELETE /admin/api/users/:id": { description: "Delete a user", category: "Admin", authentication: true },
912
+ "GET /admin/api/logs": { description: "Get application logs with filtering", category: "Admin", authentication: true },
913
+ "GET /admin/api/plugins": { description: "List all registered plugins", category: "Admin", authentication: true },
914
+ "POST /admin/api/plugins/:id/toggle": { description: "Enable or disable a plugin", category: "Admin", authentication: true },
915
+ "GET /admin/api/settings": { description: "Get application settings", category: "Admin", authentication: true },
916
+ "PUT /admin/api/settings": { description: "Update application settings", category: "Admin", authentication: true },
917
+ "GET /admin/api/forms": { description: "List all forms", category: "Admin", authentication: true },
918
+ "GET /admin/api/forms/:id": { description: "Get form details and submissions", category: "Admin", authentication: true },
919
+ "POST /admin/api/forms": { description: "Create a new form", category: "Admin", authentication: true },
920
+ "PUT /admin/api/forms/:id": { description: "Update a form", category: "Admin", authentication: true },
921
+ "DELETE /admin/api/forms/:id": { description: "Delete a form", category: "Admin", authentication: true },
922
+ "GET /admin/api/forms/:id/submissions": { description: "Get form submissions", category: "Admin", authentication: true },
923
+ "DELETE /admin/api/forms/:id/submissions/:submissionId": { description: "Delete a form submission", category: "Admin", authentication: true },
924
+ // Search endpoints
925
+ "GET /api/search": { description: "Search content using AI, FTS5, keyword, or hybrid mode", category: "Search", authentication: false },
926
+ "POST /api/search/click": { description: "Track a search result click for analytics", category: "Search", authentication: false },
927
+ "GET /admin/plugins/ai-search/api/status": { description: "Get search plugin status and configuration", category: "Search", authentication: true },
928
+ "POST /admin/plugins/ai-search/api/index": { description: "Trigger content indexing for search", category: "Search", authentication: true },
929
+ "POST /admin/plugins/ai-search/api/index/reset": { description: "Reset the search index", category: "Search", authentication: true },
930
+ "GET /admin/plugins/ai-search/api/analytics": { description: "Get search analytics and metrics", category: "Search", authentication: true },
931
+ "GET /admin/plugins/ai-search/api/analytics/queries": { description: "Get top search queries", category: "Search", authentication: true },
932
+ "GET /admin/plugins/ai-search/api/analytics/clicks": { description: "Get click-through analytics", category: "Search", authentication: true },
933
+ "GET /admin/plugins/ai-search/api/fts5/status": { description: "Get FTS5 full-text search status", category: "Search", authentication: true },
934
+ "POST /admin/plugins/ai-search/api/fts5/rebuild": { description: "Rebuild the FTS5 search index", category: "Search", authentication: true },
935
+ "GET /admin/plugins/ai-search/api/facets": { description: "Get available search facets", category: "Search", authentication: true },
936
+ "GET /admin/plugins/ai-search/api/experiments": { description: "List search A/B test experiments", category: "Search", authentication: true },
937
+ "POST /admin/plugins/ai-search/api/experiments": { description: "Create a search A/B test experiment", category: "Search", authentication: true },
938
+ "GET /admin/plugins/ai-search/api/experiments/:id": { description: "Get experiment details", category: "Search", authentication: true },
939
+ "PUT /admin/plugins/ai-search/api/experiments/:id": { description: "Update an experiment", category: "Search", authentication: true },
940
+ "DELETE /admin/plugins/ai-search/api/experiments/:id": { description: "Delete an experiment", category: "Search", authentication: true },
941
+ "POST /admin/plugins/ai-search/api/experiments/:id/start": { description: "Start an experiment", category: "Search", authentication: true },
942
+ "POST /admin/plugins/ai-search/api/experiments/:id/stop": { description: "Stop a running experiment", category: "Search", authentication: true },
943
+ "GET /admin/plugins/ai-search/api/experiments/:id/results": { description: "Get experiment results and statistics", category: "Search", authentication: true },
944
+ "GET /admin/plugins/ai-search/api/quality": { description: "Get search quality agent analysis", category: "Search", authentication: true },
945
+ "POST /admin/plugins/ai-search/api/quality/run": { description: "Run search quality analysis", category: "Search", authentication: true },
946
+ "GET /admin/plugins/ai-search/api/quality/recommendations": { description: "Get quality improvement recommendations", category: "Search", authentication: true },
947
+ "POST /admin/plugins/ai-search/api/quality/recommendations/:id/apply": { description: "Apply a quality recommendation", category: "Search", authentication: true },
948
+ "POST /admin/plugins/ai-search/api/quality/recommendations/:id/dismiss": { description: "Dismiss a quality recommendation", category: "Search", authentication: true },
949
+ "GET /admin/plugins/ai-search/api/synonyms": { description: "List search synonyms", category: "Search", authentication: true },
950
+ "POST /admin/plugins/ai-search/api/synonyms": { description: "Add a search synonym", category: "Search", authentication: true },
951
+ "DELETE /admin/plugins/ai-search/api/synonyms/:id": { description: "Delete a search synonym", category: "Search", authentication: true },
952
+ "GET /admin/plugins/ai-search/api/query-rules": { description: "List search query rules", category: "Search", authentication: true },
953
+ "POST /admin/plugins/ai-search/api/query-rules": { description: "Create a query rule", category: "Search", authentication: true },
954
+ "PUT /admin/plugins/ai-search/api/query-rules/:id": { description: "Update a query rule", category: "Search", authentication: true },
955
+ "DELETE /admin/plugins/ai-search/api/query-rules/:id": { description: "Delete a query rule", category: "Search", authentication: true },
956
+ "GET /admin/plugins/ai-search/api/settings": { description: "Get search plugin settings", category: "Search", authentication: true },
957
+ "PUT /admin/plugins/ai-search/api/settings": { description: "Update search plugin settings", category: "Search", authentication: true },
958
+ // API Key endpoints
959
+ "GET /admin/api-keys/api/keys": { description: "List all API keys", category: "API Keys", authentication: true },
960
+ "POST /admin/api-keys/api/keys": { description: "Create a new API key", category: "API Keys", authentication: true },
961
+ "DELETE /admin/api-keys/api/keys/:id": { description: "Revoke an API key", category: "API Keys", authentication: true },
962
+ "PUT /admin/api-keys/api/keys/:id": { description: "Update an API key", category: "API Keys", authentication: true },
963
+ // Cache endpoints
964
+ "GET /admin/cache/api/stats": { description: "Get cache statistics", category: "Cache", authentication: true },
965
+ "POST /admin/cache/api/purge": { description: "Purge cache entries", category: "Cache", authentication: true },
966
+ "GET /admin/cache/api/entries": { description: "List cache entries", category: "Cache", authentication: true },
967
+ "DELETE /admin/cache/api/entries/:key": { description: "Delete a specific cache entry", category: "Cache", authentication: true },
968
+ // Workflow endpoints
969
+ "GET /workflow/status/:id": { description: "Get workflow status for a content item", category: "Workflow", authentication: true },
970
+ "POST /workflow/submit/:id": { description: "Submit content for review", category: "Workflow", authentication: true },
971
+ "POST /workflow/approve/:id": { description: "Approve content in review", category: "Workflow", authentication: true },
972
+ "POST /workflow/reject/:id": { description: "Reject content in review", category: "Workflow", authentication: true },
973
+ "POST /workflow/publish/:id": { description: "Publish approved content", category: "Workflow", authentication: true },
974
+ "POST /workflow/unpublish/:id": { description: "Unpublish content", category: "Workflow", authentication: true },
975
+ "GET /workflow/history/:id": { description: "Get workflow history for a content item", category: "Workflow", authentication: true },
976
+ // Form endpoints (public)
977
+ "POST /forms/:formId/submit": { description: "Submit a form (public endpoint)", category: "Forms", authentication: false },
978
+ "GET /forms/:formId": { description: "Get form definition for rendering", category: "Forms", authentication: false },
979
+ "POST /api/forms/:formId/submit": { description: "Submit a form via API", category: "Forms", authentication: false },
980
+ "GET /api/forms/:formId": { description: "Get form definition via API", category: "Forms", authentication: false },
981
+ // System endpoints
982
+ "GET /health": { description: "Health check endpoint for monitoring", category: "System", authentication: false },
983
+ "GET /api/health": { description: "API health check with schema information", category: "System", authentication: false },
984
+ "GET /api": { description: "API root - returns API information and available endpoints", category: "System", authentication: false },
985
+ "GET /api/system/info": { description: "Get system information and version", category: "System", authentication: false },
986
+ "GET /api/system/schema": { description: "Get database schema information", category: "System", authentication: false },
987
+ // Collection shorthand routes
988
+ "GET /api/:collection": { description: "List items from a collection (shorthand route)", category: "Collections", authentication: false },
989
+ "GET /api/:collection/:id": { description: "Get a single item by ID from a collection", category: "Collections", authentication: false },
990
+ "POST /api/:collection": { description: "Create an item in a collection", category: "Collections", authentication: true },
991
+ "PUT /api/:collection/:id": { description: "Update an item in a collection", category: "Collections", authentication: true },
992
+ "DELETE /api/:collection/:id": { description: "Delete an item from a collection", category: "Collections", authentication: true },
993
+ // File serving
994
+ "GET /files/*": { description: "Serve files from R2 storage (public access)", category: "Files", authentication: false },
995
+ // Database tools
996
+ "POST /admin/database-tools/api/query": { description: "Execute a database query", category: "Admin", authentication: true },
997
+ "GET /admin/database-tools/api/tables": { description: "List database tables", category: "Admin", authentication: true },
998
+ "GET /admin/database-tools/api/tables/:name": { description: "Get table schema and sample data", category: "Admin", authentication: true },
999
+ // Seed data
1000
+ "POST /admin/seed-data/api/generate": { description: "Generate seed data for development", category: "Admin", authentication: true },
1001
+ "GET /admin/seed-data/api/status": { description: "Get seed data generation status", category: "Admin", authentication: true },
1002
+ // Email plugin
1003
+ "POST /admin/plugins/email/api/send": { description: "Send an email", category: "Admin", authentication: true },
1004
+ "GET /admin/plugins/email/api/templates": { description: "List email templates", category: "Admin", authentication: true },
1005
+ "POST /admin/plugins/email/api/test": { description: "Send a test email", category: "Admin", authentication: true }
1006
+ };
1007
+ var INCLUDED_ROUTE_PATTERNS = [
1008
+ /^\/api\//,
1009
+ // All /api/* routes
1010
+ /^\/api$/,
1011
+ // API root
1012
+ /^\/auth\/(?!login$|register$)/,
1013
+ // Auth routes except GET login/register HTML pages
1014
+ /^\/auth\/login$/,
1015
+ // POST /auth/login (method filtered later)
1016
+ /^\/auth\/register$/,
1017
+ // POST /auth/register (method filtered later)
1018
+ /^\/admin\/api\//,
1019
+ // Admin API endpoints
1020
+ /^\/admin\/api-keys\/api\//,
1021
+ // API key management
1022
+ /^\/admin\/cache\/api\//,
1023
+ // Cache management API
1024
+ /^\/admin\/plugins\/.*\/api\//,
1025
+ // Plugin API endpoints
1026
+ /^\/admin\/database-tools\/api\//,
1027
+ // Database tools API
1028
+ /^\/admin\/seed-data\/api\//,
1029
+ // Seed data API
1030
+ /^\/workflow\//,
1031
+ // Workflow endpoints
1032
+ /^\/health$/,
1033
+ // Health check
1034
+ /^\/files\//,
1035
+ // File serving
1036
+ /^\/forms\//
1037
+ // Public form endpoints
1038
+ ];
1039
+ var EXCLUDED_ROUTES = /* @__PURE__ */ new Set([
1040
+ "GET /auth/login",
1041
+ "GET /auth/register",
1042
+ "GET /auth/login/form"
1043
+ ]);
1044
+ var cachedRouteList = null;
1045
+ function isIncludedRoute(method, path) {
1046
+ const key = `${method} ${path}`;
1047
+ if (EXCLUDED_ROUTES.has(key)) {
1048
+ return false;
1049
+ }
1050
+ return INCLUDED_ROUTE_PATTERNS.some((pattern) => pattern.test(path));
1051
+ }
1052
+ function inferCategory(path) {
1053
+ if (path.startsWith("/auth/")) return "Auth";
1054
+ if (path.startsWith("/api/search")) return "Search";
1055
+ if (path.startsWith("/api/media")) return "Media";
1056
+ if (path.startsWith("/api/system")) return "System";
1057
+ if (path.startsWith("/api/content") || path.startsWith("/api/collections")) return "Content";
1058
+ if (path.startsWith("/api/forms")) return "Forms";
1059
+ if (path.startsWith("/admin/api-keys")) return "API Keys";
1060
+ if (path.startsWith("/admin/cache")) return "Cache";
1061
+ if (path.startsWith("/admin/plugins/ai-search")) return "Search";
1062
+ if (path.startsWith("/admin/api")) return "Admin";
1063
+ if (path.startsWith("/admin/database-tools")) return "Admin";
1064
+ if (path.startsWith("/admin/seed-data")) return "Admin";
1065
+ if (path.startsWith("/admin/plugins/email")) return "Admin";
1066
+ if (path.startsWith("/workflow/")) return "Workflow";
1067
+ if (path.startsWith("/forms/")) return "Forms";
1068
+ if (path.startsWith("/files/")) return "Files";
1069
+ if (path === "/health" || path.startsWith("/api")) return "System";
1070
+ if (path.match(/^\/api\/[^/]+(\/:id)?$/) && !path.startsWith("/api/content") && !path.startsWith("/api/collections") && !path.startsWith("/api/media") && !path.startsWith("/api/search") && !path.startsWith("/api/system") && !path.startsWith("/api/health") && !path.startsWith("/api/documents") && !path.startsWith("/api/forms")) return "Collections";
1071
+ return "Other";
1072
+ }
1073
+ function inferAuth(path) {
1074
+ if (path === "/health" || path === "/api" || path === "/api/health") return false;
1075
+ if (path === "/api/system/info" || path === "/api/system/schema") return false;
1076
+ if (path.startsWith("/files/")) return false;
1077
+ if (path.startsWith("/forms/") || path.startsWith("/api/forms/")) return false;
1078
+ if (path.startsWith("/admin/")) return true;
1079
+ if (path.startsWith("/workflow/")) return true;
1080
+ return "unknown";
1081
+ }
1082
+ function buildRouteList(app) {
1083
+ if (cachedRouteList) return cachedRouteList;
1084
+ if (!app) return [];
1085
+ try {
1086
+ const routes = dev.inspectRoutes(app);
1087
+ const seen = /* @__PURE__ */ new Set();
1088
+ const result = [];
1089
+ for (const route of routes) {
1090
+ if (route.isMiddleware) continue;
1091
+ if (route.method === "ALL") continue;
1092
+ const key = `${route.method} ${route.path}`;
1093
+ if (seen.has(key)) continue;
1094
+ seen.add(key);
1095
+ if (!isIncludedRoute(route.method, route.path)) continue;
1096
+ const meta = ROUTE_METADATA[key];
1097
+ if (meta) {
1098
+ result.push({
1099
+ method: route.method,
1100
+ path: route.path,
1101
+ description: meta.description,
1102
+ authentication: meta.authentication,
1103
+ category: meta.category,
1104
+ documented: true
1105
+ });
1106
+ } else {
1107
+ result.push({
1108
+ method: route.method,
1109
+ path: route.path,
1110
+ description: "",
1111
+ authentication: inferAuth(route.path),
1112
+ category: inferCategory(route.path),
1113
+ documented: false
1114
+ });
1115
+ }
1116
+ }
1117
+ const methodOrder = { GET: 0, POST: 1, PUT: 2, PATCH: 3, DELETE: 4 };
1118
+ result.sort((a, b) => {
1119
+ const catCmp = a.category.localeCompare(b.category);
1120
+ if (catCmp !== 0) return catCmp;
1121
+ const methCmp = (methodOrder[a.method] ?? 5) - (methodOrder[b.method] ?? 5);
1122
+ if (methCmp !== 0) return methCmp;
1123
+ return a.path.localeCompare(b.path);
1124
+ });
1125
+ cachedRouteList = result;
1126
+ return result;
1127
+ } catch (error) {
1128
+ console.error("Failed to inspect routes:", error);
1129
+ return [];
1130
+ }
1131
+ }
1132
+
1133
+ exports.CACHE_CONFIGS = CACHE_CONFIGS;
1134
+ exports.CATEGORY_INFO = CATEGORY_INFO;
1135
+ exports.CacheService = CacheService;
1136
+ exports.Logger = Logger;
1137
+ exports.SettingsService = SettingsService;
1138
+ exports.TelemetryService = TelemetryService;
1139
+ exports.buildRouteList = buildRouteList;
1140
+ exports.createInstallationIdentity = createInstallationIdentity;
1141
+ exports.getAppInstance = getAppInstance;
1142
+ exports.getCacheService = getCacheService2;
1143
+ exports.getLogger = getLogger;
1144
+ exports.getTelemetryService = getTelemetryService;
1145
+ exports.initLogger = initLogger;
1146
+ exports.initTelemetry = initTelemetry;
1147
+ exports.setAppInstance = setAppInstance;
1148
+ //# sourceMappingURL=chunk-BDDABDAB.cjs.map
1149
+ //# sourceMappingURL=chunk-BDDABDAB.cjs.map