@aphexcms/cms-core 0.1.7 → 0.1.9

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 (351) hide show
  1. package/package.json +6 -4
  2. package/src/lib/api/assets.ts +75 -0
  3. package/src/lib/api/client.ts +150 -0
  4. package/src/lib/api/documents.ts +102 -0
  5. package/src/lib/api/index.ts +7 -0
  6. package/src/lib/api/organizations.ts +154 -0
  7. package/src/lib/api/types.ts +34 -0
  8. package/src/lib/auth/auth-errors.ts +23 -0
  9. package/src/lib/auth/auth-hooks.ts +132 -0
  10. package/src/lib/auth/provider.ts +25 -0
  11. package/{dist/client/index.js → src/lib/client/index.ts} +19 -8
  12. package/{dist → src/lib}/components/AdminApp.svelte +4 -5
  13. package/{dist → src/lib}/components/admin/DocumentEditor.svelte +7 -7
  14. package/{dist → src/lib}/components/admin/SchemaField.svelte +1 -1
  15. package/{dist → src/lib}/components/admin/fields/ArrayField.svelte +3 -3
  16. package/{dist → src/lib}/components/admin/fields/BooleanField.svelte +1 -1
  17. package/{dist → src/lib}/components/admin/fields/ImageField.svelte +40 -13
  18. package/{dist → src/lib}/components/admin/fields/NumberField.svelte +1 -1
  19. package/{dist → src/lib}/components/admin/fields/ReferenceField.svelte +2 -2
  20. package/{dist → src/lib}/components/admin/fields/SlugField.svelte +2 -2
  21. package/{dist → src/lib}/components/admin/fields/StringField.svelte +1 -1
  22. package/{dist → src/lib}/components/admin/fields/TextareaField.svelte +1 -1
  23. package/{dist/components/index.js → src/lib/components/index.ts} +5 -1
  24. package/{dist → src/lib}/components/layout/OrganizationSwitcher.svelte +2 -2
  25. package/{dist → src/lib}/components/layout/Sidebar.svelte +1 -1
  26. package/{dist → src/lib}/components/layout/sidebar/AppSidebar.svelte +1 -1
  27. package/{dist → src/lib}/components/layout/sidebar/NavUser.svelte +1 -1
  28. package/src/lib/config.ts +18 -0
  29. package/{dist/db/adapters/index.js → src/lib/db/adapters/index.ts} +0 -1
  30. package/{dist/db/index.js → src/lib/db/index.ts} +2 -1
  31. package/src/lib/db/interfaces/asset.ts +61 -0
  32. package/src/lib/db/interfaces/document.ts +53 -0
  33. package/src/lib/db/interfaces/index.ts +98 -0
  34. package/src/lib/db/interfaces/organization.ts +51 -0
  35. package/src/lib/db/interfaces/schema.ts +13 -0
  36. package/src/lib/db/interfaces/user.ts +16 -0
  37. package/src/lib/db/utils/reference-resolver.ts +119 -0
  38. package/src/lib/define.ts +7 -0
  39. package/{dist/email/index.js → src/lib/email/index.ts} +2 -1
  40. package/src/lib/email/interfaces/email.ts +45 -0
  41. package/src/lib/engine.ts +85 -0
  42. package/src/lib/field-validation/rule.ts +287 -0
  43. package/src/lib/field-validation/utils.ts +91 -0
  44. package/src/lib/hooks.ts +142 -0
  45. package/{dist/index.js → src/lib/index.ts} +2 -1
  46. package/{dist/is-mobile.svelte.js → src/lib/is-mobile.svelte.ts} +5 -3
  47. package/src/lib/routes/assets-by-id.ts +161 -0
  48. package/src/lib/routes/assets-cdn.ts +185 -0
  49. package/src/lib/routes/assets.ts +116 -0
  50. package/src/lib/routes/documents-by-id.ts +188 -0
  51. package/src/lib/routes/documents-publish.ts +211 -0
  52. package/src/lib/routes/documents.ts +172 -0
  53. package/src/lib/routes/index.ts +13 -0
  54. package/src/lib/routes/organizations-by-id.ts +258 -0
  55. package/src/lib/routes/organizations-invitations.ts +183 -0
  56. package/src/lib/routes/organizations-members.ts +301 -0
  57. package/src/lib/routes/organizations-switch.ts +74 -0
  58. package/src/lib/routes/organizations.ts +147 -0
  59. package/src/lib/routes/schemas-by-type.ts +35 -0
  60. package/src/lib/routes/schemas.ts +19 -0
  61. package/src/lib/routes-exports.ts +42 -0
  62. package/src/lib/schema-context.svelte.ts +24 -0
  63. package/src/lib/schema-utils/cleanup.ts +116 -0
  64. package/src/lib/schema-utils/index.ts +4 -0
  65. package/src/lib/schema-utils/utils.ts +47 -0
  66. package/src/lib/schema-utils/validator.ts +58 -0
  67. package/src/lib/server/index.ts +40 -0
  68. package/src/lib/services/asset-service.ts +256 -0
  69. package/src/lib/services/index.ts +6 -0
  70. package/src/lib/storage/adapters/index.ts +2 -0
  71. package/src/lib/storage/adapters/local-storage-adapter.ts +215 -0
  72. package/{dist/storage/index.js → src/lib/storage/index.ts} +4 -2
  73. package/src/lib/storage/interfaces/index.ts +2 -0
  74. package/src/lib/storage/interfaces/storage.ts +114 -0
  75. package/src/lib/storage/providers/storage.ts +83 -0
  76. package/src/lib/types/asset.ts +81 -0
  77. package/src/lib/types/auth.ts +80 -0
  78. package/src/lib/types/config.ts +45 -0
  79. package/src/lib/types/document.ts +38 -0
  80. package/src/lib/types/index.ts +8 -0
  81. package/src/lib/types/organization.ts +119 -0
  82. package/src/lib/types/schemas.ts +151 -0
  83. package/src/lib/types/sidebar.ts +37 -0
  84. package/src/lib/types/user.ts +17 -0
  85. package/src/lib/utils/content-hash.ts +75 -0
  86. package/src/lib/utils/image-url.ts +204 -0
  87. package/src/lib/utils/index.ts +12 -0
  88. package/src/lib/utils/slug.ts +33 -0
  89. package/src/lib/utils.ts +13 -0
  90. package/dist/api/assets.d.ts +0 -48
  91. package/dist/api/assets.d.ts.map +0 -1
  92. package/dist/api/assets.js +0 -52
  93. package/dist/api/client.d.ts +0 -37
  94. package/dist/api/client.d.ts.map +0 -1
  95. package/dist/api/client.js +0 -125
  96. package/dist/api/documents.d.ts +0 -56
  97. package/dist/api/documents.d.ts.map +0 -1
  98. package/dist/api/documents.js +0 -77
  99. package/dist/api/index.d.ts +0 -7
  100. package/dist/api/index.d.ts.map +0 -1
  101. package/dist/api/index.js +0 -5
  102. package/dist/api/organizations.d.ts +0 -101
  103. package/dist/api/organizations.d.ts.map +0 -1
  104. package/dist/api/organizations.js +0 -92
  105. package/dist/api/types.d.ts +0 -23
  106. package/dist/api/types.d.ts.map +0 -1
  107. package/dist/api/types.js +0 -1
  108. package/dist/auth/auth-errors.d.ts +0 -7
  109. package/dist/auth/auth-errors.d.ts.map +0 -1
  110. package/dist/auth/auth-errors.js +0 -13
  111. package/dist/auth/auth-hooks.d.ts +0 -6
  112. package/dist/auth/auth-hooks.d.ts.map +0 -1
  113. package/dist/auth/auth-hooks.js +0 -108
  114. package/dist/auth/provider.d.ts +0 -17
  115. package/dist/auth/provider.d.ts.map +0 -1
  116. package/dist/auth/provider.js +0 -1
  117. package/dist/client/index.d.ts +0 -24
  118. package/dist/client/index.d.ts.map +0 -1
  119. package/dist/components/AdminApp.svelte.d.ts +0 -24
  120. package/dist/components/AdminApp.svelte.d.ts.map +0 -1
  121. package/dist/components/admin/AdminLayout.svelte.d.ts +0 -15
  122. package/dist/components/admin/AdminLayout.svelte.d.ts.map +0 -1
  123. package/dist/components/admin/DocumentEditor.svelte.d.ts +0 -18
  124. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +0 -1
  125. package/dist/components/admin/DocumentTypesList.svelte.d.ts +0 -14
  126. package/dist/components/admin/DocumentTypesList.svelte.d.ts.map +0 -1
  127. package/dist/components/admin/ObjectModal.svelte.d.ts +0 -15
  128. package/dist/components/admin/ObjectModal.svelte.d.ts.map +0 -1
  129. package/dist/components/admin/SchemaField.svelte.d.ts +0 -19
  130. package/dist/components/admin/SchemaField.svelte.d.ts.map +0 -1
  131. package/dist/components/admin/fields/ArrayField.svelte.d.ts +0 -12
  132. package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +0 -1
  133. package/dist/components/admin/fields/BooleanField.svelte.d.ts +0 -13
  134. package/dist/components/admin/fields/BooleanField.svelte.d.ts.map +0 -1
  135. package/dist/components/admin/fields/ImageField.svelte.d.ts +0 -15
  136. package/dist/components/admin/fields/ImageField.svelte.d.ts.map +0 -1
  137. package/dist/components/admin/fields/NumberField.svelte.d.ts +0 -14
  138. package/dist/components/admin/fields/NumberField.svelte.d.ts.map +0 -1
  139. package/dist/components/admin/fields/ReferenceField.svelte.d.ts +0 -12
  140. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +0 -1
  141. package/dist/components/admin/fields/SlugField.svelte.d.ts +0 -15
  142. package/dist/components/admin/fields/SlugField.svelte.d.ts.map +0 -1
  143. package/dist/components/admin/fields/StringField.svelte.d.ts +0 -14
  144. package/dist/components/admin/fields/StringField.svelte.d.ts.map +0 -1
  145. package/dist/components/admin/fields/TextareaField.svelte.d.ts +0 -14
  146. package/dist/components/admin/fields/TextareaField.svelte.d.ts.map +0 -1
  147. package/dist/components/fields/index.d.ts +0 -9
  148. package/dist/components/fields/index.d.ts.map +0 -1
  149. package/dist/components/index.d.ts +0 -7
  150. package/dist/components/index.d.ts.map +0 -1
  151. package/dist/components/layout/OrganizationSwitcher.svelte.d.ts +0 -11
  152. package/dist/components/layout/OrganizationSwitcher.svelte.d.ts.map +0 -1
  153. package/dist/components/layout/Sidebar.svelte.d.ts +0 -14
  154. package/dist/components/layout/Sidebar.svelte.d.ts.map +0 -1
  155. package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts +0 -11
  156. package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +0 -1
  157. package/dist/components/layout/sidebar/NavMain.svelte.d.ts +0 -19
  158. package/dist/components/layout/sidebar/NavMain.svelte.d.ts.map +0 -1
  159. package/dist/components/layout/sidebar/NavSecondary.svelte.d.ts +0 -9
  160. package/dist/components/layout/sidebar/NavSecondary.svelte.d.ts.map +0 -1
  161. package/dist/components/layout/sidebar/NavUser.svelte.d.ts +0 -9
  162. package/dist/components/layout/sidebar/NavUser.svelte.d.ts.map +0 -1
  163. package/dist/config.d.ts +0 -3
  164. package/dist/config.d.ts.map +0 -1
  165. package/dist/config.js +0 -15
  166. package/dist/db/adapters/index.d.ts +0 -1
  167. package/dist/db/adapters/index.d.ts.map +0 -1
  168. package/dist/db/index.d.ts +0 -2
  169. package/dist/db/index.d.ts.map +0 -1
  170. package/dist/db/interfaces/asset.d.ts +0 -51
  171. package/dist/db/interfaces/asset.d.ts.map +0 -1
  172. package/dist/db/interfaces/asset.js +0 -1
  173. package/dist/db/interfaces/document.d.ts +0 -36
  174. package/dist/db/interfaces/document.d.ts.map +0 -1
  175. package/dist/db/interfaces/document.js +0 -1
  176. package/dist/db/interfaces/index.d.ts +0 -73
  177. package/dist/db/interfaces/index.d.ts.map +0 -1
  178. package/dist/db/interfaces/index.js +0 -1
  179. package/dist/db/interfaces/organization.d.ts +0 -27
  180. package/dist/db/interfaces/organization.d.ts.map +0 -1
  181. package/dist/db/interfaces/organization.js +0 -1
  182. package/dist/db/interfaces/schema.d.ts +0 -21
  183. package/dist/db/interfaces/schema.d.ts.map +0 -1
  184. package/dist/db/interfaces/schema.js +0 -1
  185. package/dist/db/interfaces/user.d.ts +0 -15
  186. package/dist/db/interfaces/user.d.ts.map +0 -1
  187. package/dist/db/interfaces/user.js +0 -1
  188. package/dist/db/utils/reference-resolver.d.ts +0 -18
  189. package/dist/db/utils/reference-resolver.d.ts.map +0 -1
  190. package/dist/db/utils/reference-resolver.js +0 -80
  191. package/dist/define.d.ts +0 -3
  192. package/dist/define.d.ts.map +0 -1
  193. package/dist/define.js +0 -4
  194. package/dist/email/index.d.ts +0 -2
  195. package/dist/email/index.d.ts.map +0 -1
  196. package/dist/email/interfaces/email.d.ts +0 -42
  197. package/dist/email/interfaces/email.d.ts.map +0 -1
  198. package/dist/email/interfaces/email.js +0 -1
  199. package/dist/engine.d.ts +0 -26
  200. package/dist/engine.d.ts.map +0 -1
  201. package/dist/engine.js +0 -66
  202. package/dist/field-validation/rule.d.ts +0 -51
  203. package/dist/field-validation/rule.d.ts.map +0 -1
  204. package/dist/field-validation/rule.js +0 -221
  205. package/dist/field-validation/utils.d.ts +0 -21
  206. package/dist/field-validation/utils.d.ts.map +0 -1
  207. package/dist/field-validation/utils.js +0 -66
  208. package/dist/hooks.d.ts +0 -23
  209. package/dist/hooks.d.ts.map +0 -1
  210. package/dist/hooks.js +0 -96
  211. package/dist/index.d.ts +0 -2
  212. package/dist/index.d.ts.map +0 -1
  213. package/dist/is-mobile.svelte.d.ts +0 -5
  214. package/dist/is-mobile.svelte.d.ts.map +0 -1
  215. package/dist/routes/assets-by-id.d.ts +0 -5
  216. package/dist/routes/assets-by-id.d.ts.map +0 -1
  217. package/dist/routes/assets-by-id.js +0 -138
  218. package/dist/routes/assets-cdn.d.ts +0 -3
  219. package/dist/routes/assets-cdn.d.ts.map +0 -1
  220. package/dist/routes/assets-cdn.js +0 -155
  221. package/dist/routes/assets.d.ts +0 -4
  222. package/dist/routes/assets.d.ts.map +0 -1
  223. package/dist/routes/assets.js +0 -94
  224. package/dist/routes/documents-by-id.d.ts +0 -5
  225. package/dist/routes/documents-by-id.d.ts.map +0 -1
  226. package/dist/routes/documents-by-id.js +0 -142
  227. package/dist/routes/documents-publish.d.ts +0 -4
  228. package/dist/routes/documents-publish.d.ts.map +0 -1
  229. package/dist/routes/documents-publish.js +0 -151
  230. package/dist/routes/documents.d.ts +0 -4
  231. package/dist/routes/documents.d.ts.map +0 -1
  232. package/dist/routes/documents.js +0 -131
  233. package/dist/routes/index.d.ts +0 -6
  234. package/dist/routes/index.d.ts.map +0 -1
  235. package/dist/routes/index.js +0 -10
  236. package/dist/routes/organizations-by-id.d.ts +0 -5
  237. package/dist/routes/organizations-by-id.d.ts.map +0 -1
  238. package/dist/routes/organizations-by-id.js +0 -187
  239. package/dist/routes/organizations-invitations.d.ts +0 -4
  240. package/dist/routes/organizations-invitations.d.ts.map +0 -1
  241. package/dist/routes/organizations-invitations.js +0 -125
  242. package/dist/routes/organizations-members.d.ts +0 -5
  243. package/dist/routes/organizations-members.d.ts.map +0 -1
  244. package/dist/routes/organizations-members.js +0 -206
  245. package/dist/routes/organizations-switch.d.ts +0 -3
  246. package/dist/routes/organizations-switch.d.ts.map +0 -1
  247. package/dist/routes/organizations-switch.js +0 -53
  248. package/dist/routes/organizations.d.ts +0 -4
  249. package/dist/routes/organizations.d.ts.map +0 -1
  250. package/dist/routes/organizations.js +0 -108
  251. package/dist/routes/schemas-by-type.d.ts +0 -3
  252. package/dist/routes/schemas-by-type.d.ts.map +0 -1
  253. package/dist/routes/schemas-by-type.js +0 -25
  254. package/dist/routes/schemas.d.ts +0 -3
  255. package/dist/routes/schemas.d.ts.map +0 -1
  256. package/dist/routes/schemas.js +0 -11
  257. package/dist/routes-exports.d.ts +0 -14
  258. package/dist/routes-exports.d.ts.map +0 -1
  259. package/dist/routes-exports.js +0 -19
  260. package/dist/schema-context.svelte.d.ts +0 -10
  261. package/dist/schema-context.svelte.d.ts.map +0 -1
  262. package/dist/schema-context.svelte.js +0 -18
  263. package/dist/schema-utils/cleanup.d.ts +0 -21
  264. package/dist/schema-utils/cleanup.d.ts.map +0 -1
  265. package/dist/schema-utils/cleanup.js +0 -80
  266. package/dist/schema-utils/index.d.ts +0 -4
  267. package/dist/schema-utils/index.d.ts.map +0 -1
  268. package/dist/schema-utils/index.js +0 -4
  269. package/dist/schema-utils/utils.d.ts +0 -30
  270. package/dist/schema-utils/utils.d.ts.map +0 -1
  271. package/dist/schema-utils/utils.js +0 -37
  272. package/dist/schema-utils/validator.d.ts +0 -6
  273. package/dist/schema-utils/validator.d.ts.map +0 -1
  274. package/dist/schema-utils/validator.js +0 -45
  275. package/dist/server/index.d.ts +0 -16
  276. package/dist/server/index.d.ts.map +0 -1
  277. package/dist/server/index.js +0 -28
  278. package/dist/services/asset-service.d.ts +0 -86
  279. package/dist/services/asset-service.d.ts.map +0 -1
  280. package/dist/services/asset-service.js +0 -187
  281. package/dist/services/index.d.ts +0 -3
  282. package/dist/services/index.d.ts.map +0 -1
  283. package/dist/services/index.js +0 -4
  284. package/dist/storage/adapters/index.d.ts +0 -2
  285. package/dist/storage/adapters/index.d.ts.map +0 -1
  286. package/dist/storage/adapters/index.js +0 -2
  287. package/dist/storage/adapters/local-storage-adapter.d.ts +0 -54
  288. package/dist/storage/adapters/local-storage-adapter.d.ts.map +0 -1
  289. package/dist/storage/adapters/local-storage-adapter.js +0 -187
  290. package/dist/storage/index.d.ts +0 -3
  291. package/dist/storage/index.d.ts.map +0 -1
  292. package/dist/storage/interfaces/index.d.ts +0 -2
  293. package/dist/storage/interfaces/index.d.ts.map +0 -1
  294. package/dist/storage/interfaces/index.js +0 -2
  295. package/dist/storage/interfaces/storage.d.ts +0 -91
  296. package/dist/storage/interfaces/storage.d.ts.map +0 -1
  297. package/dist/storage/interfaces/storage.js +0 -1
  298. package/dist/storage/providers/storage.d.ts +0 -43
  299. package/dist/storage/providers/storage.d.ts.map +0 -1
  300. package/dist/storage/providers/storage.js +0 -64
  301. package/dist/types/asset.d.ts +0 -73
  302. package/dist/types/asset.d.ts.map +0 -1
  303. package/dist/types/asset.js +0 -2
  304. package/dist/types/auth.d.ts +0 -50
  305. package/dist/types/auth.d.ts.map +0 -1
  306. package/dist/types/auth.js +0 -41
  307. package/dist/types/config.d.ts +0 -47
  308. package/dist/types/config.d.ts.map +0 -1
  309. package/dist/types/config.js +0 -1
  310. package/dist/types/document.d.ts +0 -34
  311. package/dist/types/document.d.ts.map +0 -1
  312. package/dist/types/document.js +0 -1
  313. package/dist/types/index.d.ts +0 -9
  314. package/dist/types/index.d.ts.map +0 -1
  315. package/dist/types/index.js +0 -8
  316. package/dist/types/organization.d.ts +0 -105
  317. package/dist/types/organization.d.ts.map +0 -1
  318. package/dist/types/organization.js +0 -3
  319. package/dist/types/schemas.d.ts +0 -114
  320. package/dist/types/schemas.d.ts.map +0 -1
  321. package/dist/types/schemas.js +0 -1
  322. package/dist/types/sidebar.d.ts +0 -33
  323. package/dist/types/sidebar.d.ts.map +0 -1
  324. package/dist/types/sidebar.js +0 -1
  325. package/dist/types/user.d.ts +0 -14
  326. package/dist/types/user.d.ts.map +0 -1
  327. package/dist/types/user.js +0 -1
  328. package/dist/utils/content-hash.d.ts +0 -22
  329. package/dist/utils/content-hash.d.ts.map +0 -1
  330. package/dist/utils/content-hash.js +0 -67
  331. package/dist/utils/image-url.d.ts +0 -88
  332. package/dist/utils/image-url.d.ts.map +0 -1
  333. package/dist/utils/image-url.js +0 -165
  334. package/dist/utils/index.d.ts +0 -6
  335. package/dist/utils/index.d.ts.map +0 -1
  336. package/dist/utils/index.js +0 -9
  337. package/dist/utils/slug.d.ts +0 -13
  338. package/dist/utils/slug.d.ts.map +0 -1
  339. package/dist/utils/slug.js +0 -30
  340. package/dist/utils.d.ts +0 -13
  341. package/dist/utils.d.ts.map +0 -1
  342. package/dist/utils.js +0 -5
  343. /package/{dist → src/lib}/app.d.ts +0 -0
  344. /package/{dist → src/lib}/auth/MULTI_TENANCY_PLAN.md +0 -0
  345. /package/{dist → src/lib}/components/admin/AdminLayout.svelte +0 -0
  346. /package/{dist → src/lib}/components/admin/DocumentTypesList.svelte +0 -0
  347. /package/{dist → src/lib}/components/admin/ObjectModal.svelte +0 -0
  348. /package/{dist/components/fields/index.js → src/lib/components/fields/index.ts} +0 -0
  349. /package/{dist → src/lib}/components/layout/sidebar/NavMain.svelte +0 -0
  350. /package/{dist → src/lib}/components/layout/sidebar/NavSecondary.svelte +0 -0
  351. /package/{dist → src/lib}/plugins/README.md +0 -0
@@ -0,0 +1,132 @@
1
+ import type { RequestEvent } from '@sveltejs/kit';
2
+ import { redirect } from '@sveltejs/kit';
3
+ import type { DatabaseAdapter } from '../db/index';
4
+ import type { CMSConfig, Auth } from '../types/index';
5
+ import type { AuthProvider } from './provider';
6
+ import { AuthError } from './auth-errors';
7
+
8
+ export async function handleAuthHook(
9
+ event: RequestEvent,
10
+ config: CMSConfig,
11
+ authProvider: AuthProvider,
12
+ db: DatabaseAdapter
13
+ ): Promise<Response | null> {
14
+ const path = event.url.pathname;
15
+
16
+ // 1. Admin UI routes - require session authentication
17
+ if (path.startsWith('/admin')) {
18
+ try {
19
+ const session = await authProvider.requireSession(event.request, db);
20
+ event.locals.auth = session;
21
+ } catch (error) {
22
+ // If it's an AuthError, redirect to login with error code
23
+ if (error instanceof AuthError) {
24
+ const loginUrl = config.auth?.loginUrl || '/login';
25
+ throw redirect(302, `${loginUrl}?error=${error.code}`);
26
+ }
27
+ // For other errors, redirect without error code
28
+ throw redirect(302, config.auth?.loginUrl || '/login');
29
+ }
30
+ }
31
+
32
+ // 2. Asset CDN routes - accept session OR API key OR signed token
33
+ // Support both /assets/ and /media/ paths (media is Sanity-style URL)
34
+ if (path.startsWith('/assets/') || path.startsWith('/media/')) {
35
+ // Try session first (for admin UI)
36
+ let auth: Auth | null = await authProvider.getSession(event.request, db);
37
+
38
+ // If no session, try API key
39
+ if (!auth) {
40
+ auth = await authProvider.validateApiKey(event.request, db);
41
+ }
42
+
43
+ // Make auth available (can be null, route will check for signed token)
44
+ if (auth) {
45
+ event.locals.auth = auth;
46
+ }
47
+ }
48
+
49
+ // 3. API routes - accept session OR API key
50
+ if (path.startsWith('/api/')) {
51
+ // Skip auth routes (Better Auth handles these)
52
+ if (path.startsWith('/api/auth')) {
53
+ return null; // Let the main hook continue
54
+ }
55
+
56
+ // If API key is explicitly provided, prioritize it over session
57
+ // This allows public content access even when user is logged in to a different org
58
+ const hasApiKey = event.request.headers.has('x-api-key');
59
+ let auth: Auth | null = null;
60
+
61
+ if (hasApiKey) {
62
+ // API key takes precedence when explicitly provided
63
+ auth = await authProvider.validateApiKey(event.request, db);
64
+ } else {
65
+ // Otherwise, try session (for admin UI making API calls)
66
+ auth = await authProvider.getSession(event.request, db);
67
+ }
68
+
69
+ // Dynamically find the GraphQL endpoint from plugins
70
+ let graphqlEndpoint: string | undefined;
71
+ const graphqlPlugin = config.plugins?.find((p) => p.name === '@aphexcms/graphql-plugin');
72
+ if (graphqlPlugin && graphqlPlugin.routes) {
73
+ graphqlEndpoint = Object.keys(graphqlPlugin.routes)[0];
74
+ }
75
+
76
+ // Require authentication for protected API routes
77
+ const protectedApiRoutes = [
78
+ '/api/documents',
79
+ '/api/assets',
80
+ '/api/schemas',
81
+ '/api/organizations',
82
+ '/api/settings'
83
+ ];
84
+ if (graphqlEndpoint) {
85
+ protectedApiRoutes.push(graphqlEndpoint);
86
+ }
87
+ const isProtectedRoute = protectedApiRoutes.some((route) => path.startsWith(route));
88
+
89
+ if (isProtectedRoute && !auth) {
90
+ return new Response(JSON.stringify({ error: 'Unauthorized' }), {
91
+ status: 401,
92
+ headers: { 'Content-Type': 'application/json' }
93
+ });
94
+ }
95
+
96
+ // Check write permission for mutations
97
+ if (auth && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(event.request.method)) {
98
+ // Special handling for GraphQL
99
+ if (graphqlEndpoint && path.startsWith(graphqlEndpoint)) {
100
+ // We need to read the body to check if it's a mutation.
101
+ // It's important to clone the request so we don't consume the body stream.
102
+ const requestBody = await event.request.clone().text();
103
+ const isMutation = requestBody.trim().startsWith('mutation');
104
+
105
+ if (isMutation && auth.type === 'api_key' && !auth.permissions.includes('write')) {
106
+ return new Response(
107
+ JSON.stringify({ error: 'Forbidden: Write permission required for mutations' }),
108
+ {
109
+ status: 403,
110
+ headers: { 'Content-Type': 'application/json' }
111
+ }
112
+ );
113
+ }
114
+ } else {
115
+ // Existing logic for other API routes
116
+ if (auth.type === 'api_key' && !auth.permissions.includes('write')) {
117
+ return new Response(JSON.stringify({ error: 'Forbidden: Write permission required' }), {
118
+ status: 403,
119
+ headers: { 'Content-Type': 'application/json' }
120
+ });
121
+ }
122
+ }
123
+ }
124
+
125
+ // Make auth available in API routes
126
+ if (auth) {
127
+ event.locals.auth = auth;
128
+ }
129
+ }
130
+
131
+ return null; // Tell the main hook to continue
132
+ }
@@ -0,0 +1,25 @@
1
+ // packages/cms-core/src/auth/provider.ts
2
+ import type { SessionAuth, ApiKeyAuth } from '../types/index';
3
+ import type { DatabaseAdapter } from '../db/interfaces/index';
4
+
5
+ export interface AuthProvider {
6
+ // Session auth (browser, admin UI)
7
+ getSession(request: Request, db: DatabaseAdapter): Promise<SessionAuth | null>;
8
+ requireSession(request: Request, db: DatabaseAdapter): Promise<SessionAuth>;
9
+
10
+ // API key auth (programmatic access)
11
+ validateApiKey(request: Request, db: DatabaseAdapter): Promise<ApiKeyAuth | null>;
12
+ requireApiKey(
13
+ request: Request,
14
+ db: DatabaseAdapter,
15
+ permission?: 'read' | 'write'
16
+ ): Promise<ApiKeyAuth>;
17
+
18
+ // User management
19
+ getUserById(userId: string): Promise<{ id: string; name?: string; email: string } | null>;
20
+ changeUserName(userId: string, name: string): Promise<void>;
21
+
22
+ // Password reset
23
+ requestPasswordReset(email: string, redirectTo?: string): Promise<void>;
24
+ resetPassword(token: string, newPassword: string): Promise<void>;
25
+ }
@@ -1,22 +1,30 @@
1
1
  // Aphex CMS Core - Client-side exports
2
2
  // These are safe to import in the browser (no Node.js dependencies)
3
+
3
4
  // Core types (shared between client and server)
4
- export * from '../types/index.js';
5
+ export * from '../types/index';
6
+ export type { SidebarUser, SidebarNavItem, SidebarBranding, SidebarData } from '../types/sidebar';
7
+
5
8
  // Field validation (client-side validation)
6
- export * from '../field-validation/rule.js';
7
- export * from '../field-validation/utils.js';
9
+ export * from '../field-validation/rule';
10
+ export * from '../field-validation/utils';
11
+
8
12
  // Content hashing utilities (for client-side change detection)
9
- export { createContentHash, hasUnpublishedChanges } from '../utils/content-hash.js';
13
+ export { createContentHash, hasUnpublishedChanges } from '../utils/content-hash';
14
+
10
15
  // Schema context (for providing schemas to components)
11
- export { setSchemaContext, getSchemaContext } from '../schema-context.svelte.js';
16
+ export { setSchemaContext, getSchemaContext } from '../schema-context.svelte';
17
+
12
18
  // Schema utilities (for working with schemas)
13
- export * from '../schema-utils/index.js';
19
+ export * from '../schema-utils/index';
20
+
14
21
  // Components (UI components for the admin interface)
15
22
  export { default as DocumentEditor } from '../components/admin/DocumentEditor.svelte';
16
23
  export { default as DocumentTypesList } from '../components/admin/DocumentTypesList.svelte';
17
24
  export { default as SchemaField } from '../components/admin/SchemaField.svelte';
18
25
  export { default as AdminApp } from '../components/AdminApp.svelte';
19
26
  export { default as Sidebar } from '../components/layout/Sidebar.svelte';
27
+
20
28
  // Field components
21
29
  export { default as StringField } from '../components/admin/fields/StringField.svelte';
22
30
  export { default as TextareaField } from '../components/admin/fields/TextareaField.svelte';
@@ -26,6 +34,9 @@ export { default as ImageField } from '../components/admin/fields/ImageField.sve
26
34
  export { default as SlugField } from '../components/admin/fields/SlugField.svelte';
27
35
  export { default as ArrayField } from '../components/admin/fields/ArrayField.svelte';
28
36
  export { default as ReferenceField } from '../components/admin/fields/ReferenceField.svelte';
37
+
29
38
  // Utility functions (browser-safe)
30
- export * from '../utils/index.js';
31
- export * from '../api/index.js';
39
+ export * from '../utils/index';
40
+
41
+ export * from '../api/index';
42
+ export type { ApiResponse } from '../api/index';
@@ -9,10 +9,10 @@
9
9
  import { page } from '$app/state';
10
10
  import { goto } from '$app/navigation';
11
11
  import { SvelteURLSearchParams } from 'svelte/reactivity';
12
- import type { SchemaType } from '../types/index.js';
12
+ import type { SchemaType } from '../types/index';
13
13
  import DocumentEditor from './admin/DocumentEditor.svelte';
14
- import type { DocumentType } from '../types/index.js';
15
- import { documents } from '../api/index.js';
14
+ import type { DocumentType } from '../types/index';
15
+ import { documents } from '../api/index';
16
16
 
17
17
  type InitDocumentType = Pick<DocumentType, 'name' | 'title' | 'description'>;
18
18
 
@@ -35,10 +35,9 @@
35
35
  graphqlSettings = null,
36
36
  isReadOnly = false,
37
37
  activeTab = { value: 'structure' } as { value: 'structure' | 'vision' },
38
- handleTabChange = () => {},
38
+ handleTabChange = () => {}
39
39
  }: Props = $props();
40
40
 
41
-
42
41
  // Set schema context for child components
43
42
 
44
43
  const hasDocumentTypes = $derived(documentTypes.length > 0);
@@ -1,14 +1,14 @@
1
1
  <script lang="ts">
2
2
  import { Button } from '@aphexcms/ui/shadcn/button';
3
3
  import { Badge } from '@aphexcms/ui/shadcn/badge';
4
- import { documents } from '../../api/documents.js';
5
- import { ApiError } from '../../api/client.js';
4
+ import { documents } from '../../api/documents';
5
+ import { ApiError } from '../../api/client';
6
6
  import SchemaField from './SchemaField.svelte';
7
- import { findOrphanedFields, type OrphanedField } from '../../schema-utils/cleanup.js';
8
- import type { SchemaType } from 'src/types/schemas.js';
9
- import { Rule } from '../../field-validation/rule.js';
10
- import { hasUnpublishedChanges } from '../../utils/content-hash.js';
11
- import { setSchemaContext } from '../../schema-context.svelte.js';
7
+ import { findOrphanedFields, type OrphanedField } from '../../schema-utils/cleanup';
8
+ import type { SchemaType } from 'src/lib/types/schemas.js';
9
+ import { Rule } from '../../field-validation/rule';
10
+ import { hasUnpublishedChanges } from '../../utils/content-hash';
11
+ import { setSchemaContext } from '../../schema-context.svelte';
12
12
 
13
13
  interface Props {
14
14
  schemas: SchemaType[];
@@ -8,7 +8,7 @@
8
8
  validateField,
9
9
  getValidationClasses,
10
10
  type ValidationError
11
- } from '../../field-validation/utils.js';
11
+ } from '../../field-validation/utils';
12
12
 
13
13
  // Import individual field components
14
14
  import StringField from './fields/StringField.svelte';
@@ -1,9 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { Button } from '@aphexcms/ui/shadcn/button';
3
3
  import * as DropdownMenu from '@aphexcms/ui/shadcn/dropdown-menu';
4
- import type { ArrayField as ArrayFieldType, SchemaType } from '../../../types/schemas.js';
5
- import { getArrayTypes, getSchemaByName } from '../../../schema-utils/utils.js';
6
- import { getSchemaContext } from '../../../schema-context.svelte.js';
4
+ import type { ArrayField as ArrayFieldType, SchemaType } from '../../../types/schemas';
5
+ import { getArrayTypes, getSchemaByName } from '../../../schema-utils/utils';
6
+ import { getSchemaContext } from '../../../schema-context.svelte';
7
7
  import ObjectModal from '../ObjectModal.svelte';
8
8
 
9
9
  interface Props {
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Label } from '@aphexcms/ui/shadcn/label';
3
- import type { Field } from '../../../types/schemas.js';
3
+ import type { Field } from '../../../types/schemas';
4
4
 
5
5
  interface Props {
6
6
  field: Field;
@@ -1,9 +1,17 @@
1
1
  <script lang="ts">
2
2
  import { Button } from '@aphexcms/ui/shadcn/button';
3
3
  import { Trash2, Upload, Image as ImageIcon, FileImage } from 'lucide-svelte';
4
- import type { ImageValue } from '../../../types/asset.js';
5
- import type { ImageField as ImageFieldType } from '../../../types/schemas.js';
4
+ import type { ImageValue } from '../../../types/asset';
5
+ import type { ImageField as ImageFieldType } from '../../../types/schemas';
6
6
  import { assets } from '../../../api/assets';
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuTrigger,
10
+ DropdownMenuContent,
11
+ DropdownMenuLabel,
12
+ DropdownMenuGroup
13
+ } from '@aphexcms/ui/shadcn/dropdown-menu';
14
+ import { Ellipsis } from '@lucide/svelte';
7
15
 
8
16
  interface Props {
9
17
  field: ImageFieldType;
@@ -192,17 +200,36 @@
192
200
 
193
201
  <!-- Overlay controls (hidden for read-only) -->
194
202
  {#if !readonly}
195
- <div
196
- class="absolute inset-0 flex items-center justify-center gap-2 bg-black/50 opacity-0 transition-opacity group-hover:opacity-100"
197
- >
198
- <Button variant="secondary" size="sm" onclick={openFileDialog} disabled={isUploading}>
199
- <Upload size={16} class="mr-1" />
200
- Replace
201
- </Button>
202
- <Button variant="destructive" size="sm" onclick={removeImage} disabled={isUploading}>
203
- <Trash2 size={16} class="mr-1" />
204
- Remove
205
- </Button>
203
+ <div class="absolute inset-2 flex items-start justify-end gap-2">
204
+ <DropdownMenu>
205
+ <DropdownMenuTrigger><Ellipsis /></DropdownMenuTrigger>
206
+ <DropdownMenuContent>
207
+ <DropdownMenuGroup>
208
+ <DropdownMenuLabel
209
+ ><Button
210
+ variant="secondary"
211
+ size="sm"
212
+ onclick={openFileDialog}
213
+ disabled={isUploading}
214
+ >
215
+ <Upload size={16} class="mr-1" />
216
+ Replace
217
+ </Button></DropdownMenuLabel
218
+ >
219
+ <DropdownMenuLabel
220
+ ><Button
221
+ variant="destructive"
222
+ size="sm"
223
+ onclick={removeImage}
224
+ disabled={isUploading}
225
+ >
226
+ <Trash2 size={16} class="mr-1" />
227
+ Remove
228
+ </Button></DropdownMenuLabel
229
+ >
230
+ </DropdownMenuGroup>
231
+ </DropdownMenuContent>
232
+ </DropdownMenu>
206
233
  </div>
207
234
  {/if}
208
235
  </div>
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Input } from '@aphexcms/ui/shadcn/input';
3
- import type { Field } from '../../../types/schemas.js';
3
+ import type { Field } from '../../../types/schemas';
4
4
 
5
5
  interface Props {
6
6
  field: Field;
@@ -8,8 +8,8 @@
8
8
  import * as Popover from '@aphexcms/ui/shadcn/popover';
9
9
  import { Button } from '@aphexcms/ui/shadcn/button';
10
10
  import { cn } from '@aphexcms/ui/utils';
11
- import type { Field, ReferenceField as ReferenceFieldType } from '../../../types/schemas.js';
12
- import { documents } from '../../../api/documents.js';
11
+ import type { Field, ReferenceField as ReferenceFieldType } from '../../../types/schemas';
12
+ import { documents } from '../../../api/documents';
13
13
 
14
14
  interface Props {
15
15
  field: Field;
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { Input } from '@aphexcms/ui/shadcn/input';
3
3
  import { Button } from '@aphexcms/ui/shadcn/button';
4
- import type { Field } from '../../../types/schemas.js';
5
- import { generateSlug } from '../../../utils/index.js';
4
+ import type { Field } from '../../../types/schemas';
5
+ import { generateSlug } from '../../../utils/index';
6
6
 
7
7
  interface Props {
8
8
  field: Field;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Input } from '@aphexcms/ui/shadcn/input';
3
- import type { Field } from '../../../types/schemas.js';
3
+ import type { Field } from '../../../types/schemas';
4
4
 
5
5
  interface Props {
6
6
  field: Field;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Textarea } from '@aphexcms/ui/shadcn/textarea';
3
- import type { Field } from '../../../types/schemas.js';
3
+ import type { Field } from '../../../types/schemas';
4
4
 
5
5
  interface Props {
6
6
  field: Field;
@@ -1,12 +1,16 @@
1
1
  // Aphex CMS Components
2
2
  // All admin interface components -- is this being used?
3
+
3
4
  // Main admin app
4
5
  export { default as AdminApp } from './AdminApp.svelte';
6
+
5
7
  // Sidebar
6
8
  export { default as Sidebar } from './layout/Sidebar.svelte';
9
+
7
10
  // Admin components (will be migrated from your current structure)
8
11
  export { default as DocumentEditor } from './admin/DocumentEditor.svelte';
9
12
  export { default as DocumentTypesList } from './admin/DocumentTypesList.svelte';
10
13
  export { default as SchemaField } from './admin/SchemaField.svelte';
14
+
11
15
  // Field components
12
- export * from './fields/index.js';
16
+ export * from './fields/index';
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { organizations } from '../../api/index.js';
2
+ import { organizations } from '../../api/index';
3
3
  import { invalidateAll, goto } from '$app/navigation';
4
4
  import { page } from '$app/state';
5
5
  import { SvelteURLSearchParams } from 'svelte/reactivity';
@@ -17,7 +17,7 @@
17
17
  SidebarMenuButton,
18
18
  useSidebar
19
19
  } from '@aphexcms/ui/shadcn/sidebar';
20
- import type { SidebarOrganization } from '../../types/sidebar.js';
20
+ import type { SidebarOrganization } from '../../types/sidebar';
21
21
 
22
22
  type Props = {
23
23
  organizations?: SidebarOrganization[];
@@ -6,7 +6,7 @@
6
6
  import { Sun, Moon } from 'lucide-svelte';
7
7
  import { toggleMode } from 'mode-watcher';
8
8
  import { page } from '$app/state';
9
- import type { SidebarData } from '../../types/sidebar.js';
9
+ import type { SidebarData } from '../../types/sidebar';
10
10
  import AppSidebar from './sidebar/AppSidebar.svelte';
11
11
 
12
12
  type Props = {
@@ -9,7 +9,7 @@
9
9
  import OrganizationSwitcher from '../OrganizationSwitcher.svelte';
10
10
  import NavMain from './NavMain.svelte';
11
11
  import NavUser from './NavUser.svelte';
12
- import type { SidebarData } from '../../../types/sidebar.js';
12
+ import type { SidebarData } from '../../../types/sidebar';
13
13
  import type { ComponentProps } from 'svelte';
14
14
 
15
15
  type Props = ComponentProps<typeof Sidebar> & {
@@ -14,7 +14,7 @@
14
14
  DropdownMenuTrigger
15
15
  } from '@aphexcms/ui/shadcn/dropdown-menu';
16
16
  import { ChevronsUpDown, Settings, LogOut } from 'lucide-svelte';
17
- import type { AuthUser } from '../../../types/user.js';
17
+ import type { AuthUser } from '../../../types/user';
18
18
 
19
19
  type Props = {
20
20
  user: AuthUser;
@@ -0,0 +1,18 @@
1
+ // Aphex CMS Configuration System
2
+ import type { CMSConfig } from './types/index';
3
+
4
+ export function createCMSConfig(config: CMSConfig): CMSConfig {
5
+ return {
6
+ // Start with the user's config and apply defaults for missing properties
7
+ ...config,
8
+ storage: config.storage ?? null, // Default to null if not provided
9
+ customization: {
10
+ branding: {
11
+ title: 'Aphex CMS',
12
+ ...config.customization?.branding
13
+ },
14
+ ...config.customization
15
+ },
16
+ plugins: config.plugins ?? []
17
+ };
18
+ }
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  // Database adapters are now in separate packages
3
2
  // e.g., @aphexcms/postgresql-adapter, @aphexcms/mongodb-adapter
4
3
  // This file is kept for backwards compatibility but exports nothing - and potentially default adapters or something. maybe sqlite?
@@ -1,4 +1,5 @@
1
1
  // Aphex CMS Database Layer
2
2
  // Ports and adapters for database operations
3
+
3
4
  // Interfaces
4
- export * from './interfaces/index.js';
5
+ export * from './interfaces/index';
@@ -0,0 +1,61 @@
1
+ // Asset interface for asset operations
2
+ import type { Asset } from '../../types/index';
3
+
4
+ export interface AssetFilters {
5
+ organizationId: string; // Required for multi-tenancy (user's current org for RLS context)
6
+ assetType?: 'image' | 'file';
7
+ mimeType?: string;
8
+ search?: string;
9
+ limit?: number;
10
+ offset?: number;
11
+ filterOrganizationIds?: string[]; // Optional: Filter to specific org(s). RLS still enforces access.
12
+ }
13
+
14
+ export interface CreateAssetData {
15
+ organizationId: string; // Required for multi-tenancy
16
+ assetType: 'image' | 'file';
17
+ filename: string;
18
+ originalFilename: string;
19
+ mimeType: string;
20
+ size: number;
21
+ url: string;
22
+ path: string;
23
+ storageAdapter: string; // Which storage adapter was used
24
+ width?: number;
25
+ height?: number;
26
+ metadata?: any;
27
+ title?: string;
28
+ description?: string;
29
+ alt?: string;
30
+ creditLine?: string;
31
+ createdBy?: string; // User ID (optional for backward compatibility)
32
+ }
33
+
34
+ export interface UpdateAssetData {
35
+ url?: string; // Allow updating URL (for local storage after asset creation)
36
+ title?: string;
37
+ description?: string;
38
+ alt?: string;
39
+ creditLine?: string;
40
+ updatedBy?: string; // User ID (optional for backward compatibility)
41
+ }
42
+
43
+ /**
44
+ * Asset adapter interface for asset-specific operations
45
+ */
46
+ export interface AssetAdapter {
47
+ // Asset CRUD operations
48
+ createAsset(data: CreateAssetData): Promise<Asset>;
49
+ findAssetById(organizationId: string, id: string): Promise<Asset | null>;
50
+ findAssets(
51
+ organizationId: string,
52
+ filters?: Omit<AssetFilters, 'organizationId'>
53
+ ): Promise<Asset[]>;
54
+ updateAsset(organizationId: string, id: string, data: UpdateAssetData): Promise<Asset | null>;
55
+ deleteAsset(organizationId: string, id: string): Promise<boolean>;
56
+
57
+ // Asset analytics
58
+ countAssets(organizationId: string): Promise<number>;
59
+ countAssetsByType(organizationId: string): Promise<Record<string, number>>;
60
+ getTotalAssetsSize(organizationId: string): Promise<number>;
61
+ }
@@ -0,0 +1,53 @@
1
+ // Document interface for document operations
2
+ import type { Document } from '../../types/index';
3
+
4
+ export interface DocumentFilters {
5
+ organizationId: string; // Required for multi-tenancy (user's current org for RLS context)
6
+ type?: string;
7
+ status?: string;
8
+ limit?: number;
9
+ offset?: number;
10
+ depth?: number; // How deep to resolve nested references (0 = no resolution, default = 0)
11
+ filterOrganizationIds?: string[]; // Optional: Filter to specific org(s). RLS still enforces access.
12
+ }
13
+
14
+ export interface CreateDocumentData {
15
+ organizationId: string; // Required for multi-tenancy
16
+ type: string;
17
+ draftData: any;
18
+ createdBy?: string; // User ID (optional for backward compatibility)
19
+ }
20
+
21
+ export interface UpdateDocumentData {
22
+ draftData?: any;
23
+ status?: string;
24
+ updatedBy?: string; // User ID (optional for backward compatibility)
25
+ }
26
+
27
+ /**
28
+ * Document adapter interface for document-specific operations
29
+ */
30
+ export interface DocumentAdapter {
31
+ // Document CRUD operations
32
+ findManyDoc(
33
+ organizationId: string,
34
+ filters?: Omit<DocumentFilters, 'organizationId'>
35
+ ): Promise<Document[]>;
36
+ findByDocId(organizationId: string, id: string, depth?: number): Promise<Document | null>;
37
+ createDocument(data: CreateDocumentData): Promise<Document>;
38
+ updateDocDraft(
39
+ organizationId: string,
40
+ id: string,
41
+ data: any,
42
+ updatedBy?: string
43
+ ): Promise<Document | null>;
44
+ deleteDocById(organizationId: string, id: string): Promise<boolean>;
45
+
46
+ // Publishing operations
47
+ publishDoc(organizationId: string, id: string): Promise<Document | null>;
48
+ unpublishDoc(organizationId: string, id: string): Promise<Document | null>;
49
+
50
+ // Analytics/counts
51
+ countDocsByType(organizationId: string, type: string): Promise<number>;
52
+ getDocCountsByType(organizationId: string): Promise<Record<string, number>>;
53
+ }