@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,287 @@
1
+ // Sanity-style validation Rule implementation
2
+ export interface ValidationMarker {
3
+ level: 'error' | 'warning' | 'info';
4
+ message: string;
5
+ path?: string[];
6
+ }
7
+
8
+ export interface ValidationContext {
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ document?: any;
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ parent?: any;
13
+ path?: string[];
14
+ }
15
+
16
+ export interface CustomValidator<T = unknown> {
17
+ (
18
+ value: T,
19
+ context: ValidationContext
20
+ ): ValidationMarker[] | string | boolean | Promise<ValidationMarker[] | string | boolean>;
21
+ }
22
+
23
+ export interface FieldReference {
24
+ __fieldReference: true;
25
+ path: string | string[];
26
+ }
27
+
28
+ export class Rule {
29
+ private _required: boolean = false;
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ private _rules: Array<{ type: string; constraint?: any; message?: string }> = [];
32
+ private _level: 'error' | 'warning' | 'info' = 'error';
33
+ private _message?: string;
34
+
35
+ static FIELD_REF = Symbol('fieldReference');
36
+
37
+ static valueOfField(path: string | string[]): FieldReference {
38
+ return {
39
+ __fieldReference: true,
40
+ path
41
+ };
42
+ }
43
+
44
+ valueOfField(path: string | string[]): FieldReference {
45
+ return Rule.valueOfField(path);
46
+ }
47
+
48
+ required(): Rule {
49
+ const newRule = this.clone();
50
+ newRule._required = true;
51
+ return newRule;
52
+ }
53
+
54
+ optional(): Rule {
55
+ const newRule = this.clone();
56
+ newRule._required = false;
57
+ return newRule;
58
+ }
59
+
60
+ min(len: number | string | FieldReference): Rule {
61
+ const newRule = this.clone();
62
+ newRule._rules.push({ type: 'min', constraint: len });
63
+ return newRule;
64
+ }
65
+
66
+ max(len: number | string | FieldReference): Rule {
67
+ const newRule = this.clone();
68
+ newRule._rules.push({ type: 'max', constraint: len });
69
+ return newRule;
70
+ }
71
+
72
+ length(len: number | FieldReference): Rule {
73
+ const newRule = this.clone();
74
+ newRule._rules.push({ type: 'length', constraint: len });
75
+ return newRule;
76
+ }
77
+
78
+ email(): Rule {
79
+ const newRule = this.clone();
80
+ newRule._rules.push({ type: 'email' });
81
+ return newRule;
82
+ }
83
+
84
+ uri(options?: { scheme?: RegExp[]; allowRelative?: boolean }): Rule {
85
+ const newRule = this.clone();
86
+ newRule._rules.push({ type: 'uri', constraint: options });
87
+ return newRule;
88
+ }
89
+
90
+ regex(pattern: RegExp, name?: string): Rule {
91
+ const newRule = this.clone();
92
+ newRule._rules.push({ type: 'regex', constraint: { pattern, name } });
93
+ return newRule;
94
+ }
95
+
96
+ positive(): Rule {
97
+ const newRule = this.clone();
98
+ newRule._rules.push({ type: 'positive' });
99
+ return newRule;
100
+ }
101
+
102
+ negative(): Rule {
103
+ const newRule = this.clone();
104
+ newRule._rules.push({ type: 'negative' });
105
+ return newRule;
106
+ }
107
+
108
+ integer(): Rule {
109
+ const newRule = this.clone();
110
+ newRule._rules.push({ type: 'integer' });
111
+ return newRule;
112
+ }
113
+
114
+ greaterThan(num: number | FieldReference): Rule {
115
+ const newRule = this.clone();
116
+ newRule._rules.push({ type: 'greaterThan', constraint: num });
117
+ return newRule;
118
+ }
119
+
120
+ lessThan(num: number | FieldReference): Rule {
121
+ const newRule = this.clone();
122
+ newRule._rules.push({ type: 'lessThan', constraint: num });
123
+ return newRule;
124
+ }
125
+
126
+ custom<T = unknown>(fn: CustomValidator<T>): Rule {
127
+ const newRule = this.clone();
128
+ newRule._rules.push({ type: 'custom', constraint: fn });
129
+ return newRule;
130
+ }
131
+
132
+ error(message?: string): Rule {
133
+ const newRule = this.clone();
134
+ newRule._level = 'error';
135
+ newRule._message = message;
136
+ return newRule;
137
+ }
138
+
139
+ warning(message?: string): Rule {
140
+ const newRule = this.clone();
141
+ newRule._level = 'warning';
142
+ newRule._message = message;
143
+ return newRule;
144
+ }
145
+
146
+ info(message?: string): Rule {
147
+ const newRule = this.clone();
148
+ newRule._level = 'info';
149
+ newRule._message = message;
150
+ return newRule;
151
+ }
152
+
153
+ clone(): Rule {
154
+ const newRule = new Rule();
155
+ newRule._required = this._required;
156
+ newRule._rules = [...this._rules];
157
+ newRule._level = this._level;
158
+ newRule._message = this._message;
159
+ return newRule;
160
+ }
161
+
162
+ async validate(value: unknown, context: ValidationContext = {}): Promise<ValidationMarker[]> {
163
+ const markers: ValidationMarker[] = [];
164
+
165
+ // Check required
166
+ if (this._required && (value === undefined || value === null || value === '')) {
167
+ markers.push({
168
+ level: this._level,
169
+ message: this._message || 'Required',
170
+ path: context.path
171
+ });
172
+ }
173
+
174
+ // If value is empty and not required, skip other validations
175
+ if (!this._required && (value === undefined || value === null || value === '')) {
176
+ return markers;
177
+ }
178
+
179
+ // Run other validations
180
+ for (const rule of this._rules) {
181
+ try {
182
+ const result = await this.validateRule(rule, value, context);
183
+ if (result) {
184
+ markers.push({
185
+ level: this._level,
186
+ message: this._message || result,
187
+ path: context.path
188
+ });
189
+ }
190
+ } catch (error) {
191
+ markers.push({
192
+ level: 'error',
193
+ message: `Validation error: ${error instanceof Error ? error.message : 'Unknown error'}`,
194
+ path: context.path
195
+ });
196
+ }
197
+ }
198
+
199
+ return markers;
200
+ }
201
+
202
+ private async validateRule(
203
+ rule: { type: string; constraint?: any },
204
+ value: unknown,
205
+ context: ValidationContext
206
+ ): Promise<string | null> {
207
+ switch (rule.type) {
208
+ case 'min':
209
+ if (typeof value === 'string' && value.length < rule.constraint) {
210
+ return `Must be at least ${rule.constraint} characters`;
211
+ }
212
+ if (typeof value === 'number' && value < rule.constraint) {
213
+ return `Must be at least ${rule.constraint}`;
214
+ }
215
+ break;
216
+
217
+ case 'max':
218
+ if (typeof value === 'string' && value.length > rule.constraint) {
219
+ return `Must be at most ${rule.constraint} characters`;
220
+ }
221
+ if (typeof value === 'number' && value > rule.constraint) {
222
+ return `Must be at most ${rule.constraint}`;
223
+ }
224
+ break;
225
+
226
+ case 'email':
227
+ if (typeof value === 'string' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
228
+ return 'Must be a valid email address';
229
+ }
230
+ break;
231
+
232
+ case 'uri':
233
+ if (typeof value === 'string') {
234
+ try {
235
+ new URL(value);
236
+ } catch {
237
+ return 'Must be a valid URL';
238
+ }
239
+ }
240
+ break;
241
+
242
+ case 'regex':
243
+ if (typeof value === 'string' && !rule.constraint.pattern.test(value)) {
244
+ return `Must match pattern${rule.constraint.name ? ` (${rule.constraint.name})` : ''}`;
245
+ }
246
+ break;
247
+
248
+ case 'positive':
249
+ if (typeof value === 'number' && value <= 0) {
250
+ return 'Must be positive';
251
+ }
252
+ break;
253
+
254
+ case 'negative':
255
+ if (typeof value === 'number' && value >= 0) {
256
+ return 'Must be negative';
257
+ }
258
+ break;
259
+
260
+ case 'integer':
261
+ if (typeof value === 'number' && !Number.isInteger(value)) {
262
+ return 'Must be an integer';
263
+ }
264
+ break;
265
+
266
+ case 'custom': {
267
+ const customResult = await rule.constraint(value, context);
268
+ if (customResult === false) {
269
+ return 'Validation failed';
270
+ }
271
+ if (typeof customResult === 'string') {
272
+ return customResult;
273
+ }
274
+ if (Array.isArray(customResult) && customResult.length > 0) {
275
+ return customResult[0].message;
276
+ }
277
+ break;
278
+ }
279
+ }
280
+
281
+ return null;
282
+ }
283
+
284
+ isRequired(): boolean {
285
+ return this._required;
286
+ }
287
+ }
@@ -0,0 +1,91 @@
1
+ import type { Field } from '../types/index';
2
+ import { Rule } from './rule';
3
+
4
+ export interface ValidationError {
5
+ level: 'error' | 'warning' | 'info';
6
+ message: string;
7
+ }
8
+
9
+ /**
10
+ * Check if a field is required based on its validation rules
11
+ */
12
+ export function isFieldRequired(field: Field): boolean {
13
+ if (!field.validation) return false;
14
+ try {
15
+ const validationFn = Array.isArray(field.validation) ? field.validation[0] : field.validation;
16
+ if (!validationFn) return false;
17
+ const rule = validationFn(new Rule());
18
+ return rule.isRequired();
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Validate a field value against its validation rules
26
+ */
27
+ export async function validateField(
28
+ field: Field,
29
+ value: any,
30
+ context: any = {}
31
+ ): Promise<{
32
+ isValid: boolean;
33
+ errors: ValidationError[];
34
+ }> {
35
+ if (!field.validation) {
36
+ return { isValid: true, errors: [] };
37
+ }
38
+
39
+ try {
40
+ const validationFunctions = Array.isArray(field.validation)
41
+ ? field.validation
42
+ : [field.validation];
43
+
44
+ const allErrors: ValidationError[] = [];
45
+
46
+ for (const validationFn of validationFunctions) {
47
+ const rule = validationFn(new Rule());
48
+
49
+ if (!(rule instanceof Rule)) {
50
+ console.error(
51
+ `Validation function for field "${field.name}" did not return a Rule object. Make sure you are chaining validation methods and returning the result.`
52
+ );
53
+ continue;
54
+ }
55
+
56
+ const markers = await rule.validate(value, {
57
+ path: [field.name],
58
+ ...context
59
+ });
60
+
61
+ allErrors.push(
62
+ ...markers.map((marker) => ({
63
+ level: marker.level,
64
+ message: marker.message
65
+ }))
66
+ );
67
+ }
68
+
69
+ const isValid = allErrors.filter((e) => e.level === 'error').length === 0;
70
+
71
+ return { isValid, errors: allErrors };
72
+ } catch (error) {
73
+ console.error('Validation error:', error);
74
+ return {
75
+ isValid: false,
76
+ errors: [{ level: 'error', message: 'Validation failed' }]
77
+ };
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Get validation CSS classes for input styling
83
+ */
84
+ export function getValidationClasses(hasErrors: boolean): string {
85
+ if (hasErrors) {
86
+ return 'border-destructive border-2';
87
+ }
88
+
89
+ // No green styling for success - only show red for errors
90
+ return '';
91
+ }
@@ -0,0 +1,142 @@
1
+ import type { Handle } from '@sveltejs/kit';
2
+ import type { CMSConfig } from './types/index';
3
+ import type { DatabaseAdapter } from './db/index';
4
+ import type { AssetService } from './services/asset-service';
5
+ import type { StorageAdapter } from './storage/interfaces/storage';
6
+ import type { EmailAdapter } from './email/index';
7
+ import type { AuthProvider } from './auth/provider';
8
+ import { handleAuthHook } from './auth/auth-hooks';
9
+ import { createStorageAdapter as createStorageAdapterProvider } from './storage/providers/storage';
10
+ import { AssetService as AssetServiceClass } from './services/asset-service';
11
+ import { createCMS, CMSEngine } from './engine';
12
+
13
+ // Singleton instances - created once per application lifecycle
14
+ export interface CMSInstances {
15
+ config: CMSConfig;
16
+ assetService: AssetService;
17
+ storageAdapter: StorageAdapter;
18
+ databaseAdapter: DatabaseAdapter;
19
+ emailAdapter?: EmailAdapter | null;
20
+ cmsEngine: CMSEngine;
21
+ auth?: AuthProvider;
22
+ pluginRoutes?: Map<
23
+ string,
24
+ { handler: (event: any) => Promise<Response> | Response; pluginName: string }
25
+ >;
26
+ }
27
+
28
+ let cmsInstances: CMSInstances | null = null;
29
+ let lastConfigHash: string | null = null;
30
+
31
+ // Helper to generate a simple hash of schema types for change detection
32
+ function getConfigHash(config: CMSConfig): string {
33
+ const schemaNames = config.schemaTypes
34
+ .map((s) => `${s.name}:${s.fields.length}:${JSON.stringify(s.fields)}`)
35
+ .join(',');
36
+ return schemaNames;
37
+ }
38
+
39
+ // Factory function to create the default local storage adapter
40
+ function createDefaultStorageAdapter(): StorageAdapter {
41
+ return createStorageAdapterProvider('local', {
42
+ basePath: './storage/assets', // Private storage - not in static/, not served in production
43
+ baseUrl: '' // No direct URL - all access through /assets/{id}/{filename}
44
+ });
45
+ }
46
+
47
+ export function createCMSHook(config: CMSConfig): Handle {
48
+ return async ({ event, resolve }) => {
49
+ // Note: In dev mode, /storage/ might be accessible via Vite dev server
50
+ // In production, only /static/ folder is served - /storage/ is private
51
+
52
+ const currentConfigHash = getConfigHash(config);
53
+ const configChanged = lastConfigHash !== null && currentConfigHash !== lastConfigHash;
54
+
55
+ // Initialize CMS instances once at application startup
56
+ if (!cmsInstances) {
57
+ console.log('🚀 Initializing CMS...');
58
+ const databaseAdapter = config.database;
59
+ // Use the storage adapter from config, or create the default local one.
60
+ const storageAdapter = config.storage ?? createDefaultStorageAdapter();
61
+ const emailAdapter = config.email ?? null;
62
+ const assetService = new AssetServiceClass(storageAdapter, databaseAdapter);
63
+ const cmsEngine = createCMS(config, databaseAdapter);
64
+
65
+ await cmsEngine.initialize();
66
+
67
+ // Build plugin route map (do this ONCE at startup)
68
+ const pluginRoutes = new Map<
69
+ string,
70
+ { handler: (event: any) => Promise<Response> | Response; pluginName: string }
71
+ >();
72
+ if (config.plugins && config.plugins.length > 0) {
73
+ for (const plugin of config.plugins) {
74
+ if (plugin.routes) {
75
+ for (const [path, handler] of Object.entries(plugin.routes)) {
76
+ pluginRoutes.set(path, { handler, pluginName: plugin.name });
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ cmsInstances = {
83
+ config,
84
+ databaseAdapter: databaseAdapter,
85
+ assetService: assetService,
86
+ storageAdapter: storageAdapter,
87
+ emailAdapter: emailAdapter,
88
+ cmsEngine: cmsEngine,
89
+ auth: config.auth?.provider,
90
+ pluginRoutes
91
+ };
92
+
93
+ // Install plugins
94
+ if (config.plugins && config.plugins.length > 0) {
95
+ for (const plugin of config.plugins) {
96
+ console.log(`🔌 Installing plugin: ${plugin.name}`);
97
+ await plugin.install(cmsInstances);
98
+ }
99
+ }
100
+
101
+ lastConfigHash = currentConfigHash;
102
+ } else if (configChanged) {
103
+ // HMR: Config changed, re-sync schemas
104
+ console.log('🔄 Schema types changed, re-syncing...');
105
+ console.log('Old hash:', lastConfigHash?.substring(0, 100) + '...');
106
+ console.log('New hash:', currentConfigHash.substring(0, 100) + '...');
107
+ console.log(
108
+ 'Schema types being updated:',
109
+ config.schemaTypes.map((s) => s.name)
110
+ );
111
+ cmsInstances.cmsEngine.updateConfig(config);
112
+ await cmsInstances.cmsEngine.initialize();
113
+ lastConfigHash = currentConfigHash;
114
+ console.log('✅ Schema sync complete');
115
+ }
116
+
117
+ // Inject shared CMS services into locals (reuse singleton instances)
118
+ event.locals.aphexCMS = cmsInstances;
119
+
120
+ // Auth protection if configured
121
+ if (cmsInstances.auth) {
122
+ const authResponse = await handleAuthHook(
123
+ event,
124
+ config,
125
+ cmsInstances.auth,
126
+ cmsInstances.databaseAdapter
127
+ );
128
+ if (authResponse) return authResponse;
129
+ }
130
+
131
+ // Check if a plugin handles this route (O(1) lookup)
132
+ if (cmsInstances.pluginRoutes && cmsInstances.pluginRoutes.size > 0) {
133
+ const pluginRoute = cmsInstances.pluginRoutes.get(event.url.pathname);
134
+ if (pluginRoute) {
135
+ console.log(`🔌 Plugin ${pluginRoute.pluginName} handling route: ${event.url.pathname}`);
136
+ return pluginRoute.handler(event);
137
+ }
138
+ }
139
+
140
+ return resolve(event);
141
+ };
142
+ }
@@ -1,4 +1,5 @@
1
1
  // Aphex CMS Core - Main exports (client-safe only)
2
2
  // For server-side functionality, import from '@aphexcms/cms-core/server'
3
+
3
4
  // Re-export all client-safe functionality
4
- export * from './client/index.js';
5
+ export * from './client/index';
@@ -1,7 +1,9 @@
1
1
  import { MediaQuery } from 'svelte/reactivity';
2
+
2
3
  const DEFAULT_MOBILE_BREAKPOINT = 768;
4
+
3
5
  export class IsMobile extends MediaQuery {
4
- constructor(breakpoint = DEFAULT_MOBILE_BREAKPOINT) {
5
- super(`max-width: ${breakpoint - 1}px`);
6
- }
6
+ constructor(breakpoint: number = DEFAULT_MOBILE_BREAKPOINT) {
7
+ super(`max-width: ${breakpoint - 1}px`);
8
+ }
7
9
  }
@@ -0,0 +1,161 @@
1
+ import { json } from '@sveltejs/kit';
2
+ import type { RequestHandler } from '@sveltejs/kit';
3
+ import { Asset } from '../types/asset';
4
+
5
+ export const GET: RequestHandler = async ({ params, locals }) => {
6
+ try {
7
+ const { assetService } = locals.aphexCMS;
8
+ const auth = locals.auth;
9
+ const { id } = params;
10
+
11
+ if (!auth) {
12
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
13
+ }
14
+
15
+ if (!id) {
16
+ return json({ success: false, error: 'Asset ID is required' }, { status: 400 });
17
+ }
18
+
19
+ const asset = await assetService.findAssetById(auth.organizationId, id);
20
+
21
+ if (!asset) {
22
+ return json({ success: false, error: 'Asset not found' }, { status: 404 });
23
+ }
24
+
25
+ // Return JSON metadata for admin UI
26
+ return json({
27
+ success: true,
28
+ data: {
29
+ _type: asset.assetType === 'image' ? 'sanity.imageAsset' : 'sanity.fileAsset',
30
+ _id: asset.id,
31
+ url: asset.url,
32
+ originalFilename: asset.originalFilename,
33
+ mimeType: asset.mimeType,
34
+ size: asset.size,
35
+ metadata: {
36
+ dimensions:
37
+ asset.width && asset.height
38
+ ? {
39
+ width: asset.width,
40
+ height: asset.height
41
+ }
42
+ : undefined,
43
+ ...asset.metadata
44
+ },
45
+ title: asset.title,
46
+ description: asset.description,
47
+ alt: asset.alt,
48
+ creditLine: asset.creditLine,
49
+ _createdAt: asset.createdAt,
50
+ _updatedAt: asset.updatedAt
51
+ }
52
+ });
53
+ } catch (error) {
54
+ console.error('[Asset API] Error fetching asset:', error);
55
+ return json({ success: false, error: 'Failed to fetch asset' }, { status: 500 });
56
+ }
57
+ };
58
+
59
+ export const DELETE: RequestHandler = async ({ params, locals }) => {
60
+ try {
61
+ const { id } = params;
62
+ const { assetService } = locals.aphexCMS;
63
+ const auth = locals.auth;
64
+
65
+ if (!auth) {
66
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
67
+ }
68
+
69
+ if (!id) {
70
+ return json({ success: false, error: 'Asset ID is required' }, { status: 400 });
71
+ }
72
+
73
+ const result = await assetService.deleteAsset(auth.organizationId, id);
74
+
75
+ if (!result) {
76
+ return json(
77
+ { success: false, error: 'Asset not found or could not be deleted' },
78
+ { status: 404 }
79
+ );
80
+ }
81
+
82
+ return json({ success: true });
83
+ } catch (error) {
84
+ console.error('Error deleting asset:', error);
85
+ return json({ success: false, error: 'Failed to delete asset' }, { status: 500 });
86
+ }
87
+ };
88
+
89
+ export const PATCH: RequestHandler = async ({ params, locals, request }) => {
90
+ try {
91
+ const { assetService } = locals.aphexCMS;
92
+ const auth = locals.auth;
93
+ const { id } = params;
94
+
95
+ if (!auth) {
96
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
97
+ }
98
+
99
+ if (!id) {
100
+ return json({ success: false, error: 'Asset ID is required' }, { status: 400 });
101
+ }
102
+
103
+ const { title, description, alt, creditLine } = await request.json();
104
+
105
+ let updatedAsset: Asset | null;
106
+
107
+ if (auth.type == 'session') {
108
+ updatedAsset = await assetService.updateAssetMetadata(auth.organizationId, id, {
109
+ title,
110
+ description,
111
+ alt,
112
+ creditLine,
113
+ updatedBy: auth.user.id
114
+ });
115
+ } else {
116
+ updatedAsset = await assetService.updateAssetMetadata(auth.organizationId, id, {
117
+ title,
118
+ description,
119
+ alt,
120
+ creditLine,
121
+ updatedBy: auth.keyId
122
+ });
123
+ }
124
+
125
+ if (!updatedAsset) {
126
+ return json({ success: false, error: 'Asset not found' }, { status: 404 });
127
+ }
128
+
129
+ // Return API response with success wrapper
130
+ return json({
131
+ success: true,
132
+ data: {
133
+ _type: updatedAsset.assetType === 'image' ? 'sanity.imageAsset' : 'sanity.fileAsset',
134
+ _id: updatedAsset.id,
135
+ url: updatedAsset.url,
136
+ originalFilename: updatedAsset.originalFilename,
137
+ mimeType: updatedAsset.mimeType,
138
+ size: updatedAsset.size,
139
+ metadata: {
140
+ dimensions:
141
+ updatedAsset.width && updatedAsset.height
142
+ ? {
143
+ width: updatedAsset.width,
144
+ height: updatedAsset.height
145
+ }
146
+ : undefined,
147
+ ...updatedAsset.metadata
148
+ },
149
+ title: updatedAsset.title,
150
+ description: updatedAsset.description,
151
+ alt: updatedAsset.alt,
152
+ creditLine: updatedAsset.creditLine,
153
+ _createdAt: updatedAsset.createdAt,
154
+ _updatedAt: updatedAsset.updatedAt
155
+ }
156
+ });
157
+ } catch (error) {
158
+ console.error('Error updating asset:', error);
159
+ return json({ success: false, error: 'Failed to update asset' }, { status: 500 });
160
+ }
161
+ };