@sonicjs-cms/core 2.19.0 → 3.0.0-beta.3

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 (224) 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-2JTWQZHG.cjs +276 -0
  19. package/dist/chunk-2JTWQZHG.cjs.map +1 -0
  20. package/dist/{chunk-55RDMDOP.js → chunk-3TB6AT6X.js} +148 -55
  21. package/dist/chunk-3TB6AT6X.js.map +1 -0
  22. package/dist/{chunk-E4YFJBM2.cjs → chunk-673S7EBY.cjs} +621 -829
  23. package/dist/chunk-673S7EBY.cjs.map +1 -0
  24. package/dist/{chunk-ON5ZMSU4.js → chunk-6JQOUUOB.js} +3 -3
  25. package/dist/chunk-6JQOUUOB.js.map +1 -0
  26. package/dist/chunk-7LHUVREV.cjs +158 -0
  27. package/dist/chunk-7LHUVREV.cjs.map +1 -0
  28. package/dist/chunk-AI663NBO.js +821 -0
  29. package/dist/chunk-AI663NBO.js.map +1 -0
  30. package/dist/chunk-BDDABDAB.cjs +1149 -0
  31. package/dist/chunk-BDDABDAB.cjs.map +1 -0
  32. package/dist/chunk-BLMTL57B.js +767 -0
  33. package/dist/chunk-BLMTL57B.js.map +1 -0
  34. package/dist/{chunk-ABB34XUS.cjs → chunk-CHCBHIBM.cjs} +667 -19
  35. package/dist/chunk-CHCBHIBM.cjs.map +1 -0
  36. package/dist/chunk-DNQCEKUK.cjs +327 -0
  37. package/dist/chunk-DNQCEKUK.cjs.map +1 -0
  38. package/dist/chunk-EF2NQUIQ.js +323 -0
  39. package/dist/chunk-EF2NQUIQ.js.map +1 -0
  40. package/dist/chunk-GCDZZNIN.js +192 -0
  41. package/dist/chunk-GCDZZNIN.js.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-JZVHLLSI.cjs → chunk-IXUHXTHW.cjs} +2 -151
  51. package/dist/chunk-IXUHXTHW.cjs.map +1 -0
  52. package/dist/{chunk-7A4CB7T3.cjs → chunk-J5DCX3F6.cjs} +509 -91
  53. package/dist/chunk-J5DCX3F6.cjs.map +1 -0
  54. package/dist/chunk-J6JTWD2A.cjs +100 -0
  55. package/dist/chunk-J6JTWD2A.cjs.map +1 -0
  56. package/dist/chunk-JEQ7FLOD.cjs +199 -0
  57. package/dist/chunk-JEQ7FLOD.cjs.map +1 -0
  58. package/dist/chunk-K25XHMM3.js +566 -0
  59. package/dist/chunk-K25XHMM3.js.map +1 -0
  60. package/dist/{chunk-R4FOLLFB.cjs → chunk-LO6MEPRW.cjs} +8730 -11520
  61. package/dist/chunk-LO6MEPRW.cjs.map +1 -0
  62. package/dist/chunk-MHP7HYTT.js +273 -0
  63. package/dist/chunk-MHP7HYTT.js.map +1 -0
  64. package/dist/chunk-MP3Q2W76.js +387 -0
  65. package/dist/chunk-MP3Q2W76.js.map +1 -0
  66. package/dist/{chunk-OHYBNCVL.cjs → chunk-MVIZJOO5.cjs} +10 -1256
  67. package/dist/chunk-MVIZJOO5.cjs.map +1 -0
  68. package/dist/{chunk-UYJ6TJHX.cjs → chunk-NAVPFIG5.cjs} +148 -55
  69. package/dist/chunk-NAVPFIG5.cjs.map +1 -0
  70. package/dist/chunk-NUKJ54GA.cjs +245 -0
  71. package/dist/chunk-NUKJ54GA.cjs.map +1 -0
  72. package/dist/{chunk-BU7SFHGP.js → chunk-QZGABF2M.js} +3 -149
  73. package/dist/chunk-QZGABF2M.js.map +1 -0
  74. package/dist/{chunk-JZV22DEV.js → chunk-RJV6UXLZ.js} +611 -817
  75. package/dist/chunk-RJV6UXLZ.js.map +1 -0
  76. package/dist/chunk-RNZFGN4R.js +88 -0
  77. package/dist/chunk-RNZFGN4R.js.map +1 -0
  78. package/dist/{chunk-TFNTM3OA.js → chunk-SL6XS6YT.js} +645 -15
  79. package/dist/chunk-SL6XS6YT.js.map +1 -0
  80. package/dist/{chunk-OCL3HMEG.js → chunk-SO2T3OXR.js} +7004 -9807
  81. package/dist/chunk-SO2T3OXR.js.map +1 -0
  82. package/dist/chunk-VQHAJUZZ.cjs +408 -0
  83. package/dist/chunk-VQHAJUZZ.cjs.map +1 -0
  84. package/dist/{chunk-4NPCDK6B.js → chunk-VZ3NHR5Z.js} +505 -90
  85. package/dist/chunk-VZ3NHR5Z.js.map +1 -0
  86. package/dist/{chunk-4ZSNJDLS.cjs → chunk-WULONYGB.cjs} +9 -9
  87. package/dist/chunk-WULONYGB.cjs.map +1 -0
  88. package/dist/chunk-XFQHK64T.js +154 -0
  89. package/dist/chunk-XFQHK64T.js.map +1 -0
  90. package/dist/chunk-YA3TJ65D.cjs +575 -0
  91. package/dist/chunk-YA3TJ65D.cjs.map +1 -0
  92. package/dist/chunk-YP7GW2G5.cjs +866 -0
  93. package/dist/chunk-YP7GW2G5.cjs.map +1 -0
  94. package/dist/{chunk-QFWHAFEO.js → chunk-ZEZ245PW.js} +148 -858
  95. package/dist/chunk-ZEZ245PW.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 +13734 -4328
  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 +13385 -3998
  113. package/dist/index.js.map +1 -1
  114. package/dist/middleware.cjs +36 -32
  115. package/dist/middleware.d.cts +50 -7
  116. package/dist/middleware.d.ts +50 -7
  117. package/dist/middleware.js +7 -3
  118. package/dist/migrations-DK2YFPLR.js +4 -0
  119. package/dist/{migrations-H5IXZNCO.js.map → migrations-DK2YFPLR.js.map} +1 -1
  120. package/dist/migrations-YHNHTJOO.cjs +13 -0
  121. package/dist/{migrations-566IIPS2.cjs.map → migrations-YHNHTJOO.cjs.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-4NPCDK6B.js.map +0 -1
  160. package/dist/chunk-4ZSNJDLS.cjs.map +0 -1
  161. package/dist/chunk-55RDMDOP.js.map +0 -1
  162. package/dist/chunk-635JAMSE.cjs +0 -653
  163. package/dist/chunk-635JAMSE.cjs.map +0 -1
  164. package/dist/chunk-7A4CB7T3.cjs.map +0 -1
  165. package/dist/chunk-ABB34XUS.cjs.map +0 -1
  166. package/dist/chunk-BU7SFHGP.js.map +0 -1
  167. package/dist/chunk-E4YFJBM2.cjs.map +0 -1
  168. package/dist/chunk-EXNEW5US.js +0 -648
  169. package/dist/chunk-EXNEW5US.js.map +0 -1
  170. package/dist/chunk-JZV22DEV.js.map +0 -1
  171. package/dist/chunk-JZVHLLSI.cjs.map +0 -1
  172. package/dist/chunk-OCL3HMEG.js.map +0 -1
  173. package/dist/chunk-OHYBNCVL.cjs.map +0 -1
  174. package/dist/chunk-ON5ZMSU4.js.map +0 -1
  175. package/dist/chunk-QFWHAFEO.js.map +0 -1
  176. package/dist/chunk-R4FOLLFB.cjs.map +0 -1
  177. package/dist/chunk-RLMUFFUD.cjs +0 -2219
  178. package/dist/chunk-RLMUFFUD.cjs.map +0 -1
  179. package/dist/chunk-TFNTM3OA.js.map +0 -1
  180. package/dist/chunk-UYJ6TJHX.cjs.map +0 -1
  181. package/dist/chunk-WAEQXGCX.cjs +0 -1898
  182. package/dist/chunk-WAEQXGCX.cjs.map +0 -1
  183. package/dist/chunk-XWIA3HVX.js.map +0 -1
  184. package/dist/chunk-ZYAYUIZE.js +0 -2217
  185. package/dist/chunk-ZYAYUIZE.js.map +0 -1
  186. package/dist/migrations-566IIPS2.cjs +0 -13
  187. package/dist/migrations-H5IXZNCO.js +0 -4
  188. package/dist/plugin-manager-BoM3Q7o7.d.cts +0 -328
  189. package/dist/plugin-manager-Efx9RyDX.d.ts +0 -328
  190. package/migrations/001_initial_schema.sql +0 -170
  191. package/migrations/002_faq_plugin.sql +0 -86
  192. package/migrations/003_stage5_enhancements.sql +0 -121
  193. package/migrations/004_stage6_user_management.sql +0 -183
  194. package/migrations/005_stage7_workflow_automation.sql +0 -294
  195. package/migrations/006_plugin_system.sql +0 -155
  196. package/migrations/007_demo_login_plugin.sql +0 -23
  197. package/migrations/008_fix_slug_validation.sql +0 -22
  198. package/migrations/009_system_logging.sql +0 -57
  199. package/migrations/011_config_managed_collections.sql +0 -15
  200. package/migrations/012_testimonials_plugin.sql +0 -80
  201. package/migrations/013_code_examples_plugin.sql +0 -177
  202. package/migrations/014_fix_plugin_registry.sql +0 -88
  203. package/migrations/015_add_remaining_plugins.sql +0 -89
  204. package/migrations/016_remove_duplicate_cache_plugin.sql +0 -17
  205. package/migrations/017_auth_configurable_fields.sql +0 -49
  206. package/migrations/018_settings_table.sql +0 -23
  207. package/migrations/019_remove_blog_posts_collection.sql +0 -15
  208. package/migrations/020_add_email_plugin.sql +0 -22
  209. package/migrations/021_add_magic_link_auth_plugin.sql +0 -42
  210. package/migrations/022_add_tinymce_plugin.sql +0 -25
  211. package/migrations/023_add_easy_mdx_plugin.sql +0 -25
  212. package/migrations/024_add_quill_editor_plugin.sql +0 -25
  213. package/migrations/025_add_easymde_plugin.sql +0 -25
  214. package/migrations/026_add_otp_login.sql +0 -42
  215. package/migrations/027_fix_slug_field_type.sql +0 -18
  216. package/migrations/028_fix_slug_field_type_in_schemas.sql +0 -30
  217. package/migrations/029_add_forms_system.sql +0 -184
  218. package/migrations/030_add_turnstile_to_forms.sql +0 -14
  219. package/migrations/031_ai_search_plugin.sql +0 -45
  220. package/migrations/032_user_profiles.sql +0 -37
  221. package/migrations/033_form_content_integration.sql +0 -19
  222. package/migrations/034_security_audit_plugin.sql +0 -27
  223. package/migrations/035_user_profiles_data_column.sql +0 -16
  224. package/migrations/036_analytics_events.sql +0 -22
@@ -1,9 +1,365 @@
1
- import { syncCollections, syncAllFormCollections, PluginBootstrapService } from './chunk-JZV22DEV.js';
2
- import { MigrationService } from './chunk-ZYAYUIZE.js';
1
+ import { RbacService } from './chunk-BLMTL57B.js';
2
+ import { loadCollectionConfigs, getCollectionRegistry, PluginBootstrapService } from './chunk-RJV6UXLZ.js';
3
+ import { ensureScalarSchema, MigrationService } from './chunk-MHP7HYTT.js';
4
+ import { hasHookSystem, getHookSystem } from './chunk-RNZFGN4R.js';
3
5
  import { metricsTracker } from './chunk-FICTAGD4.js';
6
+ import { z } from 'zod';
4
7
  import { sign, verify } from 'hono/jwt';
5
8
  import { getCookie, setCookie } from 'hono/cookie';
6
9
 
10
+ // src/services/document-type-registry.ts
11
+ function rowToDocumentType(row) {
12
+ return {
13
+ id: row.id,
14
+ name: row.name,
15
+ displayName: row.display_name,
16
+ description: row.description,
17
+ schema: JSON.parse(row.schema),
18
+ queryableFields: JSON.parse(row.queryable_fields),
19
+ settings: JSON.parse(row.settings),
20
+ pluginId: row.plugin_id,
21
+ source: row.source,
22
+ schemaVersion: row.schema_version,
23
+ isSystem: row.is_system === 1,
24
+ isActive: row.is_active === 1,
25
+ isAuth: row.is_auth === 1,
26
+ createdAt: row.created_at,
27
+ updatedAt: row.updated_at
28
+ };
29
+ }
30
+ var DocumentTypeRegistry = class {
31
+ constructor(db) {
32
+ this.db = db;
33
+ }
34
+ cache = /* @__PURE__ */ new Map();
35
+ // Register or update a document type. Idempotent: bumps schema_version only when schema changes.
36
+ async register(def) {
37
+ const now = Math.floor(Date.now() / 1e3);
38
+ const existing = await this.findById(def.id);
39
+ const schemaJson = JSON.stringify({ queryableFields: def.queryableFields ?? [], settings: def.settings ?? {} });
40
+ const queryableJson = JSON.stringify(def.queryableFields ?? []);
41
+ const settingsJson = JSON.stringify(def.settings ?? {});
42
+ if (existing) {
43
+ const schemaChanged = schemaJson !== JSON.stringify(existing.schema);
44
+ const newVersion = schemaChanged ? existing.schemaVersion + 1 : existing.schemaVersion;
45
+ await this.db.prepare(
46
+ `UPDATE document_types SET
47
+ display_name = ?,
48
+ description = ?,
49
+ schema = ?,
50
+ queryable_fields = ?,
51
+ settings = ?,
52
+ plugin_id = ?,
53
+ schema_version = ?,
54
+ is_active = 1,
55
+ is_auth = ?,
56
+ updated_at = ?
57
+ WHERE id = ?`
58
+ ).bind(
59
+ def.displayName,
60
+ def.description ?? null,
61
+ schemaJson,
62
+ queryableJson,
63
+ settingsJson,
64
+ def.pluginId ?? null,
65
+ newVersion,
66
+ def.isAuth ? 1 : 0,
67
+ now,
68
+ def.id
69
+ ).run();
70
+ await ensureScalarSchema(this.db, def.id, def.queryableFields ?? []);
71
+ const updated = await this.findById(def.id);
72
+ this.cache.set(def.id, updated);
73
+ return updated;
74
+ }
75
+ await this.db.prepare(
76
+ `INSERT INTO document_types (id, name, display_name, description, schema, queryable_fields, settings, plugin_id, source, schema_version, is_system, is_active, is_auth, created_at, updated_at)
77
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, 1, ?, ?, ?)`
78
+ ).bind(
79
+ def.id,
80
+ def.name ?? def.id,
81
+ def.displayName,
82
+ def.description ?? null,
83
+ schemaJson,
84
+ queryableJson,
85
+ settingsJson,
86
+ def.pluginId ?? null,
87
+ def.source ?? "code",
88
+ def.isAuth ? 1 : 0,
89
+ now,
90
+ now
91
+ ).run();
92
+ await ensureScalarSchema(this.db, def.id, def.queryableFields ?? []);
93
+ const created = await this.findById(def.id);
94
+ this.cache.set(def.id, created);
95
+ return created;
96
+ }
97
+ async findById(id) {
98
+ if (this.cache.has(id)) return this.cache.get(id);
99
+ const row = await this.db.prepare("SELECT * FROM document_types WHERE id = ?").bind(id).first();
100
+ if (!row) return null;
101
+ const dt = rowToDocumentType(row);
102
+ this.cache.set(id, dt);
103
+ return dt;
104
+ }
105
+ async findAll(activeOnly = true) {
106
+ const sql = activeOnly ? "SELECT * FROM document_types WHERE is_active = 1 ORDER BY name" : "SELECT * FROM document_types ORDER BY name";
107
+ const result = await this.db.prepare(sql).all();
108
+ return (result.results ?? []).map(rowToDocumentType);
109
+ }
110
+ async deactivate(id) {
111
+ const now = Math.floor(Date.now() / 1e3);
112
+ await this.db.prepare("UPDATE document_types SET is_active = 0, updated_at = ? WHERE id = ?").bind(now, id).run();
113
+ this.cache.delete(id);
114
+ }
115
+ clearCache() {
116
+ this.cache.clear();
117
+ }
118
+ };
119
+
120
+ // src/services/document-types-seed.ts
121
+ var anyObject = z.record(z.string(), z.unknown());
122
+ async function bootstrapDocumentTypes(db) {
123
+ const registry = new DocumentTypeRegistry(db);
124
+ await registry.register({
125
+ id: "site_settings",
126
+ name: "site_settings",
127
+ displayName: "Site Settings",
128
+ description: "Global site configuration (internal; managed via admin settings UI)",
129
+ source: "system",
130
+ schema: anyObject,
131
+ settings: {
132
+ internal: true,
133
+ maxVersionsPerRoot: 1,
134
+ baseGrants: { admin: ["read", "create", "update", "delete", "manage"] }
135
+ },
136
+ queryableFields: []
137
+ });
138
+ await registry.register({
139
+ id: "blog_post",
140
+ name: "blog_post",
141
+ displayName: "Blog Post",
142
+ description: "Blog post (document-backed; edited via the content collection UI)",
143
+ source: "system",
144
+ schema: anyObject,
145
+ settings: {
146
+ baseGrants: { public: ["read"], admin: ["read", "create", "update", "delete", "publish", "manage"], editor: ["read", "create", "update", "publish"], viewer: ["read"] },
147
+ maxVersionsPerRoot: 50
148
+ },
149
+ queryableFields: [
150
+ { name: "difficulty", kind: "scalar", type: "text", column: "q_blog_difficulty" },
151
+ { name: "author", kind: "scalar", type: "text", column: "q_blog_author" }
152
+ ]
153
+ });
154
+ await registry.register({
155
+ id: "plugin",
156
+ name: "plugin",
157
+ displayName: "Plugin",
158
+ description: "System plugin record (managed by the plugin bootstrap service)",
159
+ source: "system",
160
+ schema: anyObject,
161
+ settings: {
162
+ baseGrants: { admin: ["read", "create", "update", "delete", "publish", "manage"] },
163
+ maxVersionsPerRoot: 1,
164
+ internal: true
165
+ },
166
+ queryableFields: [
167
+ { name: "status", kind: "scalar", type: "text", column: "q_plugin_status" },
168
+ { name: "category", kind: "scalar", type: "text", column: "q_plugin_category" },
169
+ { name: "isCore", kind: "scalar", type: "integer", column: "q_plugin_is_core" }
170
+ ]
171
+ });
172
+ await registry.register({
173
+ id: "tenant",
174
+ name: "tenant",
175
+ displayName: "Tenant",
176
+ description: "Tenant record (managed by the multi-tenant plugin; slug = tenant id)",
177
+ source: "system",
178
+ schema: anyObject,
179
+ settings: {
180
+ baseGrants: { admin: ["read", "create", "update", "delete", "manage"] },
181
+ maxVersionsPerRoot: 1,
182
+ internal: true
183
+ },
184
+ queryableFields: [
185
+ { name: "status", kind: "scalar", type: "text", column: "q_tenant_status" },
186
+ { name: "domain", kind: "scalar", type: "text", column: "q_tenant_domain" }
187
+ ]
188
+ });
189
+ await registry.register({
190
+ id: "user_profile",
191
+ name: "user_profile",
192
+ displayName: "User Profile",
193
+ description: "Per-user profile record (auth-owned; one document per user, slug = userId)",
194
+ source: "system",
195
+ isAuth: true,
196
+ schema: anyObject,
197
+ settings: {
198
+ // Hidden from the content admin surfaces; a single mutable record (no version history).
199
+ internal: true,
200
+ maxVersionsPerRoot: 1,
201
+ pii: true,
202
+ baseGrants: { admin: ["read", "create", "update", "delete", "manage"] }
203
+ },
204
+ queryableFields: []
205
+ });
206
+ await registry.register({
207
+ id: "media_asset",
208
+ name: "media_asset",
209
+ displayName: "Media Asset",
210
+ description: "Uploaded media file metadata (managed via the media library; backs an R2 object)",
211
+ source: "system",
212
+ schema: anyObject,
213
+ settings: {
214
+ internal: true,
215
+ maxVersionsPerRoot: 5,
216
+ baseGrants: {
217
+ admin: ["read", "create", "update", "delete", "manage"],
218
+ editor: ["read", "create", "update"],
219
+ author: ["read", "create"],
220
+ viewer: ["read"]
221
+ }
222
+ },
223
+ queryableFields: [
224
+ { name: "mimeType", kind: "scalar", type: "text", column: "q_media_mime" },
225
+ { name: "folder", kind: "scalar", type: "text", column: "q_media_folder" },
226
+ { name: "size", kind: "scalar", type: "integer", column: "q_media_size" },
227
+ { name: "tags", kind: "facet", type: "text" }
228
+ ]
229
+ });
230
+ await registry.register({
231
+ id: "plugin_activity",
232
+ name: "plugin_activity",
233
+ displayName: "Plugin Activity",
234
+ description: "Plugin lifecycle event log (installed/activated/deactivated/settings_updated/error)",
235
+ source: "system",
236
+ schema: anyObject,
237
+ settings: {
238
+ internal: true,
239
+ maxVersionsPerRoot: 1,
240
+ baseGrants: { admin: ["read", "create", "manage"] }
241
+ },
242
+ queryableFields: [
243
+ { name: "pluginId", kind: "scalar", type: "text", column: "q_plugin_activity_plugin_id" },
244
+ { name: "action", kind: "scalar", type: "text", column: "q_plugin_activity_action" }
245
+ ]
246
+ });
247
+ await registry.register({
248
+ id: "security_event",
249
+ name: "security_event",
250
+ displayName: "Security Event",
251
+ description: "Security audit event (login attempts, lockouts, suspicious activity)",
252
+ source: "system",
253
+ schema: anyObject,
254
+ settings: {
255
+ internal: true,
256
+ maxVersionsPerRoot: 1,
257
+ baseGrants: { admin: ["read", "create", "manage"] }
258
+ },
259
+ queryableFields: [
260
+ { name: "eventType", kind: "scalar", type: "text", column: "q_sa_event_type" },
261
+ { name: "severity", kind: "scalar", type: "text", column: "q_sa_severity" },
262
+ { name: "userId", kind: "scalar", type: "text", column: "q_sa_user_id" },
263
+ { name: "email", kind: "scalar", type: "text", column: "q_sa_email" },
264
+ { name: "ipAddress", kind: "scalar", type: "text", column: "q_sa_ip_address" },
265
+ { name: "blocked", kind: "scalar", type: "integer", column: "q_sa_blocked" }
266
+ ]
267
+ });
268
+ await registry.register({
269
+ id: "analytics_event",
270
+ name: "analytics_event",
271
+ displayName: "Analytics Event",
272
+ description: "Tracked analytics event (page view, user action, custom event)",
273
+ source: "system",
274
+ schema: anyObject,
275
+ settings: {
276
+ internal: true,
277
+ maxVersionsPerRoot: 1,
278
+ baseGrants: { admin: ["read", "create", "manage"] }
279
+ },
280
+ queryableFields: [
281
+ { name: "event", kind: "scalar", type: "text", column: "q_evt_event" },
282
+ { name: "category", kind: "scalar", type: "text", column: "q_evt_category" },
283
+ { name: "userId", kind: "scalar", type: "text", column: "q_evt_user_id" },
284
+ { name: "sessionId", kind: "scalar", type: "text", column: "q_evt_session_id" },
285
+ { name: "path", kind: "scalar", type: "text", column: "q_evt_path" }
286
+ ]
287
+ });
288
+ await registry.register({
289
+ id: "media_asset",
290
+ name: "media_asset",
291
+ displayName: "Media Asset",
292
+ description: "Media file metadata (R2 object key + intrinsic properties; URL derived at read time)",
293
+ source: "system",
294
+ schema: anyObject,
295
+ settings: {
296
+ baseGrants: { public: ["read"], admin: ["read", "create", "update", "delete", "publish", "manage"], editor: ["read", "create", "update"] },
297
+ maxVersionsPerRoot: 5
298
+ },
299
+ queryableFields: [
300
+ { name: "mimeType", kind: "scalar", type: "text", column: "q_media_mime" },
301
+ { name: "folder", kind: "scalar", type: "text", column: "q_media_folder" },
302
+ { name: "size", kind: "scalar", type: "integer", column: "q_media_size" },
303
+ { name: "tags", kind: "facet", type: "text" }
304
+ ]
305
+ });
306
+ for (const [id, displayName, description] of [
307
+ ["rbac_role", "RBAC Role", "Role record with embedded grants (auth-owned)"],
308
+ ["rbac_verb", "RBAC Verb", "Permission verb (auth-owned)"],
309
+ ["rbac_user_roles", "RBAC User Roles", "Per-user role assignments (auth-owned; slug = userId)"]
310
+ ]) {
311
+ await registry.register({
312
+ id,
313
+ name: id,
314
+ displayName,
315
+ description,
316
+ source: "system",
317
+ isAuth: true,
318
+ schema: anyObject,
319
+ settings: {
320
+ internal: true,
321
+ maxVersionsPerRoot: 1,
322
+ baseGrants: { admin: ["read", "create", "update", "delete", "manage"] }
323
+ },
324
+ queryableFields: []
325
+ });
326
+ }
327
+ }
328
+ async function autoRegisterCollectionDocumentTypes(db) {
329
+ const registry = new DocumentTypeRegistry(db);
330
+ const collections = getCollectionRegistry().listActive();
331
+ const registered = [];
332
+ for (const collection of collections) {
333
+ if (collection.internal) continue;
334
+ if (collection.name === "blog_post") continue;
335
+ try {
336
+ await registry.register({
337
+ id: collection.name,
338
+ name: collection.name,
339
+ displayName: collection.displayName,
340
+ description: collection.description,
341
+ source: "system",
342
+ schema: anyObject,
343
+ settings: {
344
+ baseGrants: {
345
+ public: ["read"],
346
+ admin: ["read", "create", "update", "delete", "publish", "manage"],
347
+ editor: ["read", "create", "update", "publish"],
348
+ viewer: ["read"]
349
+ },
350
+ maxVersionsPerRoot: 50,
351
+ ...collection.versioning ? { versioning: true } : {}
352
+ },
353
+ queryableFields: []
354
+ });
355
+ registered.push(collection.name);
356
+ } catch (error) {
357
+ console.error(`[document-types-seed] Failed to register collection "${collection.name}":`, error);
358
+ }
359
+ }
360
+ return registered;
361
+ }
362
+
7
363
  // src/middleware/bootstrap.ts
8
364
  var bootstrapComplete = false;
9
365
  function verifySecurityConfig(env) {
@@ -45,6 +401,9 @@ function verifySecurityConfig(env) {
45
401
  }
46
402
  function bootstrapMiddleware(config = {}) {
47
403
  return async (c, next) => {
404
+ if (hasHookSystem()) {
405
+ c.set("hookSystem", getHookSystem());
406
+ }
48
407
  if (bootstrapComplete) {
49
408
  return next();
50
409
  }
@@ -54,20 +413,48 @@ function bootstrapMiddleware(config = {}) {
54
413
  }
55
414
  try {
56
415
  console.log("[Bootstrap] Starting system initialization...");
57
- console.log("[Bootstrap] Running database migrations...");
416
+ console.log("[Bootstrap] Checking schema compatibility...");
58
417
  const migrationService = new MigrationService(c.env.DB);
59
- await migrationService.runPendingMigrations();
60
- console.log("[Bootstrap] Syncing collection configurations...");
418
+ await migrationService.ensureSchemaCompatibility();
61
419
  try {
62
- await syncCollections(c.env.DB);
420
+ const kv = c.env.CACHE_KV;
421
+ if (kv) {
422
+ const { setGlobalKVNamespace } = await import('./cache-DDARE4QE.js');
423
+ setGlobalKVNamespace(kv);
424
+ }
63
425
  } catch (error) {
64
- console.error("[Bootstrap] Error syncing collections:", error);
426
+ console.error("[Bootstrap] Error wiring CACHE_KV namespace:", error);
65
427
  }
66
- console.log("[Bootstrap] Syncing form collections...");
428
+ console.log("[Bootstrap] Populating collection registry...");
67
429
  try {
68
- await syncAllFormCollections(c.env.DB);
430
+ const configs = await loadCollectionConfigs();
431
+ getCollectionRegistry().register(configs);
432
+ console.log(`[Bootstrap] Registry populated with ${configs.length} collection(s)`);
69
433
  } catch (error) {
70
- console.error("[Bootstrap] Error syncing form collections:", error);
434
+ console.error("[Bootstrap] Error populating collection registry:", error);
435
+ }
436
+ console.log("[Bootstrap] Registering document types...");
437
+ try {
438
+ await bootstrapDocumentTypes(c.env.DB);
439
+ } catch (error) {
440
+ console.error("[Bootstrap] Error registering document types:", error);
441
+ }
442
+ try {
443
+ await repairMissingCredentialAccounts(c.env.DB);
444
+ } catch (error) {
445
+ console.error("[Bootstrap] Error repairing credential accounts:", error);
446
+ }
447
+ try {
448
+ const { RbacService: RbacService2 } = await import('./rbac-O73MFKDA.js');
449
+ await new RbacService2(c.env.DB, c.env.CACHE_KV).ensureSystemRbacSeed();
450
+ } catch (error) {
451
+ console.error("[Bootstrap] Error seeding RBAC documents:", error);
452
+ }
453
+ try {
454
+ const auto = await autoRegisterCollectionDocumentTypes(c.env.DB);
455
+ if (auto.length) console.log(`[Bootstrap] Document-backed collections registered: ${auto.join(", ")}`);
456
+ } catch (error) {
457
+ console.error("[Bootstrap] Error auto-registering collection document types:", error);
71
458
  }
72
459
  if (!config.plugins?.disableAll) {
73
460
  console.log("[Bootstrap] Bootstrapping core plugins...");
@@ -88,6 +475,27 @@ function bootstrapMiddleware(config = {}) {
88
475
  return next();
89
476
  };
90
477
  }
478
+ async function repairMissingCredentialAccounts(db) {
479
+ const { results } = await db.prepare(`
480
+ SELECT u.id, u.password_hash
481
+ FROM auth_user u
482
+ WHERE u.password_hash IS NOT NULL AND u.password_hash != ''
483
+ AND NOT EXISTS (
484
+ SELECT 1 FROM auth_account a
485
+ WHERE a.user_id = u.id AND a.provider_id = 'credential'
486
+ )
487
+ `).all();
488
+ if (!results.length) return;
489
+ console.log(`[Bootstrap] Repairing ${results.length} user(s) missing credential auth_account rows`);
490
+ const nowSec = Math.floor(Date.now() / 1e3);
491
+ for (const user of results) {
492
+ await db.prepare(`
493
+ INSERT OR IGNORE INTO auth_account (id, user_id, account_id, provider_id, password, created_at, updated_at)
494
+ VALUES (?, ?, ?, 'credential', ?, ?, ?)
495
+ `).bind(`cred-${user.id}`, user.id, user.id, user.password_hash, nowSec, nowSec).run();
496
+ }
497
+ console.log(`[Bootstrap] Credential account repair complete (${results.length} repaired)`);
498
+ }
91
499
  var JWT_SECRET_FALLBACK = "your-super-secret-jwt-key-change-in-production";
92
500
  var DEFAULT_JWT_EXPIRES_IN_SECONDS = 60 * 60 * 24 * 30;
93
501
  function parseDuration(input) {
@@ -119,14 +527,10 @@ async function getJwtExpirySecondsFromDb(db, env) {
119
527
  if (envParsed) return envParsed;
120
528
  if (db) {
121
529
  try {
122
- const row = await db.prepare("SELECT value FROM settings WHERE category = 'security' AND key = 'jwtExpiresIn'").first();
123
- if (row?.value) {
124
- let stored = row.value;
125
- try {
126
- stored = JSON.parse(row.value);
127
- } catch {
128
- }
129
- const parsed = parseDuration(stored);
530
+ const row = await db.prepare("SELECT data FROM documents WHERE type_id = 'site_settings' AND slug = 'security' AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL").first();
531
+ if (row?.data) {
532
+ const data = JSON.parse(row.data);
533
+ const parsed = parseDuration(data.jwtExpiresIn);
130
534
  if (parsed) return parsed;
131
535
  }
132
536
  } catch (err) {
@@ -141,14 +545,10 @@ async function getJwtRefreshGraceSecondsFromDb(db, env) {
141
545
  if (envParsed) return envParsed;
142
546
  if (db) {
143
547
  try {
144
- const row = await db.prepare("SELECT value FROM settings WHERE category = 'security' AND key = 'jwtRefreshGraceSeconds'").first();
145
- if (row?.value) {
146
- let stored = row.value;
147
- try {
148
- stored = JSON.parse(row.value);
149
- } catch {
150
- }
151
- const parsed = parseDuration(stored);
548
+ const row = await db.prepare("SELECT data FROM documents WHERE type_id = 'site_settings' AND slug = 'security' AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL").first();
549
+ if (row?.data) {
550
+ const data = JSON.parse(row.data);
551
+ const parsed = parseDuration(data.jwtRefreshGraceSeconds?.toString());
152
552
  if (parsed) return parsed;
153
553
  }
154
554
  } catch (err) {
@@ -374,52 +774,15 @@ var AuthManager = class _AuthManager {
374
774
  };
375
775
  var requireAuth = () => {
376
776
  return async (c, next) => {
377
- try {
378
- let token = c.req.header("Authorization")?.replace("Bearer ", "");
379
- if (!token) {
380
- token = getCookie(c, "auth_token");
381
- }
382
- if (!token) {
383
- const acceptHeader = c.req.header("Accept") || "";
384
- if (acceptHeader.includes("text/html")) {
385
- return c.redirect("/auth/login?error=Please login to access the admin area");
386
- }
387
- return c.json({ error: "Authentication required" }, 401);
388
- }
389
- const kv = c.env?.KV;
390
- let payload = null;
391
- if (kv) {
392
- const cacheKey = `auth:${token.substring(0, 20)}`;
393
- const cached = await kv.get(cacheKey, "json");
394
- if (cached) {
395
- payload = cached;
396
- }
397
- }
398
- if (!payload) {
399
- const jwtSecret = c.env?.JWT_SECRET;
400
- payload = await AuthManager.verifyToken(token, jwtSecret);
401
- if (payload && kv) {
402
- const cacheKey = `auth:${token.substring(0, 20)}`;
403
- await kv.put(cacheKey, JSON.stringify(payload), { expirationTtl: 300 });
404
- }
405
- }
406
- if (!payload) {
407
- const acceptHeader = c.req.header("Accept") || "";
408
- if (acceptHeader.includes("text/html")) {
409
- return c.redirect("/auth/login?error=Your session has expired, please login again");
410
- }
411
- return c.json({ error: "Invalid or expired token" }, 401);
412
- }
413
- c.set("user", payload);
414
- return await next();
415
- } catch (error) {
416
- console.error("Auth middleware error:", error);
777
+ const user = c.get("user");
778
+ if (!user) {
417
779
  const acceptHeader = c.req.header("Accept") || "";
418
780
  if (acceptHeader.includes("text/html")) {
419
- return c.redirect("/auth/login?error=Authentication failed, please login again");
781
+ return c.redirect("/auth/login?error=Please login to access the admin area");
420
782
  }
421
- return c.json({ error: "Authentication failed" }, 401);
783
+ return c.json({ error: "Authentication required" }, 401);
422
784
  }
785
+ return await next();
423
786
  };
424
787
  };
425
788
  var requireRole = (requiredRole) => {
@@ -443,25 +806,36 @@ var requireRole = (requiredRole) => {
443
806
  return await next();
444
807
  };
445
808
  };
446
- var optionalAuth = () => {
809
+ var requireRbac = (resource, verb) => {
447
810
  return async (c, next) => {
448
- try {
449
- let token = c.req.header("Authorization")?.replace("Bearer ", "");
450
- if (!token) {
451
- token = getCookie(c, "auth_token");
811
+ const user = c.get("user");
812
+ if (!user) {
813
+ const acceptHeader = c.req.header("Accept") || "";
814
+ if (acceptHeader.includes("text/html")) {
815
+ return c.redirect("/auth/login?error=Please login to access the admin area");
452
816
  }
453
- if (token) {
454
- const jwtSecret = c.env?.JWT_SECRET;
455
- const payload = await AuthManager.verifyToken(token, jwtSecret);
456
- if (payload) {
457
- c.set("user", payload);
458
- }
817
+ return c.json({ error: "Authentication required" }, 401);
818
+ }
819
+ const cachedPerms = c.get("rbacPerms");
820
+ let allowed;
821
+ if (cachedPerms !== void 0) {
822
+ allowed = cachedPerms.includes(`${resource}:${verb}`);
823
+ } else {
824
+ allowed = await new RbacService(c.env.DB).can(user.userId, resource, verb);
825
+ }
826
+ if (!allowed) {
827
+ const acceptHeader = c.req.header("Accept") || "";
828
+ if (acceptHeader.includes("text/html")) {
829
+ return c.redirect("/auth/login?error=You do not have permission to access this area");
459
830
  }
460
- return await next();
461
- } catch (error) {
462
- console.error("Optional auth error:", error);
463
- return await next();
831
+ return c.json({ error: "Insufficient permissions" }, 403);
464
832
  }
833
+ return await next();
834
+ };
835
+ };
836
+ var optionalAuth = () => {
837
+ return async (_c, next) => {
838
+ return await next();
465
839
  };
466
840
  };
467
841
 
@@ -529,11 +903,17 @@ var DEFAULT_EXEMPT_PATHS = [
529
903
  "/auth/login",
530
904
  "/auth/register",
531
905
  "/auth/seed-admin",
906
+ "/test-seed-defaults",
907
+ "/test-cleanup",
532
908
  "/auth/accept-invitation",
533
909
  "/auth/reset-password",
534
910
  "/auth/request-password-reset",
535
911
  "/auth/otp",
536
912
  "/auth/magic-link",
913
+ "/auth/sign-out",
914
+ "/auth/sign-in",
915
+ "/auth/sign-up",
916
+ "/auth/get-session",
537
917
  "/auth/verify",
538
918
  "/api/stripe/webhook",
539
919
  "/api/events"
@@ -697,6 +1077,45 @@ var securityHeadersMiddleware = () => {
697
1077
  };
698
1078
  };
699
1079
 
1080
+ // src/middleware/plugin-middleware.ts
1081
+ async function isPluginActive(db, pluginId) {
1082
+ try {
1083
+ const docResult = await db.prepare(
1084
+ `SELECT json_extract(data, '$.status') as status FROM documents
1085
+ WHERE slug = ? AND type_id = 'plugin' AND tenant_id = 'default'
1086
+ AND is_current_draft = 1 AND deleted_at IS NULL`
1087
+ ).bind(pluginId).first();
1088
+ return docResult?.status === "active";
1089
+ } catch (error) {
1090
+ console.error(`[isPluginActive] Error checking plugin status for ${pluginId}:`, error);
1091
+ return false;
1092
+ }
1093
+ }
1094
+ async function requireActivePlugin(db, pluginId) {
1095
+ const isActive = await isPluginActive(db, pluginId);
1096
+ if (!isActive) {
1097
+ throw new Error(`Plugin '${pluginId}' is required but is not active`);
1098
+ }
1099
+ }
1100
+ async function requireActivePlugins(db, pluginIds) {
1101
+ for (const pluginId of pluginIds) {
1102
+ await requireActivePlugin(db, pluginId);
1103
+ }
1104
+ }
1105
+ async function getActivePlugins(db) {
1106
+ try {
1107
+ const { results } = await db.prepare(
1108
+ `SELECT slug as id, json_extract(data, '$.status') as status, data FROM documents
1109
+ WHERE type_id = 'plugin' AND tenant_id = 'default'
1110
+ AND q_plugin_status = 'active' AND is_current_draft = 1 AND deleted_at IS NULL`
1111
+ ).all();
1112
+ return results || [];
1113
+ } catch (error) {
1114
+ console.error("[getActivePlugins] Error fetching active plugins:", error);
1115
+ return [];
1116
+ }
1117
+ }
1118
+
700
1119
  // src/middleware/index.ts
701
1120
  var loggingMiddleware = () => async (_c, next) => await next();
702
1121
  var detailedLoggingMiddleware = () => async (_c, next) => await next();
@@ -709,11 +1128,7 @@ var requirePermission = () => async (_c, next) => await next();
709
1128
  var requireAnyPermission = () => async (_c, next) => await next();
710
1129
  var logActivity = () => {
711
1130
  };
712
- var requireActivePlugin = () => async (_c, next) => await next();
713
- var requireActivePlugins = () => async (_c, next) => await next();
714
- var getActivePlugins = () => [];
715
- var isPluginActive = () => false;
716
1131
 
717
- export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, csrfProtection, detailedLoggingMiddleware, generateCsrfToken, getActivePlugins, getJwtExpirySeconds, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, isPluginActive, logActivity, loggingMiddleware, metricsMiddleware, optionalAuth, performanceLoggingMiddleware, rateLimit, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware, securityLoggingMiddleware, validateCsrfToken, verifySecurityConfig };
718
- //# sourceMappingURL=chunk-4NPCDK6B.js.map
719
- //# sourceMappingURL=chunk-4NPCDK6B.js.map
1132
+ export { AuthManager, DocumentTypeRegistry, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, csrfProtection, detailedLoggingMiddleware, generateCsrfToken, getActivePlugins, getJwtExpirySeconds, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, isPluginActive, logActivity, loggingMiddleware, metricsMiddleware, optionalAuth, performanceLoggingMiddleware, rateLimit, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRbac, requireRole, securityHeadersMiddleware, securityLoggingMiddleware, validateCsrfToken, verifySecurityConfig };
1133
+ //# sourceMappingURL=chunk-VZ3NHR5Z.js.map
1134
+ //# sourceMappingURL=chunk-VZ3NHR5Z.js.map