@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,185 @@
1
+ import type { RequestHandler } from '@sveltejs/kit';
2
+
3
+ export const GET: RequestHandler = async ({ params, locals, setHeaders, request }) => {
4
+ console.log('[Asset CDN] ========== ROUTE HIT ==========');
5
+ console.log('[Asset CDN] Params:', params);
6
+ try {
7
+ const { assetService, databaseAdapter, storageAdapter, cmsEngine, config } = locals.aphexCMS;
8
+ let auth = locals.auth;
9
+ const { id, filename } = params;
10
+
11
+ console.log('[Asset CDN] Request for asset:', id, filename);
12
+ console.log('[Asset CDN] Has auth?', !!auth);
13
+
14
+ // If no session auth, check for API key in headers
15
+ if (!auth) {
16
+ const apiKey = request.headers.get('x-api-key');
17
+ console.log('[Asset CDN] API key present?', !!apiKey);
18
+ if (apiKey && config.auth?.provider) {
19
+ try {
20
+ const apiKeyAuth = await config.auth.provider.validateApiKey(request, databaseAdapter);
21
+ if (apiKeyAuth) {
22
+ auth = apiKeyAuth;
23
+ console.log('[Asset CDN] Authenticated via API key, org:', apiKeyAuth.organizationId);
24
+ }
25
+ } catch (err) {
26
+ console.warn('[Asset CDN] API key validation failed:', err);
27
+ }
28
+ }
29
+ }
30
+
31
+ console.log('[Asset CDN] Auth type:', auth?.type);
32
+
33
+ if (!id) {
34
+ return new Response('Asset ID is required', { status: 400 });
35
+ }
36
+
37
+ // Try to fetch asset globally first (bypasses RLS for public assets)
38
+ const asset = await assetService.findAssetByIdGlobal(id);
39
+
40
+ console.log('[Asset CDN] Asset found globally?', !!asset);
41
+
42
+ if (!asset) {
43
+ console.warn('[Asset CDN] Asset not found:', id);
44
+ return new Response('Asset not found', { status: 404 });
45
+ }
46
+
47
+ const organizationId = auth?.organizationId;
48
+ console.log('[Asset CDN] Auth object:', JSON.stringify(auth, null, 2));
49
+ console.log('[Asset CDN] Auth organizationId:', organizationId);
50
+ console.log('[Asset CDN] Asset organizationId:', asset.organizationId);
51
+
52
+ // Check if this asset is used in a private field
53
+ // The field metadata (schemaType and fieldPath) is stored when the asset is uploaded
54
+ let isPrivate = false;
55
+
56
+ const schemaType = asset.metadata?.schemaType;
57
+ const fieldPath = asset.metadata?.fieldPath;
58
+
59
+ if (schemaType && fieldPath) {
60
+ // Get the schema definition from IN-MEMORY config (always up-to-date with code changes)
61
+ const schema = cmsEngine.getSchemaTypeByName(schemaType);
62
+ console.log(`[Asset CDN] Schema lookup for ${schemaType}:`, {
63
+ found: !!schema,
64
+ fieldCount: schema?.fields?.length
65
+ });
66
+
67
+ if (schema && schema.fields) {
68
+ // Navigate the field path to find the field definition
69
+ const findField = (fields: any[], path: string): any => {
70
+ const parts = path.split('.');
71
+ let current: any = null;
72
+
73
+ for (let i = 0; i < parts.length; i++) {
74
+ const part = parts[i];
75
+ current = fields.find((f) => f.name === part);
76
+
77
+ if (!current) return null;
78
+
79
+ // If not the last part, navigate into nested fields
80
+ if (i < parts.length - 1) {
81
+ if (current.type === 'object' && current.fields) {
82
+ fields = current.fields;
83
+ } else {
84
+ return null;
85
+ }
86
+ }
87
+ }
88
+
89
+ return current;
90
+ };
91
+
92
+ const field = findField(schema.fields, fieldPath);
93
+ console.log(`[Asset CDN] Field lookup for ${fieldPath}:`, {
94
+ found: !!field,
95
+ type: field?.type,
96
+ private: field?.private
97
+ });
98
+
99
+ if (field && field.type === 'image') {
100
+ isPrivate = field.private === true;
101
+ console.log(
102
+ `[Asset CDN] Field check: ${schemaType}.${fieldPath} - private: ${isPrivate}`
103
+ );
104
+ } else {
105
+ console.warn(`[Asset CDN] Could not find field: ${schemaType}.${fieldPath}`);
106
+ }
107
+ }
108
+ } else {
109
+ console.log('[Asset CDN] No field metadata - treating as public');
110
+ }
111
+
112
+ console.log('[Asset CDN] Asset privacy result:', { isPrivate, schemaType, fieldPath });
113
+
114
+ // If asset is private, require auth
115
+ if (isPrivate && !organizationId) {
116
+ console.warn('[Asset CDN] Private asset accessed without auth - DENIED');
117
+ return new Response('Unauthorized - This asset is private', { status: 401 });
118
+ }
119
+
120
+ // If asset is private, verify org matches
121
+ if (isPrivate && organizationId && organizationId !== asset.organizationId) {
122
+ console.warn('[Asset CDN] Org mismatch for private asset - FORBIDDEN');
123
+ return new Response('Forbidden', { status: 403 });
124
+ }
125
+
126
+ // Log the decision
127
+ if (isPrivate && organizationId) {
128
+ console.log('[Asset CDN] Private asset access ALLOWED - user has auth and org matches');
129
+ } else if (!isPrivate) {
130
+ console.log('[Asset CDN] Public asset access ALLOWED');
131
+ }
132
+
133
+ console.log('[Asset CDN] Asset found:', {
134
+ id: asset.id,
135
+ path: asset.path,
136
+ mimeType: asset.mimeType,
137
+ storageAdapter: asset.storageAdapter
138
+ });
139
+
140
+ // If asset has a direct URL (S3/R2), redirect to it
141
+ if (asset.url && asset.url.startsWith('http')) {
142
+ console.log('[Asset CDN] Redirecting to external URL:', asset.url);
143
+ return new Response(null, {
144
+ status: 302,
145
+ headers: { Location: asset.url }
146
+ });
147
+ }
148
+
149
+ // Otherwise, serve from local storage
150
+ if (!storageAdapter?.getObject) {
151
+ console.error('[Asset CDN] Storage adapter does not support getObject');
152
+ return new Response('Storage adapter does not support file serving', { status: 500 });
153
+ }
154
+
155
+ console.log('[Asset CDN] Reading file from storage:', asset.path);
156
+ const fileBuffer = await storageAdapter.getObject(asset.path);
157
+
158
+ console.log('[Asset CDN] Serving file:', {
159
+ size: fileBuffer.length,
160
+ mimeType: asset.mimeType
161
+ });
162
+
163
+ // Set appropriate headers for the asset
164
+ setHeaders({
165
+ 'Content-Type': asset.mimeType || 'application/octet-stream',
166
+ 'Content-Length': fileBuffer.length.toString(),
167
+ 'Cache-Control': 'public, max-age=31536000, immutable', // Cache for 1 year
168
+ 'Content-Disposition': `inline; filename="${encodeURIComponent(asset.originalFilename || asset.filename)}"`,
169
+ ...(asset.mimeType?.startsWith('image/') && {
170
+ 'Accept-Ranges': 'bytes'
171
+ })
172
+ });
173
+
174
+ // Convert Buffer to ArrayBuffer for Response
175
+ const arrayBuffer = fileBuffer.buffer.slice(
176
+ fileBuffer.byteOffset,
177
+ fileBuffer.byteOffset + fileBuffer.byteLength
178
+ ) as ArrayBuffer;
179
+
180
+ return new Response(arrayBuffer);
181
+ } catch (error) {
182
+ console.error('[Asset CDN] Error serving asset:', error);
183
+ return new Response('Failed to serve asset', { status: 500 });
184
+ }
185
+ };
@@ -0,0 +1,116 @@
1
+ // Aphex CMS Asset API Handlers
2
+ import { json } from '@sveltejs/kit';
3
+ import type { RequestHandler } from '@sveltejs/kit';
4
+
5
+ export const POST: RequestHandler = async ({ request, locals }) => {
6
+ try {
7
+ const { assetService } = locals.aphexCMS;
8
+ const auth = locals.auth;
9
+
10
+ if (!auth) {
11
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
12
+ }
13
+
14
+ const formData = await request.formData();
15
+ const file = formData.get('file') as File;
16
+
17
+ if (!file) {
18
+ return json({ success: false, error: 'No file provided' }, { status: 400 });
19
+ }
20
+
21
+ // Convert file to buffer
22
+ const arrayBuffer = await file.arrayBuffer();
23
+ const buffer = Buffer.from(arrayBuffer);
24
+
25
+ // Get optional metadata from form data
26
+ const title = (formData.get('title') as string) || undefined;
27
+ const description = (formData.get('description') as string) || undefined;
28
+ const alt = (formData.get('alt') as string) || undefined;
29
+ const creditLine = (formData.get('creditLine') as string) || undefined;
30
+
31
+ // Get field metadata for privacy checking
32
+ const schemaType = (formData.get('schemaType') as string) || undefined;
33
+ const fieldPath = (formData.get('fieldPath') as string) || undefined;
34
+
35
+ // Create asset upload data
36
+ const uploadData = {
37
+ buffer,
38
+ originalFilename: file.name,
39
+ mimeType: file.type,
40
+ size: file.size,
41
+ title,
42
+ description,
43
+ alt,
44
+ creditLine,
45
+ createdBy: auth.type === 'session' ? auth.user.id : undefined,
46
+ metadata: {
47
+ schemaType,
48
+ fieldPath
49
+ }
50
+ };
51
+
52
+ // Upload asset using the service
53
+ const asset = await assetService.uploadAsset(auth.organizationId, uploadData);
54
+
55
+ return json({
56
+ success: true,
57
+ data: asset
58
+ });
59
+ } catch (error) {
60
+ console.error('Asset upload failed:', error);
61
+ return json(
62
+ {
63
+ success: false,
64
+ error: 'Asset upload failed',
65
+ message: error instanceof Error ? error.message : 'Unknown error'
66
+ },
67
+ { status: 500 }
68
+ );
69
+ }
70
+ };
71
+
72
+ export const GET: RequestHandler = async ({ url, locals }) => {
73
+ try {
74
+ const { assetService } = locals.aphexCMS;
75
+ const auth = locals.auth;
76
+
77
+ if (!auth) {
78
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
79
+ }
80
+
81
+ // Parse query parameters
82
+ const assetType = url.searchParams.get('assetType') as 'image' | 'file' | undefined;
83
+ const mimeType = url.searchParams.get('mimeType') || undefined;
84
+ const search = url.searchParams.get('search') || undefined;
85
+ const limitParam = url.searchParams.get('limit');
86
+ const offsetParam = url.searchParams.get('offset');
87
+
88
+ const limit = limitParam ? parseInt(limitParam) : 20;
89
+ const offset = offsetParam ? parseInt(offsetParam) : 0;
90
+
91
+ const filters = {
92
+ assetType,
93
+ mimeType,
94
+ search,
95
+ limit: isNaN(limit) ? 20 : limit,
96
+ offset: isNaN(offset) ? 0 : offset
97
+ };
98
+
99
+ const assets = await assetService.findAssets(auth.organizationId, filters);
100
+
101
+ return json({
102
+ success: true,
103
+ data: assets
104
+ });
105
+ } catch (error) {
106
+ console.error('Failed to fetch assets:', error);
107
+ return json(
108
+ {
109
+ success: false,
110
+ error: 'Failed to fetch assets',
111
+ message: error instanceof Error ? error.message : 'Unknown error'
112
+ },
113
+ { status: 500 }
114
+ );
115
+ }
116
+ };
@@ -0,0 +1,188 @@
1
+ // Aphex CMS Document by ID API Handlers
2
+ import { json } from '@sveltejs/kit';
3
+ import type { RequestHandler } from '@sveltejs/kit';
4
+ import type { Document } from '../types/document';
5
+ import { canWrite } from '../types/auth';
6
+
7
+ // GET /api/documents/[id] - Get document by ID
8
+ export const GET: RequestHandler = async ({ params, url, locals }) => {
9
+ try {
10
+ const { databaseAdapter, auth: authProvider } = locals.aphexCMS;
11
+ const auth = locals.auth;
12
+ const { id } = params;
13
+
14
+ if (!auth) {
15
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
16
+ }
17
+
18
+ if (!id) {
19
+ return json({ success: false, error: 'Document ID is required' }, { status: 400 });
20
+ }
21
+
22
+ // Parse depth parameter
23
+ const depthParam = url.searchParams.get('depth');
24
+ const depth = depthParam ? parseInt(depthParam) : 0;
25
+ const clampedDepth = isNaN(depth) ? 0 : Math.max(0, Math.min(depth, 5)); // Clamp between 0-5
26
+
27
+ const document = await databaseAdapter.findByDocId(auth.organizationId, id, clampedDepth);
28
+
29
+ if (!document) {
30
+ return json({ success: false, error: 'Document not found' }, { status: 404 });
31
+ }
32
+
33
+ // Populate createdBy user info if available
34
+ if (document.createdBy && authProvider) {
35
+ try {
36
+ if (typeof document.createdBy === 'string') {
37
+ const user = await authProvider.getUserById(document.createdBy);
38
+ if (user) {
39
+ document.createdBy = {
40
+ id: user.id,
41
+ name: user.name,
42
+ email: user.email
43
+ };
44
+ }
45
+ }
46
+ } catch (err) {
47
+ // If user fetch fails, keep the user ID
48
+ console.warn('[documents-by-id] Failed to populate createdBy user:', err);
49
+ }
50
+ }
51
+
52
+ return json({
53
+ success: true,
54
+ data: document
55
+ });
56
+ } catch (error) {
57
+ console.error('Failed to fetch document:', error);
58
+ return json(
59
+ {
60
+ success: false,
61
+ error: 'Failed to fetch document',
62
+ message: error instanceof Error ? error.message : 'Unknown error'
63
+ },
64
+ { status: 500 }
65
+ );
66
+ }
67
+ };
68
+
69
+ // PUT /api/documents/[id] - Update document
70
+ export const PUT: RequestHandler = async ({ params, request, locals }) => {
71
+ try {
72
+ const { databaseAdapter } = locals.aphexCMS;
73
+ const auth = locals.auth;
74
+ const { id } = params;
75
+ const body = await request.json();
76
+
77
+ if (!auth) {
78
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
79
+ }
80
+
81
+ // Check write permissions (viewers are read-only)
82
+ if (!canWrite(auth)) {
83
+ return json(
84
+ {
85
+ success: false,
86
+ error: 'Forbidden',
87
+ message: 'You do not have permission to update documents. Viewers have read-only access.'
88
+ },
89
+ { status: 403 }
90
+ );
91
+ }
92
+
93
+ const documentData = body.draftData;
94
+
95
+ if (!id) {
96
+ return json({ success: false, error: 'Document ID is required' }, { status: 400 });
97
+ }
98
+
99
+ let updatedDocument: Document | null;
100
+
101
+ // NO VALIDATION FOR DRAFTS - Sanity-style: drafts can have any state
102
+ // Validation only happens on publish
103
+ if (auth.type == 'session') {
104
+ updatedDocument = await databaseAdapter.updateDocDraft(
105
+ auth.organizationId,
106
+ id,
107
+ documentData,
108
+ auth.user.id
109
+ );
110
+ } else {
111
+ updatedDocument = await databaseAdapter.updateDocDraft(
112
+ auth.organizationId,
113
+ id,
114
+ documentData,
115
+ auth.keyId
116
+ );
117
+ }
118
+
119
+ if (!updatedDocument) {
120
+ return json({ success: false, error: 'Document not found' }, { status: 404 });
121
+ }
122
+
123
+ return json({
124
+ success: true,
125
+ data: updatedDocument
126
+ });
127
+ } catch (error) {
128
+ console.error('Failed to update document:', error);
129
+ return json(
130
+ {
131
+ success: false,
132
+ error: 'Failed to update document',
133
+ message: error instanceof Error ? error.message : 'Unknown error'
134
+ },
135
+ { status: 500 }
136
+ );
137
+ }
138
+ };
139
+
140
+ // DELETE /api/documents/[id] - Delete document
141
+ export const DELETE: RequestHandler = async ({ params, locals }) => {
142
+ try {
143
+ const { databaseAdapter } = locals.aphexCMS;
144
+ const auth = locals.auth;
145
+ const { id } = params;
146
+
147
+ if (!auth) {
148
+ return json({ success: false, error: 'Unauthorized' }, { status: 401 });
149
+ }
150
+
151
+ // Check write permissions (viewers are read-only)
152
+ if (!canWrite(auth)) {
153
+ return json(
154
+ {
155
+ success: false,
156
+ error: 'Forbidden',
157
+ message: 'You do not have permission to delete documents. Viewers have read-only access.'
158
+ },
159
+ { status: 403 }
160
+ );
161
+ }
162
+
163
+ if (!id) {
164
+ return json({ success: false, error: 'Document ID is required' }, { status: 400 });
165
+ }
166
+
167
+ const success = await databaseAdapter.deleteDocById(auth.organizationId, id);
168
+
169
+ if (!success) {
170
+ return json({ success: false, error: 'Document not found' }, { status: 404 });
171
+ }
172
+
173
+ return json({
174
+ success: true,
175
+ message: 'Document deleted successfully'
176
+ });
177
+ } catch (error) {
178
+ console.error('Failed to delete document:', error);
179
+ return json(
180
+ {
181
+ success: false,
182
+ error: 'Failed to delete document',
183
+ message: error instanceof Error ? error.message : 'Unknown error'
184
+ },
185
+ { status: 500 }
186
+ );
187
+ }
188
+ };
@@ -0,0 +1,211 @@
1
+ // Aphex CMS Document Publish API Handlers
2
+ import { json } from '@sveltejs/kit';
3
+ import type { RequestHandler } from '@sveltejs/kit';
4
+ import { validateField } from '../field-validation/utils';
5
+ import { canWrite } from '../types/auth';
6
+
7
+ // POST /api/documents/[id]/publish - Publish document
8
+ export const POST: RequestHandler = async ({ params, locals }) => {
9
+ try {
10
+ const { databaseAdapter, cmsEngine } = locals.aphexCMS;
11
+ const auth = locals.auth;
12
+ const { id } = params;
13
+
14
+ if (!auth) {
15
+ return json(
16
+ {
17
+ success: false,
18
+ error: 'Unauthorized',
19
+ message: 'Authentication required'
20
+ },
21
+ { status: 401 }
22
+ );
23
+ }
24
+
25
+ // Check write permissions (viewers are read-only)
26
+ if (!canWrite(auth)) {
27
+ return json(
28
+ {
29
+ success: false,
30
+ error: 'Forbidden',
31
+ message: 'You do not have permission to publish documents. Viewers have read-only access.'
32
+ },
33
+ { status: 403 }
34
+ );
35
+ }
36
+
37
+ if (!id) {
38
+ return json(
39
+ {
40
+ success: false,
41
+ error: 'Missing document ID',
42
+ message: 'Document ID is required'
43
+ },
44
+ { status: 400 }
45
+ );
46
+ }
47
+
48
+ // Get document to validate
49
+ const document = await databaseAdapter.findByDocId(auth.organizationId, id);
50
+ if (!document || !document.draftData) {
51
+ return json(
52
+ {
53
+ success: false,
54
+ error: 'Document not found or cannot be published',
55
+ message: 'Document may not exist or may not have draft content'
56
+ },
57
+ { status: 404 }
58
+ );
59
+ }
60
+
61
+ // Get schema for validation (from config to preserve validation functions)
62
+ const schema = cmsEngine.getSchemaTypeByName(document.type);
63
+ if (!schema) {
64
+ return json(
65
+ {
66
+ success: false,
67
+ error: 'Invalid document type',
68
+ message: `Schema type '${document.type}' not found`
69
+ },
70
+ { status: 400 }
71
+ );
72
+ }
73
+
74
+ // VALIDATE before publishing - block if errors exist
75
+ const validationErrors: Array<{ field: string; errors: string[] }> = [];
76
+
77
+ for (const field of schema.fields) {
78
+ const value = document.draftData[field.name];
79
+ const result = await validateField(field, value, document.draftData);
80
+
81
+ if (!result.isValid) {
82
+ const errorMessages = result.errors
83
+ .filter((e) => e.level === 'error')
84
+ .map((e) => e.message);
85
+
86
+ if (errorMessages.length > 0) {
87
+ validationErrors.push({
88
+ field: field.name,
89
+ errors: errorMessages
90
+ });
91
+ }
92
+ }
93
+ }
94
+
95
+ // Block publishing if validation errors exist
96
+ if (validationErrors.length > 0) {
97
+ return json(
98
+ {
99
+ success: false,
100
+ error: 'Cannot publish: validation errors',
101
+ message: 'Please fix all validation errors before publishing',
102
+ validationErrors
103
+ },
104
+ { status: 400 }
105
+ );
106
+ }
107
+
108
+ // All validation passed - proceed with publish
109
+ const publishedDocument = await databaseAdapter.publishDoc(auth.organizationId, id);
110
+
111
+ if (!publishedDocument) {
112
+ return json(
113
+ {
114
+ success: false,
115
+ error: 'Document not found or cannot be published',
116
+ message: 'Document may not exist or may not have draft content'
117
+ },
118
+ { status: 404 }
119
+ );
120
+ }
121
+
122
+ return json({
123
+ success: true,
124
+ data: publishedDocument,
125
+ message: 'Document published successfully'
126
+ });
127
+ } catch (error) {
128
+ console.error('Failed to publish document:', error);
129
+ return json(
130
+ {
131
+ success: false,
132
+ error: 'Failed to publish document',
133
+ message: error instanceof Error ? error.message : 'Unknown error'
134
+ },
135
+ { status: 500 }
136
+ );
137
+ }
138
+ };
139
+
140
+ // DELETE /api/documents/[id]/publish - Unpublish document
141
+ export const DELETE: RequestHandler = async ({ params, locals }) => {
142
+ try {
143
+ const { databaseAdapter } = locals.aphexCMS;
144
+ const auth = locals.auth;
145
+ const { id } = params;
146
+
147
+ if (!auth) {
148
+ return json(
149
+ {
150
+ success: false,
151
+ error: 'Unauthorized',
152
+ message: 'Authentication required'
153
+ },
154
+ { status: 401 }
155
+ );
156
+ }
157
+
158
+ // Check write permissions (viewers are read-only)
159
+ if (!canWrite(auth)) {
160
+ return json(
161
+ {
162
+ success: false,
163
+ error: 'Forbidden',
164
+ message:
165
+ 'You do not have permission to unpublish documents. Viewers have read-only access.'
166
+ },
167
+ { status: 403 }
168
+ );
169
+ }
170
+
171
+ if (!id) {
172
+ return json(
173
+ {
174
+ success: false,
175
+ error: 'Missing document ID',
176
+ message: 'Document ID is required'
177
+ },
178
+ { status: 400 }
179
+ );
180
+ }
181
+
182
+ const unpublishedDocument = await databaseAdapter.unpublishDoc(auth.organizationId, id);
183
+
184
+ if (!unpublishedDocument) {
185
+ return json(
186
+ {
187
+ success: false,
188
+ error: 'Document not found',
189
+ message: `No document found with ID: ${id}`
190
+ },
191
+ { status: 404 }
192
+ );
193
+ }
194
+
195
+ return json({
196
+ success: true,
197
+ data: unpublishedDocument,
198
+ message: 'Document unpublished successfully'
199
+ });
200
+ } catch (error) {
201
+ console.error('Failed to unpublish document:', error);
202
+ return json(
203
+ {
204
+ success: false,
205
+ error: 'Failed to unpublish document',
206
+ message: error instanceof Error ? error.message : 'Unknown error'
207
+ },
208
+ { status: 500 }
209
+ );
210
+ }
211
+ };